diff --git a/.ci/linux-steps.yaml b/.ci/linux-steps.yaml index f695c14fe1..cab07dc8bb 100644 --- a/.ci/linux-steps.yaml +++ b/.ci/linux-steps.yaml @@ -21,7 +21,7 @@ steps: unset BOOST_ROOT echo "##vso[task.setvariable variable=BOOST_ROOT]"$BOOST_ROOT - sudo apt-get install -y --allow-unauthenticated libopenblas-dev g++ libboost1.70-dev xz-utils + sudo apt-get install -y --allow-unauthenticated libopenblas-dev g++ libboost-all-dev xz-utils if [ "$(binding)" == "python" ]; then export PYBIN=$(which python) @@ -41,7 +41,7 @@ steps: # Install cereal. wget https://github.com/USCiLab/cereal/archive/v1.3.0.tar.gz tar -xvzpf v1.3.0.tar.gz # Unpack into cereal-1.3.0/. - cd cereal-1.3.0/ + displayName: 'Install Build Dependencies' # Configure mlpack (CMake) @@ -56,12 +56,12 @@ steps: displayName: 'CMake' # Build mlpack -- script: cd build && make +- script: cd build && make && make mlpack_test condition: eq(variables['CMakeArgs'], '-DDEBUG=ON -DPROFILE=OFF -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF') displayName: 'Build' # Build mlpack -- script: cd build && make -j2 +- script: cd build && make -j2 && make -j2 mlpack_test condition: ne(variables['CMakeArgs'], '-DDEBUG=ON -DPROFILE=OFF -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF') displayName: 'Build' diff --git a/.ci/macos-steps.yaml b/.ci/macos-steps.yaml index ce3c7796f5..48b15863a9 100644 --- a/.ci/macos-steps.yaml +++ b/.ci/macos-steps.yaml @@ -45,7 +45,7 @@ steps: displayName: 'CMake' # Build mlpack -- script: cd build && make -j2 +- script: cd build && make -j2 && make -j2 mlpack_test displayName: 'Build' # Run tests via ctest. @@ -65,4 +65,4 @@ steps: inputs: pathtoPublish: 'build/Testing/' artifactName: 'Tests' - displayName: 'Publish artifacts test results' \ No newline at end of file + displayName: 'Publish artifacts test results' diff --git a/.ci/windows-steps.yaml b/.ci/windows-steps.yaml index e2a9ed38e0..a6793997e6 100644 --- a/.ci/windows-steps.yaml +++ b/.ci/windows-steps.yaml @@ -88,6 +88,7 @@ steps: # Run tests via ctest. - bash: | cd build + cmake --build . --target mlpack_test -C Release CTEST_OUTPUT_ON_FAILURE=1 ctest -T Test -C Release . -j1 displayName: 'Run tests via ctest' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9fa25191a6..a9a2574072 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -68,7 +68,7 @@ jobs: - name: Build run: | - cd build && make -j2 + cd build && make -j2 && make -j2 mlpack_test - name: Run tests via ctest run: | diff --git a/CMake/Autodownload.cmake b/CMake/Autodownload.cmake new file mode 100644 index 0000000000..b82ab001b9 --- /dev/null +++ b/CMake/Autodownload.cmake @@ -0,0 +1,56 @@ +## This function auto-downloads mlpack dependencies. +## You need to pass the LINK to download from, the name of +## the dependency, and the name of the compressed package such as +## armadillo.tar.gz +## At each download, this module sets a GENERIC_INCLUDE_DIR path, +## which means that you need to set the main path for the include +## directories for each package. +## Note that, the package should be compressed only as .tar.gz + +macro(get_deps LINK DEPS_NAME PACKAGE) + if (NOT EXISTS "${CMAKE_BINARY_DIR}/deps/${PACKAGE}") + file(DOWNLOAD ${LINK} + "${CMAKE_BINARY_DIR}/deps/${PACKAGE}" + STATUS DOWNLOAD_STATUS_LIST LOG DOWNLOAD_LOG + SHOW_PROGRESS) + list(GET DOWNLOAD_STATUS_LIST 0 DOWNLOAD_STATUS) + if (DOWNLOAD_STATUS EQUAL 0) + execute_process(COMMAND ${CMAKE_COMMAND} -E + tar xf "${CMAKE_BINARY_DIR}/deps/${PACKAGE}" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/deps/") + else () + list(GET DOWNLOAD_STATUS_LIST 1 DOWNLOAD_ERROR) + message(FATAL_ERROR + "Could not download ${DEPS_NAME}! Error code ${DOWNLOAD_STATUS}: ${DOWNLOAD_ERROR}! Error log: ${DOWNLOAD_LOG}") + endif() + endif() + # Get the name of the directory. + file (GLOB DIRECTORIES RELATIVE "${CMAKE_BINARY_DIR}/deps/" + "${CMAKE_BINARY_DIR}/deps/${DEPS_NAME}*.*") + # Clean this line when boost is removed. + if (${DEPS_NAME} MATCHES "boost") + file (GLOB DIRECTORIES RELATIVE "${CMAKE_BINARY_DIR}/deps/" + "${CMAKE_BINARY_DIR}/deps/${DEPS_NAME}*_*") + elseif(${DEPS_NAME} MATCHES "stb") + file (GLOB DIRECTORIES RELATIVE "${CMAKE_BINARY_DIR}/deps/" + "${CMAKE_BINARY_DIR}/deps/${DEPS_NAME}") + endif() + # list(FILTER) is not available on 3.5 or older, but try to keep + # configuring without filtering the list anyway + # (it works only if the file is present as .tar.gz). + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.6.0") + list(FILTER DIRECTORIES EXCLUDE REGEX ".*\.tar\.gz") + endif () + list(LENGTH DIRECTORIES DIRECTORIES_LEN) + if (DIRECTORIES_LEN GREATER 0) + list(GET DIRECTORIES 0 DEPENDENCY_DIR) + set(GENERIC_INCLUDE_DIR "${CMAKE_BINARY_DIR}/deps/${DEPENDENCY_DIR}/include") + # Clean this line when boost is removed. + if (${DEPS_NAME} MATCHES "boost") + set(Boost_INCLUDE_DIR "${CMAKE_BINARY_DIR}/deps/${DEPENDENCY_DIR}/") + endif() + else () + message(FATAL_ERROR + "Problem unpacking ${DEPS_NAME}! Expected only one directory ${DEPS_NAME};. Try to remove the directory ${CMAKE_BINARY_DIR}/deps and reconfigure.") + endif () +endmacro() diff --git a/CMake/ConfigureCrossCompile.cmake b/CMake/ConfigureCrossCompile.cmake new file mode 100644 index 0000000000..75e28bc453 --- /dev/null +++ b/CMake/ConfigureCrossCompile.cmake @@ -0,0 +1,44 @@ +# This file adds the necessary configurations to cross compile +# mlpack for embedded systems. You need to set the following variables +# from the command line: CMAKE_SYSROOT and TOOLCHAIN_PREFIX. +# This file will compile OpenBLAS if it is downloaded and it is not +# available on your system in order to find the BLAS library. If OpenBLAS will +# be compiled, the OPENBLAS_TARGET variable must be set. This can be done +# by, e.g., setting BOARD_NAME (which will set OPENBLAS_TARGET in +# `board/flags-config.cmake`). + +if (CMAKE_CROSSCOMPILING) + include(board/flags-config.cmake) + if (NOT CMAKE_SYSROOT AND (NOT TOOLCHAIN_PREFIX)) + message(FATAL_ERROR "Neither CMAKE_SYSROOT nor TOOLCHAIN_PREFIX are set; please set both of them and try again.") + elseif(NOT CMAKE_SYSROOT) + message(FATAL_ERROR "Cannot configure: CMAKE_SYSROOT must be set when performing cross-compiling!") + elseif(NOT TOOLCHAIN_PREFIX) + message(FATAL_ERROR "Cannot configure: TOOLCHAIN_PREFIX must be set when performing cross-compiling!") + endif() +endif() + +macro(search_openblas version) + set(BLA_STATIC ON) + find_package(BLAS) + if (NOT BLAS_FOUND OR (NOT BLAS_LIBRARIES)) + if(NOT OPENBLAS_TARGET) + message(FATAL_ERROR "Cannot compile OpenBLAS: OPENBLAS_TARGET is not set. Either set that variable, or set BOARD_NAME correctly!") + endif() + get_deps(https://github.com/xianyi/OpenBLAS/releases/download/v${version}/OpenBLAS-${version}.tar.gz OpenBLAS OpenBLAS-${version}.tar.gz) + if (NOT MSVC) + if (NOT EXISTS "${CMAKE_BINARY_DIR}/deps/OpenBLAS-${version}/libopenblas.a") + execute_process(COMMAND make TARGET=${OPENBLAS_TARGET} BINARY=${OPENBLAS_BINARY} HOSTCC=gcc CC=${CMAKE_C_COMPILER} FC=${CMAKE_FORTRAN_COMPILER} NO_SHARED=1 + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/deps/OpenBLAS-${version}) + endif() + file(GLOB OPENBLAS_LIBRARIES "${CMAKE_BINARY_DIR}/deps/OpenBLAS-${version}/libopenblas.a") + set(BLAS_openblas_LIBRARY ${OPENBLAS_LIBRARIES}) + set(LAPACK_openblas_LIBRARY ${OPENBLAS_LIBRARIES}) + set(BLA_VENDOR OpenBLAS) + set(BLAS_FOUND ON) + endif() + endif() + find_library(GFORTRAN NAMES libgfortran.a) + find_library(PTHREAD NAMES libpthread.a) + set(COMPILER_SUPPORT_LIBRARIES ${COMPILER_SUPPORT_LIBRARIES} ${GFORTRAN} ${PTHREAD}) +endmacro() diff --git a/CMake/FindArmadillo.cmake b/CMake/FindArmadillo.cmake index c684963f70..3d696b0abb 100644 --- a/CMake/FindArmadillo.cmake +++ b/CMake/FindArmadillo.cmake @@ -77,13 +77,14 @@ else() # don't link to armadillo in this case set(ARMADILLO_LIBRARY "") endif() + # Link to support libraries in either case on MSVC. if(NOT _ARMA_USE_WRAPPER OR MSVC) if(_ARMA_USE_LAPACK) if(ARMADILLO_FIND_QUIETLY OR NOT ARMADILLO_FIND_REQUIRED) find_package(LAPACK QUIET) else() - find_package(LAPCK REQUIRED) + find_package(LAPACK REQUIRED) endif() if(LAPACK_FOUND) set(_ARMA_SUPPORT_LIBRARIES "${_ARMA_SUPPORT_LIBRARIES}" "${LAPACK_LIBRARIES}") @@ -154,5 +155,6 @@ unset(__ARMA_SUPPORT_INCLUDE_DIRS) # Hide internal variables mark_as_advanced( - ARMADILLO_INCLUDE_DIR - ARMADILLO_LIBRARY) + ARMADILLO_INCLUDE_DIR + ARMADILLO_LIBRARY + ARMADILLO_LIBRARIES) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0aa70cb74a..daf416f5e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,8 @@ project(mlpack C CXX) include(CMake/cotire.cmake) include(CMake/CheckHash.cmake) +include(CMake/Autodownload.cmake) +include(CMake/ConfigureCrossCompile.cmake) # First, define all the compilation options. # We default to debugging mode for developers. @@ -24,15 +26,29 @@ set(ENSMALLEN_VERSION "2.10.0") set(BOOST_VERSION "1.58") set(CEREAL_VERSION "1.1.2") +# If BUILD_SHARED_LIBS is OFF then the mlpack library will be built statically. +# In addition, all mlpack CLI bindings will be linked statically as well. if (WIN32) option(BUILD_SHARED_LIBS - "Compile shared libraries (if OFF, static libraries are compiled)." OFF) + "Compile shared libraries (if OFF, static libraries and binaries are compiled)." OFF) set(DLL_COPY_DIRS "" CACHE STRING "List of directories (separated by ';') containing DLLs to copy for runtime.") set(DLL_COPY_LIBS "" CACHE STRING "List of DLLs (separated by ';') that should be copied for runtime.") -else () +elseif(CMAKE_CROSSCOMPILING) option(BUILD_SHARED_LIBS - "Compile shared libraries (if OFF, static libraries are compiled)." ON) + "Compile shared libraries (if OFF, static libraries and binaries are compiled)." OFF) +else() + option(BUILD_SHARED_LIBS + "Compile shared libraries (if OFF, static libraries and binaries are compiled)." ON) +endif() + +# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES. +if (NOT BUILD_SHARED_LIBS) + if(WIN32) + list(INSERT CMAKE_FIND_LIBRARY_SUFFIXES 0 .lib .a) + else() + set(CMAKE_FIND_LIBRARY_SUFFIXES .a) + endif() endif() # Detect whether the user passed BUILD_PYTHON_BINDINGS in order to determine if @@ -93,12 +109,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) # Include modules in the CMake directory. set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMake") -# Disable any downloads if needed. -if (DISABLE_DOWNLOADS) - set(DOWNLOAD_ENSMALLEN OFF) - set(DOWNLOAD_STB_IMAGE OFF) -endif () - # If we are on a Unix-like system, use the GNU install directories module. # Otherwise set the values manually. if (UNIX) @@ -112,12 +122,12 @@ else () endif () # This is as of yet unused. -#option(PGO "Use profile-guided optimization if not a debug build" ON) +# option(PGO "Use profile-guided optimization if not a debug build" ON) # Set the CFLAGS and CXXFLAGS depending on the options the user specified. # Only GCC-like compilers support -Wextra, and other compilers give tons of # output for -Wall, so only -Wall and -Wextra on GCC. -if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") +if (CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # Ensure that we can't compile with clang 3.4, since this causes strange # issues. if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5) @@ -144,7 +154,7 @@ endif () # If we are using MINGW, we need sections and big-obj, otherwise we create too # many sections. -if(CMAKE_COMPILER_IS_GNUCC AND WIN32) +if (CMAKE_COMPILER_IS_GNUCC AND WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections -Wa,-mbig-obj") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections -Wa,-mbig-obj") endif() @@ -153,7 +163,7 @@ endif() # OS (at least on some systems). Further, gcc sometimes optimizes calls to # math.h functions, making -lm unnecessary with gcc, but it may still be # necessary with clang. -if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") if (APPLE) # Detect OS X version. Use '/usr/bin/sw_vers -productVersion' to # extract V from '10.V.x'. @@ -166,7 +176,7 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # OSX Lion (10.7) and OS X Mountain Lion (10.8) doesn't automatically # select the right stdlib. - if(${MACOSX_VERSION} LESS 9) + if (${MACOSX_VERSION} LESS 9) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -stdlib=libc++") @@ -187,14 +197,14 @@ endif() # If we're using gcc, then we need to link against pthreads to use std::thread, # which we do in the tests. -if(CMAKE_COMPILER_IS_GNUCC) +if (CMAKE_COMPILER_IS_GNUCC) find_package(Threads) set(COMPILER_SUPPORT_LIBRARIES ${COMPILER_SUPPORT_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) endif() # Debugging CFLAGS. Turn optimizations off; turn debugging symbols on. -if(DEBUG) +if (DEBUG) if (NOT MSVC) add_definitions(-DDEBUG) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -ftemplate-backtrace-limit=0") @@ -203,10 +213,10 @@ if(DEBUG) # mlpack uses it's own mlpack::backtrace class based on Binary File Descriptor # and linux Dynamic Loader and more portable version in future - if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + if (CMAKE_SYSTEM_NAME STREQUAL "Linux") find_package(Bfd) find_package(LibDL) - if(LIBBFD_FOUND AND LIBDL_FOUND) + if (LIBBFD_FOUND AND LIBDL_FOUND) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic") set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${LIBBFD_INCLUDE_DIRS} ${LIBDL_INCLUDE_DIRS}) @@ -230,19 +240,19 @@ else() endif() # Profiling CFLAGS. Turn profiling information on. -if(CMAKE_COMPILER_IS_GNUCC AND PROFILE) +if (CMAKE_COMPILER_IS_GNUCC AND PROFILE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg") endif() # If the user asked for running test cases with verbose output, turn that on. -if(TEST_VERBOSE) +if (TEST_VERBOSE) add_definitions(-DTEST_VERBOSE) endif() # If the user asked for extra Armadillo debugging output, turn that on. -if(ARMA_EXTRA_DEBUG) +if (ARMA_EXTRA_DEBUG) add_definitions(-DARMA_EXTRA_DEBUG) endif() @@ -254,131 +264,73 @@ endif() # ARMADILLO_INCLUDE_DIRS - directories necessary for Armadillo includes # BOOST_ROOT - root of Boost installation # BOOST_INCLUDEDIR - include directory for Boost +# CEREAL_INCLUDE_DIR - include directory for cereal # ENSMALLEN_INCLUDE_DIR - include directory for ensmallen # STB_IMAGE_INCLUDE_DIR - include directory for STB image library # MATHJAX_ROOT - root of MathJax installation -find_package(Armadillo "${ARMADILLO_VERSION}" REQUIRED) +# Download and compile OpenBLAS if we are cross compiling mlpack for a specific +# architecture. The function takes the version of OpenBLAS as variable. +if (CMAKE_CROSSCOMPILING) + search_openblas(0.3.13) +endif() + +if (DISABLE_DOWNLOADS) + find_package(Armadillo "${ARMADILLO_VERSION}" REQUIRED) +else() + find_package(Armadillo "${ARMADILLO_VERSION}") + if (NOT ARMADILLO_FOUND) + get_deps(http://files.mlpack.org/armadillo-10.3.0.tar.gz armadillo armadillo-10.3.0.tar.gz) + set(ARMADILLO_INCLUDE_DIR ${GENERIC_INCLUDE_DIR}) + find_package(Armadillo REQUIRED) + endif() +endif() # Include directories for the previous dependencies. set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${ARMADILLO_INCLUDE_DIRS}) set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${ARMADILLO_LIBRARIES}) # Find stb_image.h and stb_image_write.h. -find_package(StbImage) -# Download stb_image for image loading. -if (NOT STB_IMAGE_FOUND) - if (DOWNLOAD_STB_IMAGE) - set(STB_DIR "stb") - install(DIRECTORY DESTINATION "${CMAKE_BINARY_DIR}/deps/${STB_DIR}") - file(DOWNLOAD http://mlpack.org/files/stb-2.22/stb_image.h - "${CMAKE_BINARY_DIR}/deps/${STB_DIR}/stb_image.h" - STATUS STB_IMAGE_DOWNLOAD_STATUS_LIST LOG STB_IMAGE_DOWNLOAD_LOG - SHOW_PROGRESS) - list(GET STB_IMAGE_DOWNLOAD_STATUS_LIST 0 STB_IMAGE_DOWNLOAD_STATUS) - file(DOWNLOAD http://mlpack.org/files/stb-1.13/stb_image_write.h - "${CMAKE_BINARY_DIR}/deps/${STB_DIR}/stb_image_write.h" - STATUS STB_IMAGE_WRITE_DOWNLOAD_STATUS_LIST - LOG STB_IMAGE_WRITE_DOWNLOAD_LOG - SHOW_PROGRESS) - list(GET STB_IMAGE_WRITE_DOWNLOAD_STATUS_LIST 0 - STB_IMAGE_WRITE_DOWNLOAD_STATUS) - if (STB_IMAGE_DOWNLOAD_STATUS EQUAL 0 AND - STB_IMAGE_WRITE_DOWNLOAD_STATUS EQUAL 0) - check_hash (http://mlpack.org/files/stb/hash.md5 "${CMAKE_BINARY_DIR}/deps/${STB_DIR}" - HASH_CHECK_FAIL) - if (HASH_CHECK_FAIL EQUAL 0) - set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} - "${CMAKE_BINARY_DIR}/deps/${STB_DIR}/") - message(STATUS - "Successfully downloaded stb into ${CMAKE_BINARY_DIR}/deps/${STB_DIR}/") - # Now we have to also ensure these header files get installed. - install(FILES "${CMAKE_BINARY_DIR}/deps/${STB_DIR}/stb_image.h" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") - install(FILES "${CMAKE_BINARY_DIR}/deps/${STB_DIR}/stb_image_write.h" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") - add_definitions(-DHAS_STB) - set(STB_AVAILABLE "1") - else () - message(WARNING - "stb/stb_image.h is not installed. Image utilities will not be available!") - endif () - else () - file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/deps/${STB_DIR}/") - list(GET STB_IMAGE_DOWNLOAD_STATUS_LIST 1 STB_DOWNLOAD_ERROR) - message(WARNING - "Could not download stb! Error code ${STB_DOWNLOAD_STATUS}: ${STB_DOWNLOAD_ERROR}! Error log: ${STB_DOWNLOAD_LOG}") - message(WARNING - "stb/stb_image.h is not installed. Image utilities will not be available!") - endif () - else () - message(WARNING - "stb/stb_image.h is not installed. Image utilities will not be available!") - endif () -else () - # Already has STB installed. +if (DISABLE_DOWNLOADS) + find_package(StbImage) +else() + find_package(StbImage) + if (NOT STB_IMAGE_FOUND) + get_deps(http://mlpack.org/files/stb.tar.gz stb stb.tar.gz) + set(STB_IMAGE_INCLUDE_DIR ${GENERIC_INCLUDE_DIR}) + find_package(StbImage REQUIRED) + endif() +endif() + +if (STB_IMAGE_FOUND) add_definitions(-DHAS_STB) - set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${STB_IMAGE_INCLUDE_DIR}) set(STB_AVAILABLE "1") -endif () +endif() +set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} "${STB_IMAGE_INCLUDE_DIR}") # Find ensmallen. -# Once ensmallen is readily available in package repos, the automatic downloader -# here can be removed. -find_package(Ensmallen "${ENSMALLEN_VERSION}") -if (NOT ENSMALLEN_FOUND) - if (DOWNLOAD_ENSMALLEN) - file(DOWNLOAD http://www.ensmallen.org/files/ensmallen-latest.tar.gz - "${CMAKE_BINARY_DIR}/deps/ensmallen-latest.tar.gz" - STATUS ENS_DOWNLOAD_STATUS_LIST LOG ENS_DOWNLOAD_LOG - SHOW_PROGRESS) - list(GET ENS_DOWNLOAD_STATUS_LIST 0 ENS_DOWNLOAD_STATUS) - if (ENS_DOWNLOAD_STATUS EQUAL 0) - execute_process(COMMAND ${CMAKE_COMMAND} -E - tar xzf "${CMAKE_BINARY_DIR}/deps/ensmallen-latest.tar.gz" - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/deps/") +if (DISABLE_DOWNLOADS) + find_package(Ensmallen "${ENSMALLEN_VERSION}" REQUIRED) +else() + find_package(Ensmallen "${ENSMALLEN_VERSION}") + if (NOT ENSMALLEN_FOUND) + get_deps(http://www.ensmallen.org/files/ensmallen-latest.tar.gz ensmallen ensmallen-latest.tar.gz) + set(ENSMALLEN_INCLUDE_DIR ${GENERIC_INCLUDE_DIR}) + find_package(Ensmallen REQUIRED) + endif() +endif() +set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} "${ENSMALLEN_INCLUDE_DIR}") - # Get the name of the directory. - file (GLOB ENS_DIRECTORIES RELATIVE "${CMAKE_BINARY_DIR}/deps/" - "${CMAKE_BINARY_DIR}/deps/ensmallen-[0-9]*.[0-9]*.[0-9]*") - # list(FILTER) is not available on 3.5 or older, but try to keep - # configuring without filtering the list anyway (it might work if only - # the file ensmallen-latest.tar.gz is present. - if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.6.0") - list(FILTER ENS_DIRECTORIES EXCLUDE REGEX "ensmallen-.*\.tar\.gz") - endif () - list(LENGTH ENS_DIRECTORIES ENS_DIRECTORIES_LEN) - if (ENS_DIRECTORIES_LEN EQUAL 1) - list(GET ENS_DIRECTORIES 0 ENSMALLEN_INCLUDE_DIR) - set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} - "${CMAKE_BINARY_DIR}/deps/${ENSMALLEN_INCLUDE_DIR}/include") - message(STATUS - "Successfully downloaded ensmallen into ${CMAKE_BINARY_DIR}/deps/${ENSMALLEN_INCLUDE_DIR}/") - - # Now we have to also ensure these header files get installed. - install(DIRECTORY "${CMAKE_BINARY_DIR}/deps/${ENSMALLEN_INCLUDE_DIR}/include/ensmallen_bits/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ensmallen_bits") - install(FILES "${CMAKE_BINARY_DIR}/deps/${ENSMALLEN_INCLUDE_DIR}/include/ensmallen.hpp" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") - else () - message(FATAL_ERROR "Problem unpacking ensmallen! Expected only one directory ensmallen-x.y.z/; found ${ENS_DIRECTORIES}. Try removing the directory ${CMAKE_BINARY_DIR}/deps and reconfiguring.") - endif () - else () - list(GET ENS_DOWNLOAD_STATUS_LIST 1 ENS_DOWNLOAD_ERROR) - message(FATAL_ERROR - "Could not download ensmallen! Error code ${ENS_DOWNLOAD_STATUS}: ${ENS_DOWNLOAD_ERROR}! Error log: ${ENS_DOWNLOAD_LOG}") - endif () - else () - # Release versions will have ensmallen packaged with the release so we can - # just reference that. - if (EXISTS "${CMAKE_SOURCE_DIR}/src/mlpack/core/optimizers/ensmallen/ensmallen.hpp") - set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${ARMADILLO_INCLUDE_DIRS} - "${CMAKE_SOURCE_DIR}/src/mlpack/core/optimizers/ensmallen") - else () - message(FATAL_ERROR - "Cannot find ensmallen headers! Try setting ENSMALLEN_INCLUDE_DIR!") - endif () - endif () -else () - set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} "${ENSMALLEN_INCLUDE_DIR}") -endif () - -find_package(cereal "${CEREAL_VERSION}" REQUIRED) +# Find cereal. +if (DISABLE_DOWNLOADS) + find_package(cereal "${CEREAL_VERSION}" REQUIRED) +else() + find_package(cereal "${CEREAL_VERSION}") + if (NOT CEREAL_FOUND) + get_deps(https://github.com/USCiLab/cereal/archive/refs/tags/v1.3.0.tar.gz cereal cereal-1.3.0.tar.gz) + set(CEREAL_INCLUDE_DIR ${GENERIC_INCLUDE_DIR}) + find_package(cereal REQUIRED) + endif() +endif() set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${CEREAL_INCLUDE_DIR}) # Unfortunately this configuration variable is necessary and will need to be @@ -409,8 +361,15 @@ set(Boost_ADDITIONAL_VERSIONS # TODO for the brave: transition all mlpack's CMake to 'target-based modern # CMake'. Good luck! You'll need it. set(Boost_NO_BOOST_CMAKE 1) -find_package(Boost "${BOOST_VERSION}") - +if (DISABLE_DOWNLOADS) + find_package(Boost "${BOOST_VERSION}" REQUIRED) +else() + find_package(Boost "${BOOST_VERSION}") + if (NOT Boost_FOUND) + get_deps(https://boostorg.jfrog.io/artifactory/main/release/1.76.0/source/boost_1_76_0.tar.gz boost boost_1_76_0.tar.gz) + find_package(Boost REQUIRED) + endif() +endif() set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES}) set(MLPACK_LIBRARY_DIRS ${MLPACK_LIBRARY_DIRS}) @@ -433,7 +392,7 @@ if (OPENMP_FOUND) add_definitions(-DHAS_OPENMP) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - if(OpenMP_CXX_FOUND) + if (OpenMP_CXX_FOUND) set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${OpenMP_CXX_LIBRARIES}) endif () else () diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index b7e9d6cf15..db89c05176 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -143,6 +143,7 @@ Copyright: Copyright 2020, Anmolpreet Singh Copyright 2021, Tru Hoang Copyright 2021, Mark Fischinger + Copyright 2021, Muhammad Fawwaz Mayda License: BSD-3-clause All rights reserved. diff --git a/HISTORY.md b/HISTORY.md index e3c253ec35..f8eb50f377 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -3,6 +3,8 @@ * Added Extra Trees Algorithm (#2883). Currently, it can be used using the * class `mlpack::tree::ExtraTrees`, but only through C++. + * Add Flatten T Swish activation function (`flatten-t-swish.hpp`) + * Added warm start feature to Random Forest (#2881); this feature is accessible from mlpack's bindings to different languages. @@ -49,6 +51,9 @@ * Fix Python binding build when the CMake variable `USE_OPENMP` is set to `OFF` (#2884). + * The `mlpack_test` target is no longer built as part of `make all`. Use + `make mlpack_test` to build the tests. + ### mlpack 3.4.2 ###### 2020-10-26 * Added Mean Absolute Percentage Error. diff --git a/README.md b/README.md index 21b9e09e7e..10f82a2c12 100644 --- a/README.md +++ b/README.md @@ -211,8 +211,8 @@ Options are specified with the -D flag. The allowed options include: BUILD_R_BINDINGS=(ON/OFF): whether or not to build R bindings R_EXECUTABLE=(/path/to/R): Path to specific R executable BUILD_TESTS=(ON/OFF): whether or not to build tests - BUILD_SHARED_LIBS=(ON/OFF): compile shared libraries as opposed to - static libraries + BUILD_SHARED_LIBS=(ON/OFF): compile shared libraries and executables as + opposed to static libraries DISABLE_DOWNLOADS=(ON/OFF): whether to disable all downloads during build DOWNLOAD_ENSMALLEN=(ON/OFF): If ensmallen is not found, download it ENSMALLEN_INCLUDE_DIR=(/path/to/ensmallen/include): path to include directory @@ -224,6 +224,11 @@ Options are specified with the -D flag. The allowed options include: BUILD_DOCS=(ON/OFF): build Doxygen documentation, if Doxygen is available (default ON) +For example, to build mlpack library and CLI bindings statically the following +command can be used: + + $ cmake -D BUILD_SHARED_LIBS=OFF ../ + Other tools can also be used to configure CMake, but those are not documented here. See [this section of the build guide](https://www.mlpack.org/doc/mlpack-git/doxygen/build.html#build_config) for more details, including a full list of options, and their default values. @@ -234,7 +239,7 @@ also be built. OpenMP will be used for parallelization when possible by default. Once CMake is configured, building the library is as simple as typing 'make'. -This will build all library components as well as 'mlpack_test'. +This will build all library components and bindings. $ make @@ -243,6 +248,12 @@ of the build can be specified: $ make mlpack_pca mlpack_knn mlpack_kfn +If you want to build the tests, just make the `mlpack_test` target, and use +`ctest` to run the tests: + + $ make mlpack_test + $ ctest . + If the build fails and you cannot figure out why, register an account on Github and submit an issue. The mlpack developers will quickly help you figure it out: @@ -355,6 +366,9 @@ older versions of mlpack: - [Development Site (Github)](https://www.github.com/mlpack/mlpack/) - [API documentation (Doxygen)](https://www.mlpack.org/doc/mlpack-git/doxygen/index.html) +To learn about the development goals of mlpack in the short- and medium-term +future, see the [vision document](https://www.mlpack.org/papers/vision.pdf). + ### 8. Bug reporting (see also [mlpack help](https://www.mlpack.org/questions.html)) diff --git a/board/crosscompile-toolchain.cmake b/board/crosscompile-toolchain.cmake new file mode 100644 index 0000000000..2b586e1113 --- /dev/null +++ b/board/crosscompile-toolchain.cmake @@ -0,0 +1,40 @@ +## This file handles cross-compilation configurations for aarch64, +## known as arm64. The objective of this file is to find and assign +## cross-compiler and the entire toolchain. +## +## This configuration works best with the buildroot toolchain. When using this +## file, be sure to set the TOOLCHAIN_PREFIX and CMAKE_SYSROOT variables, +## preferably via the CMake configuration command (e.g. `-DCMAKE_SYSROOT=<...>`). +## +## Currently, we recommend using buildroot toolchain for +## cross-compilation. Here is the link to download the toolchains: +## https://toolchains.bootlin.com/ + +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSROOT) +set(TOOLCHAIN_PREFIX "" CACHE STRING "Path for toolchain for cross compiler and other compilation tools.") + +# Ensure that CMake tries to build static libraries when testing the compiler. +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + +set(CMAKE_AR "${TOOLCHAIN_PREFIX}gcc-ar" CACHE FILEPATH "" FORCE) +set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc) +set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++) +set(CMAKE_LINKER ${TOOLCHAIN_PREFIX}ld) +set(CMAKE_C_ARCHIVE_CREATE " qcs ") +set(CMAKE_C_ARCHIVE_FINISH true) +set(CMAKE_FORTRAN_COMPILER ${TOOLCHAIN_PREFIX}gfortran) +set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}objcopy CACHE INTERNAL "objcopy tool") +set(CMAKE_SIZE_UTIL ${TOOLCHAIN_PREFIX}size CACHE INTERNAL "size tool") + +## Here are the standard ROOT_PATH if you are using the standard toolchain +## if you are using a different toolchain you have to specify that too. +set(CMAKE_FIND_ROOT_PATH "${CMAKE_SYSROOT}") + +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --sysroot=${CMAKE_SYSROOT}" CACHE INTERNAL "" FORCE) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) diff --git a/board/flags-config.cmake b/board/flags-config.cmake new file mode 100644 index 0000000000..06dfecd5cf --- /dev/null +++ b/board/flags-config.cmake @@ -0,0 +1,69 @@ +# This function provides a set of specific flags for each supported board +# depending on the processor type. The objective is to optimize for size. +# Thus, all of the following flags are chosen carefully to reduce binary +# footprints. + +# Set generic minimization flags for all platforms. +# These flags are the same for all cross-compilation cases. +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Os -fdata-sections -ffunction-sections") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fomit-frame-pointer -fno-unwind-tables") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-asynchronous-unwind-tables -fvisibility=hidden") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fshort-enums -finline-small-functions") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -findirect-inlining -fno-common") +#-flto -fuse-ld=gold # There is an issue with gold link when compiling on +# Ubuntu 16. At that point gcc linker did not integrate the flto support +# inside and it was a separate plugin that need to be added. Therefore, +# this can be added when mlpack Azure CI moves toward Ubuntu 20. + +set(BOARD_NAME "" CACHE STRING "Specify Board name to optimize for.") +string(TOUPPER ${BOARD_NAME} BOARD) + +# Set specific platforms CMAKE CXX flags. +if(BOARD MATCHES "RPI0" OR BOARD MATCHES "RPI1") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=arm1176jzf-s") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + set(OPENBLAS_TARGET "ARMV6") + set(OPENBLAS_BINARY "32") +elseif(BOARD MATCHES "RPI2") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a7") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + set(OPENBLAS_TARGET "ARMV7") + set(OPENBLAS_BINARY "32") +elseif(BOARD MATCHES "RPI3") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a53") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + set(OPENBLAS_TARGET "CORTEXA53") + set(OPENBLAS_BINARY "64") +elseif(BOARD MATCHES "RPI4") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a72") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + set(OPENBLAS_TARGET "CORTEXA72") + set(OPENBLAS_BINARY "64") +elseif(BOARD MATCHES "BV") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + set(OPENBLAS_TARGET "RISCV64_GENERIC") + set(OPENBLAS_BINARY "64") +elseif(BOARD MATCHES "JETSONAGX") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -matune=cortex-a76") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + set(OPENBLAS_TARGET "ARM8") + set(OPENBLAS_BINARY "64") +elseif(BOARD MATCHES "KATAMI") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=pentium3") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + set(OPENBLAS_TARGET "KATAMI") + set(OPENBLAS_BINARY "32") +elseif(BOARD MATCHES "COPPERMINE") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=pentium3") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + set(OPENBLAS_TARGET "COPPERMINE") + set(OPENBLAS_BINARY "32") +elseif(BOARD MATCHES "NORTHWOOD") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=pentium4") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + set(OPENBLAS_TARGET "NORTHWOOD") + set(OPENBLAS_BINARY "32") +elseif(BOARD) + ## TODO: update documentation with a list of the supported boards. + message(FATAL_ERROR "Given BOARD_NAME is not known; please choose a supported board from the list") +endif() diff --git a/doc/guide/build.hpp b/doc/guide/build.hpp index 9356f725cc..c35582b667 100644 --- a/doc/guide/build.hpp +++ b/doc/guide/build.hpp @@ -170,7 +170,8 @@ The full list of options mlpack allows: - PROFILE=(ON/OFF): compile with profiling symbols (default OFF) - ARMA_EXTRA_DEBUG=(ON/OFF): compile with extra Armadillo debugging symbols (default OFF) - - BUILD_TESTS=(ON/OFF): compile the \c mlpack_test program (default ON) + - BUILD_TESTS=(ON/OFF): compile the \c mlpack_test program when `make` is run + (default ON) - BUILD_CLI_EXECUTABLES=(ON/OFF): compile the mlpack command-line executables (i.e. \c mlpack_knn, \c mlpack_kfn, \c mlpack_logistic_regression, etc.) (default ON) @@ -182,7 +183,7 @@ The full list of options mlpack allows: and Gonum exist. (default OFF) - BUILD_JULIA_BINDINGS=(ON/OFF): compile Julia bindings, if Julia is found (default OFF) - - BUILD_SHARED_LIBS=(ON/OFF): compile shared libraries as opposed to + - BUILD_SHARED_LIBS=(ON/OFF): compile shared libraries and executables as opposed to static libraries (default ON) - TEST_VERBOSE=(ON/OFF): run test cases in \c mlpack_test with verbose output (default OFF) @@ -209,6 +210,14 @@ The full list of options mlpack allows: Each option can be specified to CMake with the '-D' flag. Other tools can also be used to configure CMake, but those are not documented here. +For example, if you would like to build mlpack and its CLI bindings statically, then +you need to execute the following commands: + +@code +$ cd build +$ cmake -D BUILD_SHARED_LIBS=OFF ../ +@endcode + In addition, the following directories may be specified, to find include files and libraries. These also use the '-D' flag. @@ -216,23 +225,21 @@ and libraries. These also use the '-D' flag. - ARMADILLO_LIBRARY=(/path/to/armadillo/libarmadillo.so): location of Armadillo library - BOOST_ROOT=(/path/to/boost/): path to root of boost installation + - CEREAL_INCLUDE_DIR=(/path/to/cereal/include): path to include directory for + cereal - ENSMALLEN_INCLUDE_DIR=(/path/to/ensmallen/include): path to include directory for ensmallen - STB_IMAGE_INCLUDE_DIR=(/path/to/stb/include): path to include directory for - STB image library + STB image library - MATHJAX_ROOT=(/path/to/mathjax): path to root of MathJax installation @section build_build Building mlpack Once CMake is configured, building the library is as simple as typing 'make'. -This will build all library components as well as 'mlpack_test'. +This will build all library components. @code $ make -Scanning dependencies of target mlpack -[ 1%] Building CXX object -src/mlpack/CMakeFiles/mlpack.dir/core/optimizers/aug_lagrangian/aug_lagrangian_test_functions.cpp.o -<...> @endcode It's often useful to specify \c -jN to the \c make command, which will build on @@ -247,17 +254,24 @@ $ make mlpack_pca mlpack_knn mlpack_kfn @endcode One particular component of interest is mlpack_test, which runs the mlpack test -suite. You can build this component with +suite. This is not built when @c make is run. You can build this component +with @code $ make mlpack_test @endcode We use Catch2 to write our tests. -To run all tests, you can simply run: +To run all tests, you can simply use CTest: @code -$ ./bin/mlpack_test +$ ctest . +@endcode + +Or, you can run the test suite manually: + +@code +$ bin/mlpack_test @endcode To run all tests in a particular file you can run: @@ -266,7 +280,7 @@ To run all tests in a particular file you can run: $ ./bin/mlpack_test "[testname]" @endcode -where testname is the name of the test suite. +where testname is the name of the test suite. For example to run all collaborative filtering tests implemented in cf_test.cpp you can run: @code diff --git a/src/mlpack/bindings/cli/CMakeLists.txt b/src/mlpack/bindings/cli/CMakeLists.txt index 4b94805fe5..ee64bcf331 100644 --- a/src/mlpack/bindings/cli/CMakeLists.txt +++ b/src/mlpack/bindings/cli/CMakeLists.txt @@ -50,11 +50,21 @@ if (BUILD_CLI_EXECUTABLES) add_executable(mlpack_${name} ${name}_main.cpp ) - target_link_libraries(mlpack_${name} - mlpack - ${ARMADILLO_LIBRARIES} - ${COMPILER_SUPPORT_LIBRARIES} - ) + # Build mlpack CLI binding binaries statically. + if(NOT BUILD_SHARED_LIBS) + target_link_libraries(mlpack_${name} -static + mlpack + ${ARMADILLO_LIBRARIES} + ${COMPILER_SUPPORT_LIBRARIES} + ) + else() + # Build mlpack CLI binding binaries dynamically. + target_link_libraries(mlpack_${name} + mlpack + ${ARMADILLO_LIBRARIES} + ${COMPILER_SUPPORT_LIBRARIES} + ) + endif() # Make sure that we set BINDING_TYPE to cli so the command-line program is # compiled with the correct int main() call. set_target_properties(mlpack_${name} PROPERTIES COMPILE_FLAGS diff --git a/src/mlpack/bindings/go/print_doc_functions_impl.hpp b/src/mlpack/bindings/go/print_doc_functions_impl.hpp index 3f1dcd9a5e..1f250aafb5 100644 --- a/src/mlpack/bindings/go/print_doc_functions_impl.hpp +++ b/src/mlpack/bindings/go/print_doc_functions_impl.hpp @@ -432,13 +432,6 @@ inline std::string ProgramCall(const std::string& programName) std::ostringstream ossOptions; ossOptions << "param := mlpack." << goProgramName << "Options()\n"; oss << util::HyphenateString(ossOptions.str(), 4); - std::vector outputOptions; - for (auto it = parameters.begin(); it != parameters.end(); ++it) - { - util::ParamData& d = it->second; - if (!d.input) - outputOptions.push_back(it->first); - } std::string result = oss.str(); oss.str(""); std::ostringstream ossInputs; diff --git a/src/mlpack/core/kernels/epanechnikov_kernel_impl.hpp b/src/mlpack/core/kernels/epanechnikov_kernel_impl.hpp index 15c65ebb7b..eee34daaee 100644 --- a/src/mlpack/core/kernels/epanechnikov_kernel_impl.hpp +++ b/src/mlpack/core/kernels/epanechnikov_kernel_impl.hpp @@ -58,7 +58,6 @@ double EpanechnikovKernel::ConvolutionIntegral(const VecTypeA& a, (3.0 * bandwidth) + 2.0 * distance * distance * distance / (3.0 * bandwidth * bandwidth) - std::pow(distance, 5.0) / (30.0 * std::pow(bandwidth, 4.0))); - break; case 2: return 1.0 / volumeSquared * ((2.0 / 3.0 * bandwidth * bandwidth - distance * distance) * @@ -67,12 +66,10 @@ double EpanechnikovKernel::ConvolutionIntegral(const VecTypeA& a, (distance / 6.0 + 2.0 / 9.0 * distance * std::pow(distance / bandwidth, 2.0) - distance / 72.0 * std::pow(distance / bandwidth, 4.0))); - break; default: Log::Fatal << "EpanechnikovKernel::ConvolutionIntegral(): dimension " << a.n_rows << " not supported."; return -1.0; // This line will not execute. - break; } } diff --git a/src/mlpack/core/kernels/spherical_kernel.hpp b/src/mlpack/core/kernels/spherical_kernel.hpp index 13fc549f49..48fd9365a9 100644 --- a/src/mlpack/core/kernels/spherical_kernel.hpp +++ b/src/mlpack/core/kernels/spherical_kernel.hpp @@ -56,7 +56,7 @@ class SphericalKernel * @tparam VecTypeB Type of second vector. * @param a First vector. * @param b Second vector. - * @return the convolution integral value. + * @return The convolution integral value. */ template double ConvolutionIntegral(const VecTypeA& a, const VecTypeB& b) const @@ -72,17 +72,14 @@ class SphericalKernel { case 1: return 1.0 / volumeSquared * (2.0 * bandwidth - distance); - break; case 2: return 1.0 / volumeSquared * (2.0 * bandwidth * bandwidth * acos(distance/(2.0 * bandwidth)) - distance / 4.0 * sqrt(4.0*bandwidth*bandwidth-distance*distance)); - break; default: Log::Fatal << "The spherical kernel does not support convolution\ integrals above dimension two, yet..." << std::endl; return -1.0; - break; } } double Normalizer(size_t dimension) const diff --git a/src/mlpack/core/metrics/bleu_impl.hpp b/src/mlpack/core/metrics/bleu_impl.hpp index 38e9b29437..f81d62c69a 100644 --- a/src/mlpack/core/metrics/bleu_impl.hpp +++ b/src/mlpack/core/metrics/bleu_impl.hpp @@ -178,7 +178,10 @@ ElemType BLEU::Evaluate( else geometricMean = 0.0; - ratio = ElemType(translationLength) / referenceLength; + ratio = ElemType(translationLength); + if (referenceLength > 0) + ratio /= referenceLength; + brevityPenalty = (ratio > 1.0) ? 1.0 : std::exp(1.0 - 1.0 / ratio); bleuScore = geometricMean * brevityPenalty; diff --git a/src/mlpack/core/tree/cover_tree/dual_tree_traverser.hpp b/src/mlpack/core/tree/cover_tree/dual_tree_traverser.hpp index 804c647e58..2b7a8ae378 100644 --- a/src/mlpack/core/tree/cover_tree/dual_tree_traverser.hpp +++ b/src/mlpack/core/tree/cover_tree/dual_tree_traverser.hpp @@ -86,20 +86,23 @@ class CoverTree:: /** * Helper function for traversal of the two trees. */ - void Traverse(CoverTree& queryNode, - std::map >& - referenceMap); + void Traverse( + CoverTree& queryNode, + std::map, + std::greater>& referenceMap); //! Prepare map for recursion. - void PruneMap(CoverTree& queryNode, - std::map >& - referenceMap, - std::map >& - childMap); + void PruneMap( + CoverTree& queryNode, + std::map, + std::greater>& referenceMap, + std::map, + std::greater>& childMap); - void ReferenceRecursion(CoverTree& queryNode, - std::map >& - referenceMap); + void ReferenceRecursion( + CoverTree& queryNode, + std::map, + std::greater>& referenceMap); }; } // namespace tree diff --git a/src/mlpack/core/tree/cover_tree/dual_tree_traverser_impl.hpp b/src/mlpack/core/tree/cover_tree/dual_tree_traverser_impl.hpp index 5e29d09fca..cde21d8a75 100644 --- a/src/mlpack/core/tree/cover_tree/dual_tree_traverser_impl.hpp +++ b/src/mlpack/core/tree/cover_tree/dual_tree_traverser_impl.hpp @@ -43,7 +43,7 @@ DualTreeTraverser::Traverse(CoverTree& queryNode, CoverTree& referenceNode) { // Start by creating a map and adding the reference root node to it. - std::map > refMap; + std::map, std::greater> refMap; DualCoverTreeMapEntry rootRefEntry; @@ -70,7 +70,8 @@ template void CoverTree:: DualTreeTraverser::Traverse( CoverTree& queryNode, - std::map >& referenceMap) + std::map, std::greater>& + referenceMap) { if (referenceMap.size() == 0) return; // Nothing to do! @@ -85,7 +86,7 @@ DualTreeTraverser::Traverse( // Now, reduce the scale of the query node by recursing. But we can't recurse // if the query node is a leaf node. if ((queryNode.Scale() != INT_MIN) && - (queryNode.Scale() >= (*referenceMap.rbegin()).first)) + (queryNode.Scale() >= (*referenceMap.begin()).first)) { // Recurse into the non-self-children first. The recursion order cannot // affect the runtime of the algorithm, because each query child recursion's @@ -95,11 +96,15 @@ DualTreeTraverser::Traverse( for (size_t i = 1; i < queryNode.NumChildren(); ++i) { // We need a copy of the map for this child. - std::map > childMap; + std::map, std::greater> + childMap; + PruneMap(queryNode.Child(i), referenceMap, childMap); Traverse(queryNode.Child(i), childMap); } - std::map > selfChildMap; + std::map, std::greater> + selfChildMap; + PruneMap(queryNode.Child(0), referenceMap, selfChildMap); Traverse(queryNode.Child(0), selfChildMap); } @@ -111,8 +116,7 @@ DualTreeTraverser::Traverse( // evaluations to do. Log::Assert((*referenceMap.begin()).first == INT_MIN); Log::Assert(queryNode.Scale() == INT_MIN); - std::vector& pointVector = - (*referenceMap.begin()).second; + std::vector& pointVector = referenceMap[INT_MIN]; for (size_t i = 0; i < pointVector.size(); ++i) { @@ -156,25 +160,25 @@ template void CoverTree:: DualTreeTraverser::PruneMap( CoverTree& queryNode, - std::map >& referenceMap, - std::map >& childMap) + std::map, std::greater>& + referenceMap, + std::map, std::greater>& + childMap) { if (referenceMap.empty()) return; // Nothing to do. // Copy the zero set first. - if ((*referenceMap.begin()).first == INT_MIN) + if (referenceMap.count(INT_MIN) == 1) { // Get a reference to the vector representing the entries at this scale. - std::vector& scaleVector = - (*referenceMap.begin()).second; + std::vector& scaleVector = referenceMap[INT_MIN]; // Before traversing all the points in this scale, sort by score. std::sort(scaleVector.begin(), scaleVector.end()); - const int thisScale = (*referenceMap.begin()).first; - childMap[thisScale].reserve(scaleVector.size()); - std::vector& newScaleVector = childMap[thisScale]; + childMap[INT_MIN].reserve(scaleVector.size()); + std::vector& newScaleVector = childMap[INT_MIN]; // Loop over each entry in the vector. for (size_t j = 0; j < scaleVector.size(); ++j) @@ -208,13 +212,13 @@ DualTreeTraverser::PruneMap( // If we didn't add anything, then strike this vector from the map. if (newScaleVector.size() == 0) - childMap.erase((*referenceMap.begin()).first); + childMap.erase(INT_MIN); } - typename std::map >::reverse_iterator - it = referenceMap.rbegin(); + typename std::map, + std::greater>::iterator it = referenceMap.begin(); - while ((it != referenceMap.rend())) + while ((it != referenceMap.end())) { const int thisScale = (*it).first; if (thisScale == INT_MIN) // We already did it. @@ -277,28 +281,26 @@ template void CoverTree:: DualTreeTraverser::ReferenceRecursion( CoverTree& queryNode, - std::map >& referenceMap) + std::map, std::greater>& + referenceMap) { // First, reduce the maximum scale in the reference map down to the scale of // the query node. while (!referenceMap.empty()) { + const int maxScale = ((*referenceMap.begin()).first); // Hacky bullshit to imitate jl cover tree. - if (queryNode.Parent() == NULL && (*referenceMap.rbegin()).first < - queryNode.Scale()) + if (queryNode.Parent() == NULL && maxScale < queryNode.Scale()) break; - if (queryNode.Parent() != NULL && (*referenceMap.rbegin()).first <= - queryNode.Scale()) + if (queryNode.Parent() != NULL && maxScale <= queryNode.Scale()) break; // If the query node's scale is INT_MIN and the reference map's maximum // scale is INT_MIN, don't try to recurse... - if ((queryNode.Scale() == INT_MIN) && - ((*referenceMap.rbegin()).first == INT_MIN)) + if (queryNode.Scale() == INT_MIN && maxScale == INT_MIN) break; // Get a reference to the current largest scale. - std::vector& scaleVector = - (*referenceMap.rbegin()).second; + std::vector& scaleVector = referenceMap[maxScale]; // Before traversing all the points in this scale, sort by score. std::sort(scaleVector.begin(), scaleVector.end()); @@ -308,7 +310,6 @@ DualTreeTraverser::ReferenceRecursion( { // Get a reference to the current element. const DualCoverTreeMapEntry& frame = scaleVector.at(i); - CoverTree* refNode = frame.referenceNode; // Create the score for the children. @@ -344,13 +345,12 @@ DualTreeTraverser::ReferenceRecursion( newFrame.score = childScore; // Use the score of the parent. newFrame.baseCase = baseCase; newFrame.traversalInfo = rule.TraversalInfo(); - referenceMap[newFrame.referenceNode->Scale()].push_back(newFrame); } } // Now clear the memory for this scale; it isn't needed anymore. - referenceMap.erase((*referenceMap.rbegin()).first); + referenceMap.erase(maxScale); } } diff --git a/src/mlpack/core/tree/cover_tree/single_tree_traverser_impl.hpp b/src/mlpack/core/tree/cover_tree/single_tree_traverser_impl.hpp index 728e64f39d..0721c4e090 100644 --- a/src/mlpack/core/tree/cover_tree/single_tree_traverser_impl.hpp +++ b/src/mlpack/core/tree/cover_tree/single_tree_traverser_impl.hpp @@ -80,9 +80,9 @@ SingleTreeTraverser::Traverse( // and then the vector is all the nodes in that scale which need to be // investigated. Because no point in a scale can add a point in its own // scale, we know that the vector for each scale is final when we get to it. - // In addition, map is organized in such a way that rbegin() will return the - // largest scale. - std::map > mapQueue; + // In addition, the map is organized in such a way that begin() will return + // the largest scale. + std::map, std::greater> mapQueue; // Create the score for the children. double rootChildScore = rule.Score(queryIndex, referenceNode); @@ -123,14 +123,13 @@ SingleTreeTraverser::Traverse( // Now begin the iteration through the map, but only if it has anything in it. if (mapQueue.empty()) return; - typename std::map >::reverse_iterator rit = - mapQueue.rbegin(); + int maxScale = mapQueue.cbegin()->first; // We will treat the leaves differently (below). - while ((*rit).first != INT_MIN) + while (maxScale != INT_MIN) { // Get a reference to the current scale. - std::vector& scaleVector = (*rit).second; + std::vector& scaleVector = mapQueue[maxScale]; // Before traversing all the points in this scale, sort by score. std::sort(scaleVector.begin(), scaleVector.end()); @@ -170,7 +169,9 @@ SingleTreeTraverser::Traverse( // trees using TreeTraits::FirstPointIsCentroid; this is an optimization // that (theoretically) the compiler should get right. if (point != parent) + { baseCase = rule.BaseCase(queryIndex, point); + } // Don't add the self-leaf. size_t j = 0; @@ -193,7 +194,8 @@ SingleTreeTraverser::Traverse( } // Now clear the memory for this scale; it isn't needed anymore. - mapQueue.erase((*rit).first); + mapQueue.erase(maxScale); + maxScale = mapQueue.begin()->first; } // Now deal with the leaves. diff --git a/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp b/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp index c977f0fecb..73a532b03e 100644 --- a/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/x_tree_split_impl.hpp @@ -435,7 +435,8 @@ bool XTreeSplit::SplitNonLeafNode(TreeType *tree, std::vector& relevels) bool useMinOverlapSplit = false; if (tiedOnOverlap) { - if (overlapBestAreaAxis / areaBestAreaAxis < MAX_OVERLAP) + if (areaBestAreaAxis > 0 && + overlapBestAreaAxis / areaBestAreaAxis < MAX_OVERLAP) { tree->numDescendants = 0; tree->bound.Clear(); diff --git a/src/mlpack/methods/amf/termination_policies/simple_tolerance_termination.hpp b/src/mlpack/methods/amf/termination_policies/simple_tolerance_termination.hpp index 81630e14bf..191278bf7f 100644 --- a/src/mlpack/methods/amf/termination_policies/simple_tolerance_termination.hpp +++ b/src/mlpack/methods/amf/termination_policies/simple_tolerance_termination.hpp @@ -79,7 +79,7 @@ class SimpleToleranceTermination WH = W * H; - // compute residue + // Compute residue. residueOld = residue; size_t n = V->n_rows; size_t m = V->n_cols; @@ -99,48 +99,51 @@ class SimpleToleranceTermination } } } - residue = sum / count; + + residue = sum; + if (count > 0) + residue /= count; residue = sqrt(residue); - // increment iteration count + // Increment iteration count. iteration++; Log::Info << "Iteration " << iteration << "; residue " << ((residueOld - residue) / residueOld) << ".\n"; - // if residue tolerance is not satisfied + // If residue tolerance is not satisfied. if ((residueOld - residue) / residueOld < tolerance && iteration > 4) { - // check if this is a first of successive drops + // Check if this is a first of successive drops. if (reverseStepCount == 0 && isCopy == false) { - // store a copy of W and H matrix + // Store a copy of W and H matrix. isCopy = true; this->W = W; this->H = H; - // store residue values + // Store residue values. c_index = residue; c_indexOld = residueOld; } - // increase successive drop count + // Increase successive drop count. reverseStepCount++; } - // if tolerance is satisfied + // If tolerance is satisfied. else { - // initialize successive drop count + // Initialize successive drop count. reverseStepCount = 0; - // if residue is droped below minimum scrap stored values + // If residue is droped below minimum scrap stored values. if (residue <= c_indexOld && isCopy == true) { isCopy = false; } } - // check if termination criterion is met + // Check if termination criterion is met. if (reverseStepCount == reverseStepTolerance || iteration > maxIterations) { - // if stored values are present replace them with current value as they - // represent the minimum residue point + // If stored values are present replace them with current value as they + // represent the minimum residue point. if (isCopy) { W = this->W; @@ -149,49 +152,50 @@ class SimpleToleranceTermination } return true; } - else return false; + + return false; } - //! Get current value of residue + //! Get current value of residue. const double& Index() const { return residue; } - //! Get current iteration count + //! Get current iteration count. const size_t& Iteration() const { return iteration; } - //! Access upper limit of iteration count + //! Access upper limit of iteration count. const size_t& MaxIterations() const { return maxIterations; } size_t& MaxIterations() { return maxIterations; } - //! Access tolerance value + //! Access tolerance value. const double& Tolerance() const { return tolerance; } double& Tolerance() { return tolerance; } private: - //! tolerance + //! Locally-stored tolerance. double tolerance; - //! iteration threshold + //! Locally-stored iteration threshold. size_t maxIterations; - //! pointer to matrix being factorized + //! Pointer to matrix being factorized. const MatType* V; - //! current iteration count + //! Current iteration count. size_t iteration; - //! residue values + //! Locally-stored residue values. double residueOld; double residue; - //! tolerance on successive residue drops + //! Tolerance on successive residue drops. size_t reverseStepTolerance; - //! successive residue drops + //! Successive residue drops. size_t reverseStepCount; - //! indicates whether a copy of information is available which corresponds to - //! minimum residue point + //! Indicates whether a copy of information is available which corresponds to + //! minimum residue point. bool isCopy; - //! variables to store information of minimum residue poi + //! Variables to store information of minimum residue poi. arma::mat W; arma::mat H; double c_indexOld; diff --git a/src/mlpack/methods/ann/activation_functions/CMakeLists.txt b/src/mlpack/methods/ann/activation_functions/CMakeLists.txt index 1639817716..98b03e0a91 100644 --- a/src/mlpack/methods/ann/activation_functions/CMakeLists.txt +++ b/src/mlpack/methods/ann/activation_functions/CMakeLists.txt @@ -21,6 +21,7 @@ set(SOURCES gaussian_function.hpp hard_swish_function.hpp tanh_exponential_function.hpp + silu_function.hpp ) # Add directory name to sources. diff --git a/src/mlpack/methods/ann/activation_functions/silu_function.hpp b/src/mlpack/methods/ann/activation_functions/silu_function.hpp new file mode 100644 index 0000000000..0c063a5b59 --- /dev/null +++ b/src/mlpack/methods/ann/activation_functions/silu_function.hpp @@ -0,0 +1,96 @@ +/** + * @file methods/ann/activation_functions/silu_function.hpp + * @author Fawwaz Mayda + * + * Definition and implementation of the Sigmoid Weighted Linear Unit function (SILU). + * + * For more information see the following paper + * + * @code + * @misc{elfwing2017sigmoidweighted , + * title = {Sigmoid-Weighted Linear Units for Neural Network Function Approximation in Reinforcement Learning}, + * author = {Stefan Elfwing and Eiji Uchibe and Kenji Doya}, + * year = {2017}, + * url = {https://arxiv.org/pdf/1702.03118.pdf}, + * eprint = {1702.03118}, + * archivePrefix = {arXiv}, + * primaryClass = {cs.LG} } + * @endcode + * + * 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_ACTIVATION_FUNCTIONS_SILU_FUNCTION_HPP +#define MLPACK_METHODS_ANN_ACTIVATION_FUNCTIONS_SILU_FUNCTION_HPP + +#include + +namespace mlpack { +namespace ann /* Artificial Neural Network */ { + +/** + * The SILU function, defined by + * + * @f{eqnarray*}{ + * f(x) &=& x * \frac{1}{1 + e^{-x}}\\ + * f'(x) &=& \frac{1}{1 + e^{-x}} * (1 + x * (1-\frac{1}{1 + e^{-x}}))\\ + * @f} + */ +class SILUFunction +{ + public: + /** + * Computes the SILU function. + * + * @param x Input data. + * @return f(x). + */ + static double Fn(const double x) + { + return x / (1.0 + std::exp(-x)); + } + + /** + * Computes the SILU function. + * + * @param x Input data. + * @param y The resulting output activation. + */ + template + static void Fn(const InputVecType &x, OutputVecType &y) + { + y = x / (1.0 + arma::exp(-x)); + } + + /** + * Computes the first derivative of the SILU function. + * + * @param y Input activation. + * @return f'(x) + */ + static double Deriv(const double x) + { + double sigmoid = 1.0 / (1.0 + std::exp(-x)); + return sigmoid * (1.0 + x * (1.0 - sigmoid)); + } + + /** + * Computes the first derivatives of the SILU function. + * + * @param y Input activations. + * @param x The resulting derivatives. + */ + template + static void Deriv(const InputVecType &x, OutputVecType &y) + { + OutputVecType sigmoid = 1.0 / (1.0 + arma::exp(-x)); + y = sigmoid % (1.0 + x % (1.0 - sigmoid)); + } +}; // class SILUFunction + +} // namespace ann +} // namespace mlpack + +#endif \ No newline at end of file diff --git a/src/mlpack/methods/ann/layer/CMakeLists.txt b/src/mlpack/methods/ann/layer/CMakeLists.txt index 2b181012c7..52dbebec75 100644 --- a/src/mlpack/methods/ann/layer/CMakeLists.txt +++ b/src/mlpack/methods/ann/layer/CMakeLists.txt @@ -36,6 +36,8 @@ set(SOURCES elu_impl.hpp fast_lstm.hpp fast_lstm_impl.hpp + flatten_t_swish.hpp + flatten_t_swish_impl.hpp flexible_relu.hpp flexible_relu_impl.hpp glimpse.hpp diff --git a/src/mlpack/methods/ann/layer/base_layer.hpp b/src/mlpack/methods/ann/layer/base_layer.hpp index 7169d5f474..9c6bd19478 100644 --- a/src/mlpack/methods/ann/layer/base_layer.hpp +++ b/src/mlpack/methods/ann/layer/base_layer.hpp @@ -29,6 +29,7 @@ #include #include #include +#include namespace mlpack { namespace ann /** Artificial Neural Network. */ { @@ -54,6 +55,7 @@ namespace ann /** Artificial Neural Network. */ { * - GaussianLayer * - HardSwishLayer * - TanhExpLayer + * - SILULayer * * @tparam ActivationFunction Activation function used for the embedding layer. * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, @@ -303,6 +305,18 @@ template < using TanhExpFunctionLayer = BaseLayer< ActivationFunction, InputDataType, OutputDataType>; +/** + * Standard SILU-Layer using the SILU activation function. + */ +template < + class ActivationFunction = SILUFunction, + typename InputDataType = arma::mat, + typename OutputDataType = arma::mat +> +using SILUFunctionLayer = BaseLayer< + ActivationFunction, InputDataType,OutputDataType +>; + } // namespace ann } // namespace mlpack diff --git a/src/mlpack/methods/ann/layer/flatten_t_swish.hpp b/src/mlpack/methods/ann/layer/flatten_t_swish.hpp new file mode 100644 index 0000000000..3d891b3363 --- /dev/null +++ b/src/mlpack/methods/ann/layer/flatten_t_swish.hpp @@ -0,0 +1,124 @@ +/** + * @file methods/ann/layer/flatten_t_swish.hpp + * @author Fawwaz Mayda + * + * Definition of Flatten T Swish layer first introduced in the acoustic model, + * Hock Hung Chieng, Noorhaniza Wahid, Pauline Ong, Sai Raj Kishore Perla, + * "Flatten-T Swish: a thresholded ReLU-Swish-like activation function for deep learning", 2018 + * + * 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_FLATTEN_T_SWISH_HPP +#define MLPACK_METHODS_ANN_LAYER_FLATTEN_T_SWISH_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * The Flatten T Swish activation function, defined by + * + * @f{eqnarray*}{ + * f'(x) &=& \left\{ + * \begin{array}{lr} + * frac{x}{1+exp(-x)} + T & : x \ge 0 \\ + * T & : x < 0 + * \end{array} + * \right. \\ + * f'(x) &=& \left\{ + * \begin{array}{lr} + * \sigma(x)(1 - f(x)) + f(x) & : x > 0 \\ + * 0 & : x \le 0 + * \end{array} + * \right. + * @f} + * + * @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 FlattenTSwish +{ + public: + /** + * Create the Flatten T Swish object using the specified parameters. + * The thresholded value T can be adjusted via T paramaters. + * When the x is < 0, T will be used instead of 0. + * The default value of T is -0.20 as suggested in the paper. + * @param T + */ + FlattenTSwish(const double T = -0.20); + + /** + * Ordinary feed forward pass of a neural network, evaluating the function + * f(x) by propagating the activity forward through f. + * + * @param input Input data used for evaluating the specified function. + * @param output Resulting output activation. + */ + template + void Forward(const InputType& input, OutputType& output); + + /** + * Ordinary feed backward pass of a neural network, calculating the function + * f(x) by propagating x backwards through f. Using the results from the feed + * forward pass. + * + * @param input The propagated input activation. + * @param gy The backpropagated error. + * @param g The calculated gradient. + */ + template + void Backward(const DataType& input, const DataType& gy, DataType& g); + + //! Get the output parameter. + OutputDataType const& OutputParameter() const { return outputParameter; } + //! Modify the output parameter. + OutputDataType& OutputParameter() { return outputParameter; } + + //! Get the delta. + OutputDataType const& Delta() const { return delta; } + //! Modify the delta. + OutputDataType& Delta() { return delta; } + + //! Get the T parameter. + double const& T() const { return t; } + //! Modify the T parameter. + double& T() { return t; } + + //! Get size of weights. + size_t WeightSize() const { return 0; } + + /** + * Serialize the layer. + */ + template + void serialize(Archive& ar, const uint32_t /* version */); + + private: + //! Locally-stored delta object. + OutputDataType delta; + + //! Locally-stored output parameter object. + OutputDataType outputParameter; + + //! T Parameter from paper. + double t; +}; // class FlattenTSwish + +} // namespace ann +} // namespace mlpack + +// Include implementation. +#include "flatten_t_swish_impl.hpp" + +#endif diff --git a/src/mlpack/methods/ann/layer/flatten_t_swish_impl.hpp b/src/mlpack/methods/ann/layer/flatten_t_swish_impl.hpp new file mode 100644 index 0000000000..1ce5364da8 --- /dev/null +++ b/src/mlpack/methods/ann/layer/flatten_t_swish_impl.hpp @@ -0,0 +1,80 @@ +/** + * @file methods/ann/layer/flatten_t_swish_impl.hpp + * @author Fawwaz Mayda + * + * Definition of Flatten T Swish layer first introduced in the acoustic model, + * Hock Hung Chieng, Noorhaniza Wahid, Pauline Ong, Sai Raj Kishore Perla, + * "Flatten-T Swish: a thresholded ReLU-Swish-like activation function for deep learning", 2018 + * + * 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_FLATTEN_T_SWISH_IMPL_HPP +#define MLPACK_METHODS_ANN_LAYER_FLATTEN_T_SWISH_IMPL_HPP + +// In case it hasn't yet been included. +#include "flatten_t_swish.hpp" +#include +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +FlattenTSwish::FlattenTSwish( + const double T) : t(T) +{ + // Nothing to do here. +} + +template +template +void FlattenTSwish::Forward( + const InputType& input, OutputType& output) +{ + // Placeholder for Relu values. + OutputDataType relu; + RectifierFunction::Fn(input, relu); + LogisticFunction::Fn(input, output); + // F(x) = relu * sigmoid + t. + output = relu % output + t; +} + +template +template +void FlattenTSwish::Backward( + const DataType& input, const DataType& gy, DataType& g) +{ + DataType derivate, sigmoid; + LogisticFunction::Fn(input,sigmoid); + derivate.set_size(arma::size(input)); + for(size_t i = 0; i < input.n_elem; ++i) + { + if (input(i) >= 0) + { + // F(x) = x * sigmoid(x). + // We don't put '+ t' here because this is a derivate. + derivate(i) = input(i) * sigmoid(i); + derivate(i) = sigmoid(i) * (1.0 - derivate(i)) + derivate(i); + } + else + derivate(i) = 0; + } + g = gy % derivate; +} + +template +template +void FlattenTSwish::serialize( + Archive& ar, + const uint32_t /* version */) +{ + ar(CEREAL_NVP(t)); +} + +} // namespace ann +} // namespace mlpack + +#endif \ No newline at end of file diff --git a/src/mlpack/methods/ann/layer/layer.hpp b/src/mlpack/methods/ann/layer/layer.hpp index 6d13a26772..b2f598b985 100644 --- a/src/mlpack/methods/ann/layer/layer.hpp +++ b/src/mlpack/methods/ann/layer/layer.hpp @@ -32,6 +32,7 @@ #include "dropout.hpp" #include "elu.hpp" #include "fast_lstm.hpp" +#include "flatten_t_swish.hpp" #include "flexible_relu.hpp" #include "glimpse.hpp" #include "gru.hpp" diff --git a/src/mlpack/methods/ann/layer/lp_pooling.hpp b/src/mlpack/methods/ann/layer/lp_pooling.hpp index 8423dda79f..03ef9f540e 100644 --- a/src/mlpack/methods/ann/layer/lp_pooling.hpp +++ b/src/mlpack/methods/ann/layer/lp_pooling.hpp @@ -167,9 +167,17 @@ class LpPooling for (size_t i = 0, rowidx = 0; i < output.n_rows; ++i, rowidx += strideWidth) { + size_t rowEnd = rowidx + kernelWidth - 1; + size_t colEnd = colidx + kernelHeight - 1; + + if (rowEnd > input.n_rows - 1) + rowEnd = input.n_rows - 1; + if (colEnd > input.n_cols - 1) + colEnd = input.n_cols - 1; + arma::mat subInput = input( - arma::span(rowidx, rowidx + kernelWidth - 1 - offset), - arma::span(colidx, colidx + kernelHeight - 1 - offset)); + arma::span(rowidx, rowEnd), + arma::span(colidx, colEnd)); output(i, j) = pow(arma::accu(arma::pow(subInput, normType)), 1.0 / normType); @@ -188,24 +196,39 @@ class LpPooling const arma::Mat& error, arma::Mat& output) { - const size_t rStep = input.n_rows / error.n_rows - offset; - const size_t cStep = input.n_cols / error.n_cols - offset; arma::Mat unpooledError; - for (size_t j = 0; j < input.n_cols - cStep; j += cStep) + for (size_t j = 0, colidx = 0; j < input.n_cols; j += strideHeight, colidx++) { - for (size_t i = 0; i < input.n_rows - rStep; i += rStep) + for (size_t i = 0, rowidx = 0; i < input.n_rows; i += strideWidth, rowidx++) { - const arma::Mat& inputArea = input(arma::span(i, i + rStep - 1), - arma::span(j, j + cStep - 1)); - size_t sum = pow(arma::accu(arma::pow(inputArea, normType)), + size_t rowEnd = i + kernelWidth - 1; + size_t colEnd = j + kernelHeight - 1; + + if (rowEnd > input.n_rows - 1) + { + if (floor) + continue; + rowEnd = input.n_rows - 1; + } + + if (colEnd > input.n_cols - 1) + { + if (floor) + continue; + colEnd = input.n_cols - 1; + } + + arma::mat InputArea = input(arma::span(i, rowEnd), arma::span(j, colEnd)); + + size_t sum = pow(arma::accu(arma::pow(InputArea, normType)), (normType - 1) / normType); - unpooledError = arma::Mat(inputArea.n_rows, inputArea.n_cols); - unpooledError.fill(error(i / rStep, j / cStep)); - unpooledError %= arma::pow(inputArea, normType - 1); + unpooledError = arma::Mat(InputArea.n_rows, InputArea.n_cols); + unpooledError.fill(error(rowidx, colidx) / InputArea.n_elem); + unpooledError %= arma::pow(InputArea, normType - 1); unpooledError /= sum; - output(arma::span(i, i + rStep - 1 - offset), - arma::span(j, j + cStep - 1 - offset)) += unpooledError; + output(arma::span(i, i + InputArea.n_rows - 1), + arma::span(j, j + InputArea.n_cols - 1)) += unpooledError; } } } @@ -249,9 +272,6 @@ class LpPooling //! Locally-stored reset parameter used to initialize the module once. bool reset; - //! Locally-stored stored rounding offset. - size_t offset; - //! Locally-stored number of input units. size_t batchSize; diff --git a/src/mlpack/methods/ann/layer/lp_pooling_impl.hpp b/src/mlpack/methods/ann/layer/lp_pooling_impl.hpp index 0abe08ada6..525789fe07 100644 --- a/src/mlpack/methods/ann/layer/lp_pooling_impl.hpp +++ b/src/mlpack/methods/ann/layer/lp_pooling_impl.hpp @@ -46,7 +46,6 @@ LpPooling::LpPooling( outputWidth(0), outputHeight(0), reset(false), - offset(0), batchSize(0) { // Nothing to do here. @@ -68,8 +67,6 @@ void LpPooling::Forward( (double) kernelWidth) / (double) strideWidth + 1); outputHeight = std::floor((inputHeight - (double) kernelHeight) / (double) strideHeight + 1); - - offset = 0; } else { @@ -77,8 +74,6 @@ void LpPooling::Forward( (double) kernelWidth) / (double) strideWidth + 1); outputHeight = std::ceil((inputHeight - (double) kernelHeight) / (double) strideHeight + 1); - - offset = 1; } outputTemp = arma::zeros >(outputWidth, outputHeight, diff --git a/src/mlpack/methods/ann/layer/max_pooling.hpp b/src/mlpack/methods/ann/layer/max_pooling.hpp index 098a9d100a..2547c5596a 100644 --- a/src/mlpack/methods/ann/layer/max_pooling.hpp +++ b/src/mlpack/methods/ann/layer/max_pooling.hpp @@ -188,18 +188,25 @@ class MaxPooling for (size_t i = 0, rowidx = 0; i < output.n_rows; ++i, rowidx += strideWidth) { + size_t rowEnd = rowidx + kernelWidth - 1; + size_t colEnd = colidx + kernelHeight - 1; + + if (rowEnd > input.n_rows - 1) + rowEnd = input.n_rows - 1; + if (colEnd > input.n_cols - 1) + colEnd = input.n_cols - 1; + arma::mat subInput = input( - arma::span(rowidx, rowidx + kernelWidth - 1 - offset), - arma::span(colidx, colidx + kernelHeight - 1 - offset)); + arma::span(rowidx, rowEnd), + arma::span(colidx, colEnd)); const size_t idx = pooling.Pooling(subInput); output(i, j) = subInput(idx); if (!deterministic) { - arma::Mat subIndices = indices(arma::span(rowidx, - rowidx + kernelWidth - 1 - offset), - arma::span(colidx, colidx + kernelHeight - 1 - offset)); + arma::Mat subIndices = indices(arma::span(rowidx, rowEnd), + arma::span(colidx, colEnd)); poolingIndices(i, j) = subIndices(idx); } @@ -264,8 +271,6 @@ class MaxPooling //! If true use maximum a posteriori during the forward pass. bool deterministic; - //! Locally-stored stored rounding offset. - size_t offset; //! Locally-stored number of input units. size_t batchSize; diff --git a/src/mlpack/methods/ann/layer/max_pooling_impl.hpp b/src/mlpack/methods/ann/layer/max_pooling_impl.hpp index cbc17904c4..9650a5f2c3 100644 --- a/src/mlpack/methods/ann/layer/max_pooling_impl.hpp +++ b/src/mlpack/methods/ann/layer/max_pooling_impl.hpp @@ -45,7 +45,6 @@ MaxPooling::MaxPooling( outputWidth(0), outputHeight(0), deterministic(false), - offset(0), batchSize(0) { // Nothing to do here. @@ -67,7 +66,6 @@ void MaxPooling::Forward( (double) kernelWidth) / (double) strideWidth + 1); outputHeight = std::floor((inputHeight - (double) kernelHeight) / (double) strideHeight + 1); - offset = 0; } else { @@ -75,7 +73,6 @@ void MaxPooling::Forward( (double) kernelWidth) / (double) strideWidth + 1); outputHeight = std::ceil((inputHeight - (double) kernelHeight) / (double) strideHeight + 1); - offset = 1; } outputTemp = arma::zeros >(outputWidth, outputHeight, 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 c163d0d148..92b01d80c8 100644 --- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp +++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp @@ -1,6 +1,6 @@ /** * @file methods/bayesian_linear_regression/bayesian_linear_regression.cpp - * @author Clement Mercier + * @author Clement Mercier * * Implementation of Bayesian linear regression. * @@ -58,12 +58,12 @@ double BayesianLinearRegression::Train(const arma::mat& data, beta = 1 / (var(t, 1) * 0.1); unsigned short i = 0; - double deltaAlpha = 1.0, deltaBeta = 1.0, crit = 1.0; + double deltaAlpha = 1.0, crit = 1.0; while ((crit > tolerance) && (i < maxIterations)) { deltaAlpha = -alpha; - deltaBeta = -beta; + double deltaBeta = -beta; // Update the solution. omega = eigVec * diagmat(1 / (eigVal + (alpha / beta))) * eigVecInvPhitT; diff --git a/src/mlpack/methods/cf/cf_model.cpp b/src/mlpack/methods/cf/cf_model.cpp index 226edcf1be..424726953e 100644 --- a/src/mlpack/methods/cf/cf_model.cpp +++ b/src/mlpack/methods/cf/cf_model.cpp @@ -89,31 +89,26 @@ CFWrapperBase* TrainHelper(const DecompositionPolicy& decomposition, return new CFWrapper(data, decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, mit); - break; case CFModel::ITEM_MEAN_NORMALIZATION: return new CFWrapper(data, decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, mit); - break; case CFModel::USER_MEAN_NORMALIZATION: return new CFWrapper(data, decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, mit); - break; case CFModel::OVERALL_MEAN_NORMALIZATION: return new CFWrapper(data, decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, mit); - break; case CFModel::Z_SCORE_NORMALIZATION: return new CFWrapper(data, decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, mit); - break; } // This shouldn't ever happen. diff --git a/src/mlpack/methods/det/dtree_impl.hpp b/src/mlpack/methods/det/dtree_impl.hpp index 7df858e4d2..dfdb994049 100644 --- a/src/mlpack/methods/det/dtree_impl.hpp +++ b/src/mlpack/methods/det/dtree_impl.hpp @@ -874,19 +874,13 @@ double DTree::ComputeValue(const VecType& query) const } if (subtreeLeaves == 1) // If we are a leaf... - { return std::exp(std::log(ratio) - logVolume); - } - else - { - // Return either of the two children - left or right, depending on the - // splitValue - return (query[splitDim] <= splitValue) ? + + // Return either of the two children - left or right, depending on the + // splitValue. + return (query[splitDim] <= splitValue) ? left->ComputeValue(query) : right->ComputeValue(query); - } - - return 0.0; } // Index the buckets for possible usage later. diff --git a/src/mlpack/methods/fastmks/fastmks_main.cpp b/src/mlpack/methods/fastmks/fastmks_main.cpp index 3b784f6d04..1638f64922 100644 --- a/src/mlpack/methods/fastmks/fastmks_main.cpp +++ b/src/mlpack/methods/fastmks/fastmks_main.cpp @@ -262,7 +262,7 @@ static void mlpackMain() // Delete the memory, if needed. if (IO::HasParam("reference")) delete model; - throw e; + throw; } } diff --git a/src/mlpack/methods/linear_svm/linear_svm_main.cpp b/src/mlpack/methods/linear_svm/linear_svm_main.cpp index f72b7c1b6f..ce645e964b 100644 --- a/src/mlpack/methods/linear_svm/linear_svm_main.cpp +++ b/src/mlpack/methods/linear_svm/linear_svm_main.cpp @@ -373,10 +373,6 @@ static void mlpackMain() oss << IO::GetPrintableParam("test"); std::string testOutput = oss.str(); - if (!IO::HasParam("training")) - { - numClasses = model->svm.NumClasses(); - } // Get the test dataset, and get predictions. testSet = std::move(IO::GetParam("test")); arma::Row predictions; diff --git a/src/mlpack/methods/neighbor_search/neighbor_search_rules_impl.hpp b/src/mlpack/methods/neighbor_search/neighbor_search_rules_impl.hpp index 74d3c490cd..6bf8055efd 100644 --- a/src/mlpack/methods/neighbor_search/neighbor_search_rules_impl.hpp +++ b/src/mlpack/methods/neighbor_search/neighbor_search_rules_impl.hpp @@ -397,9 +397,7 @@ inline double NeighborSearchRules:: // take the better of the two. double worstDistance = SortPolicy::BestDistance(); - double bestDistance = SortPolicy::WorstDistance(); double bestPointDistance = SortPolicy::WorstDistance(); - double auxDistance = SortPolicy::WorstDistance(); // Loop over points held in the node. for (size_t i = 0; i < queryNode.NumPoints(); ++i) @@ -411,7 +409,7 @@ inline double NeighborSearchRules:: bestPointDistance = distance; } - auxDistance = bestPointDistance; + double auxDistance = bestPointDistance; // Loop over children of the node, and use their cached information to // assemble bounds. @@ -428,7 +426,7 @@ inline double NeighborSearchRules:: // Add triangle inequality adjustment to best distance. It is possible this // could be tighter for some certain types of trees. - bestDistance = SortPolicy::CombineWorst(auxDistance, + double bestDistance = SortPolicy::CombineWorst(auxDistance, 2 * queryNode.FurthestDescendantDistance()); // Add triangle inequality adjustment to best distance of points in node. diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index de0f56d8df..2119879ab7 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -1,5 +1,8 @@ +include(CTest) + # mlpack test executable. add_executable(mlpack_test + EXCLUDE_FROM_ALL activation_functions_test.cpp adaboost_test.cpp akfn_test.cpp @@ -175,12 +178,21 @@ add_executable(mlpack_test main_tests/test_helper.hpp ) -# Link dependencies of test executable. -target_link_libraries(mlpack_test - mlpack - ${ARMADILLO_LIBRARIES} - ${COMPILER_SUPPORT_LIBRARIES} -) +if(NOT BUILD_SHARED_LIBS) +# Build mlpack test executable statically. + target_link_libraries(mlpack_test -static + mlpack + ${ARMADILLO_LIBRARIES} + ${COMPILER_SUPPORT_LIBRARIES} + ) +else() + # Build mlpack test executable dynamically. + target_link_libraries(mlpack_test + mlpack + ${ARMADILLO_LIBRARIES} + ${COMPILER_SUPPORT_LIBRARIES} + ) +endif() set_target_properties(mlpack_test PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "../core.hpp") cotire(mlpack_test) @@ -203,3 +215,5 @@ add_custom_command(TARGET mlpack_test ) add_test(NAME "catch_test" COMMAND mlpack_test WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + +set_tests_properties("catch_test" PROPERTIES TIMEOUT 0) diff --git a/src/mlpack/tests/activation_functions_test.cpp b/src/mlpack/tests/activation_functions_test.cpp index 2ae2ea344d..fcca17d2c0 100644 --- a/src/mlpack/tests/activation_functions_test.cpp +++ b/src/mlpack/tests/activation_functions_test.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include "catch.hpp" @@ -659,6 +660,48 @@ void CheckSoftminDerivativeCorrect(const arma::colvec input, } } +/** + * Implementation of the Flatten T Swish activation function test. The function is + * implemented as Flatten T Swish layer in the file flatten_t_swish.hpp. + * + * @param input Input data used for evaluating the Flatten T Swish activation function. + * @param target Target data used to evaluate the Flatten T Swish activation. + */ +void CheckFlattenTSwishActivationCorrect(const arma::colvec input, const arma::colvec target) +{ + FlattenTSwish<> fts(0.4); + arma::colvec activations; + + fts.Forward(input,activations); + for(size_t i = 0; i < activations.n_elem; ++i) + { + REQUIRE(activations.at(i) == Approx(target.at(i)).epsilon(1e-5)); + } +} + +/** + * Implementation of the Softmin activation function derivative test. + * The function is implemented as Softmin layer in the file softmin.hpp. + * + * @param input Input data used for evaluating the Softmin activation function. + * @param target Target data used to evaluate the Softmin activation. + */ + +void CheckFlattenTSwishDerivateCorrect(const arma::colvec input, const arma::colvec target) +{ + FlattenTSwish<> fts; + + // Set the error to 1 to get the actual derivative. + arma::colvec error = arma::ones(input.n_elem); + + arma::colvec derivate; + fts.Backward(input,error,derivate); + for(size_t i = 0; i < derivate.n_elem; ++i) + { + REQUIRE(derivate.at(i) == Approx(target.at(i)).epsilon(1e-5)); + } +} + /** * Basic test of the tanh function. */ @@ -1241,3 +1284,45 @@ TEST_CASE("TanhExpFunctionTest", "[ActivationFunctionsTest]") CheckActivationCorrect(activationData, desiredActivations); CheckDerivativeCorrect(desiredActivations, desiredDerivatives); } + +/** + * Basic test of the SILU(Sigmoid Weighted Linear Unit) Function + */ +TEST_CASE("SILUFunctionTest","[ActivationFunctionsTest]") +{ + // Random generated values. + const arma::colvec activationData("-2 2 4.5 -5.7 -1 1 0 10"); + + // Calculated with PyTorch. + arma::colvec desiredActivation("-0.23840583860874176 1.7615940570831299 4.450558662414551 \ + -0.01900840364396572 -0.2689414322376251 0.7310585975646973 \ + 0.0 9.99954605102539"); + + // Calculated with PyTorch. + arma::colvec desiredDerivate("0.38191673159599304 1.073788046836853 1.0392179489135742 \ + 0.49049633741378784 0.36713290214538574 0.8354039788246155 \ + 0.5 1.0004087686538696"); + + CheckActivationCorrect(activationData,desiredActivation); + CheckDerivativeCorrect(desiredActivation,desiredDerivate); +} + +/** + * Basic test of Flatten T Swish function. + */ +TEST_CASE("FlattenTSwishFunctionTest","[ActivationFunctionsTest]") +{ + // Random Value. + arma::colvec input("-4.0 -1.0 2 3 4 5 6"); + + // Hand Calculated and using PyTorch. + arma::colvec desiredActivation("0.4000000059604645 0.4000000059604645 2.1615941524505615 \ + 3.2577223777770996 4.328054904937744 5.3665361404418945 6.385164737701416"); + + // Hand Calculated and using PyTorch. + arma::colvec desiredDerivation("0.694792 0.694792 1.096893 1.079178 1.042602 \ + 1.020182 1.009048"); + + CheckFlattenTSwishActivationCorrect(input,desiredActivation); + CheckFlattenTSwishDerivateCorrect(desiredActivation,desiredDerivation); +} \ No newline at end of file diff --git a/src/mlpack/tests/akfn_test.cpp b/src/mlpack/tests/akfn_test.cpp index a5f802cd7e..1808190fbb 100644 --- a/src/mlpack/tests/akfn_test.cpp +++ b/src/mlpack/tests/akfn_test.cpp @@ -241,4 +241,3 @@ TEST_CASE("AKFNDualBallTreeTest", "[AKFNTest]") for (size_t i = 0; i < neighborsBallTree.n_elem; ++i) REQUIRE_RELATIVE_ERR(distancesBallTree(i), distancesExact(i), 0.05); } - diff --git a/src/mlpack/tests/det_test.cpp b/src/mlpack/tests/det_test.cpp index ab55a541cd..8f49d39fca 100644 --- a/src/mlpack/tests/det_test.cpp +++ b/src/mlpack/tests/det_test.cpp @@ -341,7 +341,7 @@ TEST_CASE("TestComputeValue", "[DETTest]") REQUIRE(d3 == Approx(testDTree.ComputeValue(q3)).epsilon(1e-12)); REQUIRE(0.0 == Approx(testDTree.ComputeValue(q4)).epsilon(1e-12)); - alpha = testDTree.PruneAndUpdate(alpha, testData.n_cols, false); + testDTree.PruneAndUpdate(alpha, testData.n_cols, false); double d = 1.0 / exp(log(4.0) + log(7.0) + log(7.0)); @@ -448,7 +448,7 @@ TEST_CASE("TestSparseComputeValue", "[DETTest]") REQUIRE(d3 == Approx(testDTree.ComputeValue(q3)).epsilon(1e-12)); REQUIRE(0.0 == Approx(testDTree.ComputeValue(q4)).epsilon(1e-12)); - alpha = testDTree.PruneAndUpdate(alpha, testData.n_cols, false); + testDTree.PruneAndUpdate(alpha, testData.n_cols, false); double d = 1.0 / exp(log(4.0) + log(7.0) + log(7.0)); diff --git a/src/mlpack/tests/krann_search_test.cpp b/src/mlpack/tests/krann_search_test.cpp index 68214b4a25..a548b30438 100644 --- a/src/mlpack/tests/krann_search_test.cpp +++ b/src/mlpack/tests/krann_search_test.cpp @@ -368,7 +368,8 @@ TEST_CASE("DualCoverTreeTest", "[KRANNTest]") RACoverTreeSearch tsdRann(&refTree, false, 1.0, 0.95, false, false, 5); arma::Mat qrRanks; - if (!data::Load("rann_test_qr_ranks.csv", qrRanks, false, false)) // No transpose. + // No transpose. + if (!data::Load("rann_test_qr_ranks.csv", qrRanks, false, false)) FAIL("Cannot load dataset rann_test_qr_ranks.csv"); size_t numRounds = 100; diff --git a/src/mlpack/tests/serialization.hpp b/src/mlpack/tests/serialization.hpp index b88ff5e957..361523f701 100644 --- a/src/mlpack/tests/serialization.hpp +++ b/src/mlpack/tests/serialization.hpp @@ -29,19 +29,16 @@ void TestArmadilloSerialization(arma::Cube& x) // Use type_info name to get unique file name for serialization test files. std::string fileName = FilterFileName(typeid(IArchiveType).name()); std::ofstream ofs(fileName, std::ios::binary); - bool success = true; { OArchiveType o(ofs); o(CEREAL_NVP(x)); } - REQUIRE(success == true); ofs.close(); // Now load it. arma::Cube orig(x); - success = true; std::ifstream ifs(fileName, std::ios::binary); { @@ -52,8 +49,6 @@ void TestArmadilloSerialization(arma::Cube& x) remove(fileName.c_str()); - REQUIRE(success == true); - REQUIRE(x.n_rows == orig.n_rows); REQUIRE(x.n_cols == orig.n_cols); REQUIRE(x.n_elem_slice == orig.n_elem_slice); @@ -99,19 +94,16 @@ void TestArmadilloSerialization(MatType& x) // First save it. std::string fileName = FilterFileName(typeid(IArchiveType).name()); std::ofstream ofs(fileName, std::ios::binary); - bool success = true; { OArchiveType o(ofs); o(CEREAL_NVP(x)); } - REQUIRE(success == true); ofs.close(); // Now load it. MatType orig(x); - success = true; std::ifstream ifs(fileName, std::ios::binary); { @@ -122,8 +114,6 @@ void TestArmadilloSerialization(MatType& x) remove(fileName.c_str()); - REQUIRE(success == true); - REQUIRE(x.n_rows == orig.n_rows); REQUIRE(x.n_cols == orig.n_cols); REQUIRE(x.n_elem == orig.n_elem); @@ -156,7 +146,6 @@ void SerializeObject(T& t, T& newT) { std::string fileName = FilterFileName(typeid(T).name()); std::ofstream ofs(fileName, std::ios::binary); - bool success = true; { OArchiveType o(ofs); @@ -166,8 +155,6 @@ void SerializeObject(T& t, T& newT) } ofs.close(); - REQUIRE(success == true); - std::ifstream ifs(fileName, std::ios::binary); { @@ -178,8 +165,6 @@ void SerializeObject(T& t, T& newT) ifs.close(); remove(fileName.c_str()); - - REQUIRE(success == true); } // Test mlpack serialization with all three archive types. @@ -200,7 +185,6 @@ void SerializePointerObject(T* t, T*& newT) { std::string fileName = FilterFileName(typeid(T).name()); std::ofstream ofs(fileName, std::ios::binary); - bool success = true; { OArchiveType o(ofs); @@ -208,8 +192,6 @@ void SerializePointerObject(T* t, T*& newT) } ofs.close(); - REQUIRE(success == true); - std::ifstream ifs(fileName, std::ios::binary); { @@ -218,8 +200,6 @@ void SerializePointerObject(T* t, T*& newT) } ifs.close(); remove(fileName.c_str()); - - REQUIRE(success == true); } template