diff -Nru mlpack-3.2.2/.appveyor.yml mlpack-3.3.0/.appveyor.yml --- mlpack-3.2.2/.appveyor.yml 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/.appveyor.yml 2020-04-07 13:17:16.000000000 +0000 @@ -85,8 +85,8 @@ - cd C:\projects\mlpack && mkdir build && cd build - > cmake -G "%VSVER%" - -DBLAS_LIBRARY:FILEPATH=%BLAS_LIBRARY% - -DLAPACK_LIBRARY:FILEPATH=%BLAS_LIBRARY% + -DBLAS_LIBRARIES:FILEPATH=%BLAS_LIBRARY% + -DLAPACK_LIBRARIES:FILEPATH=%BLAS_LIBRARY% -DARMADILLO_INCLUDE_DIR="C:/projects/mlpack/armadillo-8.400.0/include" -DARMADILLO_LIBRARY:FILEPATH=%ARMADILLO_LIBRARY% -DBOOST_INCLUDEDIR:PATH=%BOOST_INCLUDE% diff -Nru mlpack-3.2.2/.ci/ci.yaml mlpack-3.3.0/.ci/ci.yaml --- mlpack-3.2.2/.ci/ci.yaml 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/.ci/ci.yaml 2020-04-07 13:17:16.000000000 +0000 @@ -1,3 +1,12 @@ +trigger: + branches: + include: + - '*' +pr: + branches: + include: + - '*' + jobs: - job: Linux timeoutInMinutes: 360 @@ -14,6 +23,10 @@ Python37: python.version: '3.7' CMakeArgs: '-DDEBUG=OFF -DPROFILE=OFF -DPYTHON_EXECUTABLE=/usr/bin/python3' + Julia: + python.version: '2.7' + julia.version: '1.3.0' + CMakeArgs: '-DDEBUG=OFF -DPROFILE=OFF -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=ON -DJULIA_EXECUTABLE=/opt/julia-1.3.0/bin/julia' Markdown: python.version: '2.7' CMakeArgs: '-DDEBUG=OFF -DPROFILE=OFF -DBUILD_MARKDOWN_BINDINGS=ON -DBUILD_PYTHON_BINDINGS=OFF' @@ -24,7 +37,7 @@ - job: macOS timeoutInMinutes: 360 pool: - vmImage: macOS-10.13 + vmImage: macOS-10.14 strategy: matrix: Plain: @@ -36,27 +49,14 @@ Python37: python.version: '3.7' CMakeArgs: '-DDEBUG=OFF -DPROFILE=OFF' + Julia: + python.version: '2.7' + julia.version: '1.3.0' + CMakeArgs: '-DDEBUG=OFF -DPROFILE=OFF -DBUILD_JULIA_BINDINGS=ON -DBUILD_PYTHON_BINDINGS=OFF' steps: - template: macos-steps.yaml -- job: WindowsVS14 - timeoutInMinutes: 360 - displayName: Windows VS14 - pool: - vmImage: vs2015-win2012r2 - strategy: - matrix: - Plain: - CMakeArgs: '-DDEBUG=ON -DPROFILE=OFF -DBUILD_PYTHON_BINDINGS=OFF' - CMakeGenerator: '-G "Visual Studio 14 2015 Win64"' - MSBuildVersion: '14.0' - ArchiveNoLibs: 'mlpack-windows-vs14-no-libs.zip' - ArchiveLibs: 'mlpack-windows-vs14.zip' - ArchiveTests: 'mlpack_test-vs14.xml' - steps: - - template: windows-steps.yaml - - job: WindowsVS15 timeoutInMinutes: 360 displayName: Windows VS15 diff -Nru mlpack-3.2.2/.ci/linux-steps.yaml mlpack-3.3.0/.ci/linux-steps.yaml --- mlpack-3.2.2/.ci/linux-steps.yaml 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/.ci/linux-steps.yaml 2020-04-07 13:17:16.000000000 +0000 @@ -12,7 +12,7 @@ # Install build dependencies - script: | git clone --depth 1 https://github.com/mlpack/jenkins-conf.git conf - + sudo add-apt-repository ppa:mhier/libboost-latest sudo apt-get update @@ -26,6 +26,7 @@ if [ '$(python.version)' == '2.7' ]; then sudo apt-get install -y --allow-unauthenticated python-pip cython python-numpy python-pandas sudo pip install --upgrade --ignore-installed setuptools cython + sudo pip install "zipp<3.1" fi if [ '$(python.version)' == '3.7' ]; then @@ -33,10 +34,14 @@ sudo pip3 install --upgrade --ignore-installed setuptools cython pandas fi + if [ 'a$(julia.version)' != 'a' ]; then + wget https://julialang-s3.julialang.org/bin/linux/x64/1.3/julia-1.3.0-linux-x86_64.tar.gz + sudo tar -C /opt/ -xvpf julia-1.3.0-linux-x86_64.tar.gz + fi + # Install armadillo. curl https://ftp.fau.de/macports/distfiles/armadillo/armadillo-8.400.0.tar.xz | tar -xvJ && cd armadillo* cmake . && make && sudo make install && cd .. - sudo cp .travis/config.hpp /usr/include/armadillo_bits/config.hpp displayName: 'Install Build Dependencies' # Configure mlpack (CMake) @@ -47,27 +52,21 @@ - script: cd build && make -j2 displayName: 'Build' -# Run tests -- script: cd build && bin/mlpack_test --result_code=no --report_level=detailed --log_level=test_suite --log_format=HRF --log_sink=res.txt - displayName: 'Run tests' - -# Process test results -- bash: | - python conf/ci/convert.py > mlpack_test.xml - displayName: 'Process test results' +# Run tests via ctest. +- script: cd build && CTEST_OUTPUT_ON_FAILURE=1 ctest -T Test . + displayName: 'Run tests via ctest' # Publish test results to Azure Pipelines - task: PublishTestResults@2 inputs: - testResultsFormat: JUnit - testResultsFiles: 'mlpack_test.xml' + testResultsFormat: cTest + testResultsFiles: build/Testing/*/Test.xml failTaskOnFailedTests: true displayName: 'Publish tests' # Publish build artifacts to Azure Pipelines - task: PublishBuildArtifacts@1 inputs: - pathtoPublish: 'mlpack_test.xml' - artifactName: 'mlpack_test_linux.xml' + pathtoPublish: 'build/Testing/' + artifactName: 'Tests' displayName: 'Publish artifacts test results' - diff -Nru mlpack-3.2.2/.ci/macos-steps.yaml mlpack-3.3.0/.ci/macos-steps.yaml --- mlpack-3.2.2/.ci/macos-steps.yaml 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/.ci/macos-steps.yaml 2020-04-07 13:17:16.000000000 +0000 @@ -14,9 +14,13 @@ set -e sudo xcode-select --switch /Applications/Xcode_10.1.app/Contents/Developer unset BOOST_ROOT - pip install cython numpy pandas + pip install cython numpy pandas zipp configparser brew install openblas armadillo boost + if [ "a$(julia.version)" != "a" ]; then + brew cask install julia + fi + git clone --depth 1 https://github.com/mlpack/jenkins-conf.git conf displayName: 'Install Build Dependencies' @@ -32,27 +36,21 @@ - script: cd build && make -j2 displayName: 'Build' -# Run tests -- script: cd build && bin/mlpack_test --result_code=no --report_level=detailed --log_level=test_suite --log_format=HRF --log_sink=res.txt - displayName: 'Run tests' - -# Process test results -- bash: | - python conf/ci/convert.py > mlpack_test.xml - displayName: 'Process test results' +# Run tests via ctest. +- script: cd build && CTEST_OUTPUT_ON_FAILURE=1 ctest -T Test . + displayName: 'Run tests via ctest' # Publish test results to Azure Pipelines - task: PublishTestResults@2 inputs: - testResultsFormat: JUnit - testResultsFiles: 'mlpack_test.xml' + testResultsFormat: cTest + testResultsFiles: build/Testing/*/Test.xml failTaskOnFailedTests: true displayName: 'Publish tests' # Publish build artifacts to Azure Pipelines - task: PublishBuildArtifacts@1 inputs: - pathtoPublish: 'mlpack_test.xml' - artifactName: 'mlpack_test_macos.xml' + pathtoPublish: 'build/Testing/' + artifactName: 'Tests' displayName: 'Publish artifacts test results' - diff -Nru mlpack-3.2.2/.ci/windows-steps.yaml mlpack-3.3.0/.ci/windows-steps.yaml --- mlpack-3.2.2/.ci/windows-steps.yaml 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/.ci/windows-steps.yaml 2020-04-07 13:17:16.000000000 +0000 @@ -28,8 +28,9 @@ # Configure armadillo - bash: | git clone --depth 1 https://github.com/mlpack/jenkins-conf.git conf - - curl http://masterblaster.mlpack.org:5005/armadillo-8.400.0.tar.gz | tar xvz + + curl -O http://masterblaster.mlpack.org:5005/armadillo-8.400.0.tar.gz -o armadillo-8.400.0.tar.gz + tar -xzvf armadillo-8.400.0.tar.gz cd armadillo-8.400.0/ && cmake $(CMakeGenerator) \ -DBLAS_LIBRARY:FILEPATH=$(Agent.ToolsDirectory)/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a \ @@ -59,12 +60,13 @@ cmake $(CMakeGenerator) ` $(CMakeArgs) ` - -DBLAS_LIBRARY:FILEPATH=$(Agent.ToolsDirectory)\OpenBLAS.0.2.14.1\lib\native\lib\x64\libopenblas.dll.a ` - -DLAPACK_LIBRARY:FILEPATH=$(Agent.ToolsDirectory)\OpenBLAS.0.2.14.1\lib\native\lib\x64\libopenblas.dll.a ` + -DBLAS_LIBRARIES:FILEPATH=$(Agent.ToolsDirectory)\OpenBLAS.0.2.14.1\lib\native\lib\x64\libopenblas.dll.a ` + -DLAPACK_LIBRARIES:FILEPATH=$(Agent.ToolsDirectory)\OpenBLAS.0.2.14.1\lib\native\lib\x64\libopenblas.dll.a ` -DARMADILLO_INCLUDE_DIR="..\armadillo-8.400.0\include" ` -DARMADILLO_LIBRARY="..\armadillo-8.400.0\Release\armadillo.lib" ` -DBOOST_INCLUDEDIR=$(Agent.ToolsDirectory)\boost.1.60.0.0\lib\native\include ` -DBOOST_LIBRARYDIR=$(Agent.ToolsDirectory)\boost_libs ` + -DBUILD_JULIA_BINDINGS=OFF ` -DCMAKE_BUILD_TYPE=Release .. displayName: 'Configure mlpack' @@ -95,10 +97,11 @@ Release/mlpack_test.exe --result_code=no --report_level=detailed --log_level=test_suite --log_format=HRF --log_sink=res.txt displayName: 'Run tests' -# Process test results +# Run tests via ctest. - bash: | - python conf/ci/convert.py > mlpack_test.xml - displayName: 'Process test results' + cd build + CTEST_OUTPUT_ON_FAILURE=1 ctest -T Test -C Release . + displayName: 'Run tests via ctest' # Copy artifacts - powershell: | @@ -138,14 +141,14 @@ displayName: 'Publish artifacts complete' - task: PublishBuildArtifacts@1 inputs: - pathtoPublish: 'mlpack_test.xml' - artifactName: $(ArchiveTests) + pathtoPublish: 'build/Testing/' + artifactName: 'Tests' displayName: 'Publish artifacts test results' # Publish test results to Azure Pipelines - task: PublishTestResults@2 inputs: - testResultsFormat: JUnit - testResultsFiles: 'mlpack_test.xml' + testResultsFormat: cTest + testResultsFiles: build/Testing/*/Test.xml failTaskOnFailedTests: true displayName: 'Publish tests' diff -Nru mlpack-3.2.2/CMake/ARMA_FindACML.cmake mlpack-3.3.0/CMake/ARMA_FindACML.cmake --- mlpack-3.2.2/CMake/ARMA_FindACML.cmake 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/CMake/ARMA_FindACML.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -# - Find AMD's ACML library (no includes) which provides optimised BLAS and LAPACK functions -# This module defines -# ACML_LIBRARIES, the libraries needed to use ACML. -# ACML_FOUND, If false, do not try to use ACML. -# also defined, but not for general use are -# ACML_LIBRARY, where to find the ACML library. - -set(ACML_NAMES ${ACML_NAMES} acml) -find_library(ACML_LIBRARY - NAMES ${ACML_NAMES} - PATHS /usr/lib64 /usr/lib /usr/*/lib64 /usr/*/lib /usr/*/gfortran64/lib/ /usr/*/gfortran32/lib/ /usr/local/lib64 /usr/local/lib /opt/lib64 /opt/lib /opt/*/lib64 /opt/*/lib /opt/*/gfortran64/lib/ /opt/*/gfortran32/lib/ - ) - -if (ACML_LIBRARY) - set(ACML_LIBRARIES ${ACML_LIBRARY}) - set(ACML_FOUND "YES") -else () - set(ACML_FOUND "NO") -endif () - - -if (ACML_FOUND) - if (NOT ACML_FIND_QUIETLY) - message(STATUS "Found the ACML library: ${ACML_LIBRARIES}") - endif () -else () - if (ACML_FIND_REQUIRED) - message(FATAL_ERROR "Could not find the ACML library") - endif () -endif () - -# Deprecated declarations. -get_filename_component (NATIVE_ACML_LIB_PATH ${ACML_LIBRARY} PATH) - -mark_as_advanced( - ACML_LIBRARY - ) diff -Nru mlpack-3.2.2/CMake/ARMA_FindACMLMP.cmake mlpack-3.3.0/CMake/ARMA_FindACMLMP.cmake --- mlpack-3.2.2/CMake/ARMA_FindACMLMP.cmake 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/CMake/ARMA_FindACMLMP.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -# - Find AMD's ACMLMP library (no includes) which provides optimised and parallelised BLAS and LAPACK functions -# This module defines -# ACMLMP_LIBRARIES, the libraries needed to use ACMLMP. -# ACMLMP_FOUND, If false, do not try to use ACMLMP. -# also defined, but not for general use are -# ACMLMP_LIBRARY, where to find the ACMLMP library. - -set(ACMLMP_NAMES ${ACMLMP_NAMES} acml_mp) -find_library(ACMLMP_LIBRARY - NAMES ${ACMLMP_NAMES} - PATHS /usr/lib64 /usr/lib /usr/*/lib64 /usr/*/lib /usr/*/gfortran64_mp/lib/ /usr/*/gfortran32_mp/lib/ /usr/local/lib64 /usr/local/lib /opt/lib64 /opt/lib /opt/*/lib64 /opt/*/lib /opt/*/gfortran64_mp/lib/ /opt/*/gfortran32_mp/lib/ - ) - -if (ACMLMP_LIBRARY) - set(ACMLMP_LIBRARIES ${ACMLMP_LIBRARY}) - set(ACMLMP_FOUND "YES") -else () - set(ACMLMP_FOUND "NO") -endif () - - -if (ACMLMP_FOUND) - if (NOT ACMLMP_FIND_QUIETLY) - message(STATUS "Found the ACMLMP library: ${ACMLMP_LIBRARIES}") - endif () -else () - if (ACMLMP_FIND_REQUIRED) - message(FATAL_ERROR "Could not find the ACMLMP library") - endif () -endif () - -# Deprecated declarations. -get_filename_component (NATIVE_ACMLMP_LIB_PATH ${ACMLMP_LIBRARY} PATH) - -mark_as_advanced( - ACMLMP_LIBRARY - ) diff -Nru mlpack-3.2.2/CMake/ARMA_FindARPACK.cmake mlpack-3.3.0/CMake/ARMA_FindARPACK.cmake --- mlpack-3.2.2/CMake/ARMA_FindARPACK.cmake 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/CMake/ARMA_FindARPACK.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -# - Try to find ARPACK -# Once done this will define -# -# ARPACK_FOUND - system has ARPACK -# ARPACK_LIBRARY - Link this to use ARPACK - - -find_library(ARPACK_LIBRARY - NAMES arpack - PATHS /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib - ) - - -if (ARPACK_LIBRARY) - set(ARPACK_FOUND YES) -else () - # Search for PARPACK. - find_library(ARPACK_LIBRARY - NAMES parpack - PATHS /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib - ) - - if (ARPACK_LIBRARY) - set(ARPACK_FOUND YES) - else () - set(ARPACK_FOUND NO) - endif () -endif () - - -if (ARPACK_FOUND) - if (NOT ARPACK_FIND_QUIETLY) - message(STATUS "Found an ARPACK library: ${ARPACK_LIBRARY}") - endif () -else () - if (ARPACK_FIND_REQUIRED) - message(FATAL_ERROR "Could not find an ARPACK library") - endif () -endif () diff -Nru mlpack-3.2.2/CMake/ARMA_FindBLAS.cmake mlpack-3.3.0/CMake/ARMA_FindBLAS.cmake --- mlpack-3.2.2/CMake/ARMA_FindBLAS.cmake 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/CMake/ARMA_FindBLAS.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -# - Find a BLAS library (no includes) -# This module defines -# BLAS_LIBRARIES, the libraries needed to use BLAS. -# BLAS_FOUND, If false, do not try to use BLAS. -# also defined, but not for general use are -# BLAS_LIBRARY, where to find the BLAS library. - -set(BLAS_NAMES ${BLAS_NAMES} blas) - -# Find the ATLAS version preferentially. -find_library(BLAS_LIBRARY - NAMES ${BLAS_NAMES} - PATHS /usr/lib64/atlas /usr/lib/atlas /usr/local/lib64/atlas /usr/local/lib/atlas - NO_DEFAULT_PATH) - -find_library(BLAS_LIBRARY - NAMES ${BLAS_NAMES} - PATHS /usr/lib64/atlas /usr/lib/atlas /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib - ) - -if (BLAS_LIBRARY) - set(BLAS_LIBRARIES ${BLAS_LIBRARY}) - set(BLAS_FOUND "YES") -else () - set(BLAS_FOUND "NO") -endif () - - -if (BLAS_FOUND) - if (NOT BLAS_FIND_QUIETLY) - message(STATUS "Found BLAS: ${BLAS_LIBRARIES}") - endif () -else () - if (BLAS_FIND_REQUIRED) - message(FATAL_ERROR "Could not find BLAS") - endif () -endif () - -# Deprecated declarations. -get_filename_component (NATIVE_BLAS_LIB_PATH ${BLAS_LIBRARY} PATH) - -mark_as_advanced( - BLAS_LIBRARY - ) diff -Nru mlpack-3.2.2/CMake/ARMA_FindCBLAS.cmake mlpack-3.3.0/CMake/ARMA_FindCBLAS.cmake --- mlpack-3.2.2/CMake/ARMA_FindCBLAS.cmake 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/CMake/ARMA_FindCBLAS.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -# - Find CBLAS (includes and library) -# This module defines -# CBLAS_INCLUDE_DIR -# CBLAS_LIBRARIES -# CBLAS_FOUND -# also defined, but not for general use are -# CBLAS_LIBRARY, where to find the library. - -find_path(CBLAS_INCLUDE_DIR cblas.h -/usr/include/atlas/ -/usr/local/include/atlas/ -/usr/include/ -/usr/local/include/ -) - -set(CBLAS_NAMES ${CBLAS_NAMES} cblas) -find_library(CBLAS_LIBRARY - NAMES ${CBLAS_NAMES} - PATHS /usr/lib64/atlas-sse3 /usr/lib64/atlas /usr/lib64 /usr/local/lib64/atlas /usr/local/lib64 /usr/lib/atlas-sse3 /usr/lib/atlas-sse2 /usr/lib/atlas-sse /usr/lib/atlas-3dnow /usr/lib/atlas /usr/lib /usr/local/lib/atlas /usr/local/lib - ) - -if (CBLAS_LIBRARY AND CBLAS_INCLUDE_DIR) - set(CBLAS_LIBRARIES ${CBLAS_LIBRARY}) - set(CBLAS_FOUND "YES") -else () - set(CBLAS_FOUND "NO") -endif () - - -if (CBLAS_FOUND) - if (NOT CBLAS_FIND_QUIETLY) - message(STATUS "Found a CBLAS library: ${CBLAS_LIBRARIES}") - endif () -else () - if (CBLAS_FIND_REQUIRED) - message(FATAL_ERROR "Could not find a CBLAS library") - endif () -endif () - -# Deprecated declarations. -set (NATIVE_CBLAS_INCLUDE_PATH ${CBLAS_INCLUDE_DIR} ) -get_filename_component (NATIVE_CBLAS_LIB_PATH ${CBLAS_LIBRARY} PATH) - -mark_as_advanced( - CBLAS_LIBRARY - CBLAS_INCLUDE_DIR - ) diff -Nru mlpack-3.2.2/CMake/ARMA_FindCLAPACK.cmake mlpack-3.3.0/CMake/ARMA_FindCLAPACK.cmake --- mlpack-3.2.2/CMake/ARMA_FindCLAPACK.cmake 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/CMake/ARMA_FindCLAPACK.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -# - Find a version of CLAPACK (includes and library) -# This module defines -# CLAPACK_INCLUDE_DIR -# CLAPACK_LIBRARIES -# CLAPACK_FOUND -# also defined, but not for general use are -# CLAPACK_LIBRARY, where to find the library. - -find_path(CLAPACK_INCLUDE_DIR clapack.h -/usr/include/atlas/ -/usr/local/include/atlas/ -/usr/include/ -/usr/local/include/ -) - -set(CLAPACK_NAMES ${CLAPACK_NAMES} lapack_atlas) -set(CLAPACK_NAMES ${CLAPACK_NAMES} clapack) -find_library(CLAPACK_LIBRARY - NAMES ${CLAPACK_NAMES} - PATHS /usr/lib64/atlas-sse3 /usr/lib64/atlas /usr/lib64 /usr/local/lib64/atlas /usr/local/lib64 /usr/lib/atlas-sse3 /usr/lib/atlas-sse2 /usr/lib/atlas-sse /usr/lib/atlas-3dnow /usr/lib/atlas /usr/lib /usr/local/lib/atlas /usr/local/lib - ) - -if (CLAPACK_LIBRARY AND CLAPACK_INCLUDE_DIR) - set(CLAPACK_LIBRARIES ${CLAPACK_LIBRARY}) - set(CLAPACK_FOUND "YES") -else () - set(CLAPACK_FOUND "NO") -endif () - - -if (CLAPACK_FOUND) - if (NOT CLAPACK_FIND_QUIETLY) - message(STATUS "Found a CLAPACK library: ${CLAPACK_LIBRARIES}") - endif () -else () - if (CLAPACK_FIND_REQUIRED) - message(FATAL_ERROR "Could not find a CLAPACK library") - endif () -endif () - -# Deprecated declarations. -set (NATIVE_CLAPACK_INCLUDE_PATH ${CLAPACK_INCLUDE_DIR} ) -get_filename_component (NATIVE_CLAPACK_LIB_PATH ${CLAPACK_LIBRARY} PATH) - -mark_as_advanced( - CLAPACK_LIBRARY - CLAPACK_INCLUDE_DIR - ) diff -Nru mlpack-3.2.2/CMake/ARMA_FindLAPACK.cmake mlpack-3.3.0/CMake/ARMA_FindLAPACK.cmake --- mlpack-3.2.2/CMake/ARMA_FindLAPACK.cmake 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/CMake/ARMA_FindLAPACK.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -# - Find a LAPACK library (no includes) -# This module defines -# LAPACK_LIBRARIES, the libraries needed to use LAPACK. -# LAPACK_FOUND, If false, do not try to use LAPACK. -# also defined, but not for general use are -# LAPACK_LIBRARY, where to find the LAPACK library. - -set(LAPACK_NAMES ${LAPACK_NAMES} lapack) - -# Check ATLAS paths preferentially, using this necessary hack (I love CMake). -find_library(LAPACK_LIBRARY - NAMES ${LAPACK_NAMES} - PATHS /usr/lib64/atlas /usr/lib/atlas /usr/local/lib64/atlas /usr/local/lib/atlas - NO_DEFAULT_PATH) - -find_library(LAPACK_LIBRARY - NAMES ${LAPACK_NAMES} - PATHS /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib - ) - -if (LAPACK_LIBRARY) - set(LAPACK_LIBRARIES ${LAPACK_LIBRARY}) - set(LAPACK_FOUND "YES") -else () - set(LAPACK_FOUND "NO") -endif () - - -if (LAPACK_FOUND) - if (NOT LAPACK_FIND_QUIETLY) - message(STATUS "Found LAPACK: ${LAPACK_LIBRARIES}") - endif () -else () - if (LAPACK_FIND_REQUIRED) - message(FATAL_ERROR "Could not find LAPACK") - endif () -endif () - -# Deprecated declarations. -get_filename_component (NATIVE_LAPACK_LIB_PATH ${LAPACK_LIBRARY} PATH) - -mark_as_advanced( - LAPACK_LIBRARY - ) diff -Nru mlpack-3.2.2/CMake/ARMA_FindMKL.cmake mlpack-3.3.0/CMake/ARMA_FindMKL.cmake --- mlpack-3.2.2/CMake/ARMA_FindMKL.cmake 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/CMake/ARMA_FindMKL.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -# - Find the MKL libraries (no includes) -# This module defines -# MKL_LIBRARIES, the libraries needed to use Intel's implementation of BLAS & LAPACK. -# MKL_FOUND, If false, do not try to use MKL. - -set(MKL_NAMES ${MKL_NAMES} mkl_lapack) -set(MKL_NAMES ${MKL_NAMES} mkl_intel_thread) -set(MKL_NAMES ${MKL_NAMES} mkl_core) -set(MKL_NAMES ${MKL_NAMES} guide) -set(MKL_NAMES ${MKL_NAMES} mkl) -set(MKL_NAMES ${MKL_NAMES} iomp5) -#set(MKL_NAMES ${MKL_NAMES} pthread) - -if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(MKL_NAMES ${MKL_NAMES} mkl_intel_lp64) -else() - set(MKL_NAMES ${MKL_NAMES} mkl_intel) -endif() - -foreach (MKL_NAME ${MKL_NAMES}) - find_library(${MKL_NAME}_LIBRARY - NAMES ${MKL_NAME} - PATHS /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib /opt/intel/lib/intel64 /opt/intel/lib/ia32 /opt/intel/mkl/lib/lib64 /opt/intel/mkl/lib/intel64 /opt/intel/mkl/lib/ia32 /opt/intel/mkl/lib /opt/intel/*/mkl/lib/intel64 /opt/intel/*/mkl/lib/ia32/ /opt/mkl/*/lib/em64t /opt/mkl/*/lib/32 /opt/intel/mkl/*/lib/em64t /opt/intel/mkl/*/lib/32 - ) - - set(TMP_LIBRARY ${${MKL_NAME}_LIBRARY}) - - if(TMP_LIBRARY) - set(MKL_LIBRARIES ${MKL_LIBRARIES} ${TMP_LIBRARY}) - endif() -endforeach() - -if (MKL_LIBRARIES) - set(MKL_FOUND "YES") -else () - set(MKL_FOUND "NO") -endif () - -if (MKL_FOUND) - if (NOT MKL_FIND_QUIETLY) - message(STATUS "Found MKL libraries: ${MKL_LIBRARIES}") - endif () -else () - if (MKL_FIND_REQUIRED) - message(FATAL_ERROR "Could not find MKL libraries") - endif () -endif () - -# mark_as_advanced(MKL_LIBRARY) diff -Nru mlpack-3.2.2/CMake/ARMA_FindOpenBLAS.cmake mlpack-3.3.0/CMake/ARMA_FindOpenBLAS.cmake --- mlpack-3.2.2/CMake/ARMA_FindOpenBLAS.cmake 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/CMake/ARMA_FindOpenBLAS.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -# - Find the OpenBLAS library (no includes) -# This module defines -# OpenBLAS_LIBRARIES, the libraries needed to use OpenBLAS. -# OpenBLAS_FOUND, If false, do not try to use OpenBLAS. -# also defined, but not for general use are -# OpenBLAS_LIBRARY, where to find the OpenBLAS library. - -set(OpenBLAS_NAMES ${OpenBLAS_NAMES} openblas) -find_library(OpenBLAS_LIBRARY - NAMES ${OpenBLAS_NAMES} - PATHS /lib64 /lib /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib - ) - -if (OpenBLAS_LIBRARY) - set(OpenBLAS_LIBRARIES ${OpenBLAS_LIBRARY}) - set(OpenBLAS_FOUND "YES") -else () - set(OpenBLAS_FOUND "NO") -endif () - - -if (OpenBLAS_FOUND) - if (NOT OpenBLAS_FIND_QUIETLY) - message(STATUS "Found the OpenBLAS library: ${OpenBLAS_LIBRARIES}") - endif () -else () - if (OpenBLAS_FIND_REQUIRED) - message(FATAL_ERROR "Could not find the OpenBLAS library") - endif () -endif () - -# Deprecated declarations. -get_filename_component (NATIVE_OpenBLAS_LIB_PATH ${OpenBLAS_LIBRARY} PATH) - -mark_as_advanced( - OpenBLAS_LIBRARY - ) diff -Nru mlpack-3.2.2/CMake/ConfigureGenerate.cmake mlpack-3.3.0/CMake/ConfigureGenerate.cmake --- mlpack-3.2.2/CMake/ConfigureGenerate.cmake 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/CMake/ConfigureGenerate.cmake 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,11 @@ +# ConfigureGenerate.cmake: generate an mlpack binding file given input +# arguments. +# +# This file depends on the following variables being set: +# +# * GENERATE_CPP_IN: the .cpp.in file to configure. +# * GENERATE_CPP_OUT: the .cpp file we'll generate. +# +# Any other defined variables will be passed on to the file that is being +# generated. +configure_file(${GENERATE_CPP_IN} ${GENERATE_CPP_OUT}) diff -Nru mlpack-3.2.2/CMake/ConfigureGeneratePYX.cmake mlpack-3.3.0/CMake/ConfigureGeneratePYX.cmake --- mlpack-3.2.2/CMake/ConfigureGeneratePYX.cmake 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/CMake/ConfigureGeneratePYX.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -# ConfigureGeneratePYX.cmake: generate an mlpack .pyx file given input -# arguments. -# -# This file depends on the following variables being set: -# -# * GENERATE_CPP_IN: the .cpp.in file to configure. -# * GENERATE_CPP_OUT: the .cpp file we'll generate. -# * PROGRAM_MAIN_FILE: the file containing the main() function. -# * PROGRAM_NAME: the name of the program (i.e. "pca"). -configure_file(${GENERATE_CPP_IN} ${GENERATE_CPP_OUT}) diff -Nru mlpack-3.2.2/CMake/FindArmadillo.cmake mlpack-3.3.0/CMake/FindArmadillo.cmake --- mlpack-3.2.2/CMake/FindArmadillo.cmake 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/CMake/FindArmadillo.cmake 2020-04-07 13:17:16.000000000 +0000 @@ -1,41 +1,41 @@ -# - Find Armadillo -# Find the Armadillo C++ library -# -# Using Armadillo: -# find_package(Armadillo REQUIRED) -# include_directories(${ARMADILLO_INCLUDE_DIRS}) -# add_executable(foo foo.cc) -# target_link_libraries(foo ${ARMADILLO_LIBRARIES}) -# This module sets the following variables: -# ARMADILLO_FOUND - set to true if the library is found -# ARMADILLO_INCLUDE_DIRS - list of required include directories -# ARMADILLO_LIBRARIES - list of libraries to be linked -# ARMADILLO_VERSION_MAJOR - major version number -# ARMADILLO_VERSION_MINOR - minor version number -# ARMADILLO_VERSION_PATCH - patch version number -# ARMADILLO_VERSION_STRING - version number as a string (ex: "1.0.4") -# ARMADILLO_VERSION_NAME - name of the version (ex: "Antipodean Antileech") - -#============================================================================= -# Copyright 2011 Clement Creusot -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. +#[=======================================================================[.rst: +FindArmadillo +------------- + +Find the Armadillo C++ library. +Armadillo is a library for linear algebra & scientific computing. + +Using Armadillo: + +:: + + find_package(Armadillo REQUIRED) + include_directories(${ARMADILLO_INCLUDE_DIRS}) + add_executable(foo foo.cc) + target_link_libraries(foo ${ARMADILLO_LIBRARIES}) + +This module sets the following variables: + +:: + + ARMADILLO_FOUND - set to true if the library is found + ARMADILLO_INCLUDE_DIRS - list of required include directories + ARMADILLO_LIBRARIES - list of libraries to be linked + ARMADILLO_VERSION_MAJOR - major version number + ARMADILLO_VERSION_MINOR - minor version number + ARMADILLO_VERSION_PATCH - patch version number + ARMADILLO_VERSION_STRING - version number as a string (ex: "1.0.4") + ARMADILLO_VERSION_NAME - name of the version (ex: "Antipodean Antileech") +#]=======================================================================] find_path(ARMADILLO_INCLUDE_DIR NAMES armadillo PATHS "$ENV{ProgramFiles}/Armadillo/include" ) - if(ARMADILLO_INCLUDE_DIR) # ------------------------------------------------------------------------ # Extract version information from @@ -52,318 +52,117 @@ if(EXISTS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/arma_version.hpp") # Read and parse armdillo version header file for version number - file(READ "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/arma_version.hpp" _armadillo_HEADER_CONTENTS) - string(REGEX REPLACE ".*#define ARMA_VERSION_MAJOR ([0-9]+).*" "\\1" ARMADILLO_VERSION_MAJOR "${_armadillo_HEADER_CONTENTS}") - string(REGEX REPLACE ".*#define ARMA_VERSION_MINOR ([0-9]+).*" "\\1" ARMADILLO_VERSION_MINOR "${_armadillo_HEADER_CONTENTS}") - string(REGEX REPLACE ".*#define ARMA_VERSION_PATCH ([0-9]+).*" "\\1" ARMADILLO_VERSION_PATCH "${_armadillo_HEADER_CONTENTS}") + file(STRINGS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/arma_version.hpp" _ARMA_HEADER_CONTENTS REGEX "#define ARMA_VERSION_[A-Z]+ ") + string(REGEX REPLACE ".*#define ARMA_VERSION_MAJOR ([0-9]+).*" "\\1" ARMADILLO_VERSION_MAJOR "${_ARMA_HEADER_CONTENTS}") + string(REGEX REPLACE ".*#define ARMA_VERSION_MINOR ([0-9]+).*" "\\1" ARMADILLO_VERSION_MINOR "${_ARMA_HEADER_CONTENTS}") + string(REGEX REPLACE ".*#define ARMA_VERSION_PATCH ([0-9]+).*" "\\1" ARMADILLO_VERSION_PATCH "${_ARMA_HEADER_CONTENTS}") # WARNING: The number of spaces before the version name is not one. - string(REGEX REPLACE ".*#define ARMA_VERSION_NAME\ +\"([0-9a-zA-Z\ _-]+)\".*" "\\1" ARMADILLO_VERSION_NAME "${_armadillo_HEADER_CONTENTS}") + string(REGEX REPLACE ".*#define ARMA_VERSION_NAME\ +\"([0-9a-zA-Z\ _-]+)\".*" "\\1" ARMADILLO_VERSION_NAME "${_ARMA_HEADER_CONTENTS}") endif() set(ARMADILLO_VERSION_STRING "${ARMADILLO_VERSION_MAJOR}.${ARMADILLO_VERSION_MINOR}.${ARMADILLO_VERSION_PATCH}") endif () - -#====================== - -# Determine what support libraries are being used, and whether or not we need to -# link against them. We need to look in config.hpp. -set(SUPPORT_INCLUDE_DIRS "") -set(SUPPORT_LIBRARIES "") -set(ARMA_NEED_LIBRARY true) # Assume true. if(EXISTS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/config.hpp") - file(READ "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/config.hpp" _armadillo_CONFIG_CONTENTS) - # ARMA_USE_WRAPPER - string(REGEX MATCH "\r?\n[\t ]*#define[ \t]+ARMA_USE_WRAPPER[ \t]*\r?\n" ARMA_USE_WRAPPER "${_armadillo_CONFIG_CONTENTS}") - - # ARMA_USE_LAPACK - string(REGEX MATCH "\r?\n[\t ]*#if[\t ]+!defined[(]ARMA_USE_LAPACK[)][\t ]*\r?\n[\t ]*#define[ \t]+ARMA_USE_LAPACK[ \t]*\r?\n" ARMA_USE_LAPACK "${_armadillo_CONFIG_CONTENTS}") - - # ARMA_USE_BLAS - string(REGEX MATCH "\r?\n[\t ]*#if[\t ]+!defined[(]ARMA_USE_BLAS[)][\t ]*\r?\n[\t ]*#define[ \t]+ARMA_USE_BLAS[ \t]*\r?\n" ARMA_USE_BLAS "${_armadillo_CONFIG_CONTENTS}") - # ARMA_USE_ARPACK - # ARMA_USE_ARPACK - string(REGEX MATCH "\r?\n[\t ]*#if[\t ]+!defined[(]ARMA_USE_ARPACK[)][\t ]*\r?\n[\t ]*#define[ \t]+ARMA_USE_ARPACK[ \t]*\r?\n" ARMA_USE_ARPACK "${_armadillo_CONFIG_CONTENTS}") - - # Look for #define ARMA_USE_HDF5. - string(REGEX MATCH "\r?\n[\t ]*#if[\t ]+!defined[(]ARMA_USE_HDF5[)][\t ]*\r?\n[\t ]*#define[ \t]+ARMA_USE_HDF5[ \t]*\r?\n" ARMA_USE_HDF5 "${_armadillo_CONFIG_CONTENTS}") - - # If we aren't wrapping, things get a little more complex. - if("${ARMA_USE_WRAPPER}" STREQUAL "") - set(ARMA_NEED_LIBRARY false) - message(STATUS "ARMA_USE_WRAPPER is not defined, so all dependencies of " - "Armadillo must be manually linked.") - - set(HAVE_LAPACK false) - set(HAVE_BLAS false) - - # Search for LAPACK/BLAS (or replacement). - if ((NOT "${ARMA_USE_LAPACK}" STREQUAL "") AND - (NOT "${ARMA_USE_BLAS}" STREQUAL "")) - # In order of preference: MKL, ACML, OpenBLAS, ATLAS - set(MKL_FIND_QUIETLY true) - include(ARMA_FindMKL) - set(ACMLMP_FIND_QUIETLY true) - include(ARMA_FindACMLMP) - set(ACML_FIND_QUIETLY true) - include(ARMA_FindACML) - - if (MKL_FOUND) - message(STATUS "Using MKL for LAPACK/BLAS: ${MKL_LIBRARIES}") - - set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${MKL_LIBRARIES}") - set(HAVE_LAPACK true) - set(HAVE_BLAS true) - elseif (ACMLMP_FOUND) - message(STATUS "Using multi-core ACML libraries for LAPACK/BLAS: - ${ACMLMP_LIBRARIES}") - - set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${ACMLMP_LIBRARIES}") - set(HAVE_LAPACK true) - set(HAVE_BLAS true) - elseif (ACML_FOUND) - message(STATUS "Using ACML for LAPACK/BLAS: ${ACML_LIBRARIES}") - - set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${ACML_LIBRARIES}") - set(HAVE_LAPACK true) - set(HAVE_BLAS true) - endif () - endif () - - # If we haven't found BLAS, try. - if (NOT "${ARMA_USE_BLAS}" STREQUAL "" AND NOT HAVE_BLAS) - # Search for BLAS. - set(OpenBLAS_FIND_QUIETLY true) - include(ARMA_FindOpenBLAS) - set(CBLAS_FIND_QUIETLY true) - include(ARMA_FindCBLAS) - set(BLAS_FIND_QUIETLY true) - include(ARMA_FindBLAS) - - if (OpenBLAS_FOUND) - # Warn if ATLAS is found also. - if (CBLAS_FOUND) - message(STATUS "Warning: both OpenBLAS and ATLAS have been found; " - "ATLAS will not be used.") - endif () - message(STATUS "Using OpenBLAS for BLAS: ${OpenBLAS_LIBRARIES}") - - set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${OpenBLAS_LIBRARIES}") - set(HAVE_BLAS true) - elseif (CBLAS_FOUND) - message(STATUS "Using ATLAS for BLAS: ${CBLAS_LIBRARIES}") - - set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${CBLAS_LIBRARIES}") - set(SUPPORT_INCLUDE_DIRS "${SUPPORT_INCLUDE_DIRS}" - "${CBLAS_INCLUDE_DIR}") - set(HAVE_BLAS true) - elseif (BLAS_FOUND) - message(STATUS "Using standard BLAS: ${BLAS_LIBRARIES}") - - set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${BLAS_LIBRARIES}") - set(HAVE_BLAS true) - endif () - endif () - - # If we haven't found LAPACK, try. - if (NOT "${ARMA_USE_LAPACK}" STREQUAL "" AND NOT HAVE_LAPACK) - # Search for LAPACK. - set(CLAPACK_FIND_QUIETLY true) - include(ARMA_FindCLAPACK) - set(LAPACK_FIND_QUIETLY true) - include(ARMA_FindLAPACK) - - # Only use ATLAS if OpenBLAS isn't being used. - if (CLAPACK_FOUND AND NOT OpenBLAS_FOUND) - message(STATUS "Using ATLAS for LAPACK: ${CLAPACK_LIBRARIES}") - - set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${CLAPACK_LIBRARIES}") - set(SUPPORT_INCLUDE_DIRS "${SUPPORT_INCLUDE_DIRS}" - "${CLAPACK_INCLUDE_DIR}") - set(HAVE_LAPACK true) - elseif (LAPACK_FOUND) - message(STATUS "Using standard LAPACK: ${LAPACK_LIBRARIES}") - - set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${LAPACK_LIBRARIES}") - set(HAVE_LAPACK true) - endif () - endif () - - if (NOT "${ARMA_USE_LAPACK}" STREQUAL "" AND NOT HAVE_LAPACK) - message(FATAL_ERROR "Cannot find LAPACK library, but ARMA_USE_LAPACK is " - "set. Try specifying LAPACK libraries manually by setting the " - "LAPACK_LIBRARY variable.") - endif () - - if (NOT "${ARMA_USE_BLAS}" STREQUAL "" AND NOT HAVE_BLAS) - message(FATAL_ERROR "Cannot find BLAS library, but ARMA_USE_BLAS is set. " - "Try specifying BLAS libraries manually by setting the BLAS_LIBRARY " - "variable.") - endif () - - # Search for ARPACK (or replacement). - if (NOT "${ARMA_USE_ARPACK}" STREQUAL "") - # Use Armadillo ARPACK-finding procedure. - set(ARPACK_FIND_QUIETLY true) - include(ARMA_FindARPACK) - - if (NOT ARPACK_FOUND) - message(FATAL_ERROR "ARMA_USE_ARPACK is defined in " - "armadillo_bits/config.hpp, but ARPACK cannot be found. Try " - "specifying ARPACK_LIBRARY.") - endif () - - set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${ARPACK_LIBRARY}") - endif () - - # Search for HDF5 (or replacement). - if (NOT "${ARMA_USE_HDF5}" STREQUAL "") - find_package(HDF5 QUIET) - - if(NOT HDF5_FOUND) - # On Debian systems, the HDF5 package has been split into multiple - # packages so that it is co-installable. But this may mean that the - # include files are hidden somewhere very odd that the FindHDF5.cmake - # script will not find. Thus, we'll also quickly check pkgconfig to see - # if there is information on what to use there. - find_package(PkgConfig) - if (PKG_CONFIG_FOUND) - pkg_check_modules(HDF5 hdf5) - # But using pkgconfig is a little weird because HDF5_LIBRARIES won't - # be filled with exact library paths, like the other scripts. So - # instead what we get is HDF5_LIBRARY_DIRS which is the equivalent of - # what we'd pass to -L. - if (HDF5_FOUND) - # I'm not sure what I think of doing this here... - link_directories("${HDF5_LIBRARY_DIRS}") - endif() - endif() - endif() - - if(NOT HDF5_FOUND) - # We tried but didn't find it. - message(FATAL_ERROR "Armadillo HDF5 support is enabled, but HDF5 " - "cannot be found on the system. Consider disabling HDF5 support.") - endif() - - set(SUPPORT_INCLUDE_DIRS "${SUPPORT_INCLUDE_DIRS}" "${HDF5_INCLUDE_DIRS}") - set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${HDF5_LIBRARIES}") - endif () - - else() - # Some older versions still require linking against HDF5 since they did not - # wrap libhdf5. This was true for versions older than 4.300. - if(NOT "${ARMA_USE_HDF5}" STREQUAL "" AND - "${ARMADILLO_VERSION_STRING}" VERSION_LESS "4.300.0") - message(STATUS "Armadillo HDF5 support is enabled and manual linking is " - "required.") - # We have HDF5 support and need to link against HDF5. - find_package(HDF5) - - if(NOT HDF5_FOUND) - # On Debian systems, the HDF5 package has been split into multiple - # packages so that it is co-installable. But this may mean that the - # include files are hidden somewhere very odd that the FindHDF5.cmake - # script will not find. Thus, we'll also quickly check pkgconfig to see - # if there is information on what to use there. - find_package(PkgConfig) - if (PKG_CONFIG_FOUND) - pkg_check_modules(HDF5 hdf5) - # But using pkgconfig is a little weird because HDF5_LIBRARIES won't - # be filled with exact library paths, like the other scripts. So - # instead what we get is HDF5_LIBRARY_DIRS which is the equivalent of - # what we'd pass to -L. - if (HDF5_FOUND) - # I'm not sure what I think of doing this here... - link_directories("${HDF5_LIBRARY_DIRS}") - endif() - endif() - endif() - - if(NOT HDF5_FOUND) - # We tried but didn't find it. - message(FATAL_ERROR "Armadillo HDF5 support is enabled, but HDF5 " - "cannot be found on the system. Consider disabling HDF5 support.") - endif() + file(STRINGS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/config.hpp" _ARMA_CONFIG_CONTENTS REGEX "^#define ARMA_USE_[A-Z]+") + string(REGEX MATCH "ARMA_USE_WRAPPER" _ARMA_USE_WRAPPER "${_ARMA_CONFIG_CONTENTS}") + string(REGEX MATCH "ARMA_USE_LAPACK" _ARMA_USE_LAPACK "${_ARMA_CONFIG_CONTENTS}") + string(REGEX MATCH "ARMA_USE_BLAS" _ARMA_USE_BLAS "${_ARMA_CONFIG_CONTENTS}") + string(REGEX MATCH "ARMA_USE_ARPACK" _ARMA_USE_ARPACK "${_ARMA_CONFIG_CONTENTS}") + string(REGEX MATCH "ARMA_USE_HDF5" _ARMA_USE_HDF5 "${_ARMA_CONFIG_CONTENTS}") +endif() - set(SUPPORT_INCLUDE_DIRS "${HDF5_INCLUDE_DIRS}") - set(SUPPORT_LIBRARIES "${HDF5_LIBRARIES}") - endif() +include(FindPackageHandleStandardArgs) - # Versions between 4.300 and 4.500 did successfully wrap HDF5, but didn't have good support for setting the include directory correctly. - if(NOT "${ARMA_USE_HDF5}" STREQUAL "" AND - "${ARMADILLO_VERSION_STRING}" VERSION_GREATER "4.299.0" AND - "${ARMADILLO_VERSION_STRING}" VERSION_LESS "4.450.0") - message(STATUS "Armadillo HDF5 support is enabled and include " - "directories must be found.") - find_package(HDF5) - - if(NOT HDF5_FOUND) - # On Debian systems, the HDF5 package has been split into multiple - # packages so that it is co-installable. But this may mean that the - # include files are hidden somewhere very odd that the FindHDF5.cmake - # script will not find. Thus, we'll also quickly check pkgconfig to see - # if there is information on what to use there. - find_package(PkgConfig) - if (PKG_CONFIG_FOUND) - pkg_check_modules(HDF5 hdf5) - endif() - endif() - - if(NOT HDF5_FOUND) - # We tried but didn't find it. - message(FATAL_ERROR "Armadillo HDF5 support is enabled, but HDF5 " - "cannot be found on the system. Consider disabling HDF5 support.") - endif() +# If _ARMA_USE_WRAPPER is set, then we just link to armadillo, but if it's not then we need support libraries instead +set(_ARMA_SUPPORT_LIBRARIES) - set(SUPPORT_INCLUDE_DIRS "${HDF5_INCLUDE_DIRS}") - endif() - - endif() -else() - message(FATAL_ERROR "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/config.hpp not " - "found! Cannot determine what to link against.") -endif() - -if (ARMA_NEED_LIBRARY) +if(_ARMA_USE_WRAPPER) # UNIX paths are standard, no need to write. find_library(ARMADILLO_LIBRARY NAMES armadillo PATHS "$ENV{ProgramFiles}/Armadillo/lib" "$ENV{ProgramFiles}/Armadillo/lib64" "$ENV{ProgramFiles}/Armadillo" ) + set(_ARMA_REQUIRED_VARS ARMADILLO_LIBRARY ARMADILLO_INCLUDE_DIR VERSION_VAR ARMADILLO_VERSION_STRING) +else() + # don't link to armadillo in this case + set(ARMADILLO_LIBRARY "") + if(_ARMA_USE_LAPACK) + if(ARMADILLO_FIND_QUIETLY OR NOT ARMADILLO_FIND_REQUIRED) + find_package(LAPACK QUIET) + else() + find_package(LAPCK REQUIRED) + endif() + if(LAPACK_FOUND) + set(_ARMA_SUPPORT_LIBRARIES "${_ARMA_SUPPORT_LIBRARIES}" "${LAPACK_LIBRARIES}") + endif() + endif() + if(_ARMA_USE_BLAS) + if(ARMADILLO_FIND_QUIETLY OR NOT ARMADILLO_FIND_REQUIRED) + find_package(BLAS QUIET) + else() + find_package(BLAS REQUIRED) + endif() + if(BLAS_FOUND) + set(_ARMA_SUPPORT_LIBRARIES "${_ARMA_SUPPORT_LIBRARIES}" "${BLAS_LIBRARIES}") + endif() + endif() + if(_ARMA_USE_ARPACK) + if(ARMADILLO_FIND_QUIETLY OR NOT ARMADILLO_FIND_REQUIRED) + find_package(ARPACK QUIET) + else() + find_package(ARPACK REQUIRED) + endif() + if(ARPACK_FOUND) + set(_ARMA_SUPPORT_LIBRARIES "${_ARMA_SUPPORT_LIBRARIES}" "${ARPACK_LIBRARIES}") + endif() + endif() + if(_ARMA_USE_HDF5) + find_package(HDF5 QUIET) + if(NOT HDF5_FOUND) + # On Debian systems, the HDF5 package has been split into multiple + # packages so that it is co-installable. But this may mean that the + # include files are hidden somewhere very odd that FindHDF5.cmake will + # not find. Thus, we'll also quickly check pkgconfig to see if there is + # information on what to use there. + message(WARNING "HDF5 required but not found; using PkgConfig") + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_check_modules(HDF5 REQUIRED hdf5) + link_directories("${HDF5_LIBRARY_DIRS}") + else() + message(FATAL_ERROR "PkgConfig (Used to help find HDF5) was not found") + endif() + endif() + set(_ARMA_SUPPORT_INCLUDE_DIRS "${HDF5_INCLUDE_DIRS}") + set(_ARMA_SUPPORT_LIBRARIES "${_ARMA_SUPPORT_LIBRARIES}" "${HDF5_LIBRARIES}") + endif() + set(ARMADILLO_FOUND true) + set(_ARMA_REQUIRED_VARS ARMADILLO_INCLUDE_DIR VERSION_VAR ARMADILLO_VERSION_STRING) +endif() - # Checks 'REQUIRED', 'QUIET' and versions. - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(Armadillo - REQUIRED_VARS ARMADILLO_LIBRARY ARMADILLO_INCLUDE_DIR - VERSION_VAR ARMADILLO_VERSION_STRING) - # version_var fails with cmake < 2.8.4. -else () - # Checks 'REQUIRED', 'QUIET' and versions. - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(Armadillo - REQUIRED_VARS ARMADILLO_INCLUDE_DIR - VERSION_VAR ARMADILLO_VERSION_STRING) -endif () +find_package_handle_standard_args(Armadillo REQUIRED_VARS ${_ARMA_REQUIRED_VARS}) if (ARMADILLO_FOUND) - # Also include support include directories. - set(ARMADILLO_INCLUDE_DIRS ${ARMADILLO_INCLUDE_DIR} ${SUPPORT_INCLUDE_DIRS}) - # Also include support libraries to link against. - if (ARMA_NEED_LIBRARY) - set(ARMADILLO_LIBRARIES ${ARMADILLO_LIBRARY} ${SUPPORT_LIBRARIES}) - else () - set(ARMADILLO_LIBRARIES ${SUPPORT_LIBRARIES}) - endif () - message(STATUS "Armadillo libraries: ${ARMADILLO_LIBRARIES}") + set(ARMADILLO_INCLUDE_DIRS ${ARMADILLO_INCLUDE_DIR}) + set(ARMADILLO_LIBRARIES ${ARMADILLO_LIBRARY} ${_ARMA_SUPPORT_LIBRARIES}) endif () +# Clean up internal variables +unset(_ARMA_REQUIRED_VARS) +unset(_ARMA_SUPPORT_LIBRARIES) +unset(_ARMA_USE_WRAPPER) +unset(_ARMA_USE_LAPACK) +unset(_ARMA_USE_BLAS) +unset(_ARMA_USE_ARPACK) +unset(_ARMA_USE_HDF5) +unset(_ARMA_CONFIG_CONTENTS) +unset(_ARMA_HEADER_CONTENTS) +unset(__ARMA_SUPPORT_INCLUDE_DIRS) # Hide internal variables mark_as_advanced( ARMADILLO_INCLUDE_DIR ARMADILLO_LIBRARY) - -#====================== diff -Nru mlpack-3.2.2/CMake/FindARPACK.cmake mlpack-3.3.0/CMake/FindARPACK.cmake --- mlpack-3.2.2/CMake/FindARPACK.cmake 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/CMake/FindARPACK.cmake 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,55 @@ +# Searches for an installation of the ARPACK library. On success, it sets the following variables: +# +# ARPACK_FOUND Set to true to indicate the library was found +# ARPACK_LIBRARIES All libraries needed to use ARPACK (with full path) +# +# To specify an additional directory to search, set ARPACK_ROOT. +# +# TODO: Do we need to explicitly search for BLAS and LAPACK as well? The source distribution statically links these to +# libarpack. Are there any installations that don't do this or the equivalent? +# +# Author: Siddhartha Chaudhuri, 2009 +# + +SET(ARPACK_FOUND FALSE) + +# First look in user-provided root directory, then look in system locations +FIND_LIBRARY(ARPACK_LIBRARIES NAMES arpack libarpack ARPACK libARPACK PATHS "${ARPACK_ROOT}" "${ARPACK_ROOT}/lib" + NO_DEFAULT_PATH) +IF(NOT ARPACK_LIBRARIES) + FIND_LIBRARY(ARPACK_LIBRARIES NAMES arpack libarpack ARPACK libARPACK) +ENDIF(NOT ARPACK_LIBRARIES) + +IF(ARPACK_LIBRARIES) + # On OS X we probably also need gfortran and BLAS and LAPACK libraries + IF(APPLE) + FIND_LIBRARY(ARPACK_LAPACK_LIBRARY NAMES lapack LAPACK PATHS "${ARPACK_ROOT}" "${ARPACK_ROOT}/lib") + FIND_LIBRARY(ARPACK_BLAS_LIBRARY NAMES blas BLAS PATHS "${ARPACK_ROOT}" "${ARPACK_ROOT}/lib") + FIND_LIBRARY(ARPACK_GFORTRAN_LIBRARY NAMES gfortran PATHS "${ARPACK_ROOT}" "${ARPACK_ROOT}/lib" + PATH_SUFFIXES "" "gfortran/lib" "../gfortran/lib") + + IF(ARPACK_BLAS_LIBRARY) + SET(ARPACK_LIBRARIES ${ARPACK_LIBRARIES} ${ARPACK_BLAS_LIBRARY}) + ENDIF(ARPACK_BLAS_LIBRARY) + + IF(ARPACK_LAPACK_LIBRARY) + SET(ARPACK_LIBRARIES ${ARPACK_LIBRARIES} ${ARPACK_LAPACK_LIBRARY}) + ENDIF(ARPACK_LAPACK_LIBRARY) + + IF(ARPACK_GFORTRAN_LIBRARY) + SET(ARPACK_LIBRARIES ${ARPACK_LIBRARIES} ${ARPACK_GFORTRAN_LIBRARY}) + ENDIF(ARPACK_GFORTRAN_LIBRARY) + ENDIF(APPLE) + + SET(ARPACK_FOUND TRUE) +ENDIF(ARPACK_LIBRARIES) + +IF(ARPACK_FOUND) + IF(NOT ARPACK_FIND_QUIETLY) + MESSAGE(STATUS "Found ARPACK: libraries at ${ARPACK_LIBRARIES}") + ENDIF(NOT ARPACK_FIND_QUIETLY) +ELSE(ARPACK_FOUND) + IF(ARPACK_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "ARPACK not found") + ENDIF(ARPACK_FIND_REQUIRED) +ENDIF(ARPACK_FOUND) diff -Nru mlpack-3.2.2/CMake/FindJulia.cmake mlpack-3.3.0/CMake/FindJulia.cmake --- mlpack-3.2.2/CMake/FindJulia.cmake 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/CMake/FindJulia.cmake 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,31 @@ +# FindJulia.cmake +# +# Based on Jay's implementation: +# https://gist.github.com/JayKickliter/06d0e7c4f84ef7ccc7a9 +if (JULIA_FOUND) + return() +endif() + +# Find the Julia program. +find_program(JULIA_EXECUTABLE julia DOC "Julia executable") + +# Get the Julia version. +if (JULIA_EXECUTABLE) + execute_process( + COMMAND ${JULIA_EXECUTABLE} --version + OUTPUT_VARIABLE JULIA_VERSION_STRING + RESULT_VARIABLE RESULT + ) + if (RESULT EQUAL 0) + string(REGEX REPLACE ".*([0-9]+\\.[0-9]+\\.[0-9]+).*" "\\1" + JULIA_VERSION_STRING ${JULIA_VERSION_STRING}) + endif () +endif () + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + Julia + REQUIRED_VARS JULIA_EXECUTABLE + VERSION_VAR JULIA_VERSION_STRING + FAIL_MESSAGE "Julia not found" +) diff -Nru mlpack-3.2.2/CMake/FindStbImage.cmake mlpack-3.3.0/CMake/FindStbImage.cmake --- mlpack-3.2.2/CMake/FindStbImage.cmake 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/CMake/FindStbImage.cmake 2020-04-07 13:17:16.000000000 +0000 @@ -6,13 +6,32 @@ # STB_IMAGE_INCLUDE_DIR - list of required include directories file(GLOB STB_IMAGE_SEARCH_PATHS + ${CMAKE_BINARY_DIR}/deps/ ${CMAKE_BINARY_DIR}/deps/stb) find_path(STB_IMAGE_INCLUDE_DIR - NAMES stb_image.h stb_image_write.h - PATHS ${STB_IMAGE_SEARCH_PATHS}) + NAMES stb/stb_image.h stb/stb_image_write.h + PATHS ${STB_IMAGE_SEARCH_PATHS}) if(STB_IMAGE_INCLUDE_DIR) set(STB_IMAGE_FOUND YES) +else () + find_path(STB_IMAGE_INCLUDE_DIR + NAMES stb_image.h stb_image_write.h + PATHS ${STB_IMAGE_SEARCH_PATHS}) + + if(STB_IMAGE_INCLUDE_DIR) + set(STB_IMAGE_FOUND YES) + endif () +endif () + +# Make sure that stb/ is the last part of the include directory, if it was +# found. +if (STB_IMAGE_INCLUDE_DIR) + string(REGEX MATCH ".*stb[/]?" STB_INCLUDE_HAS_TRAILING_STB + "${STB_IMAGE_INCLUDE_DIR}") + if (NOT STB_INCLUDE_HAS_TRAILING_STB) + set(STB_IMAGE_INCLUDE_DIR "${STB_IMAGE_INCLUDE_DIR}/stb/") + endif () endif () # Checks 'REQUIRED'. diff -Nru mlpack-3.2.2/CMake/GenerateBinding.cmake mlpack-3.3.0/CMake/GenerateBinding.cmake --- mlpack-3.2.2/CMake/GenerateBinding.cmake 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/CMake/GenerateBinding.cmake 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,9 @@ +# GenerateBinding.cmake: a CMake script that actually runs the given program to +# generate an mlpack binding file. +# +# This script depends on the following arguments: +# +# GENERATE_BINDING_PROGRAM: the program to run to generate the binding file. +# BINDING_OUTPUT_FILE: the file to store the output in. +execute_process(COMMAND ${GENERATE_BINDING_PROGRAM} + OUTPUT_FILE ${BINDING_OUTPUT_FILE}) diff -Nru mlpack-3.2.2/CMake/julia/ConfigureJuliaHCPP.cmake mlpack-3.3.0/CMake/julia/ConfigureJuliaHCPP.cmake --- mlpack-3.2.2/CMake/julia/ConfigureJuliaHCPP.cmake 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/CMake/julia/ConfigureJuliaHCPP.cmake 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,71 @@ +# ConfigureJuliaHCPP.cmake: generate an mlpack .h file for a Julia binding given +# input arguments. +# +# This file depends on the following variables being set: +# +# * PROGRAM_NAME: name of the binding +# * PROGRAM_MAIN_FILE: the file containing the mlpackMain() function. +# * JULIA_H_IN: path of the julia_method.h.in file. +# * JULIA_H_OUT: name of the output .h file. +# * JULIA_CPP_IN: path of the julia_method.cpp.in file. +# * JULIA_CPP_OUT: name of the output .cpp file. +# +# We need to parse the main file and find any PARAM_MODEL_* lines. +file(READ "${PROGRAM_MAIN_FILE}" MAIN_FILE) + +# Grab all "PARAM_MODEL_IN(Model,", "PARAM_MODEL_IN_REQ(Model,", +# "PARAM_MODEL_OUT(Model,". +string(REGEX MATCHALL "PARAM_MODEL_IN\\([A-Za-z_]*," MODELS_IN "${MAIN_FILE}") +string(REGEX MATCHALL "PARAM_MODEL_IN_REQ\\([A-Za-z_]*," MODELS_IN_REQ + "${MAIN_FILE}") +string(REGEX MATCHALL "PARAM_MODEL_OUT\\([A-Za-z_]*," MODELS_OUT "${MAIN_FILE}") + +string(REGEX REPLACE "PARAM_MODEL_IN\\(" "" MODELS_IN_STRIP1 "${MODELS_IN}") +string(REGEX REPLACE "," "" MODELS_IN_STRIP2 "${MODELS_IN_STRIP1}") + +string(REGEX REPLACE "PARAM_MODEL_IN_REQ\\(" "" MODELS_IN_REQ_STRIP1 + "${MODELS_IN_REQ}") +string(REGEX REPLACE "," "" MODELS_IN_REQ_STRIP2 "${MODELS_IN_REQ_STRIP1}") + +string(REGEX REPLACE "PARAM_MODEL_OUT\\(" "" MODELS_OUT_STRIP1 "${MODELS_OUT}") +string(REGEX REPLACE "," "" MODELS_OUT_STRIP2 "${MODELS_OUT_STRIP1}") + +set(MODEL_TYPES ${MODELS_IN_STRIP2} ${MODELS_IN_REQ_STRIP2} ${MODELS_OUT_STRIP2}) +if (MODEL_TYPES) + list(REMOVE_DUPLICATES MODEL_TYPES) +endif () + +# Now, generate the definitions of the functions we need. +set(MODEL_PTR_DEFNS "") +set(MODEL_PTR_IMPLS "") +foreach (MODEL_TYPE ${MODEL_TYPES}) + # Generate the definition. + set(MODEL_PTR_DEFNS "${MODEL_PTR_DEFNS} +// Get the pointer to a ${MODEL_TYPE} parameter. +void* CLI_GetParam${MODEL_TYPE}Ptr(const char* paramName); +// Set the pointer to a ${MODEL_TYPE} parameter. +void CLI_SetParam${MODEL_TYPE}Ptr(const char* paramName, void* ptr); + +") + + # Generate the implementation. + set(MODEL_PTR_IMPLS "${MODEL_PTR_IMPLS} +// Get the pointer to a ${MODEL_TYPE} parameter. +void* CLI_GetParam${MODEL_TYPE}Ptr(const char* paramName) +{ + return (void*) CLI::GetParam<${MODEL_TYPE}*>(paramName); +} + +// Set the pointer to a ${MODEL_TYPE} parameter. +void CLI_SetParam${MODEL_TYPE}Ptr(const char* paramName, void* ptr) +{ + CLI::GetParam<${MODEL_TYPE}*>(paramName) = (${MODEL_TYPE}*) ptr; + CLI::SetPassed(paramName); +} + +") +endforeach () + +# Now configure both of the files. +configure_file("${JULIA_H_IN}" "${JULIA_H_OUT}") +configure_file("${JULIA_CPP_IN}" "${JULIA_CPP_OUT}") diff -Nru mlpack-3.2.2/CMake/mlpack_coverage.in mlpack-3.3.0/CMake/mlpack_coverage.in --- mlpack-3.2.2/CMake/mlpack_coverage.in 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/CMake/mlpack_coverage.in 2020-04-07 13:17:16.000000000 +0000 @@ -77,10 +77,10 @@ # Run the tests. if [ "$test_case" = "ALL" ]; then echo "Running all the tests..." - @CMAKE_BINARY_DIR@/bin/mlpack_test + "@CMAKE_BINARY_DIR@"/bin/mlpack_test elif ! [ "$test_case" = "" ]; then echo "Running test suite: $test_case" - @CMAKE_BINARY_DIR@/bin/mlpack_test --run_test=$test_case + "@CMAKE_BINARY_DIR@"/bin/mlpack_test --run_test=$test_case fi # Generate coverage based on executed tests. diff -Nru mlpack-3.2.2/CMakeLists.txt mlpack-3.3.0/CMakeLists.txt --- mlpack-3.2.2/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -13,9 +13,11 @@ option(TEST_VERBOSE "Run test cases with verbose output." OFF) option(BUILD_TESTS "Build tests." ON) option(BUILD_CLI_EXECUTABLES "Build command-line executables." ON) +option(DISABLE_DOWNLOADS "Disable downloads of dependencies during build." OFF) option(DOWNLOAD_ENSMALLEN "If ensmallen is not found, download it." ON) option(DOWNLOAD_STB_IMAGE "Download stb_image for image loading." ON) option(BUILD_PYTHON_BINDINGS "Build Python bindings." ON) +option(BUILD_JULIA_BINDINGS "Build Julia bindings." ON) if (WIN32) option(BUILD_SHARED_LIBS @@ -48,6 +50,12 @@ # 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) @@ -144,7 +152,7 @@ # Setup build for test coverage if(BUILD_WITH_COVERAGE) - # Currently coverage only works with GNU g++ + # Currently coverage only works with GNU g++. if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") # Find gcov and lcov find_program(GCOV gcov) @@ -156,6 +164,7 @@ endif() set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} "supc++") + set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} "quadmath") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -fno-inline -fno-inline-small-functions -fno-default-inline -fprofile-arcs -fkeep-inline-functions") message(STATUS "Adding debug compile options for code coverage.") # Remove optimizations for better line coverage @@ -236,6 +245,7 @@ # BOOST_INCLUDEDIR - include directory for Boost # BOOST_LIBRARYDIR - library directory for Boost # 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 8.400.0 REQUIRED) @@ -282,51 +292,6 @@ endif () endif() -# On Windows, Armadillo should be using LAPACK and BLAS but we still need to -# link against it. We don't want to use the FindLAPACK or FindBLAS modules -# because then we are required to have a FORTRAN compiler (argh!) so we will try -# and find LAPACK and BLAS ourselves, using a slightly modified variant of the -# script Armadillo uses to find these. -if (WIN32) - find_library(LAPACK_LIBRARY - NAMES lapack liblapack lapack_win32_MT lapack_win32 - PATHS "C:/Program Files/Armadillo" - PATH_SUFFIXES "examples/lib_win32/") - - if (NOT LAPACK_LIBRARY) - message(FATAL_ERROR "Cannot find LAPACK library (.lib)!") - endif () - - find_library(BLAS_LIBRARY - NAMES blas libblas blas_win32_MT blas_win32 - PATHS "C:/Program Files/Armadillo" - PATH_SUFFIXES "examples/lib_win32/") - - if (NOT BLAS_LIBRARY) - message(FATAL_ERROR "Cannot find BLAS library (.lib)!") - endif () - - # Piggyback LAPACK and BLAS linking into Armadillo link. - set(ARMADILLO_LIBRARIES - ${ARMADILLO_LIBRARIES} ${BLAS_LIBRARY} ${LAPACK_LIBRARY}) - - # Ensure that the libraries are added to the MSVC IDE runtime path. - get_filename_component(BLAS_DIR ${BLAS_LIBRARY} DIRECTORY) - get_filename_component(LAPACK_DIR ${LAPACK_LIBRARY} DIRECTORY) - - # Sometimes, especially with an OpenBLAS install via nuget, the DLLs are - # actually in ../../bin/x64/. Automatically add these. - if (EXISTS "${BLAS_DIR}/../../bin/x64/") - get_filename_component(BLAS_DLL_DIR "${BLAS_DIR}/../../bin/x64" ABSOLUTE) - set(DLL_COPY_DIRS ${DLL_COPY_DIRS} "${BLAS_DLL_DIR}") - endif () - - if (EXISTS "${LAPACK_DIR}/../../bin/x64/") - get_filename_component(LAPACK_DLL_DIR "${LAPACK_DIR}/../../bin/x64" ABSOLUTE) - set(DLL_COPY_DIRS ${DLL_COPY_DIRS} "${BLAS_DLL_DIR}") - 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}) @@ -363,6 +328,7 @@ 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!") @@ -383,6 +349,7 @@ # Already has STB installed. add_definitions(-DHAS_STB) set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${STB_IMAGE_INCLUDE_DIR}) + set(STB_AVAILABLE "1") endif () @@ -392,20 +359,25 @@ find_package(Ensmallen 2.10.0) if (NOT ENSMALLEN_FOUND) if (DOWNLOAD_ENSMALLEN) - file(DOWNLOAD http://www.ensmallen.org/files/ensmallen-2.10.4.tar.gz - "${CMAKE_BINARY_DIR}/deps/ensmallen-2.10.4.tar.gz" + file(DOWNLOAD http://www.ensmallen.org/files/ensmallen-2.12.0.tar.gz + "${CMAKE_BINARY_DIR}/deps/ensmallen-2.12.0.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-2.10.4.tar.gz" + tar xzf "${CMAKE_BINARY_DIR}/deps/ensmallen-2.12.0.tar.gz" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/deps/") # 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 ENS_DIRECTORIES EXCLUDE REGEX "ensmallen-.*\.tar\.gz") + # 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-2.12.0.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) @@ -443,6 +415,9 @@ # Unfortunately this configuration variable is necessary and will need to be # updated as time goes on and new versions are released. set(Boost_ADDITIONAL_VERSIONS + "1.72.0" "1.72" + "1.71.0" "1.71" + "1.70.0" "1.70" "1.69.0" "1.69" "1.68.0" "1.68" "1.67.0" "1.67" @@ -454,17 +429,14 @@ "1.61.1" "1.61.0" "1.61" "1.60.1" "1.60.0" "1.60" "1.59.1" "1.59.0" "1.59" - "1.58.1" "1.58.0" "1.58" - "1.57.1" "1.57.0" "1.57" - "1.56.1" "1.56.0" "1.56" - "1.55.1" "1.55.0" "1.55" - "1.54.1" "1.54.0" "1.54" - "1.53.1" "1.53.0" "1.53" - "1.52.1" "1.52.0" "1.52" - "1.51.1" "1.51.0" "1.51" - "1.50.1" "1.50.0" "1.50" - "1.49.1" "1.49.0" "1.49") -find_package(Boost 1.49 + "1.58.1" "1.58.0" "1.58") +# Disable forced config-mode CMake search for Boost, which only imports targets +# and does not set the variables that we need. +# +# 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 1.58 COMPONENTS program_options unit_test_framework @@ -715,7 +687,7 @@ if ("${first}" STREQUAL "/") # We need to split the directory and the library. string(REGEX REPLACE "(.*/)[^/]*$" "\\1" library_dir "${lib}") - string(REGEX REPLACE ".*/lib([^/]*).so.*$" "\\1" library_name "${lib}") + string(REGEX REPLACE ".*/lib([^/]*)[.][a-z]*[.]*$" "\\1" library_name "${lib}") list(APPEND MLPACK_LIBRARIES_LIST "-L${library_dir}") list(APPEND MLPACK_LIBRARIES_LIST "-l${library_name}") diff -Nru mlpack-3.2.2/CONTRIBUTING.md mlpack-3.3.0/CONTRIBUTING.md --- mlpack-3.2.2/CONTRIBUTING.md 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/CONTRIBUTING.md 2020-04-07 13:17:16.000000000 +0000 @@ -28,3 +28,49 @@ have already been reviewed, and pull request contributors are encouraged to seek multiple reviews. Reviews from anyone not on the Contributors team are always appreciated and encouraged! + +## Reviewing Pull Requests + +All mlpack contributors who choose to review and provide feedback on pull +requests have a responsibility to both the project and the individual making +the contribution. + +Reviews and feedback should be +[helpful, insightful, and geared towards improving the contribution]( + https://www.youtube.com/watch?v=NNXk_WJzyMI). +If there are reasons why you feel the PR should not be merged, explain +what those are. Be open to having your mind changed. Be open to +working with the contributor to make the pull request better. + +Please don't leave dismissive or disrespectful reviews! It's not helpful for +anyone. + +When reviewing a pull request, the primary goals are: + +- For the codebase/project to improve +- For the person submitting the request to succeed + +Even if a pull request does not get merged, the submitters should come away +from the experience feeling like their effort was not wasted or unappreciated. +Every pull request from a new contributor is an opportunity to grow the community. + +When changes are necessary, request them, do not demand them, and do not assume +that the contributor already knows how to do that. Be there to lend a helping +hand in case of need. + +Since there can sometimes be a lot more pull requests being opened than +reviewed, we highly encourage everyone to review each others pull request +keeping in mind all the above mentioned points. + +Let's welcome new contributors with ❤️. + +## Pull Request Waiting Time + +mlpack is a community-driven project, so everyone only works on it in their +free time; this means it may take some time for them to review pull requests. +While gentle reminders are welcome, please be patient and avoid constantly +messaging contributors or tagging them on pull requests. + +Typically small PRs will be reviewed within a handful of days; larger PRs might +take a few weeks for an initial review, and it may be a little bit longer in +times of high activity. diff -Nru mlpack-3.2.2/COPYRIGHT.txt mlpack-3.3.0/COPYRIGHT.txt --- mlpack-3.2.2/COPYRIGHT.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/COPYRIGHT.txt 2020-04-07 13:17:16.000000000 +0000 @@ -118,8 +118,19 @@ Copyright 2019, Heet Sankesara Copyright 2019, Jeffin Sam Copyright 2019, Vikas S Shetty + Copyright 2019, Khizir Siddiqui Copyright 2019, Tejasvi Tomar Copyright 2019, Jai Agarwal + Copyright 2019, Ziyang Jiang + Copyright 2019, Rohit Kartik + Copyright 2019, Aditya Viki + Copyright 2019, Kartik Dutt + Copyright 2020, Sriram S K + Copyright 2020, Manoranjan Kumar Bharti ( Nakul Bharti ) + Copyright 2020, Saraansh Tandon + Copyright 2020, Gaurav Singh + Copyright 2020, Lakshya Ojha + Copyright 2020, Bisakh Mondal License: BSD-3-clause All rights reserved. diff -Nru mlpack-3.2.2/debian/changelog mlpack-3.3.0/debian/changelog --- mlpack-3.2.2/debian/changelog 2020-04-11 12:54:21.000000000 +0000 +++ mlpack-3.3.0/debian/changelog 2020-04-23 16:22:07.000000000 +0000 @@ -1,8 +1,17 @@ -mlpack (3.2.2-3.1910.1) eoan; urgency=medium +mlpack (3.3.0-1.1910.1) eoan; urgency=medium - * PPA build for Ubuntu 19.10 ("eoan") + * PPA build for eoan - -- Dirk Eddelbuettel Sat, 11 Apr 2020 07:54:21 -0500 + -- Dirk Eddelbuettel Thu, 23 Apr 2020 11:22:07 -0500 + +mlpack (3.3.0-1) unstable; urgency=medium + + * New upstream release + * Set upstream metadata fields: Bug-Database, Bug-Submit, Repository, + Repository-Browse. + * Bump policy + + -- Barak A. Pearlmutter Fri, 17 Apr 2020 11:55:25 +0100 mlpack (3.2.2-3) unstable; urgency=medium diff -Nru mlpack-3.2.2/debian/control mlpack-3.3.0/debian/control --- mlpack-3.2.2/debian/control 2020-02-21 15:30:39.000000000 +0000 +++ mlpack-3.3.0/debian/control 2020-04-17 10:55:25.000000000 +0000 @@ -19,7 +19,7 @@ python3-pytest-runner, txt2man, doxygen, doxygen-latex, graphviz, latexmk -Standards-Version: 4.4.1 +Standards-Version: 4.5.0 Rules-Requires-Root: no Homepage: https://www.mlpack.org/ Vcs-Git: https://salsa.debian.org/science-team/mlpack.git diff -Nru mlpack-3.2.2/debian/patches/0001-build-Doxygen.patch mlpack-3.3.0/debian/patches/0001-build-Doxygen.patch --- mlpack-3.2.2/debian/patches/0001-build-Doxygen.patch 2020-02-21 15:13:49.000000000 +0000 +++ mlpack-3.3.0/debian/patches/0001-build-Doxygen.patch 2020-04-17 10:55:25.000000000 +0000 @@ -11,10 +11,10 @@ 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt -index 26757a5..922f141 100644 +index 4bb2eef..ff4dd40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt -@@ -666,7 +666,7 @@ if (DOXYGEN_FOUND) +@@ -638,7 +638,7 @@ if (DOXYGEN_FOUND) ) # Generate documentation. diff -Nru mlpack-3.2.2/debian/upstream/metadata mlpack-3.3.0/debian/upstream/metadata --- mlpack-3.2.2/debian/upstream/metadata 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/debian/upstream/metadata 2020-04-17 10:55:25.000000000 +0000 @@ -0,0 +1,4 @@ +Bug-Database: https://github.com/mlpack/mlpack/issues +Bug-Submit: https://github.com/mlpack/mlpack/issues/new +Repository: https://github.com/mlpack/mlpack.git +Repository-Browse: https://github.com/mlpack/mlpack diff -Nru mlpack-3.2.2/doc/examples/sample-ml-app/sample-ml-app/sample-ml-app.vcxproj mlpack-3.3.0/doc/examples/sample-ml-app/sample-ml-app/sample-ml-app.vcxproj --- mlpack-3.2.2/doc/examples/sample-ml-app/sample-ml-app/sample-ml-app.vcxproj 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/doc/examples/sample-ml-app/sample-ml-app/sample-ml-app.vcxproj 2020-04-07 13:17:16.000000000 +0000 @@ -104,16 +104,16 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) false - C:\boost\boost_1_66_0;C:\mlpack\armadillo-8.500.1\include;C:\mlpack\mlpack-3.2.2\build\include;%(AdditionalIncludeDirectories) + C:\boost\boost_1_66_0;C:\mlpack\armadillo-8.500.1\include;C:\mlpack\mlpack-3.3.0\build\include;%(AdditionalIncludeDirectories) Console true - C:\mlpack\mlpack-3.2.2\build\Debug\mlpack.lib;C:\boost\boost_1_66_0\lib64-msvc-14.1\libboost_serialization-vc141-mt-gd-x64-1_66.lib;C:\boost\boost_1_66_0\lib64-msvc-14.1\libboost_program_options-vc141-mt-gd-x64-1_66.lib;%(AdditionalDependencies) + C:\mlpack\mlpack-3.3.0\build\Debug\mlpack.lib;C:\boost\boost_1_66_0\lib64-msvc-14.1\libboost_serialization-vc141-mt-gd-x64-1_66.lib;C:\boost\boost_1_66_0\lib64-msvc-14.1\libboost_program_options-vc141-mt-gd-x64-1_66.lib;%(AdditionalDependencies) - xcopy /y "C:\mlpack\mlpack-3.2.2\build\Debug\mlpack.dll" $(OutDir) -xcopy /y "C:\mlpack\mlpack-3.2.2\packages\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.dll" $(OutDir) + xcopy /y "C:\mlpack\mlpack-3.3.0\build\Debug\mlpack.dll" $(OutDir) +xcopy /y "C:\mlpack\mlpack-3.3.0\packages\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.dll" $(OutDir) xcopy /y "$(ProjectDir)..\..\..\..\src\mlpack\tests\data\german.csv" "$(ProjectDir)data\german.csv*" diff -Nru mlpack-3.2.2/doc/guide/build.hpp mlpack-3.3.0/doc/guide/build.hpp --- mlpack-3.2.2/doc/guide/build.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/doc/guide/build.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -2,10 +2,11 @@ @section build_buildintro Introduction -This document discusses how to build mlpack from source. However, mlpack is in -the repositories of many Linux distributions and so it may be easier to use the -package manager for your system. For example, on Ubuntu, you can install mlpack -with the following command: +This document discusses how to build mlpack from source. These build directions +will work for any Linux-like shell environment (for example Ubuntu, macOS, +FreeBSD etc). However, mlpack is in the repositories of many Linux distributions +and so it may be easier to use the package manager for your system. For example, +on Ubuntu, you can install mlpack with the following command: @code $ sudo apt-get install libmlpack-dev @@ -29,7 +30,7 @@ is based on older versions). You can download the latest mlpack release from here: -mlpack-3.2.2 +mlpack-3.3.0 @section build_simple Simple Linux build instructions @@ -37,9 +38,9 @@ below directly to build and install mlpack. @code -$ wget https://www.mlpack.org/files/mlpack-3.2.2.tar.gz -$ tar -xvzpf mlpack-3.2.2.tar.gz -$ mkdir mlpack-3.2.2/build && cd mlpack-3.2.2/build +$ wget https://www.mlpack.org/files/mlpack-3.3.0.tar.gz +$ tar -xvzpf mlpack-3.3.0.tar.gz +$ mkdir mlpack-3.3.0/build && cd mlpack-3.3.0/build $ cmake ../ $ make -j4 # The -j is the number of cores you want to use for a build. $ sudo make install @@ -64,8 +65,8 @@ First we should unpack the mlpack source and create a build directory. @code -$ tar -xvzpf mlpack-3.2.2.tar.gz -$ cd mlpack-3.2.2 +$ tar -xvzpf mlpack-3.3.0.tar.gz +$ cd mlpack-3.3.0 $ mkdir build @endcode @@ -78,7 +79,7 @@ - Armadillo >= 8.400.0 (with LAPACK support) - Boost (math_c99, program_options, serialization, unit_test_framework, heap, - spirit) >= 1.49 + spirit) >= 1.58 - ensmallen >= 2.10.0 (will be downloaded if not found) In addition, mlpack has the following optional dependencies: @@ -94,15 +95,30 @@ - pandas >= 0.15.0 - pytest-runner -In Ubuntu and Debian, you can get all of these dependencies through apt: +In Ubuntu (>= 18.04) and Debian (>= 10) all of these dependencies can be +installed through apt: @code # apt-get install libboost-math-dev libboost-program-options-dev libboost-test-dev libboost-serialization-dev libarmadillo-dev binutils-dev - python-pandas python-numpy cython python-setuptools libensmallen-dev - libstb-dev + python-pandas python-numpy cython python-setuptools @endcode +If you are using Ubuntu 19.10 or newer, you can also install @c libensmallen-dev +and @c libstb-dev, so that CMake does not need to automatically download those +packages: + +@code +# apt-get install libensmallen-dev libstb-dev +@endcode + +@note For older versions of Ubuntu and Debian, Armadillo needs to be built from +source as apt installs an older version. So you need to omit +\c libarmadillo-dev from the code snippet above and instead use +this link + to download the required file. Extract this file and follow the README in the + uncompressed folder to build and install Armadillo. + On Fedora, Red Hat, or CentOS, these same dependencies can be obtained via dnf: @code @@ -146,18 +162,21 @@ (default ON) - BUILD_PYTHON_BINDINGS=(ON/OFF): compile the bindings for Python, if the necessary Python libraries are available (default ON except on Windows) - - MATLAB_BINDINGS=(ON/OFF): Compile MATLAB bindings if MATLAB is found - (default OFF) + - BUILD_JULIA_BINDINGS=(ON/OFF): compile Julia bindings, if Julia is found + (default ON) - BUILD_SHARED_LIBS=(ON/OFF): compile shared libraries as opposed to static libraries (default ON) - TEST_VERBOSE=(ON/OFF): run test cases in \c mlpack_test with verbose output (default OFF) + - DISABLE_DOWNLOADS=(ON/OFF): Disable downloads of dependencies during build + (default OFF) - DOWNLOAD_ENSMALLEN=(ON/OFF): If ensmallen is not found, download it (default ON) - DOWNLOAD_STB_IMAGE=(ON/OFF): If STB is not found, download it (default ON) - BUILD_WITH_COVERAGE=(ON/OFF): Build with support for code coverage tools (gcc only) (default OFF) - - PYTHON_EXECUTABLE=(/path/to/python_version): Path to specific Python executable + - PYTHON_EXECUTABLE=(/path/to/python_version): Path to specific Python executable + - JULIA_EXECUTABLE=(/path/to/julia): Path to specific Julia executable - BUILD_MARKDOWN_BINDINGS=(ON/OFF): Build Markdown bindings for website documentation (default OFF) - MATHJAX=(ON/OFF): use MathJax for generated Doxygen documentation (default @@ -180,6 +199,8 @@ - BOOST_ROOT=(/path/to/boost/): path to root of boost installation - 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 - MATHJAX_ROOT=(/path/to/mathjax): path to root of MathJax installation @section build_build Building mlpack @@ -227,7 +248,7 @@ https://github.com/mlpack/mlpack -Alternately, mlpack help can be found in IRC at \#mlpack on irc.freenode.net. +Alternately, mlpack help can be found in IRC at \#mlpack on chat.freenode.net. @section install Installing mlpack diff -Nru mlpack-3.2.2/doc/guide/build_windows.hpp mlpack-3.3.0/doc/guide/build_windows.hpp --- mlpack-3.2.2/doc/guide/build_windows.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/doc/guide/build_windows.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -3,6 +3,7 @@ * @author German Lancioni * @author Miguel Canteras * @author Shikhar Jaiswal + * @author Ziyang Jiang @page build_windows Building mlpack From Source on Windows @@ -39,11 +40,11 @@ This tutorial has been designed and tested using: - Windows 10 -- Visual Studio 2017 (toolset v141) +- Visual Studio 2019 (toolset v142) - mlpack - OpenBLAS.0.2.14.1 -- boost_1_66_0-msvc-14.1-64 -- armadillo-8.500.1 +- boost_1_71_0-msvc-14.2-64 +- armadillo (newest version) - and x64 configuration The directories and paths used in this tutorial are just for reference purposes. @@ -51,7 +52,8 @@ @section build_windows_prereqs Pre-requisites - Install CMake for Windows (win64-x64 version from https://cmake.org/download/) -and make sure you can use it from the Command Prompt (may need to add to the PATH) +and make sure you can use it from the Command Prompt (may need to add the PATH to +system environment variables or manually set the PATH before running CMake) - Download the latest mlpack release from here: mlpack website @@ -64,6 +66,7 @@ - Project location: "C:\mlpack\mlpack" - Project name: mlpack - Finish +- Make sure the solution configuration is "Debug" and the solution platform is "x64" for this Visual Studio project - We will use this Visual Studio project to get the OpenBLAS dependency in the next section @section build_windows_dependencies Dependencies @@ -80,7 +83,7 @@ You can either get Boost via NuGet or you can download the prebuilt Windows binaries separately. This tutorial follows the second approach for simplicity. -- Download the "Prebuilt Windows binaries" of the Boost library ("boost_1_66_0-msvc-14.1-64") from +- Download the "Prebuilt Windows binaries" of the Boost library ("boost_1_71_0-msvc-14.2-64") from Sourceforge @note Make sure you download the MSVC version that matches your Visual Studio @@ -96,11 +99,12 @@ - Run cmake: @code -cmake -G "Visual Studio 15 2017 Win64" -DBLAS_LIBRARY:FILEPATH="C:/mlpack/mlpack/packages/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DLAPACK_LIBRARY:FILEPATH="C:/mlpack/mlpack/packages/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" .. +cmake -G "Visual Studio 16 2019" -A x64 -DBLAS_LIBRARY:FILEPATH="C:/mlpack/mlpack/packages/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DLAPACK_LIBRARY:FILEPATH="C:/mlpack/mlpack/packages/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" .. @endcode @note If you are using different directory paths, a different configuration (e.g. Release) -or a different VS version, update the cmake command accordingly. +or a different VS version, update the cmake command accordingly. If CMake cannot identify the +compiler version, check if the Visual Studio compiler and Windows SDK are installed correctly. - Once it has successfully finished, open "C:\mlpack\armadillo\build\armadillo.sln" - Build > Build Solution @@ -114,7 +118,7 @@ - Run cmake: @code -cmake -G "Visual Studio 15 2017 Win64" -DBLAS_LIBRARY:FILEPATH="C:/mlpack/mlpack/packages/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DLAPACK_LIBRARY:FILEPATH="C:/mlpack/mlpack/packages/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DARMADILLO_INCLUDE_DIR="C:/mlpack/armadillo/include" -DARMADILLO_LIBRARY:FILEPATH="C:/mlpack/armadillo/build/Debug/armadillo.lib" -DBOOST_INCLUDEDIR:PATH="C:/boost/" -DBOOST_LIBRARYDIR:PATH="C:/boost/lib64-msvc-14.1" -DDEBUG=OFF -DPROFILE=OFF .. +cmake -G "Visual Studio 16 2019" -A x64 -DBLAS_LIBRARIES:FILEPATH="C:/mlpack/mlpack/packages/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DLAPACK_LIBRARIES:FILEPATH="C:/mlpack/mlpack/packages/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DARMADILLO_INCLUDE_DIR="C:/mlpack/armadillo/include" -DARMADILLO_LIBRARY:FILEPATH="C:/mlpack/armadillo/build/Debug/armadillo.lib" -DBOOST_INCLUDEDIR:PATH="C:/boost/" -DBOOST_LIBRARYDIR:PATH="C:/boost/lib64-msvc-14.2" -DDEBUG=OFF -DPROFILE=OFF .. @endcode @note cmake will attempt to automatically download the ensmallen dependency. If for some reason cmake can't download the dependency, you will need to manually download ensmallen from http://ensmallen.org/ and extract it to "C:\mlpack\mlpack\deps\". Then, specify the path to ensmallen using the flag: -DENSMALLEN_INCLUDE_DIR=C:/mlpack/mlpack/deps/ensmallen/include @@ -142,16 +146,16 @@ - If there is an error and Boost is not found, try "Add Entry" with the following variables and reconfigure: - Name: `BOOST_INCLUDEDIR`; type `PATH`; value `C:/boost/` - - Name: `BOOST_LIBRARYDIR`; type `PATH`; value `C:/boost/lib64-msvc-14.1` + - Name: `BOOST_LIBRARYDIR`; type `PATH`; value `C:/boost/lib64-msvc-14.2` - If Boost is still not found, try adding the following variables and reconfigure: - Name: `Boost_INCLUDE_DIR`; type `PATH`; value `C:/boost/` - - Name: `Boost_PROGRAM_OPTIONS_LIBRARY_DEBUG`; type `FILEPATH`; value should be `C:/boost/lib64-msvc-14.1/boost_program_options-vc141-mt-gd-x64-1_66.lib` - - Name: `Boost_PROGRAM_OPTIONS_LIBRARY_RELEASE`; type `FILEPATH`; value should be `C:/boost/lib64-msvc-14.1/boost_program_options-vc141-mt-x64-1_66.lib` - - Name: `Boost_SERIALIZATION_LIBRARY_DEBUG`; type `FILEPATH`; value should be `C:/boost/lib64-msvc-14.1/boost_serialization-vc141-mt-gd-x64-1_66.lib` - - Name: `Boost_SERIALIZATION_LIBRARY_RELEASE`; type `FILEPATH`; value should be `C:/boost/lib64-msvc-14.1/boost_program_options-vc141-mt-x64-1_66.lib` - - Name: `Boost_UNIT_TEST_FRAMEWORK_LIBRARY_DEBUG`; type `FILEPATH`; value should be `C:/boost/lib64-msvc-14.1/boost_unit_test_framework-vc141-mt-gd-x64-1_66.lib` - - Name: `Boost_UNIT_TEST_FRAMEWORK_LIBRARY_RELEASE`; type `FILEPATH`; value should be `C:/boost/lib64-msvc-14.1/boost_unit_test_framework-vc141-mt-x64-1_66.lib` + - Name: `Boost_PROGRAM_OPTIONS_LIBRARY_DEBUG`; type `FILEPATH`; value should be `C:/boost/lib64-msvc-14.2/boost_program_options-vc142-mt-gd-x64-1_71.lib` + - Name: `Boost_PROGRAM_OPTIONS_LIBRARY_RELEASE`; type `FILEPATH`; value should be `C:/boost/lib64-msvc-14.2/boost_program_options-vc142-mt-x64-1_71.lib` + - Name: `Boost_SERIALIZATION_LIBRARY_DEBUG`; type `FILEPATH`; value should be `C:/boost/lib64-msvc-14.2/boost_serialization-vc142-mt-gd-x64-1_71.lib` + - Name: `Boost_SERIALIZATION_LIBRARY_RELEASE`; type `FILEPATH`; value should be `C:/boost/lib64-msvc-14.2/boost_program_options-vc142-mt-x64-1_71.lib` + - Name: `Boost_UNIT_TEST_FRAMEWORK_LIBRARY_DEBUG`; type `FILEPATH`; value should be `C:/boost/lib64-msvc-14.2/boost_unit_test_framework-vc142-mt-gd-x64-1_71.lib` + - Name: `Boost_UNIT_TEST_FRAMEWORK_LIBRARY_RELEASE`; type `FILEPATH`; value should be `C:/boost/lib64-msvc-14.2/boost_unit_test_framework-vc142-mt-x64-1_71.lib` - Once CMake has configured successfully, hit "Generate" to create the `.sln` file. @section build_windows_additional_information Additional Information diff -Nru mlpack-3.2.2/doc/guide/formats.hpp mlpack-3.3.0/doc/guide/formats.hpp --- mlpack-3.2.2/doc/guide/formats.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/doc/guide/formats.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -2,11 +2,36 @@ @section formatintro Introduction -mlpack supports a wide variety of data and model formats for use in both its +mlpack supports a wide variety of data (including images) and model formats for use in both its command-line programs and in C++ programs using mlpack via the mlpack::data::Load() function. This tutorial discusses the formats that are supported and how to use them. +@section toc_tut Table of Contents + +This tutorial is split into the following sections: + + - \ref formatintro + - \ref toc_tut + - Data + - Data Formats + - \ref formatsimple + - \ref formattypes + - \ref formatcpp + - \ref sparseload + - \ref formatcat + - \ref formatcatcpp + - Image Support + - \ref intro_imagetut + - \ref model_api_imagetut + - \ref imageinfo_api_imagetut + - \ref load_api_imagetut + - \ref save_api_imagetut + - Models + - \ref formatmodels + - \ref formatmodelscpp + - \ref formatfinal + @section formatsimple Simple examples to load data in C++ The example code snippets below load data from different formats into an @@ -295,6 +320,131 @@ There is more functionality to the DatasetInfo class; for more information, see the mlpack::data::DatasetInfo documentation. +@section intro_imagetut Loading and Saving Images + +Image datasets are becoming increasingly popular in deep learning. + +mlpack's image saving/loading functionality is based on [stb/](https://github.com/nothings/stb). + +@section model_api_imagetut Image Utilities API + +Image utilities supports loading and saving of images. + +It supports filetypes "jpg", "png", "tga", "bmp", "psd", "gif", "hdr", "pic", +"pnm" for loading and "jpg", "png", "tga", "bmp", "hdr" for saving. + +The datatype associated is unsigned char to support RGB values in the range +1-255. To feed data into the network typecast of `arma::Mat` may be required. +Images are stored in the matrix as (width * height * channels, NumberOfImages). +Therefore @c imageMatrix.col(0) would be the first image if images are loaded in +@c imageMatrix. + +@section imageinfo_api_imagetut Accessing Metadata of Images: ImageInfo + +ImageInfo class contains the metadata of the images. +@code +ImageInfo(const size_t width, + const size_t height, + const size_t channels, + const size_t quality = 90); +@endcode + +The @c quality member denotes the compression of the image if it is saved as +`jpg`; it takes values from 0 to 100. + +@section load_api_imagetut Loading Images in C++ + +Standalone loading of images. + +@code +template +bool Load(const std::string& filename, + arma::Mat& matrix, + ImageInfo& info, + const bool fatal); +@endcode + +The example below loads a test image. It also fills up the ImageInfo class +object. + +@code +data::ImageInfo info; +data::Load("test_image.png", matrix, info, false); +@endcode + +ImageInfo requires height, width, number of channels of the image. + +@code +size_t height = 64, width = 64, channels = 1; +data::ImageInfo info(width, height, channels); +@endcode + +More than one image can be loaded into the same matrix. + +Loading multiple images: + +@code +template +bool Load(const std::vector& files, + arma::Mat& matrix, + ImageInfo& info, + const bool fatal); +@endcode + +@code +data::ImageInfo info; +std::vector> files{"test_image1.bmp","test_image2.bmp"}; +data::Load(files, matrix, info, false); +@endcode + +@section save_api_imagetut Saving Images in C++ + +Save images expects a matrix of type unsigned char in the form (width * height * channels, NumberOfImages). +Just like load it can be used to save one image or multiple images. Besides image data it also expects the shape of the image as input (width, height, channels). + +Saving one image: + +@code + template + bool Save(const std::string& filename, + arma::Mat& matrix, + ImageInfo& info, + const bool fatal, + const bool transpose); +@endcode + +@code + data::ImageInfo info; + info.width = info.height = 25; + info.channels = 3; + info.quality = 90; + data::Save("test_image.bmp", matrix, info, false, true); +@endcode + +If the matrix contains more than one image, only the first one is saved. + +Saving multiple images: + +@code + template + bool Save(const std::vector& files, + arma::Mat& matrix, + ImageInfo& info, + const bool fatal, + const bool transpose); +@endcode + +@code + data::ImageInfo info; + info.width = info.height = 25; + info.channels = 3; + info.quality = 90; + std::vector> files{"test_image1.bmp", "test_image2.bmp"}; + data::Save(files, matrix, info, false, true); +@endcode + +Multiple images are saved according to the vector of filenames specified. + @section formatmodels Loading and saving models Using \c boost::serialization, mlpack is able to load and save machine learning diff -Nru mlpack-3.2.2/doc/guide/julia_quickstart.hpp mlpack-3.3.0/doc/guide/julia_quickstart.hpp --- mlpack-3.2.2/doc/guide/julia_quickstart.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/doc/guide/julia_quickstart.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,192 @@ +/** + * @file julia_quickstart.hpp + * @author Ryan Curtin + +@page julia_quickstart mlpack in Julia quickstart guide + +@section julia_quickstart_intro Introduction + +This page describes how you can quickly get started using mlpack from Julia and +gives a few examples of usage, and pointers to deeper documentation. + +This quickstart guide is also available for +@ref cli_quickstart "the command-line" and @ref python_quickstart "Python". + +@section julia_quickstart_install Installing mlpack + +Installing the mlpack bindings for Julia is straightforward; you can just use +@c Pkg: + +@code{.julia} +using Pkg +Pkg.add("mlpack") +@endcode + +Building the Julia bindings from scratch is a little more in-depth, though. For +information on that, follow the instructions on the @ref build page, and be sure +to specify @c -DBUILD_JULIA_BINDINGS=ON to CMake; you may need to also set the +location of the Julia program with @c -DJULIA_EXECUTABLE=/path/to/julia. + +@section julia_quickstart_example Simple mlpack quickstart example + +As a really simple example of how to use mlpack from Julia, let's do some +simple classification on a subset of the standard machine learning @c covertype +dataset. We'll first split the dataset into a training set and a testing set, +then we'll train an mlpack random forest on the training data, and finally we'll +print the accuracy of the random forest on the test dataset. + +You can copy-paste this code directly into Julia to run it. You may need to add +some extra packages with, e.g., `using Pkg; Pkg.add("CSV"); +Pkg.add("DataFrames"); Pkg.add("Zlib")`. + +@code{.julia} +using CSV +using DataFrames +using Libz +using mlpack + +# Load the dataset from an online URL. Replace with 'covertype.csv.gz' if you +# want to use on the full dataset. +df = CSV.read(ZlibInflateInputStream(open(download( + "http://www.mlpack.org/datasets/covertype-small.csv.gz")))) + +# Split the labels. +labels = df[!, :label][:] +dataset = select!(df, Not(:label)) + +# Split the dataset using mlpack. The output comes back as a dictionary, +# which we'll unpack for clarity of code. +test, test_labels, train, train_labels = mlpack.preprocess_split( + input=dataset, + input_labels=labels, + test_ratio=0.3) + +# Train a random forest. +rf_model, _, _ = mlpack.random_forest(training=train, + labels=train_labels, + print_training_accuracy=true, + num_trees=10, + minimum_leaf_size=3) + +# Predict the labels of the test points. +_, predictions, _ = mlpack.random_forest(input_model=rf_model, + test=test) + +# Now print the accuracy. The third return value ('probabilities'), which we +# ignored here, could also be used to generate an ROC curve. +correct = sum(predictions .== test_labels) +print("$(correct) out of $(length(test_labels)) test points correct " * + "($(correct / length(test_labels) * 100.0)%).\n") +@endcode + +We can see that we achieve reasonably good accuracy on the test dataset (80%+); +if we use the full @c covertype.csv.gz, the accuracy should increase +significantly (but training will take longer). + +It's easy to modify the code above to do more complex things, or to use +different mlpack learners, or to interface with other machine learning toolkits. + +@section julia_quickstart_whatelse What else does mlpack implement? + +The example above has only shown a little bit of the functionality of mlpack. +Lots of other commands are available with different functionality. A full list +of each of these commands and full documentation can be found on the following +page: + + - Julia documentation + +You can also use the Julia REPL to explore the @c mlpack module and its +functions; every function comes with comprehensive documentation. + +For more information on what mlpack does, see https://www.mlpack.org/. +Next, let's go through another example for providing movie recommendations with +mlpack. + +@section julia_quickstart_movierecs Using mlpack for movie recommendations + +In this example, we'll train a collaborative filtering model using mlpack's +cf() method. We'll train this on the MovieLens dataset from +https://grouplens.org/datasets/movielens/, and then we'll use the model that we +train to give recommendations. + +You can copy-paste this code directly into Julia to run it. + +@code{.julia} +using CSV +using mlpack +using Libz +using DataFrames + +# Load the dataset from an online URL. Replace with 'covertype.csv.gz' if you +# want to use on the full dataset. +ratings = CSV.read(ZlibInflateInputStream(open(download( + "http://www.mlpack.org/datasets/ml-20m/ratings-only.csv.gz")))) +movies = CSV.read(ZlibInflateInputStream(open(download( + "http://www.mlpack.org/datasets/ml-20m/movies.csv.gz")))) + +# Hold out 10% of the dataset into a test set so we can evaluate performance. +ratings_test, _, ratings_train, _ = mlpack.preprocess_split(ratings; + test_ratio=0.1, verbose=true) + +# Train the model. Change the rank to increase/decrease the complexity of the +# model. +_, cf_model = mlpack.cf(training=ratings_train, + test=ratings_test, + rank=10, + verbose=true, + algorithm="RegSVD") + +# Now query the 5 top movies for user 1. +output, _ = mlpack.cf(input_model=cf_model, + query=[1], + recommendations=10, + verbose=true, + max_iterations=10) + +print("Recommendations for user 1:\n") +for i in 1:10 + print(" $(i): $(movies[output[i], :][3])\n") +end +@endcode + +Here is some example output, showing that user 1 seems to have good taste in +movies: + +@code{.unparsed} +Recommendations for user 1: + 0: Casablanca (1942) + 1: Pan's Labyrinth (Laberinto del fauno, El) (2006) + 2: Godfather, The (1972) + 3: Answer This! (2010) + 4: Life Is Beautiful (La Vita è bella) (1997) + 5: Adventures of Tintin, The (2011) + 6: Dark Knight, The (2008) + 7: Out for Justice (1991) + 8: Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb (1964) + 9: Schindler's List (1993) +@endcode + +@section julia_quickstart_nextsteps Next steps with mlpack + +Now that you have done some simple work with mlpack, you have seen how it can +easily plug into a data science workflow in Julia. A great thing to do next +would be to look at more documentation for the Julia mlpack bindings: + + - Julia mlpack + binding documentation + +Also, mlpack is much more flexible from C++ and allows much greater +functionality. So, more complicated tasks are possible if you are willing to +write C++ (or perhaps CxxWrap.jl). To get started learning about mlpack in C++, +the following resources might be helpful: + + - mlpack + C++ tutorials + - mlpack + build and installation guide + - Simple + sample C++ mlpack programs + - mlpack + Doxygen documentation homepage + + */ diff -Nru mlpack-3.2.2/doc/guide/python_quickstart.hpp mlpack-3.3.0/doc/guide/python_quickstart.hpp --- mlpack-3.2.2/doc/guide/python_quickstart.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/doc/guide/python_quickstart.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -31,9 +31,9 @@ @code{.sh} sudo apt-get install libboost-all-dev g++ cmake libarmadillo-dev python-pip wget sudo pip install cython setuptools distutils numpy pandas -wget https://www.mlpack.org/files/mlpack-3.2.2.tar.gz -tar -xvzpf mlpack-3.2.2.tar.gz -mkdir -p mlpack-3.2.2/build/ && cd mlpack-3.2.2/build/ +wget https://www.mlpack.org/files/mlpack-3.3.0.tar.gz +tar -xvzpf mlpack-3.3.0.tar.gz +mkdir -p mlpack-3.3.0/build/ && cd mlpack-3.3.0/build/ cmake ../ && make -j4 && sudo make install @endcode diff -Nru mlpack-3.2.2/doc/guide/sample_ml_app.hpp mlpack-3.3.0/doc/guide/sample_ml_app.hpp --- mlpack-3.2.2/doc/guide/sample_ml_app.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/doc/guide/sample_ml_app.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -27,20 +27,20 @@ - Right click on the project and select Properties, select the x64 Debug profile - Under C/C++ > General > Additional Include Directories add: @code - - C:\boost\boost_1_66_0 - - C:\mlpack\armadillo-8.500.1\include - - C:\mlpack\mlpack-3.2.2\build\include + - C:\boost\boost_1_71_0\lib\native\include + - C:\mlpack\armadillo-9.800.3\include + - C:\mlpack\mlpack-3.3.0\build\include @endcode - Under Linker > Input > Additional Dependencies add: @code - - C:\mlpack\mlpack-3.2.2\build\Debug\mlpack.lib - - C:\boost\boost_1_66_0\lib64-msvc-14.1\libboost_serialization-vc141-mt-gd-x64-1_66.lib - - C:\boost\boost_1_66_0\lib64-msvc-14.1\libboost_program_options-vc141-mt-gd-x64-1_66.lib + - C:\mlpack\mlpack-3.3.0\build\Debug\mlpack.lib + - C:\boost\boost_1_71_0\lib64-msvc-14.2\libboost_serialization-vc142-mt-gd-x64-1_71.lib + - C:\boost\boost_1_71_0\lib64-msvc-14.2\libboost_program_options-vc142-mt-gd-x64-1_71.lib @endcode - Under Build Events > Post-Build Event > Command Line add: @code - - xcopy /y "C:\mlpack\mlpack-3.2.2\build\Debug\mlpack.dll" $(OutDir) - - xcopy /y "C:\mlpack\mlpack-3.2.2\packages\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.dll" $(OutDir) + - xcopy /y "C:\mlpack\mlpack-3.3.0\build\Debug\mlpack.dll" $(OutDir) + - xcopy /y "C:\mlpack\mlpack-3.3.0\packages\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.dll" $(OutDir) @endcode @note Recent versions of Visual Studio set "Conformance Mode" enabled by default. This causes some issues with diff -Nru mlpack-3.2.2/doc/tutorials/ann/ann.txt mlpack-3.3.0/doc/tutorials/ann/ann.txt --- mlpack-3.2.2/doc/tutorials/ann/ann.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/doc/tutorials/ann/ann.txt 2020-04-07 13:17:16.000000000 +0000 @@ -195,35 +195,79 @@ representation. @code -// Load the training set. -arma::mat dataset; -data::Load("thyroid_train.csv", dataset, true); - -// Split the labels from the training set. -arma::mat trainData = dataset.submat(0, 0, dataset.n_rows - 4, - dataset.n_cols - 1); - -// Split the data from the training set. -arma::mat trainLabelsTemp = dataset.submat(dataset.n_rows - 3, 0, - dataset.n_rows - 1, dataset.n_cols - 1); - -// Initialize the network. -FFN<> model; -model.Add >(trainData.n_rows, 8); -model.Add >(); -model.Add >(8, 3); -model.Add >(); - -// Train the model. -model.Train(trainData, trainLabels); - -// Use the Predict method to get the assignments. -arma::mat assignments; -model.Predict(trainData, assignments); +#include +#include +#include + +using namespace mlpack; +using namespace mlpack::ann; + +int main() +{ + // Load the training set and testing set. + arma::mat trainData; + data::Load("thyroid_train.csv", trainData, true); + arma::mat testData; + data::Load("thyroid_test.csv", testData, true); + + // Split the labels from the training set and testing set respectively. + arma::mat trainLabels = trainData.row(trainData.n_rows - 1); + arma::mat testLabels = testData.row(testData.n_rows - 1); + trainData.shed_row(trainData.n_rows - 1); + testData.shed_row(testData.n_rows - 1); + + // Initialize the network. + FFN<> model; + model.Add >(trainData.n_rows, 8); + model.Add >(); + model.Add >(8, 3); + model.Add >(); + + // Train the model. + model.Train(trainData, trainLabels); + + // Use the Predict method to get the predictions. + arma::mat predictionTemp; + model.Predict(testData, predictionTemp); + + /* + Since the predictionsTemp is of dimensions (3 x number_of_data_points) + with continuous values, we first need to reduce it to a dimension of + (1 x number_of_data_points) with scalar values, to be able to compare with + testLabels. + + The first step towards doing this is to create a matrix of zeros with the + desired dimensions (1 x number_of_data_points). + + In predictionsTemp, the 3 dimensions for each data point correspond to the + probabilities of belonging to the three possible classes. + */ + arma::mat prediction = arma::zeros(1, predictionTemp.n_cols); + + // Find index of max prediction for each data point and store in "prediction" + for (size_t i = 0; i < predictionTemp.n_cols; ++i) + { + // we add 1 to the max index, so that it matches the actual test labels. + prediction(i) = arma::as_scalar(arma::find( + arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)) + 1; + } + + /* + Compute the error between predictions and testLabels, + now that we have the desired predictions. + */ + size_t correct = arma::accu(prediction == testLabels); + double classificationError = 1 - double(correct) / testData.n_cols; + + // Print out the classification error for the testing dataset. + std::cout << "Classification Error for the Test set: " << classificationError << std::endl; + return 0; +} @endcode -Now, the matrix assignments holds the classification of each point in the -dataset. +Now, the matrix prediction holds the classification of each point in the +dataset. Subsequently, we find the classification error by comparing it +with testLabels. In the next example, we create simple noisy sine sequences, which are trained later on, using the RNN class in the `RNNModel()` method. @@ -318,7 +362,7 @@ @code template -void Forward(const arma::Mat&& input, arma::Mat&& output); +void Forward(const arma::Mat& input, arma::Mat& output); @endcode The method should calculate the output of the layer given the input matrix and @@ -329,9 +373,9 @@ @code template -void Backward(const arma::Mat&& input, - arma::Mat&& gy, - arma::Mat&& g); +void Backward(const arma::Mat& input, + const arma::Mat& gy, + arma::Mat& g); @endcode Finally, if the layer is differentiable, the layer must also implement @@ -339,9 +383,9 @@ @code template -void Gradient(const arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient); +void Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient); @endcode The Gradient function should calculate the gradient with respect to the input @@ -424,21 +468,21 @@ @code template -void Forward(const InputType&& input, OutputType&& output) +void Forward(const InputType& input, OutputType& output) { output = arma::ones(input.n_rows, input.n_cols); } template -void Backward(const InputType&& input, ErrorType&& gy, GradientType&& g) +void Backward(const InputType& input, const ErrorType& gy, GradientType& g) { g = arma::zeros(gy.n_rows, gy.n_cols) + gy; } template -void Gradient(const InputType&& input, - ErrorType&& error, - GradientType&& gradient) +void Gradient(const InputType& input, + ErrorType& error, + GradientType& gradient) { gradient = arma::zeros(input.n_rows, input.n_cols) * error; } diff -Nru mlpack-3.2.2/doc/tutorials/image/image.txt mlpack-3.3.0/doc/tutorials/image/image.txt --- mlpack-3.2.2/doc/tutorials/image/image.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/doc/tutorials/image/image.txt 2020-04-07 13:17:16.000000000 +0000 @@ -46,7 +46,6 @@ const size_t channels); @endcode Other public memebers include: - - flipVertical Flip the image vertical upon loading. - quality Compression of the image if saved as jpg (0-100). @section load_api_imagetut Load @@ -61,7 +60,8 @@ * @param matrix Matrix to load the image into. * @param info An object of ImageInfo class. * @param fatal If an error should be reported as fatal (default false). - * @param transpose If true, transpose the matrix after loading. + * @param transpose If true, flips the image, same as transposing the + * matrix after loading. * @return Boolean value indicating success or failure of load. */ template @@ -97,7 +97,8 @@ * @param matrix Matrix to save the image from. * @param info An object of ImageInfo class. * @param fatal If an error should be reported as fatal (default false). - * @param transpose If true, transpose the matrix after loading. + * @param transpose If true, flips the image, same as transposing the + * matrix after loading. * @return Boolean value indicating success or failure of load. */ template @@ -129,7 +130,8 @@ * @param matrix Matrix to save the image from. * @param info An object of ImageInfo class. * @param fatal If an error should be reported as fatal (default false). - * @param transpose If true, transpose the matrix after loading. + * @param transpose If true, flips the image, same as transposing the + * matrix after loading. * @return Boolean value indicating success or failure of load. */ template @@ -160,7 +162,8 @@ * @param matrix Matrix to save the image from. * @param info An object of ImageInfo class. * @param fatal If an error should be reported as fatal (default false). - * @param transpose If true, transpose the matrix after loading. + * @param transpose If true, Flips the image, same as transposing the + * matrix after loading. * @return Boolean value indicating success or failure of load. */ template diff -Nru mlpack-3.2.2/doc/tutorials/reinforcement_learning/reinforcement_learning.txt mlpack-3.3.0/doc/tutorials/reinforcement_learning/reinforcement_learning.txt --- mlpack-3.2.2/doc/tutorials/reinforcement_learning/reinforcement_learning.txt 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/doc/tutorials/reinforcement_learning/reinforcement_learning.txt 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,399 @@ +/*! +@file rl.txt +@author Sriram S K +@author Joel Joseph +@brief Tutorial for how to use the Reinforcement Learning module in mlpack. + +@page rltutorial Reinforcement Learning Tutorial + +@section intro_rltut Introduction + +Reinforcement Learning is one of the hottest topics right now, with +interest surging after DeepMind published their article on training +deep neural networks to play Atari games to great success. mlpack +implements a complete end-to-end framework for Reinforcement Learning, +featuring multiple environments, policies and methods. Of course, +custom environments and policies can be used and plugged into the +existing framework with no runtime overhead. + +mlpack implements typical benchmark environments (Acrobot, Mountain car etc.), +commonly used policies, replay methods and supports asynchronous +learning as well. In addition, it can [communicate](https://github.com/zoq/gym_tcp_api) +with the OpenAI Gym toolkit for more environments. + +@section toc_rltut Table of Contents + +This tutorial is split into the following sections: + + - \ref intro_rltut + - \ref toc_rltut + - \ref environment_rltut + - \ref agent_components_rltut + - \ref q_learning_rltut + - \ref async_learning_rltut + - \ref further_rltut + +@section environment_rltut Reinforcement Learning Environments + +mlpack implements a number of the most popular environments used for testing +RL agents and algorithms. These include the Cart Pole, Acrobot, Mountain Car +and their variations. Of course, as mentioned above, you can communicate with +OpenAI Gym for other environments, like the Atari video games. + +A key component of mlpack is its extensibility. It is a simple process to create +your own custom environments, specific to your needs, and use it with mlpack's +RL framework. All the environments implement a few specific methods and classes +which are used by the agents while learning. + +- \c State: The State class is a representation of the environment. For the CartPole, + this would involve storing the position, velocity, angle and angular velocity. + +- \c Action: It is an enum naming all the possible actions the agent can take in the + environment. Continuing with the CartPole example, the Action enum would simply + contain the two possible actions, backward and forward. + +- \c Sample: This method is perhaps the heart of the environment, providing rewards to + the agent depending on the state and the action taken, and updates the state based on + the action taken as well. + +Of course, your custom environment will most likely make use of a number of helper methods, depending +on your application, such as the \c Dsdt method in the \c Acrobot environment, used in the \c RK4 +iterative method (also another helper method) to estimate the next state. + +@section agent_components_rltut Components of an RL Agent + +A Reinforcement Learning agent, in general, takes actions in an environment in order +to maximize a cumulative reward. To that end, it requires a way to choose actions (\b policy) +and a way to sample previous experiences (\b replay). + +An example of a simple policy would be an epsilon-greedy policy. Using such a policy, the agent +will choose actions greedily with some probability epsilon. This probability is slowly decreased +over time, balancing the line between exploration and exploitation. + +Similarly, an example of a simple replay would be a random replay. At each time step, the +interactions between the agent and the environment are saved to a memory buffer and previous +experiences are sampled from the buffer to train the agent. + +Instantiating the components of an agent can be easily done by passing the Environment as +a templated argument and the parameters of the policy/replay to the constructor. + +To create a Greedy Policy and Prioritized Replay for the CartPole environment, we would do the +following: + +@code +GreedyPolicy policy(1.0, 1000, 0.1); +PrioritizedReplay replayMethod(10, 10000, 0.6); +@endcode + +The arguments to `policy` are the initial epsilon values, the interval of decrease in its value +and the value at which epsilon bottoms out and won't be reduced further. The arguments to +`replayMethod` are size of the batch returned, the number of examples stored in memory, and the +degree of prioritization. + +In addition to the above components, an RL agent requires many hyperparameters to be tuned during + it's training period. These parameters include everything from the discount rate of the future +reward to whether Double Q-learning should be used or not. The `TrainingConfig` class can be +instantiated and configured as follows: + +@code + TrainingConfig config; + config.StepSize() = 0.01; + config.Discount() = 0.9; + config.TargetNetworkSyncInterval() = 100; + config.ExplorationSteps() = 100; + config.DoubleQLearning() = false; + config.StepLimit() = 200; +@endcode + +The object `config` describes an RL agent, using a step size of 0.01 for the optimization process, +a discount factor of 0.9, sync interval of 200 episodes. This agent only starts learning after storing +100 exploration steps, has a step limit of 200, and does not utilize double q-learning. + +In this way, we can easily configure an RL agent with the desired hyperparameters. + +@section q_learning_rltut Q-Learning in mlpack + +Here, we demonstrate Q-Learning in mlpack through the use of a simple example, the training of a Q-Learning +agent on the CartPole environment. The code has been broken into chunks for easy understanding. + +@code +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace mlpack; +using namespace mlpack::ann; +using namespace ens; +using namespace mlpack::rl; +@endcode + +We include all the necessary components of our toy example and declare namespaces for convenience. + +@code +int main() +{ + // Set up the network. + FFN, GaussianInitialization> model(MeanSquaredError<>(), + GaussianInitialization(0, 0.001)); + model.Add>(4, 128); + model.Add>(); + model.Add>(128, 128); + model.Add>(); + model.Add>(128, 2); + +@endcode + +The first step in setting our Q-learning agent is to setup the network for it to use. Here, +we use mlpack's ann module to setup a simple FFN network, consisting of a single hidden layer. + +@note +The network constructed here has an input shape of 4 and output shape of 2. This corresponds to +the structure of the CartPole environment, where each state is represented as a column vector with +4 data members (position, velocity, angle, angular velocity). Similarly, the output shape is represented +by the number of possible actions, which in this case, is only 2 (foward and backward). + +The next step would be to setup the other components of the Q-learning agent, namely its policy, replay +method and hyperparameters. + +@code + // Set up the policy and replay method. + GreedyPolicy policy(1.0, 1000, 0.1, 0.99); + RandomReplay replayMethod(10, 10000); + + TrainingConfig config; + config.StepSize() = 0.01; + config.Discount() = 0.9; + config.TargetNetworkSyncInterval() = 100; + config.ExplorationSteps() = 100; + config.DoubleQLearning() = false; + config.StepLimit() = 200; +@endcode + +And now, we get to the heart of the program, declaring a Q-Learning agent. + +@code + QLearning + agent(std::move(config), std::move(model), std::move(policy), + std::move(replayMethod)); +@endcode + +Here, we call the `QLearning` constructor, passing in the type of environment, +network, updater, policy and replay. We use `decltype(var)` as a shorthand for +the variable, saving us the trouble of copying the lengthy templated type. + +Similarly, `std::move` is called for convenience, moving the components instead of +duplicating them and copying them over. + +We have our Q-Learning agent `agent` ready to be trained on the Cart Pole environment. + +@code + arma::running_stat averageReturn; + size_t episodes = 0; + bool converged = true; + while (true) + { + double episodeReturn = agent.Episode(); + averageReturn(episodeReturn); + episodes += 1; + + if (episodes > 1000) + { + std::cout << "Cart Pole with DQN failed." << std::endl; + converged = false; + break; + } + + /** + * Reaching running average return 35 is enough to show it works. + */ + std::cout << "Average return: " << averageReturn.mean() + << " Episode return: " << episodeReturn << std::endl; + if (averageReturn.mean() > 35) + break; + } + if (converged) + std::cout << "Hooray! Q-Learning agent successfully trained" << std::endl; + + return 0; +} +@endcode + +We set up a loop to train the agent. The exit condition is determined by the average +reward which can be computed with `arma::running_stat`. It is used for storing running +statistics of scalars, which in this case is the reward signal. The agent can be said +to have converged when the average return reaches a predetermined value (i.e. > 35). + +Conversely, if the average return does not go beyond that amount even after a thousand +episodes, we can conclude that the agent will not converge and exit the training loop. + +@section async_learning_rltut + +In 2016, Researchers at Deepmind and University of Montreal published their paper +"Asynchronous Methods for Deep Reinforcement Learning". In it they described asynchronous +variants of four standard reinforcement learning algorithms: + - One-Step SARSA + - One-Step Q-Learning + - N-Step Q-Learning + - Advantage Actor-Critic(A3C) + +Online RL algorithms and Deep Neural Networks make an unstable combination because of the +non-stationary and correlated nature of online updates. Although this is solved by Experience Replay, +it has several drawbacks: it uses more memory and computation per real interaction; and it requires +off-policy learning algorithms. + +Asynchronous methods, instead of experience replay, asynchronously executes multiple agents +in parallel, on multiple instances of the environment, which solves all the above problems. + +Here, we demonstrate Asynchronous Learning methods in mlpack through the training of an async +agent. Asynchronous learning involves training several agents simultaneously. Here, each of the +agents are referred to as "workers". Currently mlpack has One-Step Q-Learning worker, N-Step +Q-Learning worker and One-Step SARSA worker. + +Let's examine the sample code in chunks. + +Apart from the includes used for the q-learning example, two more have to be included: + +@code +#include +#include +@endcode + +Here we don't use experience replay, and instead of a single policy, we use three different +policies, each corresponding to its worker. Number of workers created, depends on the number of +policies given in the Aggregated Policy. The column vector contains the probability distribution +for each child policy. We should make sure its size is same as the number of policies and the sum +of its elements is equal to 1. + +@code +AggregatedPolicy> policy({GreedyPolicy(0.7, 5000, 0.1), + GreedyPolicy(0.7, 5000, 0.01), + GreedyPolicy(0.7, 5000, 0.5)}, + arma::colvec("0.4 0.3 0.3")); +@endcode + +Now, we will create the "OneStepQLearning" agent. We could have used "NStepQLearning" or "OneStepSarsa" +here according to our requirement. + +@code +OneStepQLearning + agent(std::move(config), std::move(model), std::move(policy)); +@endcode + +Here, unlike the Q-Learning example, instead of the entire while loop, we use the Train method of the Asynchronous +Learning class inside a for loop. 100 training episodes will take around 50 seconds. + +@code +for (int i = 0; i < 100; i++) +{ + agent.Train(measure); +} +@endcode + +What is "measure" here? It is a lambda function which returns a boolean value (indicating the end of training) +and accepts the episode return (total reward of a deterministic test episode) as parameter. +So, let's create that. + +@code +arma::vec returns(20, arma::fill::zeros); +size_t position = 0; +size_t episode = 0; + +auto measure = [&returns, &position, &episode](double episodeReturn) +{ + if(episode > 10000) return true; + + returns[position++] = episodeReturn; + position = position % returns.n_elem; + episode++; + + std::cout << "Episode No.: " << episode + << "; Episode Return: " << episodeReturn + << "; Average Return: " << arma::mean(returns) << endl; +}; +@endcode + +This will train three different agents on three CPU threads asynchronously and use this data to update the +action value estimate. +Voila, thats all there is to it. + +Here is the full code to try this right away: + +@code +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace mlpack; +using namespace mlpack::ann; +using namespace mlpack::rl; +int main() +{ + // Set up the network. + FFN, GaussianInitialization> model(MeanSquaredError<>(), GaussianInitialization(0, 0.001)); + model.Add>(4, 128); + model.Add>(); + model.Add>(128, 128); + model.Add>(); + model.Add>(128, 2); + + AggregatedPolicy> policy({GreedyPolicy(0.7, 5000, 0.1), + GreedyPolicy(0.7, 5000, 0.01), + GreedyPolicy(0.7, 5000, 0.5)}, + arma::colvec("0.4 0.3 0.3")); + + TrainingConfig config; + config.StepSize() = 0.01; + config.Discount() = 0.9; + config.TargetNetworkSyncInterval() = 100; + config.ExplorationSteps() = 100; + config.DoubleQLearning() = false; + config.StepLimit() = 200; + + OneStepQLearning + agent(std::move(config), std::move(model), std::move(policy)); + + arma::vec returns(20, arma::fill::zeros); + size_t position = 0; + size_t episode = 0; + + auto measure = [&returns, &position, &episode](double episodeReturn) + { + if(episode > 10000) return true; + + returns[position++] = episodeReturn; + position = position % returns.n_elem; + episode++; + + std::cout << "Episode No.: " << episode + << "; Episode Return: " << episodeReturn + << "; Average Return: " << arma::mean(returns) << endl; + }; + + for (int i = 0; i < 100; i++) + { + agent.Train(measure); + } +} +@endcode + +@section further_rltut Further documentation + +For further documentation on the rl classes, consult the \ref mlpack::rl +"complete API documentation". + +*/ diff -Nru mlpack-3.2.2/doc/tutorials/tutorials.txt mlpack-3.3.0/doc/tutorials/tutorials.txt --- mlpack-3.2.2/doc/tutorials/tutorials.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/doc/tutorials/tutorials.txt 2020-04-07 13:17:16.000000000 +0000 @@ -13,6 +13,7 @@ - \ref python_quickstart - \ref cli_quickstart + - \ref julia_quickstart @section introd_tut Introductory Tutorials diff -Nru mlpack-3.2.2/GOVERNANCE.md mlpack-3.3.0/GOVERNANCE.md --- mlpack-3.2.2/GOVERNANCE.md 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/GOVERNANCE.md 2020-04-07 13:17:16.000000000 +0000 @@ -1,4 +1,4 @@ -# mlpack governance structure (DRAFT) +# mlpack governance structure Revised Oct. 21st, 2019. @@ -17,7 +17,7 @@ mlpack aims to be an open and welcoming environment, and as such, we have a code of conduct that helps foster this environment. See -(here)[https://github.com/mlpack/mlpack/blob/master/CODE_OF_CONDUCT.md] for +[here](https://github.com/mlpack/mlpack/blob/master/CODE_OF_CONDUCT.md) for more information. ## Teams & Roles diff -Nru mlpack-3.2.2/HISTORY.md mlpack-3.3.0/HISTORY.md --- mlpack-3.2.2/HISTORY.md 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/HISTORY.md 2020-04-07 13:17:16.000000000 +0000 @@ -1,3 +1,87 @@ +### mlpack 3.3.0 +###### 2020-04-07 + * Templated return type of `Forward function` of loss functions (#2339). + + * Added `R2 Score` regression metric (#2323). + + * Added `mean squared logarithmic error` loss function for neural networks + (#2210). + + * Added `mean bias loss function` for neural networks (#2210). + + * The DecisionStump class has been marked deprecated; use the `DecisionTree` + class with `NoRecursion=true` or use `ID3DecisionStump` instead (#2099). + + * Added `probabilities_file` parameter to get the probabilities matrix of + AdaBoost classifier (#2050). + + * Fix STB header search paths (#2104). + + * Add `DISABLE_DOWNLOADS` CMake configuration option (#2104). + + * Add padding layer in TransposedConvolutionLayer (#2082). + + * Fix pkgconfig generation on non-Linux systems (#2101). + + * Use log-space to represent HMM initial state and transition probabilities + (#2081). + + * Add functions to access parameters of `Convolution` and `AtrousConvolution` + layers (#1985). + + * Add Compute Error function in lars regression and changing Train function to + return computed error (#2139). + + * Add Julia bindings (#1949). Build settings can be controlled with the + `BUILD_JULIA_BINDINGS=(ON/OFF)` and `JULIA_EXECUTABLE=/path/to/julia` CMake + parameters. + + * CMake fix for finding STB include directory (#2145). + + * Add bindings for loading and saving images (#2019); `mlpack_image_converter` + from the command-line, `mlpack.image_converter()` from Python. + + * Add normalization support for CF binding (#2136). + + * Add Mish activation function (#2158). + + * Update `init_rules` in AMF to allow users to merge two initialization + rules (#2151). + + * Add GELU activation function (#2183). + + * Better error handling of eigendecompositions and Cholesky decompositions + (#2088, #1840). + + * Add LiSHT activation function (#2182). + + * Add Valid and Same Padding for Transposed Convolution layer (#2163). + + * Add CELU activation function (#2191) + + * Add Log-Hyperbolic-Cosine Loss function (#2207) + + * Change neural network types to avoid unnecessary use of rvalue references + (#2259). + + * Bump minimum Boost version to 1.58 (#2305). + + * Refactor STB support so `HAS_STB` macro is not needed when compiling against + mlpack (#2312). + + * Add Hard Shrink Activation Function (#2186). + + * Add Soft Shrink Activation Function (#2174). + + * Add Hinge Embedding Loss Function (#2229). + + * Add Cosine Embedding Loss Function (#2209). + + * Add Margin Ranking Loss Function (#2264). + + * Bugfix for incorrect parameter vector sizes in logistic regression and + softmax regression (#2359). + ### mlpack 3.2.2 ###### 2019-11-26 * Add `valid` and `same` padding option in `Convolution` and `Atrous @@ -20,6 +104,8 @@ * Add `__version__` to `__init__.py` (#2092). + * Correctly handle RNN sequences that are shorter than the value of rho (#2102). + ### mlpack 3.2.1 ###### 2019-10-01 * Enforce CMake version check for ensmallen (#2032). diff -Nru mlpack-3.2.2/LICENSE.txt mlpack-3.3.0/LICENSE.txt --- mlpack-3.2.2/LICENSE.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/LICENSE.txt 2020-04-07 13:17:16.000000000 +0000 @@ -17,7 +17,7 @@ is used in src/mlpack/core/data/load_image.hpp. ---- -Copyright (c) 2007-2018, mlpack contributors (see COPYRIGHT.txt) +Copyright (c) 2007-2020, mlpack contributors (see COPYRIGHT.txt) All rights reserved. Redistribution and use of mlpack in source and binary forms, with or without diff -Nru mlpack-3.2.2/README.md mlpack-3.3.0/README.md --- mlpack-3.2.2/README.md 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/README.md 2020-04-07 13:17:16.000000000 +0000 @@ -14,16 +14,16 @@

- Jenkins - Appveyor + Jenkins Coveralls License + NumFOCUS

Download: - current stable version (3 2.1) + current stable version (3.2.2)

@@ -31,8 +31,10 @@ bindings to other languages. It is meant to be a machine learning analog to LAPACK, and aims to implement a wide array of machine learning methods and functions as a "swiss army knife" for machine learning researchers. In addition -to its powerful C++ interface, mlpack also provides command-line programs and -Python bindings. +to its powerful C++ interface, mlpack also provides command-line programs, +Python bindings, and Julia bindings. + +[//]: # (numfocus-fiscal-sponsor-attribution) mlpack uses an [open governance model](./GOVERNANCE.md) and is fiscally sponsored by [NumFOCUS](https://numfocus.org/). Consider making a @@ -41,7 +43,7 @@ variety of other needs.
- + @@ -98,11 +100,11 @@ mlpack has the following dependencies: - Armadillo >= 8.400.0 + Armadillo >= 8.400.0 Boost (program_options, math_c99, unit_test_framework, serialization, - spirit) - CMake >= 3.3.2 - ensmallen >= 2.10.0 + spirit) >= 1.58.0 + CMake >= 3.3.2 + ensmallen >= 2.10.0 All of those should be available in your distribution's package manager. If not, you will have to compile each of them by hand. See the documentation for @@ -116,6 +118,9 @@ numpy pandas >= 0.15.0 +If you would like to build the Julia bindings, make sure that Julia >= 1.3.0 is +installed. + If the STB library headers are available, image loading support will be compiled. @@ -123,10 +128,11 @@ ### 4. Building mlpack from source -This section discusses how to build mlpack from source. However, mlpack is in -the repositories of many Linux distributions, so it may be easier to use the -package manager for your system. For example, on Ubuntu, you can install mlpack -with the following command: +This document discusses how to build mlpack from source. These build directions +will work for any Linux-like shell environment (for example Ubuntu, macOS, +FreeBSD etc). However, mlpack is in the repositories of many Linux distributions +and so it may be easier to use the package manager for your system. For example, +on Ubuntu, you can install mlpack with the following command: $ sudo apt-get install libmlpack-dev @@ -179,13 +185,18 @@ BUILD_CLI_EXECUTABLES=(ON/OFF): whether or not to build command-line programs BUILD_PYTHON_BINDINGS=(ON/OFF): whether or not to build Python bindings PYTHON_EXECUTABLE=(/path/to/python_version): Path to specific Python executable + BUILD_JULIA_BINDINGS=(ON/OFF): whether or not to build Julia bindings + JULIA_EXECUTABLE=(/path/to/julia): Path to specific Julia executable BUILD_TESTS=(ON/OFF): whether or not to build tests BUILD_SHARED_LIBS=(ON/OFF): compile shared libraries 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 - DOWNLOAD_STB_IMAGE=(ON/OFF): If STB is not found, download it ENSMALLEN_INCLUDE_DIR=(/path/to/ensmallen/include): path to include directory for ensmallen + DOWNLOAD_STB_IMAGE=(ON/OFF): If STB is not found, download it + STB_IMAGE_INCLUDE_DIR=(/path/to/stb/include): path to include directory for + STB image library USE_OPENMP=(ON/OFF): whether or not to use OpenMP if available Other tools can also be used to configure CMake, but those are not documented @@ -201,6 +212,7 @@ This will build all library components as well as 'mlpack_test'. $ make + If you do not want to build everything in the library, individual components of the build can be specified: @@ -211,7 +223,7 @@ [mlpack on Github](https://www.github.com/mlpack/mlpack/) -Alternately, mlpack help can be found in IRC at `#mlpack` on irc.freenode.net. +Alternately, mlpack help can be found in IRC at `#mlpack` on chat.freenode.net. If you wish to install mlpack to `/usr/local/include/mlpack/`, `/usr/local/lib/`, and `/usr/local/bin/`, make sure you have root privileges (or write permissions @@ -316,7 +328,7 @@ - [mlpack documentation](https://www.mlpack.org/docs.html) - [Tutorials](https://www.mlpack.org/doc/mlpack-git/doxygen/tutorials.html) - [Development Site (Github)](https://www.github.com/mlpack/mlpack/) - - [API documentation](https://www.mlpack.org/doc/mlpack-git/doxygen/index.html) + - [API documentation (Doxygen)](https://www.mlpack.org/doc/mlpack-git/doxygen/index.html) ### 8. Bug reporting diff -Nru mlpack-3.2.2/src/mlpack/bindings/CMakeLists.txt mlpack-3.3.0/src/mlpack/bindings/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/bindings/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -1,6 +1,7 @@ # All we have to do is recurse into the subdirectories. set(DIRS cli + julia markdown python tests diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/CMakeLists.txt mlpack-3.3.0/src/mlpack/bindings/julia/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/bindings/julia/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,159 @@ +if (BUILD_JULIA_BINDINGS) + ## We need to check here if Julia is even available. Although actually + ## technically, I'm not sure if we even need to know! For the tests though we + ## do. So it's probably a good idea to check. + find_package(Julia 1.3.0) + + if (NOT JULIA_FOUND) + # We can't build anything, so define the macro to do nothing. + macro (add_julia_binding name) + # Do nothing. + endmacro () + + return () + endif () + + add_custom_target(julia ALL) + + add_custom_command(TARGET julia PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/) + + add_library(mlpack_julia_util + julia_util.h + julia_util.cpp) + target_link_libraries(mlpack_julia_util mlpack) + set_target_properties(mlpack_julia_util PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/") + add_dependencies(julia mlpack_julia_util) + + # Now configure Project.toml. + file(READ "${CMAKE_SOURCE_DIR}/src/mlpack/core/util/version.hpp" + VERSION_HPP_CONTENTS) + string(REGEX REPLACE ".*#define MLPACK_VERSION_MAJOR ([0-9]+).*" "\\1" + MLPACK_VERSION_MAJOR "${VERSION_HPP_CONTENTS}") + string(REGEX REPLACE ".*#define MLPACK_VERSION_MINOR ([0-9]+).*" "\\1" + MLPACK_VERSION_MINOR "${VERSION_HPP_CONTENTS}") + string(REGEX REPLACE ".*#define MLPACK_VERSION_PATCH [\"]?([0-9x]+)[\"]?.*" + "\\1" MLPACK_VERSION_PATCH "${VERSION_HPP_CONTENTS}") + + set(PACKAGE_VERSION + "${MLPACK_VERSION_MAJOR}.${MLPACK_VERSION_MINOR}.${MLPACK_VERSION_PATCH}") + + get_property(CYTHON_INCLUDE_DIRECTORIES DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + PROPERTY INCLUDE_DIRECTORIES) + configure_file(${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/mlpack/Project.toml.in + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/Project.toml) + # Configure cli.jl.in with the right suffix for libraries. + configure_file(${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/mlpack/cli.jl.in + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/cli.jl) + + # Create the empty mlpack.jl file that we will fill with includes using the + # exsiting template. Unfortunately COPY doesn't let us change the extension + # so we need a follow-up RENAME command. + file(COPY + "${CMAKE_CURRENT_SOURCE_DIR}/mlpack/mlpack.jl.in" + DESTINATION + "${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/") + file(RENAME + "${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/mlpack.jl.in" + "${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/mlpack.jl") + + file(WRITE + "${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/functions.jl" + "# This file imports all of the mlpack functions into the mlpack module." + "\n\n") +endif () + +macro (add_julia_binding name) +if (BUILD_JULIA_BINDINGS) + # We have to take multiple steps. + + # 1. Generate julia_${name}.h and julia_${name}.cpp. + add_custom_command(OUTPUT + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/julia_${name}.h + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/julia_${name}.cpp + COMMAND ${CMAKE_COMMAND} + -DPROGRAM_NAME="${name}" + -DPROGRAM_MAIN_FILE="${CMAKE_CURRENT_SOURCE_DIR}/${name}_main.cpp" + -DJULIA_H_IN="${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/julia_method.h.in" + -DJULIA_H_OUT="${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/julia_${name}.h" + -DJULIA_CPP_IN="${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/julia_method.cpp.in" + -DJULIA_CPP_OUT="${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/julia_${name}.cpp" + -P ${CMAKE_SOURCE_DIR}/CMake/julia/ConfigureJuliaHCPP.cmake + DEPENDS ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/julia_method.h.in + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/julia_method.cpp.in + ${CMAKE_SOURCE_DIR}/CMake/julia/ConfigureJuliaHCPP.cmake) + + # 2. Build libmlpack_julia_${name}.so. + add_library(mlpack_julia_${name} + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/julia_${name}.h + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/julia_${name}.cpp) + target_link_libraries(mlpack_julia_${name} mlpack mlpack_julia_util) + set_target_properties(mlpack_julia_${name} PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/") + + # 3. Generate ${name}.jl. + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/generate_jl_${name}.cpp + COMMAND ${CMAKE_COMMAND} + -DNAME=${name} + -DGENERATE_CPP_IN=${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/generate_jl.cpp.in + -DGENERATE_CPP_OUT=${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/generate_jl_${name}.cpp + -DPROGRAM_MAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/${name}_main.cpp + -DMLPACK_JL_LIB_SUFFIX=${CMAKE_SHARED_LIBRARY_SUFFIX} + -P ${CMAKE_SOURCE_DIR}/CMake/ConfigureGenerate.cmake + DEPENDS ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/generate_jl.cpp.in + ${CMAKE_SOURCE_DIR}/CMake/ConfigureGenerate.cmake) + + add_executable(generate_jl_${name} + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/generate_jl_${name}.cpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/print_jl.hpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/print_jl.cpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/get_julia_type.hpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/get_param.hpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/get_printable_param.hpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/julia_option.hpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/print_doc_functions.hpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/print_doc_functions_impl.hpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/print_input_param.hpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/print_input_processing.hpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/print_input_processing_impl.hpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/print_output_processing.hpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/print_output_processing_impl.hpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/print_param_defn.hpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/print_type_doc.hpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/print_type_doc_impl.hpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/default_param.hpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/default_param_impl.hpp + ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/strip_type.hpp) + target_link_libraries(generate_jl_${name} mlpack ${MLPACK_LIBRARIES}) + set_target_properties(generate_jl_${name} PROPERTIES + COMPILE_FLAGS "-DBINDING_TYPE=BINDING_TYPE_JL" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/bin/") + add_custom_command(TARGET generate_jl_${name} POST_BUILD + COMMAND ${CMAKE_COMMAND} + -DGENERATE_BINDING_PROGRAM="${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/bin/generate_jl_${name}" + -DBINDING_OUTPUT_FILE=${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/${name}.jl + -P ${CMAKE_SOURCE_DIR}/CMake/GenerateBinding.cmake) + + # Add the generate_jl_${name} target to the list of targets that are built + # when 'make julia' is typed. + add_dependencies(julia mlpack_julia_${name}) + add_dependencies(julia generate_jl_${name}) + + # Append the binding to the mlpack.jl file. (Note that this is done at + # configuration time.) + file(APPEND + "${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/mlpack.jl" + "include(\"${name}.jl\")\n") + + # Append the code to define the function in the module. + file(APPEND + "${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/functions.jl" + "${name} = _Internal.${name}\n") +endif () +endmacro () + +if (BUILD_TESTS AND BUILD_JULIA_BINDINGS) + add_subdirectory(tests) +endif () diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/default_param.hpp mlpack-3.3.0/src/mlpack/bindings/julia/default_param.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/default_param.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/default_param.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,95 @@ +/** + * @file default_param.hpp + * @author Ryan Curtin + * + * Return the default value of a parameter, depending on its type. + * + * 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_BINDINGS_JULIA_DEFAULT_PARAM_HPP +#define MLPACK_BINDINGS_JULIA_DEFAULT_PARAM_HPP + +#include +#include +#include + +namespace mlpack { +namespace bindings { +namespace julia { + +/** + * Return the default value of an option. This is for regular types. + */ +template +std::string DefaultParamImpl( + const util::ParamData& data, + const typename boost::disable_if>::type* = 0, + const typename boost::disable_if>::type* = 0, + const typename boost::disable_if>::type* = 0, + const typename boost::disable_if>::type* = 0, + const typename boost::disable_if>>::type* = 0); + +/** + * Return the default value of a vector option. + */ +template +std::string DefaultParamImpl( + const util::ParamData& data, + const typename boost::enable_if>::type* = 0); + +/** + * Return the default value of a string option. + */ +template +std::string DefaultParamImpl( + const util::ParamData& data, + const typename boost::enable_if>::type* = 0); + +/** + * Return the default value of a matrix option, a tuple option, a + * serializable option, or a string option (this returns the default filename, + * or '' if the default is no file). + */ +template +std::string DefaultParamImpl( + const util::ParamData& data, + const typename boost::enable_if_c< + arma::is_arma_type::value || + std::is_same>::value>::type* /* junk */ = 0); + +/** + * Return the default value of a model option (this returns the default + * filename, or '' if the default is no file). + */ +template +std::string DefaultParamImpl( + const util::ParamData& data, + const typename boost::disable_if>::type* = 0, + const typename boost::enable_if>::type* = 0); + +/** + * Return the default value of an option. This is the function that will be + * placed into the CLI functionMap. + */ +template +void DefaultParam(const util::ParamData& data, + const void* /* input */, + void* output) +{ + std::string* outstr = (std::string*) output; + *outstr = DefaultParamImpl::type>(data); +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +// Include implementation. +#include "default_param_impl.hpp" + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/default_param_impl.hpp mlpack-3.3.0/src/mlpack/bindings/julia/default_param_impl.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/default_param_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/default_param_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,147 @@ +/** + * @file default_param_impl.hpp + * @author Ryan Curtin + * + * Return the default value of a parameter, depending on its type. + * + * 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_BINDINGS_JULIA_DEFAULT_PARAM_IMPL_HPP +#define MLPACK_BINDINGS_JULIA_DEFAULT_PARAM_IMPL_HPP + +#include "default_param.hpp" + +namespace mlpack { +namespace bindings { +namespace julia { + +/** + * Return the default value of an option. + */ +template +std::string DefaultParamImpl( + const util::ParamData& data, + const typename boost::disable_if>::type* /* junk */, + const typename boost::disable_if>::type* /* junk */, + const typename boost::disable_if>::type* /* junk */, + const typename boost::disable_if>::type*, + const typename boost::disable_if>>::type* /* junk */) +{ + std::ostringstream oss; + if (std::is_same::value) + oss << "false"; + else + oss << boost::any_cast(data.value); + + return oss.str(); +} + +/** + * Return the default value of a vector option. + */ +template +std::string DefaultParamImpl( + const util::ParamData& data, + const typename boost::enable_if>::type* /* junk */) +{ + // Print each element in an array delimited by square brackets. + std::ostringstream oss; + const T& vector = boost::any_cast(data.value); + oss << "["; + if (std::is_same>::value) + { + if (vector.size() > 0) + { + for (size_t i = 0; i < vector.size() - 1; ++i) + { + oss << "\"" << vector[i] << "\", "; + } + + oss << "\"" << vector[vector.size() - 1] << "\""; + } + + oss << "]"; + } + else + { + if (vector.size() > 0) + { + for (size_t i = 0; i < vector.size() - 1; ++i) + { + oss << vector[i] << ", "; + } + + oss << vector[vector.size() - 1]; + } + + oss << "]"; + } + return oss.str(); +} + +/** + * Return the default value of a string option. + */ +template +std::string DefaultParamImpl( + const util::ParamData& data, + const typename boost::enable_if>::type*) +{ + const std::string& s = *boost::any_cast(&data.value); + return "\"" + s + "\""; +} + +/** + * Return the default value of a matrix option (this returns the default + * filename, or '' if the default is no file). + */ +template +std::string DefaultParamImpl( + const util::ParamData& /* data */, + const typename boost::enable_if_c< + arma::is_arma_type::value || + std::is_same>::value>::type* /* junk */) +{ + // Get the filename and return it, or return an empty string. + if (std::is_same::value || + std::is_same::value) + { + return "Float64[]"; + } + else if (std::is_same>::value || + std::is_same>::value) + { + return "Int[]"; + } + else if (std::is_same>::value) + { + return "zeros(Int, 0, 0)"; + } + else + { + return "zeros(0, 0)"; + } +} + +/** + * Return the default value of a model option (always "nothing"). + */ +template +std::string DefaultParamImpl( + const util::ParamData& /* data */, + const typename boost::disable_if>::type* /* junk */, + const typename boost::enable_if>::type* /* junk */) +{ + return "nothing"; +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/generate_jl.cpp.in mlpack-3.3.0/src/mlpack/bindings/julia/generate_jl.cpp.in --- mlpack-3.2.2/src/mlpack/bindings/julia/generate_jl.cpp.in 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/generate_jl.cpp.in 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,39 @@ +/** + * @file generate_jl.cpp.in + * @author Ryan Curtin + * + * This is a template file to call the PrintJL() function for a given binding. + */ +#define BINDING_TYPE BINDING_TYPE_JL +// Disable debug output. +#ifdef DEBUG + #define HAD_DEBUG + #undef DEBUG +#endif +#include +#ifdef HAD_DEBUG + #undef HAD_DEBUG + #define DEBUG +#endif + +#include +#include +#include + +// This will include the ParamData options that are part of the program. +#include <${PROGRAM_MAIN_FILE}> + +using namespace mlpack; +using namespace mlpack::bindings; +using namespace mlpack::bindings::julia; +using namespace std; +using namespace mlpack::util; + +int main(int /* argc */, char** /* argv */) +{ + // All the parameters are registered, but stored, so restore them. + // programName is defined in mlpack_main.hpp. + CLI::RestoreSettings(programName); + + PrintJL(*CLI::GetSingleton().doc, "${NAME}", "${MLPACK_JL_LIB_SUFFIX}"); +} diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/get_julia_type.hpp mlpack-3.3.0/src/mlpack/bindings/julia/get_julia_type.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/get_julia_type.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/get_julia_type.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,141 @@ +/** + * @file get_julia_type.hpp + * @author Ryan Curtin + * + * Get the Julia-named type of an mlpack C++ type. + * + * 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_BINDINGS_JULIA_GET_JULIA_TYPE_HPP +#define MLPACK_BINDINGS_JULIA_GET_JULIA_TYPE_HPP + +#include + +namespace mlpack { +namespace bindings { +namespace julia { + +template +inline std::string GetJuliaType( + const typename std::enable_if::value>::type* = 0, + const typename std::enable_if::value>::type* = 0, + const typename std::enable_if>::value>::type* = 0, + const typename std::enable_if::value>::type* = 0) +{ + return "unknown_"; // This will cause an error most likely... +} + +template<> +inline std::string GetJuliaType( + const typename std::enable_if::value>::type*, + const typename std::enable_if::value>::type*, + const typename std::enable_if>::value>::type*, + const typename std::enable_if::value>::type*) +{ + return "Bool"; +} + +template<> +inline std::string GetJuliaType( + const typename std::enable_if::value>::type*, + const typename std::enable_if::value>::type*, + const typename std::enable_if>::value>::type*, + const typename std::enable_if::value>::type*) +{ + return "Int"; +} + +template<> +inline std::string GetJuliaType( + const typename std::enable_if::value>::type*, + const typename std::enable_if::value>::type*, + const typename std::enable_if>::value>::type*, + const typename std::enable_if::value>::type*) +{ + return "UInt"; +} + +template<> +inline std::string GetJuliaType( + const typename std::enable_if::value>::type*, + const typename std::enable_if::value>::type*, + const typename std::enable_if>::value>::type*, + const typename std::enable_if::value>::type*) +{ + // I suppose on some systems this may not be 64 bit. + return "Float64"; +} + +template<> +inline std::string GetJuliaType( + const typename std::enable_if< + !util::IsStdVector::value>::type*, + const typename std::enable_if< + !arma::is_arma_type::value>::type*, + const typename std::enable_if>::value>::type*, + const typename std::enable_if< + !data::HasSerialize::value>::type*) +{ + return "String"; +} + +template +inline std::string GetJuliaType( + const typename std::enable_if::value>::type* = 0, + const typename std::enable_if>::value>::type* = 0, + const typename std::enable_if::value>::type* = 0) +{ + return "Vector{" + GetJuliaType() + "}"; +} + +template +inline std::string GetJuliaType( + const typename std::enable_if::value>::type* = 0, + const typename std::enable_if>::value>::type* = 0, + const typename std::enable_if::value>::type* = 0) +{ + // size_t matrices are special: we want to represent them in Julia as + // Array{Int, X} not UInt because Julia displays UInts strangely. + if (std::is_same::value) + return std::string("Array{Int, ") + (T::is_col || T::is_row ? "1" : "2") + + "}"; + else + return "Array{" + GetJuliaType() + ", " + + (T::is_col || T::is_row ? "1" : "2") + "}"; +} + +template +inline std::string GetJuliaType( + const typename std::enable_if>::value>::type* = 0) +{ + return "Tuple{Array{Bool, 1}, Array{Float64, 2}}"; +} + +// for serializable types +template +inline std::string GetJuliaType( + const typename std::enable_if::value>::type* = 0, + const typename std::enable_if::value>::type* = 0, + const typename std::enable_if::value>::type* = 0) +{ + // Serializable types are just held as a pointer to nothing... + return "Ptr{Nothing}"; +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/get_param.hpp mlpack-3.3.0/src/mlpack/bindings/julia/get_param.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/get_param.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/get_param.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,37 @@ +/** + * @file get_param.hpp + * @author Ryan Curtin + * + * Get a parameter for a Julia binding. + * + * 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_BINDINGS_JULIA_GET_PARAM_HPP +#define MLPACK_BINDINGS_JULIA_GET_PARAM_HPP + +#include + +namespace mlpack { +namespace bindings { +namespace julia { + +/** + * All Julia binding types are exactly what is held in the ParamData, so no + * special handling is necessary. + */ +template +void GetParam(const util::ParamData& d, + const void* /* input */, + void* output) +{ + *((T**) output) = const_cast(boost::any_cast(&d.value)); +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/get_printable_param.hpp mlpack-3.3.0/src/mlpack/bindings/julia/get_printable_param.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/get_printable_param.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/get_printable_param.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,126 @@ +/** + * @file get_printable_param.hpp + * @author Ryan Curtin + * + * Get a printable version of parameters. + * + * 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_BINDINGS_JULIA_GET_PRINTABLE_PARAM_HPP +#define MLPACK_BINDINGS_JULIA_GET_PRINTABLE_PARAM_HPP + +#include +#include + +namespace mlpack { +namespace bindings { +namespace julia { + +/** + * Print an option of a simple type. + */ +template +std::string GetPrintableParam( + const util::ParamData& data, + const typename boost::disable_if>::type* = 0, + const typename boost::disable_if>::type* = 0, + const typename boost::disable_if>::type* = 0, + const typename boost::disable_if>>::type* = 0) +{ + std::ostringstream oss; + oss << boost::any_cast(data.value); + return oss.str(); +} + +/** + * Print a vector option, with spaces between it. + */ +template +std::string GetPrintableParam( + const util::ParamData& data, + const typename boost::enable_if>::type* = 0) +{ + const T& t = boost::any_cast(data.value); + + std::ostringstream oss; + for (size_t i = 0; i < t.size(); ++i) + oss << t[i] << " "; + return oss.str(); +} + +/** + * Print a matrix option (this prints its size). + */ +template +std::string GetPrintableParam( + const util::ParamData& data, + const typename boost::enable_if>::type* = 0) +{ + // Get the matrix. + const T& matrix = boost::any_cast(data.value); + + std::ostringstream oss; + oss << matrix.n_rows << "x" << matrix.n_cols << " matrix"; + return oss.str(); +} + +/** + * Print a serializable class option (this prints the class name). + */ +template +std::string GetPrintableParam( + const util::ParamData& data, + const typename boost::disable_if>::type* = 0, + const typename boost::enable_if>::type* = 0) +{ + std::ostringstream oss; + oss << data.cppType << " model at " << boost::any_cast(data.value); + return oss.str(); +} + +/** + * Print a combination DatasetInfo/matrix parameter. + */ +template +std::string GetPrintableParam( + const util::ParamData& data, + const typename boost::enable_if>>::type* = 0) +{ + // Get the matrix. + const T& tuple = boost::any_cast(data.value); + const arma::mat& matrix = std::get<1>(tuple); + + std::ostringstream oss; + oss << matrix.n_rows << "x" << matrix.n_cols << " matrix with dimension type " + << "information"; + return oss.str(); +} + +/** + * Print an option into a std::string. This should print a short, one-line + * representation of the object. The string will be stored in the output + * pointer. + * + * @param data Parameter data struct. + * @param input Unused parameter. + * @param output Output storage for the string. + */ +template +void GetPrintableParam(const util::ParamData& data, + const void* /* input */, + void* output) +{ + *((std::string*) output) = + GetPrintableParam::type>(data); +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/get_printable_type.hpp mlpack-3.3.0/src/mlpack/bindings/julia/get_printable_type.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/get_printable_type.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/get_printable_type.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,84 @@ +/** + * @file get_printable_type.hpp + * @author Ryan Curtin + * + * Get the printable type of a parameter. This type is not the C++ type but + * instead the Julia type that a user would use. + * + * 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_BINDINGS_JULIA_GET_PRINTABLE_TYPE_HPP +#define MLPACK_BINDINGS_JULIA_GET_PRINTABLE_TYPE_HPP + +namespace mlpack { +namespace bindings { +namespace julia { + +/** + * Return a string representing the command-line type of an option. + */ +template +std::string GetPrintableType( + const util::ParamData& data, + const typename boost::disable_if>::type* = 0, + const typename boost::disable_if>::type* = 0, + const typename boost::disable_if>::type* = 0, + const typename boost::disable_if>>::type* = 0); + +/** + * Return a string representing the command-line type of a vector. + */ +template +std::string GetPrintableType( + const util::ParamData& data, + const typename std::enable_if::value>::type* = 0); + +/** + * Return a string representing the command-line type of a matrix option. + */ +template +std::string GetPrintableType( + const util::ParamData& data, + const typename std::enable_if::value>::type* = 0); + +/** + * Return a string representing the command-line type of a matrix tuple option. + */ +template +std::string GetPrintableType( + const util::ParamData& data, + const typename std::enable_if>::value>::type* = 0); + +/** + * Return a string representing the command-line type of a model. + */ +template +std::string GetPrintableType( + const util::ParamData& data, + const typename boost::disable_if>::type* = 0, + const typename boost::enable_if>::type* = 0); + +/** + * Print the command-line type of an option into a string. + */ +template +void GetPrintableType(const util::ParamData& data, + const void* /* input */, + void* output) +{ + *((std::string*) output) = + GetPrintableType::type>(data); +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#include "get_printable_type_impl.hpp" + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/get_printable_type_impl.hpp mlpack-3.3.0/src/mlpack/bindings/julia/get_printable_type_impl.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/get_printable_type_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/get_printable_type_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,114 @@ +/** + * @file get_printable_type_impl.hpp + * @author Ryan Curtin + * + * Get the printable type of a parameter. This type is not the C++ type but + * instead the Julia type that a user would use. + * + * 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_BINDINGS_JULIA_GET_PRINTABLE_TYPE_IMPL_HPP +#define MLPACK_BINDINGS_JULIA_GET_PRINTABLE_TYPE_IMPL_HPP + +#include "get_printable_type.hpp" + +namespace mlpack { +namespace bindings { +namespace julia { + +/** + * Return a string representing the command-line type of an option. + */ +template +std::string GetPrintableType( + const util::ParamData& data, + const typename boost::disable_if>::type*, + const typename boost::disable_if>::type*, + const typename boost::disable_if>::type*, + const typename boost::disable_if>>::type*) +{ + if (std::is_same::value) + return "Bool"; + else if (std::is_same::value) + return "Int"; + else if (std::is_same::value) + return "Float64"; + else if (std::is_same::value) + return "String"; + else + throw std::invalid_argument("unknown parameter type " + data.cppType); +} + +/** + * Return a string representing the command-line type of a vector. + */ +template +std::string GetPrintableType( + const util::ParamData& data, + const typename std::enable_if::value>::type*) +{ + if (std::is_same>::value) + return "Array{Int, 1}"; + else if (std::is_same>::value) + return "Array{String, 1}"; + else + throw std::invalid_argument("unknown vector type " + data.cppType); +} + +/** + * Return a string representing the command-line type of a matrix option. + */ +template +std::string GetPrintableType( + const util::ParamData& data, + const typename std::enable_if::value>::type*) +{ + if (std::is_same::value) + return "Float64 matrix-like"; + else if (std::is_same>::value) + return "Int matrix-like"; + else if (std::is_same::value) + return "Float64 vector-like"; + else if (std::is_same>::value) + return "Int vector-like"; + else if (std::is_same::value) + return "Float64 vector-like"; + else if (std::is_same>::value) + return "Int vector-like"; + else + throw std::invalid_argument("unknown Armadillo type " + data.cppType); +} + +/** + * Return a string representing the command-line type of a matrix tuple option. + */ +template +std::string GetPrintableType( + const util::ParamData& /* data */, + const typename std::enable_if>::value>::type*) +{ + return "Tuple{Array{Bool, 1}, Array{Float64, 2}}"; +} + +/** + * Return a string representing the command-line type of a model. + */ +template +std::string GetPrintableType( + const util::ParamData& /* data */, + const typename boost::disable_if>::type*, + const typename boost::enable_if>::type*) +{ + return "Ptr{Nothing} (mlpack model)"; +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/julia_method.cpp.in mlpack-3.3.0/src/mlpack/bindings/julia/julia_method.cpp.in --- mlpack-3.2.2/src/mlpack/bindings/julia/julia_method.cpp.in 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/julia_method.cpp.in 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,43 @@ +/** + * @file julia_${PROGRAM_NAME}.cpp + * + * This is an autogenerated file containing implementations of C functions to be + * called by the Julia ${PROGRAM_NAME} binding. + */ +#include "julia_${PROGRAM_NAME}.h" + +#define BINDING_TYPE BINDING_TYPE_JL +#include <${PROGRAM_MAIN_FILE}> + +static void ${PROGRAM_NAME}_mlpackMain() +{ + mlpackMain(); +} + +extern "C" +{ + +bool ${PROGRAM_NAME}() +{ + try + { + ${PROGRAM_NAME}_mlpackMain(); + return true; + } + catch (std::runtime_error& e) + { + std::cout << e.what() << std::endl; + return false; + } +} + +void loadSymbols() +{ + // Do nothing. +} + +// Any implementations of methods for dealing with model pointers will be put +// below this comment, if needed. +${MODEL_PTR_IMPLS} + +} diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/julia_method.h.in mlpack-3.3.0/src/mlpack/bindings/julia/julia_method.h.in --- mlpack-3.2.2/src/mlpack/bindings/julia/julia_method.h.in 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/julia_method.h.in 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,29 @@ +/** + * @file julia_${PROGRAM_NAME}.h + * + * This is an autogenerated header file for functions specified to the %NAME% + * binding to be called by Julia. + */ +#ifndef JULIA_${PROGRAM_NAME}_H +#define JULIA_${PROGRAM_NAME}_H + +#if defined(__cplusplus) || defined(c_plusplus) + +extern "C" +{ +#endif + +bool ${PROGRAM_NAME}(); + +// This is just used to force Julia to load each .so in the order we need. +void loadSymbols(); + +// Any definitions of methods for dealing with model pointers will be put below +// this comment, if needed. +${MODEL_PTR_DEFNS} + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/julia_option.hpp mlpack-3.3.0/src/mlpack/bindings/julia/julia_option.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/julia_option.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/julia_option.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,118 @@ +/** + * @file julia_option.hpp + * @author Ryan Curtin + * + * The Julia option type. + * + * 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_BINDINGS_JULIA_JULIA_OPTION_HPP +#define MLPACK_BINDINGS_JULIA_JULIA_OPTION_HPP + +#include +#include "get_param.hpp" +#include "get_printable_param.hpp" +#include "print_param_defn.hpp" +#include "print_input_param.hpp" +#include "print_input_processing.hpp" +#include "print_output_processing.hpp" +#include "print_doc.hpp" +#include "default_param.hpp" + +namespace mlpack { +namespace bindings { +namespace julia { + +// Defined in mlpack_main.hpp. +extern std::string programName; + +/** + * The Julia option class. + */ +template +class JuliaOption +{ + public: + /** + * Construct a JuliaOption object. When constructed, it will register itself + * with CLI. The testName parameter is not used and added for compatibility + * reasons. + */ + JuliaOption(const T defaultValue, + const std::string& identifier, + const std::string& description, + const std::string& alias, + const std::string& cppName, + const bool required = false, + const bool input = true, + const bool noTranspose = false, + const std::string& /* testName */ = "") + { + // Create the ParamData object to give to CLI. + util::ParamData data; + + data.desc = description; + data.name = identifier; + data.tname = TYPENAME(T); + data.alias = alias[0]; + data.wasPassed = false; + data.noTranspose = noTranspose; + data.required = required; + data.input = input; + data.loaded = false; + + // Only "verbose" will be persistent. + if (identifier == "verbose") + data.persistent = true; + else + data.persistent = false; + data.cppType = cppName; + + // Every parameter we'll get from Julia will have the correct type. + data.value = boost::any(defaultValue); + + // Restore the parameters for this program. + if (identifier != "verbose") + CLI::RestoreSettings(programName, false); + + // Set the function pointers that we'll need. All of these function + // pointers will be used by both the program that generates the pyx, and + // also the binding itself. (The binding itself will only use GetParam, + // GetPrintableParam, and GetRawParam.) + CLI::GetSingleton().functionMap[data.tname]["GetParam"] = &GetParam; + CLI::GetSingleton().functionMap[data.tname]["GetPrintableParam"] = + &GetPrintableParam; + + // These are used by the jl generator. + CLI::GetSingleton().functionMap[data.tname]["PrintParamDefn"] = + &PrintParamDefn; + CLI::GetSingleton().functionMap[data.tname]["PrintInputParam"] = + &PrintInputParam; + CLI::GetSingleton().functionMap[data.tname]["PrintOutputProcessing"] = + &PrintOutputProcessing; + CLI::GetSingleton().functionMap[data.tname]["PrintInputProcessing"] = + &PrintInputProcessing; + CLI::GetSingleton().functionMap[data.tname]["PrintDoc"] = &PrintDoc; + + // This is needed for the Markdown binding output. + CLI::GetSingleton().functionMap[data.tname]["DefaultParam"] = + &DefaultParam; + + // Add the ParamData object, then store. This is necessary because we may + // import more than one .so that uses CLI, so we have to keep the options + // separate. programName is a global variable from mlpack_main.hpp. + CLI::Add(std::move(data)); + if (identifier != "verbose") + CLI::StoreSettings(programName); + CLI::ClearSettings(); + } +}; + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/julia_util.cpp mlpack-3.3.0/src/mlpack/bindings/julia/julia_util.cpp --- mlpack-3.2.2/src/mlpack/bindings/julia/julia_util.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/julia_util.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,586 @@ +/** + * @file julia_util.cpp + * @author Ryan Curtin + * + * Implementations of Julia binding functionality. + * + * 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 + +using namespace mlpack; + +extern "C" { + +/** + * Call CLI::RestoreSettings() for a given program name. + */ +void CLI_RestoreSettings(const char* programName) +{ + CLI::RestoreSettings(programName); +} + +/** + * Call CLI::SetParam(). + */ +void CLI_SetParamInt(const char* paramName, int paramValue) +{ + CLI::GetParam(paramName) = paramValue; + CLI::SetPassed(paramName); +} + +/** + * Call CLI::SetParam(). + */ +void CLI_SetParamDouble(const char* paramName, double paramValue) +{ + CLI::GetParam(paramName) = paramValue; + CLI::SetPassed(paramName); +} + +/** + * Call CLI::SetParam(). + */ +void CLI_SetParamString(const char* paramName, const char* paramValue) +{ + CLI::GetParam(paramName) = paramValue; + CLI::SetPassed(paramName); +} + +/** + * Call CLI::SetParam(). + */ +void CLI_SetParamBool(const char* paramName, bool paramValue) +{ + CLI::GetParam(paramName) = paramValue; + CLI::SetPassed(paramName); +} + +/** + * Call CLI::SetParam>() to set the length. + */ +void CLI_SetParamVectorStrLen(const char* paramName, + const size_t length) +{ + CLI::GetParam>(paramName).clear(); + CLI::GetParam>(paramName).resize(length); + CLI::SetPassed(paramName); +} + +/** + * Call CLI::SetParam>() to set an individual element. + */ +void CLI_SetParamVectorStrStr(const char* paramName, + const char* str, + const size_t element) +{ + CLI::GetParam>(paramName)[element] = + std::string(str); +} + +/** + * Call CLI::SetParam>(). + */ +void CLI_SetParamVectorInt(const char* paramName, + int* ints, + const size_t length) +{ + // Create a std::vector object; unfortunately this requires copying the + // vector elements. + std::vector vec; + vec.resize(length); + for (size_t i = 0; i < length; ++i) + vec[i] = ints[i]; + + CLI::GetParam>(paramName) = std::move(vec); + CLI::SetPassed(paramName); +} + +/** + * Call CLI::SetParam(). + */ +void CLI_SetParamMat(const char* paramName, + double* memptr, + const size_t rows, + const size_t cols, + const bool pointsAsRows) +{ + // Create the matrix as an alias. + arma::mat m(memptr, arma::uword(rows), arma::uword(cols), false, true); + CLI::GetParam(paramName) = pointsAsRows ? m.t() : std::move(m); + CLI::SetPassed(paramName); +} + +/** + * Call CLI::SetParam>(). + */ +void CLI_SetParamUMat(const char* paramName, + size_t* memptr, + const size_t rows, + const size_t cols, + const bool pointsAsRows) +{ + // Create the matrix as an alias. + arma::Mat m(memptr, arma::uword(rows), arma::uword(cols), false, + true); + CLI::GetParam>(paramName) = pointsAsRows ? m.t() : + std::move(m); + CLI::SetPassed(paramName); +} + +/** + * Call CLI::SetParam(). + */ +void CLI_SetParamRow(const char* paramName, + double* memptr, + const size_t cols) +{ + arma::rowvec m(memptr, arma::uword(cols), false, true); + CLI::GetParam(paramName) = std::move(m); + CLI::SetPassed(paramName); +} + +/** + * Call CLI::SetParam>(). + */ +void CLI_SetParamURow(const char* paramName, + size_t* memptr, + const size_t cols) +{ + arma::Row m(memptr, arma::uword(cols), false, true); + CLI::GetParam>(paramName) = std::move(m); + CLI::SetPassed(paramName); +} + +/** + * Call CLI::SetParam(). + */ +void CLI_SetParamCol(const char* paramName, + double* memptr, + const size_t rows) +{ + arma::vec m(memptr, arma::uword(rows), false, true); + CLI::GetParam(paramName) = std::move(m); + CLI::SetPassed(paramName); +} + +/** + * Call CLI::SetParam>(). + */ +void CLI_SetParamUCol(const char* paramName, + size_t* memptr, + const size_t rows) +{ + arma::Col m(memptr, arma::uword(rows), false, true); + CLI::GetParam>(paramName) = std::move(m); + CLI::SetPassed(paramName); +} + +/** + * Call CLI::SetParam>(). + */ +void CLI_SetParamMatWithInfo(const char* paramName, + bool* dimensions, + double* memptr, + const size_t rows, + const size_t cols, + const bool pointsAreRows) +{ + data::DatasetInfo d(pointsAreRows ? cols : rows); + for (size_t i = 0; i < d.Dimensionality(); ++i) + { + d.Type(i) = (dimensions[i]) ? data::Datatype::categorical : + data::Datatype::numeric; + } + + arma::mat m(memptr, arma::uword(rows), arma::uword(cols), false, true); + std::get<0>(CLI::GetParam>( + paramName)) = std::move(d); + std::get<1>(CLI::GetParam>( + paramName)) = pointsAreRows ? std::move(m.t()) : std::move(m); + CLI::SetPassed(paramName); +} + +/** + * Call CLI::GetParam(). + */ +int CLI_GetParamInt(const char* paramName) +{ + return CLI::GetParam(paramName); +} + +/** + * Call CLI::GetParam(). + */ +double CLI_GetParamDouble(const char* paramName) +{ + return CLI::GetParam(paramName); +} + +/** + * Call CLI::GetParam(). + */ +const char* CLI_GetParamString(const char* paramName) +{ + return CLI::GetParam(paramName).c_str(); +} + +/** + * Call CLI::GetParam(). + */ +bool CLI_GetParamBool(const char* paramName) +{ + return CLI::GetParam(paramName); +} + +/** + * Call CLI::GetParam>() and get the length of the + * vector. + */ +size_t CLI_GetParamVectorStrLen(const char* paramName) +{ + return CLI::GetParam>(paramName).size(); +} + +/** + * Call CLI::GetParam>() and get the i'th string. + */ +const char* CLI_GetParamVectorStrStr(const char* paramName, const size_t i) +{ + return CLI::GetParam>(paramName)[i].c_str(); +} + +/** + * Call CLI::GetParam>() and get the length of the vector. + */ +size_t CLI_GetParamVectorIntLen(const char* paramName) +{ + return CLI::GetParam>(paramName).size(); +} + +/** + * Call CLI::GetParam>() and return a pointer to the vector. + * The vector will be created in-place and it is expected that the calling + * function will take ownership. + */ +int* CLI_GetParamVectorIntPtr(const char* paramName) +{ + const size_t size = CLI::GetParam>(paramName).size(); + int* ints = new int[size]; + + for (size_t i = 0; i < size; ++i) + ints[i] = CLI::GetParam>(paramName)[i]; + + return ints; +} + +/** + * Get the number of rows in a matrix parameter. + */ +size_t CLI_GetParamMatRows(const char* paramName) +{ + return CLI::GetParam(paramName).n_rows; +} + +/** + * Get the number of columns in a matrix parameter. + */ +size_t CLI_GetParamMatCols(const char* paramName) +{ + return CLI::GetParam(paramName).n_cols; +} + +/** + * Get the memory pointer for a matrix parameter. + * Note that this will assume that whatever is calling will take ownership of + * the memory! + */ +double* CLI_GetParamMat(const char* paramName) +{ + // Are we using preallocated memory? If so we have to handle this more + // carefully. + arma::mat& mat = CLI::GetParam(paramName); + if (mat.n_elem <= arma::arma_config::mat_prealloc) + { + // Copy the memory to something that we can give back to Julia. + double* newMem = new double[mat.n_elem]; + arma::arrayops::copy(newMem, mat.mem, mat.n_elem); + return newMem; // We believe Julia will free it. Hopefully we are right. + } + else + { + arma::access::rw(mat.mem_state) = 1; + return mat.memptr(); + } +} + +/** + * Get the number of rows in an unsigned matrix parameter. + */ +size_t CLI_GetParamUMatRows(const char* paramName) +{ + return CLI::GetParam>(paramName).n_rows; +} + +/** + * Get the number of columns in an unsigned matrix parameter. + */ +size_t CLI_GetParamUMatCols(const char* paramName) +{ + return CLI::GetParam>(paramName).n_cols; +} + +/** + * Get the memory pointer for an unsigned matrix parameter. + * Note that this will assume that whatever is calling will take ownership of + * the memory! + */ +size_t* CLI_GetParamUMat(const char* paramName) +{ + arma::Mat& mat = CLI::GetParam>(paramName); + + // Are we using preallocated memory? If so we have to handle this more + // carefully. + if (mat.n_elem <= arma::arma_config::mat_prealloc) + { + // Copy the memory to something that we can give back to Julia. + size_t* newMem = new size_t[mat.n_elem]; + arma::arrayops::copy(newMem, mat.mem, mat.n_elem); + // We believe Julia will free it. Hopefully we are right. + return newMem; + } + else + { + arma::access::rw(mat.mem_state) = 1; + return mat.memptr(); + } +} + +/** + * Get the number of rows in a column vector parameter. + */ +size_t CLI_GetParamColRows(const char* paramName) +{ + return CLI::GetParam(paramName).n_rows; +} + +/** + * Get the memory pointer for a column vector parameter. + * Note that this will assume that whatever is calling will take ownership of + * the memory! + */ +double* CLI_GetParamCol(const char* paramName) +{ + // Are we using preallocated memory? If so we have to handle this more + // carefully. + arma::vec& vec = CLI::GetParam(paramName); + if (vec.n_elem <= arma::arma_config::mat_prealloc) + { + // Copy the memory to something we can give back to Julia. + double* newMem = new double[vec.n_elem]; + arma::arrayops::copy(newMem, vec.mem, vec.n_elem); + return newMem; // We believe Julia will free it. Hopefully we are right. + } + else + { + arma::access::rw(vec.mem_state) = 1; + return vec.memptr(); + } +} + +/** + * Get the number of columns in an unsigned column vector parameter. + */ +size_t CLI_GetParamUColRows(const char* paramName) +{ + return CLI::GetParam>(paramName).n_rows; +} + +/** + * Get the memory pointer for an unsigned column vector parameter. + * Note that this will assume that whatever is calling will take ownership of + * the memory! + */ +size_t* CLI_GetParamUCol(const char* paramName) +{ + arma::Col& vec = CLI::GetParam>(paramName); + + // Are we using preallocated memory? If so we have to handle this more + // carefully. + if (vec.n_elem <= arma::arma_config::mat_prealloc) + { + // Copy the memory to something we can give back to Julia. + size_t* newMem = new size_t[vec.n_elem]; + arma::arrayops::copy(newMem, vec.mem, vec.n_elem); + // We believe Julia will free it. Hopefully we are right. + return newMem; + } + else + { + arma::access::rw(vec.mem_state) = 1; + return vec.memptr(); + } +} + +/** + * Get the number of columns in a row parameter. + */ +size_t CLI_GetParamRowCols(const char* paramName) +{ + return CLI::GetParam(paramName).n_cols; +} + +/** + * Get the memory pointer for a row parameter. + * Note that this will assume that whatever is calling will take ownership of + * the memory! + */ +double* CLI_GetParamRow(const char* paramName) +{ + // Are we using preallocated memory? If so we have to handle this more + // carefully. + arma::rowvec& vec = CLI::GetParam(paramName); + if (vec.n_elem <= arma::arma_config::mat_prealloc) + { + // Copy the memory to something we can give back to Julia. + double* newMem = new double[vec.n_elem]; + arma::arrayops::copy(newMem, vec.mem, vec.n_elem); + return newMem; + } + else + { + arma::access::rw(vec.mem_state) = 1; + return vec.memptr(); + } +} + +/** + * Get the number of columns in a row parameter. + */ +size_t CLI_GetParamURowCols(const char* paramName) +{ + return CLI::GetParam>(paramName).n_cols; +} + +/** + * Get the memory pointer for a row parameter. + * Note that this will assume that whatever is calling will take ownership of + * the memory! + */ +size_t* CLI_GetParamURow(const char* paramName) +{ + arma::Row& vec = CLI::GetParam>(paramName); + + // Are we using preallocated memory? If so we have to handle this more + // carefully. + if (vec.n_elem <= arma::arma_config::mat_prealloc) + { + // Copy the memory to something we can give back to Julia. + size_t* newMem = new size_t[vec.n_elem]; + arma::arrayops::copy(newMem, vec.mem, vec.n_elem); + return newMem; + } + else + { + arma::access::rw(vec.mem_state) = 1; + return vec.memptr(); + } +} + +/** + * Get the number of rows in a matrix with DatasetInfo parameter. + */ +size_t CLI_GetParamMatWithInfoRows(const char* paramName) +{ + return std::get<1>(CLI::GetParam>( + paramName)).n_rows; +} + +/** + * Get the number of columns in a matrix with DatasetInfo parameter. + */ +size_t CLI_GetParamMatWithInfoCols(const char* paramName) +{ + return std::get<1>(CLI::GetParam>( + paramName)).n_cols; +} + +/** + * Get a pointer to an array of booleans representing whether or not dimensions + * are categorical. The calling function is expected to handle the memory + * management. + */ +bool* CLI_GetParamMatWithInfoBoolPtr(const char* paramName) +{ + const data::DatasetInfo& d = std::get<0>( + CLI::GetParam>(paramName)); + + bool* dims = new bool[d.Dimensionality()]; + for (size_t i = 0; i < d.Dimensionality(); ++i) + dims[i] = (d.Type(i) == data::Datatype::numeric) ? false : true; + + return dims; +} + +/** + * Get a pointer to the memory of the matrix. The calling function is expected + * to own the memory. + */ +double* CLI_GetParamMatWithInfoPtr(const char* paramName) +{ + // Are we using preallocated memory? If so we have to handle this more + // carefully. + arma::mat& m = std::get<1>( + CLI::GetParam>(paramName)); + if (m.n_elem <= arma::arma_config::mat_prealloc) + { + double* newMem = new double[m.n_elem]; + arma::arrayops::copy(newMem, m.mem, m.n_elem); + return newMem; + } + else + { + arma::access::rw(m.mem_state) = 1; + return m.memptr(); + } +} + +/** + * Enable verbose output. + */ +void CLI_EnableVerbose() +{ + Log::Info.ignoreInput = false; +} + +/** + * Disable verbose output. + */ +void CLI_DisableVerbose() +{ + Log::Info.ignoreInput = true; +} + +/** + * Reset the state of all timers. + */ +void CLI_ResetTimers() +{ + CLI::GetSingleton().timer.Reset(); +} + +/** + * Set an argument as passed to the CLI object. + */ +void CLI_SetPassed(const char* paramName) +{ + CLI::SetPassed(paramName); +} + +} // extern "C" diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/julia_util.h mlpack-3.3.0/src/mlpack/bindings/julia/julia_util.h --- mlpack-3.2.2/src/mlpack/bindings/julia/julia_util.h 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/julia_util.h 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,295 @@ +/** + * @file julia_util.h + * @author Ryan Curtin + * + * Some utility functions in C that can be called from Julia with ccall() in + * order to interact with the CLI interface. + */ +#ifndef MLPACK_BINDINGS_JULIA_JULIA_UTIL_H +#define MLPACK_BINDINGS_JULIA_JULIA_UTIL_H + +#if defined(__cplusplus) || defined(c_plusplus) + +#include +#include +extern "C" +{ +#else +#include +#include +#endif + +/** + * Call CLI::RestoreSettings() for a given program name. + */ +void CLI_RestoreSettings(const char* programName); + +/** + * Call CLI::SetParam(). + */ +void CLI_SetParamInt(const char* paramName, int paramValue); + +/** + * Call CLI::SetParam(). + */ +void CLI_SetParamDouble(const char* paramName, double paramValue); + +/** + * Call CLI::SetParam(). + */ +void CLI_SetParamString(const char* paramName, const char* paramValue); + +/** + * Call CLI::SetParam(). + */ +void CLI_SetParamBool(const char* paramName, bool paramValue); + +/** + * Call CLI::SetParam>() to set the length. + */ +void CLI_SetParamVectorStrLen(const char* paramName, + const size_t length); + +/** + * Call CLI::SetParam>() to set an individual element. + */ +void CLI_SetParamVectorStrStr(const char* paramName, + const char* str, + const size_t element); + +/** + * Call CLI::SetParam>(). + */ +void CLI_SetParamVectorInt(const char* paramName, + int* ints, + const size_t length); + +/** + * Call CLI::SetParam(). + */ +void CLI_SetParamMat(const char* paramName, + double* memptr, + const size_t rows, + const size_t cols, + const bool pointsAsRows); + +/** + * Call CLI::SetParam>(). + */ +void CLI_SetParamUMat(const char* paramName, + size_t* memptr, + const size_t rows, + const size_t cols, + const bool pointsAsRows); + +/** + * Call CLI::SetParam(). + */ +void CLI_SetParamRow(const char* paramName, + double* memptr, + const size_t cols); + +/** + * Call CLI::SetParam>(). + */ +void CLI_SetParamURow(const char* paramName, + size_t* memptr, + const size_t cols); + +/** + * Call CLI::SetParam(). + */ +void CLI_SetParamCol(const char* paramName, + double* memptr, + const size_t rows); + +/** + * Call CLI::SetParam>(). + */ +void CLI_SetParamUCol(const char* paramName, + size_t* memptr, + const size_t rows); + +/** + * Call CLI::SetParam>(). + */ +void CLI_SetParamMatWithInfo(const char* paramName, + bool* dimensions, + double* memptr, + const size_t rows, + const size_t cols, + const bool pointsAreRows); + +/** + * Call CLI::GetParam(). + */ +int CLI_GetParamInt(const char* paramName); + +/** + * Call CLI::GetParam(). + */ +double CLI_GetParamDouble(const char* paramName); + +/** + * Call CLI::GetParam(). + */ +const char* CLI_GetParamString(const char* paramName); + +/** + * Call CLI::GetParam(). + */ +bool CLI_GetParamBool(const char* paramName); + +/** + * Call CLI::GetParam>() and get the length of the + * vector. + */ +size_t CLI_GetParamVectorStrLen(const char* paramName); + +/** + * Call CLI::GetParam>() and get the i'th string. + */ +const char* CLI_GetParamVectorStrStr(const char* paramName, const size_t i); + +/** + * Call CLI::GetParam>() and get the length of the vector. + */ +size_t CLI_GetParamVectorIntLen(const char* paramName); + +/** + * Call CLI::GetParam>() and return a pointer to the vector. + * The vector will be created in-place and it is expected that the calling + * function will take ownership. + */ +int* CLI_GetParamVectorIntPtr(const char* paramName); + +/** + * Get the number of rows in a matrix parameter. + */ +size_t CLI_GetParamMatRows(const char* paramName); + +/** + * Get the number of columns in a matrix parameter. + */ +size_t CLI_GetParamMatCols(const char* paramName); + +/** + * Get the memory pointer for a matrix parameter. + * Note that this will assume that whatever is calling will take ownership of + * the memory! + */ +double* CLI_GetParamMat(const char* paramName); + +/** + * Get the number of rows in an unsigned matrix parameter. + */ +size_t CLI_GetParamUMatRows(const char* paramName); + +/** + * Get the number of columns in an unsigned matrix parameter. + */ +size_t CLI_GetParamUMatCols(const char* paramName); + +/** + * Get the memory pointer for an unsigned matrix parameter. + * Note that this will assume that whatever is calling will take ownership of + * the memory! + */ +size_t* CLI_GetParamUMat(const char* paramName); + +/** + * Get the number of rows in a column parameter. + */ +size_t CLI_GetParamColRows(const char* paramName); + +/** + * Get the memory pointer for a column vector parameter. + * Note that this will assume that whatever is calling will take ownership of + * the memory! + */ +double* CLI_GetParamCol(const char* paramName); + +/** + * Get the number of columns in an unsigned column vector parameter. + */ +size_t CLI_GetParamUColRows(const char* paramName); + +/** + * Get the memory pointer for an unsigned column vector parameter. + * Note that this will assume that whatever is calling will take ownership of + * the memory! + */ +size_t* CLI_GetParamUCol(const char* paramName); + +/** + * Get the number of columns in a row parameter. + */ +size_t CLI_GetParamRowCols(const char* paramName); + +/** + * Get the memory pointer for a row parameter. + * Note that this will assume that whatever is calling will take ownership of + * the memory! + */ +double* CLI_GetParamRow(const char* paramName); + +/** + * Get the number of columns in a row parameter. + */ +size_t CLI_GetParamURowCols(const char* paramName); + +/** + * Get the memory pointer for a row parameter. + * Note that this will assume that whatever is calling will take ownership of + * the memory! + */ +size_t* CLI_GetParamURow(const char* paramName); + +/** + * Get the number of rows in a matrix with DatasetInfo parameter. + */ +size_t CLI_GetParamMatWithInfoRows(const char* paramName); + +/** + * Get the number of columns in a matrix with DatasetInfo parameter. + */ +size_t CLI_GetParamMatWithInfoCols(const char* paramName); + +/** + * Get a pointer to an array of booleans representing whether or not dimensions + * are categorical. The calling function is expected to handle the memory + * management. + */ +bool* CLI_GetParamMatWithInfoBoolPtr(const char* paramName); + +/** + * Get a pointer to the memory of the matrix. The calling function is expected + * to own the memory. + */ +double* CLI_GetParamMatWithInfoPtr(const char* paramName); + +/** + * Enable verbose output. + */ +void CLI_EnableVerbose(); + +/** + * Disable verbose output. + */ +void CLI_DisableVerbose(); + +/** + * Reset timers. + */ +void CLI_ResetTimers(); + +/** + * Set an argument as passed to the CLI object. + */ +void CLI_SetPassed(const char* paramName); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/mlpack/cli.jl.in mlpack-3.3.0/src/mlpack/bindings/julia/mlpack/cli.jl.in --- mlpack-3.2.2/src/mlpack/bindings/julia/mlpack/cli.jl.in 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/mlpack/cli.jl.in 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,360 @@ +module cli + +export CLIRestoreSettings +export CLISetParam +export CLISetParamMat +export CLISetParamUMat +export CLISetParamRow +export CLISetParamCol +export CLISetParamURow +export CLISetParamUCol +export CLIGetParamBool +export CLIGetParamInt +export CLIGetParamDouble +export CLIGetParamString +export CLIGetParamVectorStr +export CLIGetParamVectorInt +export CLIGetParamMat +export CLIGetParamUMat +export CLIGetParamCol +export CLIGetParamRow +export CLIGetParamUCol +export CLIGetParamURow +export CLIGetParamMatWithInfo +export CLIEnableVerbose +export CLIDisableVerbose +export CLISetPassed + +const library = joinpath(@__DIR__, "libmlpack_julia_util${CMAKE_SHARED_LIBRARY_SUFFIX}") + +# Utility function to convert 1d object to 2d. +function convert_to_2d(in::Array{T, 1})::Array{T, 2} where T + reshape(in, length(in), 1) +end + +# Utility function to convert 2d object to 1d. Fails if the size of one +# dimension is not 1. +function convert_to_1d(in::Array{T, 2})::Array{T, 1} where T + if size(in, 1) != 1 && size(in, 2) != 1 + throw(ArgumentError("given matrix must be 1-dimensional; but its size is " * + "$(size(in))")) + end + + vec(in) +end + +# Utility function to convert to and return a matrix. +function to_matrix(input, T::Type) + if isa(input, Array{T, 1}) + convert_to_2d(input) + else + convert(Array{T, 2}, input) + end +end + +# Utility function to convert to and return a vector. +function to_vector(input, T::Type) + if isa(input, Array{T, 1}) + input + else + convert_to_1d(convert(Array{T, 2}, input)) + end +end + +function CLIRestoreSettings(programName::String) + ccall((:CLI_RestoreSettings, library), Nothing, (Cstring,), programName); +end + +function CLISetParam(paramName::String, paramValue::Int) + ccall((:CLI_SetParamInt, library), Nothing, (Cstring, Cint), paramName, + Cint(paramValue)); +end + +function CLISetParam(paramName::String, paramValue::Float64) + ccall((:CLI_SetParamDouble, library), Nothing, (Cstring, Float64), paramName, + paramValue); +end + +function CLISetParam(paramName::String, paramValue::Bool) + ccall((:CLI_SetParamBool, library), Nothing, (Cstring, Bool), paramName, + paramValue); +end + +function CLISetParam(paramName::String, paramValue::String) + ccall((:CLI_SetParamString, library), Nothing, (Cstring, Cstring), paramName, + paramValue); +end + +function CLISetParamMat(paramName::String, + paramValue, + pointsAsRows::Bool) + paramMat = to_matrix(paramValue, Float64) + ccall((:CLI_SetParamMat, library), Nothing, (Cstring, Ptr{Float64}, Csize_t, + Csize_t, Bool), paramName, Base.pointer(paramMat), size(paramMat, 1), + size(paramMat, 2), pointsAsRows); +end + +function CLISetParamUMat(paramName::String, + paramValue, + pointsAsRows::Bool) + paramMat = to_matrix(paramValue, Int) + + # Sanity check. + if minimum(paramMat) <= 0 + throw(DomainError("Input $(paramName) cannot have 0 or negative values! " * + "Must be 1 or greater.")) + end + + m = convert(Array{Csize_t, 2}, paramMat .- 1) + ccall((:CLI_SetParamUMat, library), Nothing, (Cstring, Ptr{Csize_t}, Csize_t, + Csize_t, Bool), paramName, Base.pointer(m), size(paramValue, 1), + size(paramValue, 2), pointsAsRows); +end + +function CLISetParam(paramName::String, + vector::Vector{String}) + # For this we have to set the size of the vector then each string + # sequentially. I am not sure if this is fully necessary but I have some + # reservations about Julia's support for passing arrays of strings correctly + # as a const char**. + ccall((:CLI_SetParamVectorStrLen, library), Nothing, (Cstring, Csize_t), + paramName, size(vector, 1)); + for i in 1:size(vector, 1) + ccall((:CLI_SetParamVectorStrStr, library), Nothing, (Cstring, Cstring, + Csize_t), paramName, vector[i], i .- 1); + end +end + +function CLISetParam(paramName::String, + vector::Vector{Int}) + cint_vec = convert(Vector{Cint}, vector) + ccall((:CLI_SetParamVectorInt, library), Nothing, (Cstring, Ptr{Cint}, + Csize_t), paramName, Base.pointer(cint_vec), size(cint_vec, 1)); +end + +function CLISetParam(paramName::String, + matWithInfo::Tuple{Array{Bool, 1}, Array{Float64, 2}}, + pointsAsRows::Bool) + ccall((:CLI_SetParamMatWithInfo, library), Nothing, (Cstring, Ptr{Bool}, + Ptr{Float64}, Int, Int, Bool), paramName, + Base.pointer(matWithInfo[1]), Base.pointer(matWithInfo[2]), + size(matWithInfo[2], 1), size(matWithInfo[2], 2), pointsAsRows); +end + +function CLISetParamRow(paramName::String, + paramValue) + paramVec = to_vector(paramValue, Float64) + ccall((:CLI_SetParamRow, library), Nothing, (Cstring, Ptr{Float64}, Csize_t), + paramName, Base.pointer(paramVec), size(paramVec, 1)); +end + +function CLISetParamCol(paramName::String, + paramValue) + paramVec = to_vector(paramValue, Float64) + ccall((:CLI_SetParamCol, library), Nothing, (Cstring, Ptr{Float64}, Csize_t), + paramName, Base.pointer(paramVec), size(paramVec, 1)); +end + +function CLISetParamURow(paramName::String, + paramValue) + paramVec = to_vector(paramValue, Int) + + # Sanity check. + if minimum(paramVec) <= 0 + throw(DomainError("Input $(paramName) cannot have 0 or negative values! " * + "Must be 1 or greater.")) + end + m = convert(Array{Csize_t, 1}, paramVec .- 1) + + ccall((:CLI_SetParamURow, library), Nothing, (Cstring, Ptr{Csize_t}, Csize_t), + paramName, Base.pointer(m), size(paramValue, 1)); +end + +function CLISetParamUCol(paramName::String, + paramValue) + paramVec = to_vector(paramValue, Int) + + # Sanity check. + if minimum(paramVec) <= 0 + throw(DomainError("Input $(paramName) cannot have 0 or negative values! " * + "Must be 1 or greater.")) + end + m = convert(Array{Csize_t, 1}, paramValue .- 1) + + ccall((:CLI_SetParamUCol, library), Nothing, (Cstring, Ptr{Csize_t}, Csize_t), + paramName, Base.pointer(m), size(paramValue, 1)); +end + +function CLIGetParamBool(paramName::String) + return ccall((:CLI_GetParamBool, library), Bool, (Cstring,), paramName) +end + +function CLIGetParamInt(paramName::String) + return Int(ccall((:CLI_GetParamInt, library), Cint, (Cstring,), paramName)) +end + +function CLIGetParamDouble(paramName::String) + return ccall((:CLI_GetParamDouble, library), Float64, (Cstring,), paramName) +end + +function CLIGetParamString(paramName::String) + return ccall((:CLI_GetParamString, library), Cstring, (Cstring,), paramName) +end + +function CLIGetParamVectorStr(paramName::String) + local size::Csize_t + local ptr::Ptr{String} + + # Get the size of the vector, then each element. + size = ccall((:CLI_GetParamVectorStrLen, library), Csize_t, (Cstring,), + paramName); + out = Array{String, 1}() + for i = 1:size + s = ccall((:CLI_GetParamVectorStrStr, library), Cstring, (Cstring, Csize_t), + paramName, i .- 1) + push!(out, Base.unsafe_string(s)) + end + + return out +end + +function CLIGetParamVectorInt(paramName::String) + local size::Csize_t + local ptr::Ptr{Cint} + + # Get the size of the vector, then the pointer to it. We will own the + # pointer. + size = ccall((:CLI_GetParamVectorIntLen, library), Csize_t, (Cstring,), + paramName); + ptr = ccall((:CLI_GetParamVectorIntPtr, library), Ptr{Cint}, (Cstring,), + paramName); + + return convert(Array{Int, 1}, Base.unsafe_wrap(Array{Cint, 1}, ptr, (size), + own=true)) +end + +function CLIGetParamMat(paramName::String, pointsAsRows::Bool) + # Can we return different return types? For now let's restrict to a matrix to + # make it easy... + local ptr::Ptr{Float64} + local rows::Csize_t, cols::Csize_t; + # I suppose it would be possible to do this all in one call, but this seems + # easy enough. + rows = ccall((:CLI_GetParamMatRows, library), Csize_t, (Cstring,), paramName); + cols = ccall((:CLI_GetParamMatCols, library), Csize_t, (Cstring,), paramName); + ptr = ccall((:CLI_GetParamMat, library), Ptr{Float64}, (Cstring,), paramName); + + if pointsAsRows + # In this case we have to transpose, unfortunately. + m = Base.unsafe_wrap(Array{Float64, 2}, ptr, (rows, cols), own=true) + return m'; + else + # Here no transpose is necessary. + return Base.unsafe_wrap(Array{Float64, 2}, ptr, (rows, cols), own=true); + end +end + +function CLIGetParamUMat(paramName::String, pointsAsRows::Bool) + # Can we return different return types? For now let's restrict to a matrix to + # make it easy... + local ptr::Ptr{Csize_t} + local rows::Csize_t, cols::Csize_t; + # I suppose it would be possible to do this all in one call, but this seems + # easy enough. + rows = ccall((:CLI_GetParamUMatRows, library), Csize_t, (Cstring,), paramName); + cols = ccall((:CLI_GetParamUMatCols, library), Csize_t, (Cstring,), paramName); + ptr = ccall((:CLI_GetParamUMat, library), Ptr{Csize_t}, (Cstring,), paramName); + + if pointsAsRows + # In this case we have to transpose, unfortunately. + m = Base.unsafe_wrap(Array{Csize_t, 2}, ptr, (rows, cols), own=true); + return convert(Array{Int, 2}, m' .+ 1) # Add 1 because these are indexes. + else + # Here no transpose is necessary. + m = Base.unsafe_wrap(Array{Csize_t, 2}, ptr, (rows, cols), own=true); + return convert(Array{Int, 2}, m .+ 1) + end +end + +function CLIGetParamCol(paramName::String) + local ptr::Ptr{Float64}; + local rows::Csize_t; + + rows = ccall((:CLI_GetParamColRows, library), Csize_t, (Cstring,), paramName); + ptr = ccall((:CLI_GetParamCol, library), Ptr{Float64}, (Cstring,), paramName); + + return Base.unsafe_wrap(Array{Float64, 1}, ptr, rows, own=true); +end + +function CLIGetParamRow(paramName::String) + local ptr::Ptr{Float64}; + local cols::Csize_t; + + cols = ccall((:CLI_GetParamRowCols, library), Csize_t, (Cstring,), paramName); + ptr = ccall((:CLI_GetParamRow, library), Ptr{Float64}, (Cstring,), paramName); + + return Base.unsafe_wrap(Array{Float64, 1}, ptr, cols, own=true); +end + +function CLIGetParamUCol(paramName::String) + local ptr::Ptr{Csize_t}; + local rows::Csize_t; + + rows = ccall((:CLI_GetParamUColRows, library), Csize_t, (Cstring,), paramName); + ptr = ccall((:CLI_GetParamUCol, library), Ptr{Csize_t}, (Cstring,), paramName); + + m = Base.unsafe_wrap(Array{Csize_t, 1}, ptr, rows, own=true); + return convert(Array{Int, 1}, m .+ 1) +end + +function CLIGetParamURow(paramName::String) + local ptr::Ptr{Csize_t}; + local cols::Csize_t; + + cols = ccall((:CLI_GetParamURowCols, library), Csize_t, (Cstring,), paramName); + ptr = ccall((:CLI_GetParamURow, library), Ptr{Csize_t}, (Cstring,), paramName); + + m = Base.unsafe_wrap(Array{Csize_t, 1}, ptr, cols, own=true); + return convert(Array{Int, 1}, m .+ 1) +end + +function CLIGetParamMatWithInfo(paramName::String, pointsAsRows::Bool) + local ptrBool::Ptr{Bool}; + local ptrData::Ptr{Float64}; + local rows::Csize_t; + local cols::Csize_t; + + rows = ccall((:CLI_GetParamMatWithInfoRows, library), Csize_t, (Cstring,), + paramName); + cols = ccall((:CLI_GetParamMatWithInfoCols, library), Csize_t, (Cstring,), + paramName); + ptrBool = ccall((:CLI_GetParamMatWithInfoBoolPtr, library), Ptr{Bool}, + (Cstring,), paramName); + ptrMem = ccall((:CLI_GetParamMatWithInfoPtr, library), Ptr{Float64}, + (Cstring,), paramName); + + types = Base.unsafe_wrap(Array{Bool, 1}, ptrBool, (rows), own=true) + if pointsAsRows + # In this case we have to transpose, unfortunately. + m = Base.unsafe_wrap(Array{Float64, 2}, ptr, (rows, cols), own=true) + return (types, m'); + else + # Here no transpose is necessary. + return (types, Base.unsafe_wrap(Array{Float64, 2}, ptr, (rows, cols), + own=true)); + end +end + +function CLIEnableVerbose() + ccall((:CLI_EnableVerbose, library), Nothing, ()); +end + +function CLIDisableVerbose() + ccall((:CLI_DisableVerbose, library), Nothing, ()); +end + +function CLISetPassed(paramName::String) + ccall((:CLI_SetPassed, library), Nothing, (Cstring,), paramName); +end + +end # module cli diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/mlpack/mlpack.jl.in mlpack-3.3.0/src/mlpack/bindings/julia/mlpack/mlpack.jl.in --- mlpack-3.2.2/src/mlpack/bindings/julia/mlpack/mlpack.jl.in 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/mlpack/mlpack.jl.in 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,30 @@ +""" + mlpack + +mlpack is a fast, flexible machine learning library, written in C++, that aims +to provide fast, extensible implementations of cutting-edge machine learning +algorithms. This module provides those implementations as Julia functions. + +Each function inside the module performs a specific machine learning task. + +For complete documentation of these functions, including example usage, see the +mlpack website's documentation for the Julia bindings: + +https://www.mlpack.org/doc/stable/julia_documentation.html + +Each function also contains an equivalent docstring; the Julia REPL's help +functionality can be used to access the documentation that way. +""" +module mlpack + +""" + mlpack._Internal + +This module contains internal implementations details of mlpack. There +shouldn't be any need to go digging around in here if you're just using mlpack. +(But don't let this comment discourage you if you're just curious and poking +around!) +""" +module _Internal + +include("cli.jl") diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/mlpack/Project.toml.in mlpack-3.3.0/src/mlpack/bindings/julia/mlpack/Project.toml.in --- mlpack-3.2.2/src/mlpack/bindings/julia/mlpack/Project.toml.in 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/mlpack/Project.toml.in 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,9 @@ +name = "mlpack" +uuid = "cf18a64e-e90e-11e8-37b7-fb5df6478bc0" +version = "${PACKAGE_VERSION}" +author = [ "mlpack developers " ] + +[deps] + +[compat] +julia = "1.3" diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/print_doc_functions.hpp mlpack-3.3.0/src/mlpack/bindings/julia/print_doc_functions.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/print_doc_functions.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/print_doc_functions.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,138 @@ +/** + * @file print_doc_functions.hpp + * @author Ryan Curtin + * + * This file contains functions useful for printing documentation strings + * related to Julia bindings. + * + * 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_BINDINGS_JULIA_PRINT_DOC_FUNCTIONS_HPP +#define MLPACK_BINDINGS_JULIA_PRINT_DOC_FUNCTIONS_HPP + +#include + +namespace mlpack { +namespace bindings { +namespace julia { + +/** + * Given the name of a binding, print its Julia name (this just returns the + * binding name). + */ +inline std::string GetBindingName(const std::string& bindingName); + +/** + * Print any imports for Julia. + */ +inline std::string PrintImport(const std::string& bindingName); + +/** + * Print any special information about output options. + */ +inline std::string PrintOutputOptionInfo(); + +/** + * Print documentation for each of the types. + */ +inline std::string PrintTypeDocs(); + +/** + * Given a parameter type, print the corresponding value. + */ +template +inline std::string PrintValue(const T& value, bool quotes); + +// Special overload for booleans. +template<> +inline std::string PrintValue(const bool& value, bool quotes); + +/** + * Given a parameter name, print its corresponding default value. + */ +inline std::string PrintDefault(const std::string& paramName); + +/** + * Print a dataset type parameter. + */ +inline std::string PrintDataset(const std::string& dataset); + +/** + * Print a model type parameter. + */ +inline std::string PrintModel(const std::string& model); + +/** + * Print the type of a parameter that a user would specify from Julia. + */ +inline std::string PrintType(const util::ParamData& param); + +// Recursion base case. +inline std::string PrintInputOptions(); + +/** + * Print an input option. This will throw an exception if the parameter does + * not exist in CLI. For a parameter 'x' with value '5', this will print + * something like x=5. + */ +template +std::string PrintInputOptions(const std::string& paramName, + const T& value, + Args... args); + +// Recursion base case. +inline std::string PrintOutputOptions(); + +template +std::string PrintOutputOptions(const std::string& paramName, + const T& value, + Args... args); + +/** + * Given a name of a binding and a variable number of arguments (and their + * contents), print the corresponding function call. + */ +template +std::string ProgramCall(const std::string& programName, Args... args); + +/** + * Given the parameter name, determine what it would actually be when passed to + * the command line. + */ +inline std::string ParamString(const std::string& paramName); + +/** + * Print whether or not we should ignore a check on the given parameter. For + * Julia bindings, we ignore any checks on output parameters, so if paramName + * is an output parameter, this returns true. + */ +inline bool IgnoreCheck(const std::string& paramName); + +/** + * Print whether or not we should ignore a check on the given set of + * constraints. For Julia bindings, we ignore any checks on output parameters, + * so if any parameter is an output parameter, this returns true. + */ +inline bool IgnoreCheck(const std::vector& constraints); + +/** + * Print whether or not we should ignore a check on the given set of + * constraints. For Julia bindings, we ignore any checks on output parameters, + * so if any constraint parameter or the main parameter are output parameters, + * this returns true. + */ +inline bool IgnoreCheck( + const std::vector>& constraints, + const std::string& paramName); + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +// Include implementation. +#include "print_doc_functions_impl.hpp" + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/print_doc_functions_impl.hpp mlpack-3.3.0/src/mlpack/bindings/julia/print_doc_functions_impl.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/print_doc_functions_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/print_doc_functions_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,566 @@ +/** + * @file print_doc_functions_impl.hpp + * @author Ryan Curtin + * + * This file contains functions useful for printing documentation strings + * related to Julia bindings. + * + * 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_BINDINGS_JULIA_PRINT_DOC_FUNCTIONS_IMPL_HPP +#define MLPACK_BINDINGS_JULIA_PRINT_DOC_FUNCTIONS_IMPL_HPP + +#include + +namespace mlpack { +namespace bindings { +namespace julia { + +/** + * Given the name of a binding, print its Julia name. + */ +inline std::string GetBindingName(const std::string& bindingName) +{ + return bindingName + "()"; +} + +/** + * Print any imports for CLI (there are none, so this returns an empty string). + */ +inline std::string PrintImport(const std::string& bindingName) +{ + return "using mlpack: " + bindingName; +} + +/** + * Print any special information about output options. + */ +inline std::string PrintOutputOptionInfo() +{ + return "Results are returned as a tuple, and can be unpacked directly into " + "return values or stored directly as a tuple; undesired results can be " + "ignored with the _ keyword."; +} + +/** + * Given a parameter type, print the corresponding value. + */ +template +inline std::string PrintValue(const T& value, bool quotes) +{ + std::ostringstream oss; + if (quotes) + oss << "`"; + oss << value; + if (quotes) + oss << "`"; + return oss.str(); +} + +// Special overload for booleans. +template<> +inline std::string PrintValue(const bool& value, bool quotes) +{ + if (quotes && value) + return "\"true\""; + else if (quotes && !value) + return "\"false\""; + else if (!quotes && value) + return "true"; + else + return "false"; +} + +/** + * Given a parameter name, print its corresponding default value. + */ +inline std::string PrintDefault(const std::string& paramName) +{ + if (CLI::Parameters().count(paramName) == 0) + throw std::invalid_argument("unknown parameter " + paramName + "!"); + + const util::ParamData& d = CLI::Parameters()[paramName]; + + std::string defaultValue; + CLI::GetSingleton().functionMap[d.tname]["DefaultParam"](d, NULL, (void*) + &defaultValue); + + return defaultValue; +} + +// Recursion base case. +inline std::string CreateInputArguments() { return ""; } + +/** + * This prints anything that is required to create an input value. We only need + * to create input values for matrices. + */ +template +inline std::string CreateInputArguments(const std::string& paramName, + const T& value, + Args... args) +{ + // We only need to do anything if it is an input option. + if (CLI::Parameters().count(paramName) > 0) + { + const util::ParamData& d = CLI::Parameters()[paramName]; + std::ostringstream oss; + + if (d.input) + { + if (d.cppType == "arma::mat" || + d.cppType == "arma::vec" || + d.cppType == "arma::rowvec" || + d.cppType == "std::tuple") + { + oss << "julia> " << value << " = CSV.read(\"" << value << ".csv\")" + << std::endl; + } + else if (d.cppType == "arma::Mat" || + d.cppType == "arma::Row" || + d.cppType == "arma::Col") + { + oss << "julia> " << value << " = CSV.read(\"" << value + << ".csv\"; type=Int)" << std::endl; + } + } + + oss << CreateInputArguments(args...); + + return oss.str(); + } + else + { + // Unknown parameter! + throw std::runtime_error("Unknown parameter '" + paramName + "' " + + "encountered while assembling documentation! Check PROGRAM_INFO() " + + "declaration."); + } +} + +// Recursion base case. +inline std::string PrintInputOptions() { return ""; } + +/** + * This prints an argument, assuming that it is already known whether or not it + * is required. + */ +template +inline std::string PrintInputOption(const std::string& paramName, + const T& value, + const bool required, + const bool quotes) +{ + std::ostringstream oss; + if (!required) + oss << paramName << "="; + + if (quotes) + oss << "\""; + + oss << value; + + if (quotes) + oss << "\""; + + return oss.str(); +} + +// Base case: no modification needed. +inline void GetOptions( + std::vector>& /* results */, + bool /* input */) +{ + // Nothing to do. +} + +/** + * Assemble a vector of string tuples indicating parameter names and what should + * be printed for them. (For output parameters, we just need to print the + * value.) + */ +template +inline void GetOptions( + std::vector>& results, + bool input, + const std::string& paramName, + const T& value, + Args... args) +{ + // Determine whether or not the value is required. + if (CLI::Parameters().count(paramName) > 0) + { + const util::ParamData& d = CLI::Parameters()[paramName]; + + if (d.input && input) + { + // Print and add to results. + results.push_back(std::make_tuple(paramName, + PrintInputOption(paramName, value, d.required, + d.tname == TYPENAME(std::string)))); + } + else + { + std::ostringstream oss; + oss << value; + results.push_back(std::make_tuple(paramName, oss.str())); + } + + GetOptions(results, input, args...); + } + else + { + // Unknown parameter! + throw std::runtime_error("Unknown parameter '" + paramName + "' " + + "encountered while assembling documentation! Check PROGRAM_INFO() " + + "declaration."); + } +} + +/** + * Print the input options for a program call. For a parameter 'x' with value + * '5', this will print something like x=5; however, the 'x=' will be omitted if + * the parameter is required. + */ +template +inline std::string PrintInputOptions(Args... args) +{ + // Gather list of required and non-required options. + std::vector inputOptions; + for (auto it = CLI::Parameters().begin(); it != CLI::Parameters().end(); ++it) + { + const util::ParamData& d = it->second; + if (d.input && d.required) + { + // Ignore some parameters. + if (d.name != "help" && d.name != "info" && + d.name != "version") + inputOptions.push_back(it->first); + } + } + + for (auto it = CLI::Parameters().begin(); it != CLI::Parameters().end(); ++it) + { + const util::ParamData& d = it->second; + if (d.input && !d.required && + d.name != "help" && d.name != "info" && + d.name != "version") + inputOptions.push_back(it->first); + } + + // Now collect the way that we print all the parameters. + std::vector> printedParameters; + GetOptions(printedParameters, true, args...); + + // Next, we need to match each option. Note that required options will come + // first. + std::ostringstream oss; + bool doneWithRequired = false; + bool printedAny = false; + for (size_t i = 0; i < inputOptions.size(); ++i) + { + const util::ParamData& d = CLI::Parameters()[inputOptions[i]]; + // Does this option exist? + bool found = false; + size_t index = printedParameters.size(); + for (size_t j = 0; j < printedParameters.size(); ++j) + { + if (inputOptions[i] == std::get<0>(printedParameters[j])) + { + found = true; + index = j; + break; + } + } + + if (found) + { + // Print this as an option. We may need a preceding comma. + if (printedAny) + { + if (!d.required && !doneWithRequired) + { + doneWithRequired = true; + oss << "; "; + } + else + { + oss << ", "; + } + } + else if (!d.required && !doneWithRequired) + { + // No required arguments for this binding. + doneWithRequired = true; + } + + // Print the parameter itself. + printedAny = true; + oss << std::get<1>(printedParameters[index]); + } + else if (d.required) + { + throw std::invalid_argument("Required parameter '" + inputOptions[i] + + "' not passed in list of input arguments to PROGRAM_CALL()!"); + } + } + + return oss.str(); +} + +// Recursion base case. +inline std::string PrintOutputOptions() { return ""; } + +template +inline std::string PrintOutputOptions(Args... args) +{ + // Get the list of output options for the binding. + std::vector outputOptions; + for (auto it = CLI::Parameters().begin(); it != CLI::Parameters().end(); ++it) + { + const util::ParamData& d = it->second; + if (!d.input) + outputOptions.push_back(it->first); + } + + // Now get the full list of output options that we have. + std::vector> passedOptions; + GetOptions(passedOptions, false, args...); + + // Next, iterate over all the options. + std::ostringstream oss; + for (size_t i = 0; i < outputOptions.size(); ++i) + { + // Does this option exist? + bool found = false; + size_t index = passedOptions.size(); + for (size_t j = 0; j < passedOptions.size(); ++j) + { + if (outputOptions[i] == std::get<0>(passedOptions[j])) + { + found = true; + index = j; + break; + } + } + + if (found) + { + // We have received this option, so print it. + if (i > 0) + oss << ", "; + oss << std::get<1>(passedOptions[index]); + } + else + { + // We don't care about this option. + if (i > 0) + oss << ", "; + oss << "_"; + } + } + + return oss.str(); +} + +/** + * Given a name of a binding and a variable number of arguments (and their + * contents), print the corresponding function call. + */ +template +inline std::string ProgramCall(const std::string& programName, Args... args) +{ + std::ostringstream oss; + + // The code should appear in a Markdown code block. + oss << "```julia" << std::endl; + + // Print any input argument definitions. The only input argument definitions + // will be the definitions of matrices, which use the CSV.jl package, so we + // should also include a `using CSV` in there too. + std::string inputArgs = CreateInputArguments(args...); + if (inputArgs != "") + inputArgs = "julia> using CSV\n" + inputArgs; + + oss << inputArgs; + + std::ostringstream ossCall; + ossCall << "julia> "; + + // Find out if we have any output options first. + std::ostringstream ossOutput; + ossOutput << PrintOutputOptions(args...); + if (ossOutput.str() != "") + ossCall << ossOutput.str() << " = "; + ossCall << programName << "("; + + // Now process each input option. + ossCall << PrintInputOptions(args...); + ossCall << ")"; + + // Since `julia> ` is 8 characters, let's indent 12 otherwise it looks weird. + oss << util::HyphenateString(ossCall.str(), 12); + + // Close the Markdown code block. + oss << std::endl << "```"; + + return oss.str(); +} + +/** + * Given the name of a model, print it. Here we do not need to modify anything. + */ +inline std::string PrintModel(const std::string& modelName) +{ + return "`" + modelName + "`"; +} + +/** + * Given the name of a matrix, print it. Here we do not need to modify + * anything. + */ +inline std::string PrintDataset(const std::string& datasetName) +{ + return "`" + datasetName + "`"; +} + +/** + * Given the name of a binding, print its invocation. + */ +inline std::string ProgramCall(const std::string& programName) +{ + std::ostringstream result; + result << "julia> "; + + // First, print all output options. + const std::map& parameters = CLI::Parameters(); + size_t outputs = 0; + for (auto it = parameters.begin(); it != parameters.end(); ++it) + { + if (!it->second.input) + { + if (outputs > 0) + result << ", "; + result << it->second.name; + ++outputs; + } + } + + if (outputs > 0) + result << " = "; + + result << programName << "("; + + // Store length for hyphenation. + const size_t hyphenationLength = (result.str().size() > 35) ? 10 : + result.str().size(); + + // Now, print all required input options. + size_t inputs = 0; + for (auto it = parameters.begin(); it != parameters.end(); ++it) + { + if (it->second.input && it->second.required) + { + if (inputs > 0) + result << ", "; + result << it->second.name; + ++inputs; + } + } + + // Lastly, print all non-required input options. + size_t nonreqInputs = 0; + for (auto it = parameters.begin(); it != parameters.end(); ++it) + { + if (it->second.input && !it->second.required) + { + if (inputs == 0 && nonreqInputs == 0) + result << " ; "; + else if (nonreqInputs == 0) + result << "; "; + else + result << ", "; + + result << it->second.name; + result << "="; + std::string value; + CLI::GetSingleton().functionMap[it->second.tname]["DefaultParam"]( + it->second, NULL, (void*) &value); + result << value; + ++nonreqInputs; + } + } + + result << ")"; + + return util::HyphenateString(result.str(), hyphenationLength); +} + +/** + * Print any closing call to a program. For a Julia binding this is a closing + * brace. + */ +inline std::string ProgramCallClose() +{ + return ")"; +} + +/** + * Given the parameter name, determine what it would actually be when passed to + * the command line. + */ +inline std::string ParamString(const std::string& paramName) +{ + // For a Julia binding we don't need to know the type. + return "`" + paramName + "`"; +} + +/** + * Given the parameter name and an argument, return what should be written as + * documentation when referencing that argument. + */ +template +inline std::string ParamString(const std::string& paramName, const T& value) +{ + std::ostringstream oss; + oss << paramName << " = " << value; + return oss.str(); +} + +inline bool IgnoreCheck(const std::string& paramName) +{ + return !CLI::Parameters()[paramName].input; +} + +inline bool IgnoreCheck(const std::vector& constraints) +{ + for (size_t i = 0; i < constraints.size(); ++i) + { + if (!CLI::Parameters()[constraints[i]].input) + return true; + } + + return false; +} + +inline bool IgnoreCheck( + const std::vector>& constraints, + const std::string& paramName) +{ + for (size_t i = 0; i < constraints.size(); ++i) + { + if (!CLI::Parameters()[constraints[i].first].input) + return true; + } + + return !CLI::Parameters()[paramName].input; +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/print_doc.hpp mlpack-3.3.0/src/mlpack/bindings/julia/print_doc.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/print_doc.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/print_doc.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,65 @@ +/** + * @file print_doc.hpp + * @author Ryan Curtin + * + * Print inline documentation for a single option. + * + * 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_BINDINGS_JULIA_PRINT_DOC_HPP +#define MLPACK_BINDINGS_JULIA_PRINT_DOC_HPP + +namespace mlpack { +namespace bindings { +namespace julia { + +template +void PrintDoc(const util::ParamData& d, const void* /* input */, void* output) +{ + // "type" is a reserved keyword or function. + const std::string juliaName = (d.name == "type") ? "type_" : d.name; + + std::ostringstream& oss = *((std::ostringstream*) output); + + oss << "`" << juliaName << "::" << GetJuliaType() << "`: " << d.desc; + + // Print a default, if possible. Defaults aren't printed for matrix or model + // parameters. + if (!d.required) + { + if (d.cppType == "std::string" || + d.cppType == "double" || + d.cppType == "int" || + d.cppType == "bool") + { + oss << " Default value `"; + if (d.cppType == "std::string") + { + oss << boost::any_cast(d.value); + } + else if (d.cppType == "double") + { + oss << boost::any_cast(d.value); + } + else if (d.cppType == "int") + { + oss << boost::any_cast(d.value); + } + else if (d.cppType == "bool") + { + oss << (boost::any_cast(d.value) ? "true" : "false"); + } + oss << "`." << std::endl; + } + } +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#endif + diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/print_input_param.hpp mlpack-3.3.0/src/mlpack/bindings/julia/print_input_param.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/print_input_param.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/print_input_param.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,61 @@ +/** + * @file print_input_param.hpp + * @author Ryan Curtin + * + * Print the declaration of an input parameter as part of a line in a Julia + * function definition. + * + * 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_BINDINGS_JULIA_PRINT_INPUT_PARAM_HPP +#define MLPACK_BINDINGS_JULIA_PRINT_INPUT_PARAM_HPP + +#include "get_julia_type.hpp" + +namespace mlpack { +namespace bindings { +namespace julia { + +/** + * Print the declaration of an input parameter as part of a line in a Julia + * function definition. This doesn't include any commas or anything. + */ +template +void PrintInputParam(const util::ParamData& d, + const void* /* input */, + void* /* output */) +{ + // "type" is a reserved keyword or function. + const std::string juliaName = (d.name == "type") ? "type_" : d.name; + + std::cout << juliaName; + + if (!arma::is_arma_type::value) + { + std::cout << "::"; + // If it's required, then we need the type. + if (d.required) + { + std::cout << GetJuliaType::type>(); + } + else + { + std::cout << "Union{" + << GetJuliaType::type>() + << ", Missing} = missing"; + } + } + else if (!d.required) + { + std::cout << " = missing"; + } +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/print_input_processing.hpp mlpack-3.3.0/src/mlpack/bindings/julia/print_input_processing.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/print_input_processing.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/print_input_processing.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,84 @@ +/** + * @file print_input_processing.hpp + * @author Ryan Curtin + * + * Print Julia code to handle input arguments. + * + * 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_BINDINGS_JULIA_PRINT_INPUT_PROCESSING_HPP +#define MLPACK_BINDINGS_JULIA_PRINT_INPUT_PROCESSING_HPP + +namespace mlpack { +namespace bindings { +namespace julia { + +/** + * Print the input processing (basically calling CLI::GetParam<>()) for a + * non-serializable type. + */ +template +void PrintInputProcessing( + const util::ParamData& d, + const std::string& functionName, + const typename std::enable_if::value>::type* = 0, + const typename std::enable_if>::value>::type* = 0); + +/** + * Print the input processing for an Armadillo type. + */ +template +void PrintInputProcessing( + const util::ParamData& d, + const std::string& functionName, + const typename std::enable_if::value>::type* = 0, + const typename std::enable_if>::value>::type* = 0); + +/** + * Print the input processing for a serializable type. + */ +template +void PrintInputProcessing( + const util::ParamData& d, + const std::string& functionName, + const typename std::enable_if::value>::type* = 0, + const typename std::enable_if::value>::type* = 0, + const typename std::enable_if>::value>::type* = 0); + +/** + * Print the input processing (basically calling CLI::GetParam<>()) for a + * matrix with DatasetInfo type. + */ +template +void PrintInputProcessing( + const util::ParamData& d, + const std::string& functionName, + const typename std::enable_if>::value>::type* = 0); + +/** + * Print the input processing (basically calling CLI::GetParam<>()) for a type. + */ +template +void PrintInputProcessing(const util::ParamData& d, + const void* input, + void* /* output */) +{ + // Call out to the right overload. + PrintInputProcessing::type>(d, + *((std::string*) input)); +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#include "print_input_processing_impl.hpp" + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/print_input_processing_impl.hpp mlpack-3.3.0/src/mlpack/bindings/julia/print_input_processing_impl.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/print_input_processing_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/print_input_processing_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,194 @@ +/** + * @file print_input_processing_impl.hpp + * @author Ryan Curtin + * + * Print Julia code to handle input arguments. + * + * 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_BINDINGS_JULIA_PRINT_INPUT_PROCESSING_IMPL_HPP +#define MLPACK_BINDINGS_JULIA_PRINT_INPUT_PROCESSING_IMPL_HPP + +#include "strip_type.hpp" +#include "get_julia_type.hpp" + +namespace mlpack { +namespace bindings { +namespace julia { + +/** + * Print the input processing (basically calling CLI::GetParam<>()) for a + * non-serializable type. + */ +template +void PrintInputProcessing( + const util::ParamData& d, + const std::string& /* functionName */, + const typename std::enable_if::value>::type*, + const typename std::enable_if>::value>::type*) +{ + // "type" is a reserved keyword or function. + const std::string juliaName = (d.name == "type") ? "type_" : d.name; + + // Here we can just call CLISetParam() directly; we don't need a separate + // overload. + if (d.required) + { + // This gives us code like the following: + // + // CLISetParam("", ) + std::cout << " CLISetParam(\"" << d.name << "\", " << juliaName << ")" + << std::endl; + } + else + { + // This gives us code like the following: + // + // if !ismissing() + // CLISetParam("", convert(, )) + // end + std::cout << " if !ismissing(" << juliaName << ")" << std::endl; + std::cout << " CLISetParam(\"" << d.name << "\", convert(" + << GetJuliaType() << ", " << juliaName << "))" << std::endl; + std::cout << " end" << std::endl; + } +} + +/** + * Print the input processing for an Armadillo type. + */ +template +void PrintInputProcessing( + const util::ParamData& d, + const std::string& /* functionName */, + const typename std::enable_if::value>::type*, + const typename std::enable_if>::value>::type*) +{ + // "type" is a reserved keyword or function. + const std::string juliaName = (d.name == "type") ? "type_" : d.name; + + // If the argument is not required, then we have to encase the code in an if. + size_t extraIndent = 0; + if (!d.required) + { + std::cout << " if !ismissing(" << juliaName << ")" << std::endl; + extraIndent = 2; + } + + // For an Armadillo type, we have to call a different overload for columns and + // rows than for regular matrices. + std::string uChar = (std::is_same::value) ? + "U" : ""; + std::string indent(extraIndent + 2, ' '); + std::string matTypeModifier = ""; + std::string extra = ""; + if (T::is_row) + { + matTypeModifier = "Row"; + } + else if (T::is_col) + { + matTypeModifier = "Col"; + } + else + { + matTypeModifier = "Mat"; + extra = ", points_are_rows"; + } + + // Now print the CLISetParam call. + std::cout << indent << "CLISetParam" << uChar << matTypeModifier << "(\"" + << d.name << "\", " << juliaName << extra << ")" << std::endl; + + if (!d.required) + { + std::cout << " end" << std::endl; + } +} + +/** + * Print the input processing for a serializable type. + */ +template +void PrintInputProcessing( + const util::ParamData& d, + const std::string& functionName, + const typename std::enable_if::value>::type*, + const typename std::enable_if::value>::type*, + const typename std::enable_if>::value>::type*) +{ + // "type" is a reserved keyword or function. + const std::string juliaName = (d.name == "type") ? "type_" : d.name; + + // If the argument is not required, then we have to encase the code in an if. + size_t extraIndent = 0; + if (!d.required) + { + std::cout << " if !ismissing(" << juliaName << ")" << std::endl; + extraIndent = 2; + } + + std::string indent(extraIndent + 2, ' '); + std::string type = StripType(d.cppType); + std::cout << indent << functionName << "_internal.CLISetParam" << type + << "Ptr(\"" << d.name << "\", convert(" + << GetJuliaType::type>() << ", " + << juliaName << "))" << std::endl; + + if (!d.required) + { + std::cout << " end" << std::endl; + } +} + +/** + * Print the input processing (basically calling CLI::GetParam<>()) for a + * matrix with DatasetInfo type. + */ +template +void PrintInputProcessing( + const util::ParamData& d, + const std::string& /* functionName */, + const typename std::enable_if>::value>::type*) +{ + // "type" is a reserved keyword or function. + const std::string juliaName = (d.name == "type") ? "type_" : d.name; + + // Here we can just call CLISetParam() directly; we don't need a separate + // overload. But we do have to pass in points_are_rows. + if (d.required) + { + // This gives us code like the following: + // + // CLISetParam("", convert(, )) + std::cout << " CLISetParam(\"" << d.name << "\", convert(" + << GetJuliaType() << ", " << juliaName << "), points_are_rows)" + << std::endl; + } + else + { + // This gives us code like the following: + // + // if !ismissing() + // CLISetParam("", convert(, )) + // end + std::cout << " if !ismissing(" << juliaName << ")" << std::endl; + std::cout << " CLISetParam(\"" << d.name << "\", convert(" + << GetJuliaType() << ", " << juliaName << "), points_are_rows)" + << std::endl; + std::cout << " end" << std::endl; + } +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/print_jl.cpp mlpack-3.3.0/src/mlpack/bindings/julia/print_jl.cpp --- mlpack-3.2.2/src/mlpack/bindings/julia/print_jl.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/print_jl.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,287 @@ +/** + * @file print_jl.cpp + * @author Ryan Curtin + * + * Implementation of utility PrintJL() 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. + */ +#include "print_jl.hpp" +#include + +using namespace mlpack; +using namespace std; + +namespace mlpack { +namespace bindings { +namespace julia { + +extern std::string programName; + +/** + * Print the code for a .jl binding for an mlpack program to stdout. + */ +void PrintJL(const util::ProgramDoc& programInfo, + const string& functionName, + const std::string& mlpackJuliaLibSuffix) +{ + // Restore parameters. + CLI::RestoreSettings(programInfo.programName); + + const map& parameters = CLI::Parameters(); + typedef map::const_iterator ParamIter; + + // First, let's get a list of input and output options. We'll take two passes + // so that the required input options are the first in the list. + vector inputOptions, outputOptions; + for (ParamIter it = parameters.begin(); it != parameters.end(); ++it) + { + const util::ParamData& d = it->second; + if (d.input && d.required) + { + // Ignore some parameters. + if (d.name != "help" && d.name != "info" && + d.name != "version") + inputOptions.push_back(it->first); + } + else if (!d.input) + { + outputOptions.push_back(it->first); + } + } + + for (ParamIter it = parameters.begin(); it != parameters.end(); ++it) + { + const util::ParamData& d = it->second; + if (d.input && !d.required && + d.name != "help" && d.name != "info" && + d.name != "version") + inputOptions.push_back(it->first); + } + + // First, define what we are exporting. + cout << "export " << functionName << endl; + cout << endl; + + // We need to include utility functions. + cout << "using mlpack._Internal.cli" << endl; + cout << endl; + + // Make sure the libraries we need are accessible. + cout << "const " << functionName << "Library = joinpath(@__DIR__, " + << "\"libmlpack_julia_" << functionName << mlpackJuliaLibSuffix << "\")" + << endl; + cout << endl; + + // Define mlpackMain() function to call. + cout << "# Call the C binding of the mlpack " << functionName << " binding." + << endl; + cout << "function " << functionName << "_mlpackMain()" << endl; + cout << " success = ccall((:" << functionName << ", " << functionName + << "Library), Bool, ())" << endl; + cout << " if !success" << endl; + cout << " # Throw an exception---false means there was a C++ exception." + << endl; + cout << " throw(ErrorException(\"mlpack binding error; see output\"))" + << endl; + cout << " end" << endl; + cout << "end" << endl; + cout << endl; + + // If we have any model types, we need to define functions to set and get + // their values from the CLI object. We do this with the PrintParamDefn() + // function. We'll gather all names of classes we've done this with, so that + // we don't print any duplicates. This should all be done inside of an + // internal module. + cout << "\" Internal module to hold utility functions. \"" << endl; + cout << "module " << functionName << "_internal" << endl; + cout << " import .." << functionName << "Library" << endl; + cout << endl; + + set classNames; + for (ParamIter it = parameters.begin(); it != parameters.end(); ++it) + { + const util::ParamData& d = it->second; + if (classNames.count(d.cppType) == 0) + { + CLI::GetSingleton().functionMap[d.tname]["PrintParamDefn"](d, (void*) + &functionName, NULL); + + // Avoid adding this definition again. + classNames.insert(d.cppType); + } + } + + // End the module. + cout << "end # module" << endl; + cout << endl; + + // Print the documentation. + cout << "\"\"\"" << endl; + cout << " " << functionName << "("; + + // Print a list of input arguments after the function name. + bool defaults = false; + for (size_t i = 0; i < inputOptions.size(); ++i) + { + const string& opt = inputOptions[i]; + const util::ParamData& d = parameters.at(opt); + + if (!defaults && !d.required) + { + // Open the bracket. + cout << "; ["; + defaults = true; + } + else if (i > 0) + { + cout << ", "; + } + + cout << d.name; + } + if (defaults) + cout << "]"; + cout << ")" << endl; + cout << endl; + + // Next print the description. + cout << util::HyphenateString(programInfo.documentation(), 0) << endl; + + // Next, print information on the input options. + cout << endl; + cout << "# Arguments" << endl; + cout << endl; + + for (size_t i = 0; i < inputOptions.size(); ++i) + { + const string& opt = inputOptions[i]; + const util::ParamData& d = parameters.at(opt); + + std::ostringstream oss; + oss << " - "; + + CLI::GetSingleton().functionMap[d.tname]["PrintDoc"](d, NULL, (void*) &oss); + + cout << util::HyphenateString(oss.str(), 6) << endl; + } + + cout << endl; + cout << "# Return values" << endl; + cout << endl; + + for (size_t i = 0; i < outputOptions.size(); ++i) + { + const string& opt = outputOptions[i]; + const util::ParamData& d = parameters.at(opt); + + std::ostringstream oss; + oss << " - "; + + CLI::GetSingleton().functionMap[d.tname]["PrintDoc"](d, NULL, (void*) &oss); + + cout << util::HyphenateString(oss.str(), 6) << endl; + } + cout << endl; + + cout << "\"\"\"" << endl; + + // Print the signature. + cout << "function " << functionName << "("; + const size_t indent = 10 + functionName.size(); + + // Print required input arguments as part of the function signature, followed + // by non-required input arguments. + defaults = false; + for (size_t i = 0; i < inputOptions.size(); ++i) + { + const string& opt = inputOptions[i]; + const util::ParamData& d = parameters.at(opt); + + if (!defaults && !d.required) + { + cout << ";" << endl << string(indent, ' '); + defaults = true; + } + else if (i > 0) + { + cout << "," << endl << string(indent, ' '); + } + + CLI::GetSingleton().functionMap[d.tname]["PrintInputParam"](d, NULL, + NULL); + } + + // Print the 'points_are_rows' option. + if (!defaults) + cout << ";" << endl << string(indent, ' '); + else + cout << "," << endl << string(indent, ' '); + cout << "points_are_rows::Bool = true)" << endl; + + // Force symbols to load. + cout << " # Force the symbols to load." << endl; + cout << " ccall((:loadSymbols, " << functionName << "Library), Nothing, ());" + << endl; + cout << endl; + + // Restore CLI settings. + cout << " CLIRestoreSettings(\"" << programName << "\")" << endl; + cout << endl; + + // Handle each input argument's processing before calling mlpackMain(). + cout << " # Process each input argument before calling mlpackMain()." + << endl; + for (const string& opt : inputOptions) + { + if (opt != "verbose") + { + const util::ParamData& d = parameters.at(opt); + CLI::GetSingleton().functionMap[d.tname]["PrintInputProcessing"](d, + &functionName, NULL); + } + } + + // Special handling for verbose output. + cout << " if verbose !== nothing && verbose === true" << endl; + cout << " CLIEnableVerbose()" << endl; + cout << " else" << endl; + cout << " CLIDisableVerbose()" << endl; + cout << " end" << endl; + cout << endl; + + // Mark output parameters as passed. + for (const string& opt : outputOptions) + { + const util::ParamData& d = parameters.at(opt); + cout << " CLISetPassed(\"" << d.name << "\")" << endl; + } + + // Call the program. + cout << " # Call the program." << endl; + cout << " " << functionName << "_mlpackMain()" << endl; + cout << endl; + + // Extract the results in order. + cout << " return "; + string indentStr(9, ' '); + for (size_t i = 0; i < outputOptions.size(); ++i) + { + const util::ParamData& d = parameters.at(outputOptions[i]); + CLI::GetSingleton().functionMap[d.tname]["PrintOutputProcessing"](d, + &functionName, NULL); + + // Print newlines if we are returning multiple output options. + if (i + 1 < outputOptions.size()) + cout << "," << endl << indentStr; + } + + cout << endl << "end" << endl; +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/print_jl.hpp mlpack-3.3.0/src/mlpack/bindings/julia/print_jl.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/print_jl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/print_jl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,32 @@ +/** + * @file print_jl.hpp + * @author Ryan Curtin + * + * Definition of utility PrintJL() 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_BINDINGS_JULIA_PRINT_JL_HPP +#define MLPACK_BINDINGS_JULIA_PRINT_JL_HPP + +#include + +namespace mlpack { +namespace bindings { +namespace julia { + +/** + * Print the code for a .jl binding for an mlpack program to stdout. + */ +void PrintJL(const util::ProgramDoc& programInfo, + const std::string& functionName, + const std::string& mlpackJuliaLibSuffix); + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/print_output_processing.hpp mlpack-3.3.0/src/mlpack/bindings/julia/print_output_processing.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/print_output_processing.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/print_output_processing.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,85 @@ +/** + * @file print_output_processing.hpp + * @author Ryan Curtin + * + * Print Julia code to handle output arguments. + * + * 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_BINDINGS_JULIA_PRINT_OUTPUT_PROCESSING_HPP +#define MLPACK_BINDINGS_JULIA_PRINT_OUTPUT_PROCESSING_HPP + +#include + +namespace mlpack { +namespace bindings { +namespace julia { + +/** + * Print the output processing (basically calling CLI::GetParam<>()) for a + * non-serializable type. + */ +template +void PrintOutputProcessing( + const util::ParamData& d, + const std::string& functionName, + const typename std::enable_if::value>::type* = 0, + const typename std::enable_if>::value>::type* = 0); + +/** + * Print the output processing for an Armadillo type. + */ +template +void PrintOutputProcessing( + const util::ParamData& d, + const std::string& functionName, + const typename std::enable_if::value>::type* = 0, + const typename std::enable_if>::value>::type* = 0); + +/** + * Print the output processing for a serializable type. + */ +template +void PrintOutputProcessing( + const util::ParamData& d, + const std::string& functionName, + const typename std::enable_if::value>::type* = 0, + const typename std::enable_if::value>::type* = 0, + const typename std::enable_if>::value>::type* = 0); + +/** + * Print the output processing for a mat/DatasetInfo tuple type. + */ +template +void PrintOutputProcessing( + const util::ParamData& d, + const std::string& functionName, + const typename std::enable_if>::value>::type* = 0); + +/** + * Print the output processing (basically calling CLI::GetParam<>()) for a type. + */ +template +void PrintOutputProcessing(const util::ParamData& d, + const void* input, + void* /* output */) +{ + // Call out to the right overload. + PrintOutputProcessing::type>(d, + *((std::string*) input)); +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#include "print_output_processing_impl.hpp" + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/print_output_processing_impl.hpp mlpack-3.3.0/src/mlpack/bindings/julia/print_output_processing_impl.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/print_output_processing_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/print_output_processing_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,128 @@ +/** + * @file print_output_processing_impl.hpp + * @author Ryan Curtin + * + * Print Julia code to handle output arguments. + * + * 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_BINDINGS_JULIA_PRINT_OUTPUT_PROCESSING_IMPL_HPP +#define MLPACK_BINDINGS_JULIA_PRINT_OUTPUT_PROCESSING_IMPL_HPP + +#include "print_output_processing.hpp" + +#include "strip_type.hpp" +#include "get_julia_type.hpp" + +namespace mlpack { +namespace bindings { +namespace julia { + +/** + * Print the output processing (basically calling CLI::GetParam<>()) for a + * non-serializable type. + */ +template +void PrintOutputProcessing( + const util::ParamData& d, + const std::string& /* functionName */, + const typename std::enable_if::value>::type*, + const typename std::enable_if>::value>::type*) +{ + std::string type; + if (std::is_same::value) + type = "Bool"; + else if (std::is_same::value) + type = "Int"; + else if (std::is_same::value) + type = "Double"; + else if (std::is_same::value) + type = "String"; + else if (std::is_same>::value) + type = "VectorStr"; + else if (std::is_same>::value) + type = "VectorInt"; + else + type = "Unknown"; + + // Strings need a little special handling. + if (std::is_same::value) + std::cout << "Base.unsafe_string("; + + std::cout << "CLIGetParam" << type << "(\"" << d.name << "\")"; + + if (std::is_same::value) + std::cout << ")"; +} + +/** + * Print the output processing for an Armadillo type. + */ +template +void PrintOutputProcessing( + const util::ParamData& d, + const std::string& /* functionName */, + const typename std::enable_if::value>::type*, + const typename std::enable_if>::value>::type*) +{ + std::string uChar = (std::is_same::value) ? + "U" : ""; + std::string matTypeSuffix = ""; + std::string extra = ""; + if (T::is_row) + { + matTypeSuffix = "Row"; + } + else if (T::is_col) + { + matTypeSuffix = "Col"; + } + else + { + matTypeSuffix = "Mat"; + extra = ", points_are_rows"; + } + + std::cout << "CLIGetParam" << uChar << matTypeSuffix << "(\"" << d.name + << "\"" << extra << ")"; +} + +/** + * Print the output processing for a serializable type. + */ +template +void PrintOutputProcessing( + const util::ParamData& d, + const std::string& functionName, + const typename std::enable_if::value>::type*, + const typename std::enable_if::value>::type*, + const typename std::enable_if>::value>::type*) +{ + std::cout << functionName << "_internal.CLIGetParam" << StripType(d.cppType) + << "Ptr(\"" << d.name << "\")"; +} + +/** + * Print the output processing for a mat/DatasetInfo tuple type. + */ +template +void PrintOutputProcessing( + const util::ParamData& d, + const std::string& /* functionName */, + const typename std::enable_if>::value>::type*) +{ + std::cout << "CLIGetParamMatWithInfo(\"" << d.name << "\")"; +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/print_param_defn.hpp mlpack-3.3.0/src/mlpack/bindings/julia/print_param_defn.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/print_param_defn.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/print_param_defn.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,107 @@ +/** + * @file print_param_defn.hpp + * @author Ryan Curtin + * + * If the type is serializable, we need to define a special utility function to + * set a CLI parameter of that type. + * + * 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_BINDINGS_JULIA_PRINT_PARAM_DEFN_HPP +#define MLPACK_BINDINGS_JULIA_PRINT_PARAM_DEFN_HPP + +#include "strip_type.hpp" + +namespace mlpack { +namespace bindings { +namespace julia { + +/** + * If the type is not serializable, print nothing. + */ +template +void PrintParamDefn( + const util::ParamData& /* d */, + const std::string& /* programName */, + const typename std::enable_if::value>::type* = 0, + const typename std::enable_if::value>::type* = 0) +{ + // Do nothing. +} + +/** + * Matrices are serializable but here we also print nothing. + */ +template +void PrintParamDefn( + const util::ParamData& /* d */, + const std::string& /* programName */, + const typename std::enable_if::value>::type* = 0) +{ + // Do nothing. +} + +/** + * For non-matrix serializable types we need to print something. + */ +template +void PrintParamDefn( + const util::ParamData& d, + const std::string& programName, + const typename std::enable_if::value>::type* = 0, + const typename std::enable_if::value>::type* = 0) +{ + // We need to print something of the form below: + // + // function CLIGetParamPtr(paramName::String) + // return ccall((:CLIGetParamPtr, Library), + // Ptr{Nothing}, (Cstring,), paramName) + // end + // + // function CLISetParamPtr(paramName::String, ptr::Ptr{Nothing}) + // ccall((:CLISetParamPtr, Library), Nothing, + // (Cstring, Ptr{Nothing}), paramName, ptr) + // end + std::string type = StripType(d.cppType); + std::cout << "\" Get the value of a model pointer parameter of type " << type + << ".\"" << std::endl; + std::cout << "function CLIGetParam" << type << "Ptr(paramName::String)" + << std::endl; + std::cout << " return ccall((:CLI_GetParam" << type << "Ptr, " + << programName << "Library), Ptr{Nothing}, " + << "(Cstring,), paramName)" << std::endl; + std::cout << "end" << std::endl; + std::cout << std::endl; + + std::cout << "\" Set the value of a model pointer parameter of type " << type + << ".\"" << std::endl; + std::cout << "function CLISetParam" << type << "Ptr(paramName::String, " + << "ptr::Ptr{Nothing})" << std::endl; + std::cout << " ccall((:CLI_SetParam" << type << "Ptr, " + << programName << "Library), Nothing, (Cstring, " + << "Ptr{Nothing}), paramName, ptr)" << std::endl; + std::cout << "end" << std::endl; + std::cout << std::endl; +} + +/** + * If the type is serializable, print the definition of a special utility + * function to set a CLI parameter of that type to stdout. + */ +template +void PrintParamDefn(const util::ParamData& d, + const void* input, + void* /* output */) +{ + PrintParamDefn::type>(d, + *(std::string*) input); +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/print_type_doc.hpp mlpack-3.3.0/src/mlpack/bindings/julia/print_type_doc.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/print_type_doc.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/print_type_doc.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,86 @@ +/** + * @file print_type_doc.hpp + * @author Ryan Curtin + * + * Print documentation for a given type, detailing what the type actually is to + * the user. + * + * 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_BINDINGS_JULIA_PRINT_TYPE_DOC_HPP +#define MLPACK_BINDINGS_JULIA_PRINT_TYPE_DOC_HPP + +#include + +namespace mlpack { +namespace bindings { +namespace julia { + +/** + * Return a string representing the command-line type of an option. + */ +template +std::string PrintTypeDoc( + const util::ParamData& data, + const typename boost::disable_if>::type* = 0, + const typename boost::disable_if>::type* = 0, + const typename boost::disable_if>::type* = 0, + const typename boost::disable_if>>::type* = 0); + +/** + * Return a string representing the command-line type of a vector. + */ +template +std::string PrintTypeDoc( + const util::ParamData& data, + const typename std::enable_if::value>::type* = 0); + +/** + * Return a string representing the command-line type of a matrix option. + */ +template +std::string PrintTypeDoc( + const util::ParamData& data, + const typename std::enable_if::value>::type* = 0); + +/** + * Return a string representing the command-line type of a matrix tuple option. + */ +template +std::string PrintTypeDoc( + const util::ParamData& data, + const typename std::enable_if>::value>::type* = 0); + +/** + * Return a string representing the command-line type of a model. + */ +template +std::string PrintTypeDoc( + const util::ParamData& data, + const typename boost::disable_if>::type* = 0, + const typename boost::enable_if>::type* = 0); + +/** + * Print the command-line type of an option into a string. + */ +template +void PrintTypeDoc(const util::ParamData& data, + const void* /* input */, + void* output) +{ + *((std::string*) output) = + PrintTypeDoc::type>(data); +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#include "print_type_doc_impl.hpp" + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/print_type_doc_impl.hpp mlpack-3.3.0/src/mlpack/bindings/julia/print_type_doc_impl.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/print_type_doc_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/print_type_doc_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,169 @@ +/** + * @file print_type_doc_impl.hpp + * @author Ryan Curtin + * + * Print documentation for a given type. + * + * 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_BINDINGS_JULIA_PRINT_TYPE_DOC_IMPL_HPP +#define MLPACK_BINDINGS_JULIA_PRINT_TYPE_DOC_IMPL_HPP + +#include "print_type_doc.hpp" + +namespace mlpack { +namespace bindings { +namespace julia { + +/** + * Return a string representing the command-line type of an option. + */ +template +std::string PrintTypeDoc( + const util::ParamData& data, + const typename boost::disable_if>::type*, + const typename boost::disable_if>::type*, + const typename boost::disable_if>::type*, + const typename boost::disable_if>>::type*) +{ + // A flag type. + if (std::is_same::value) + { + return "A boolean flag option (`true` or `false`)."; + } + // An integer. + else if (std::is_same::value) + { + return "An integer (i.e., `1`)."; + } + // A floating point value. + else if (std::is_same::value) + { + return "A floating-point number (i.e., `0.5`)."; + } + // A string. + else if (std::is_same::value) + { + return "A character string (i.e., `\"hello\"`)."; + } + // Not sure what it is... + else + { + throw std::invalid_argument("unknown parameter type " + data.cppType); + } +} + +/** + * Return a string representing the command-line type of a vector. + */ +template +std::string PrintTypeDoc( + const util::ParamData& data, + const typename std::enable_if::value>::type*) +{ + if (std::is_same>::value) + { + return "A vector of integers; i.e., `[0, 1, 2]`."; + } + else if (std::is_same>::value) + { + return "A vector of strings; i.e., `[\"hello\", \"goodbye\"]`."; + } + else + { + throw std::invalid_argument("unknown vector type " + data.cppType); + } +} + +/** + * Return a string representing the command-line type of a matrix option. + */ +template +std::string PrintTypeDoc( + const util::ParamData& data, + const typename std::enable_if::value>::type*) +{ + if (std::is_same::value) + { + if (T::is_col || T::is_row) + { + return "A 1-d vector-like containing `Float64` data (could be an " + "`Array{Float64, 1}`, an `Array{Float64, 2}` with one dimension " + "of size 1, or anything convertible to `Array{Float64, 1}`."; + } + else + { + return "A 2-d matrix-like containing `Float64` data (could be an " + "`Array{Float64, 2}` or a `DataFrame` or anything convertible to an " + "`Array{Float64, 2}`). It is expected that each row of the matrix " + "corresponds to a data point, unless `points_are_rows` is set to " + "`false` when calling mlpack bindings."; + } + } + else if (std::is_same::value) + { + if (T::is_col || T::is_row) + { + return "A 1-d vector-like containing `Int` data (elements should be " + "greater than or equal to 0). Could be an `Array{Int, 1}`, an " + "`Array{Int, 2}` with one dimension of size 1, or anything " + "convertible to `Array{Int, 1}`."; + } + else + { + return "A 2-d matrix-like containing `Int` data (elements should be " + "greater than or equal to 0). Could be an `Array{Int, 2}` or a " + "`DataFrame` or anything convertible to an `Array{Int, 2}`. It is " + "expected that each row of the matrix corresponds to a data point, " + "unless `points_are_rows` is set to `false` when calling mlpack " + "bindings."; + } + } + else + { + throw std::invalid_argument("unknown matrix type " + data.cppType); + } +} + +/** + * Return a string representing the command-line type of a matrix tuple option. + */ +template +std::string PrintTypeDoc( + const util::ParamData& /* data */, + const typename std::enable_if>::value>::type*) +{ + return "A 2-d array containing `Float64` data along with a boolean array " + "indicating which dimensions are categorical (represented by `true`) and " + "which are numeric (represented by `false`). The number of elements in " + "the boolean array should be the same as the dimensionality of the data " + "matrix. It is expected that each row of the matrix corresponds to a " + "single data point, unless `points_are_rows` is set to `false` when " + "calling mlpack bindings."; +} + +/** + * Return a string representing the command-line type of a model. + */ +template +std::string PrintTypeDoc( + const util::ParamData& /* data */, + const typename boost::disable_if>::type*, + const typename boost::enable_if>::type*) +{ + return "An mlpack model pointer. This type holds a pointer to C++ memory " + "containing the mlpack model. Note that this means the mlpack model " + "itself cannot be easily inspected in Julia. However, the pointer can " + "be passed to subsequent calls to mlpack functions."; +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/strip_type.hpp mlpack-3.3.0/src/mlpack/bindings/julia/strip_type.hpp --- mlpack-3.2.2/src/mlpack/bindings/julia/strip_type.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/strip_type.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,49 @@ +/** + * @filename strip_type.hpp + * @author Ryan Curtin + * + * Given a C++ type name, turn it into something that has no special characters + * that can simply be printed. + * + * 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_BINDINGS_JULIA_STRIP_TYPE_HPP +#define MLPACK_BINDINGS_JULIA_STRIP_TYPE_HPP + +namespace mlpack { +namespace bindings { +namespace julia { + +/** + * Given a C++ type name, turn it into something that has no special characters + * that can simply be printed. This is similar to but not identical to + * mlpack::bindings::python::StripType(). + * + * @param cppType C++ type as a string. + * @return Stripped type with no special characters. + */ +inline std::string StripType(std::string cppType) +{ + // Basically what we need to do is strip any '<' (template bits) from the + // type. We'll try first by removing any instances of <>. + const size_t loc = cppType.find("<>"); + if (loc != std::string::npos) + cppType.replace(loc, 2, ""); + + // Let's just replace any invalid characters with valid '_' characters. + std::replace(cppType.begin(), cppType.end(), '<', '_'); + std::replace(cppType.begin(), cppType.end(), '>', '_'); + std::replace(cppType.begin(), cppType.end(), ' ', '_'); + std::replace(cppType.begin(), cppType.end(), ',', '_'); + + return cppType; +} + +} // namespace julia +} // namespace bindings +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/tests/CMakeLists.txt mlpack-3.3.0/src/mlpack/bindings/julia/tests/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/bindings/julia/tests/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/tests/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,6 @@ +# Add the Julia binding test. +add_julia_binding(test_julia_binding) + +add_test(NAME julia_binding_test + COMMAND ${JULIA_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/runtests.jl + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/) diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/tests/runtests.jl mlpack-3.3.0/src/mlpack/bindings/julia/tests/runtests.jl --- mlpack-3.2.2/src/mlpack/bindings/julia/tests/runtests.jl 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/tests/runtests.jl 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,326 @@ +# @file runtests.jl +# @author Ryan Curtin +# +# Tests for the Julia bindings. +using Pkg +Pkg.activate(".") +using Test +using mlpack + +include(joinpath(pwd(), "src/test_julia_binding.jl")) + +# The return order for the binding is this: +# +# col_out, double_out, int_out, matrix_and_info_out, matrix_out, model_bw_out, +# model_out, row_out, str_vector_out, string_out, ucol_out, umatrix_out, +# urow_out, vector_out +# +# That's a lot of parameters! But this is an atypical binding... + +# Test that when we run the binding correctly (with correct input parameters), +# we get the expected output. +@testset "TestRunBindingCorrectly" begin + _, dblOut, intOut, _, _, _, _, _, _, strOut, _, _, _, _ = + test_julia_binding(4.0, 12, "hello", + flag1=true) + + @test strOut == "hello2" + @test intOut == 13 + @test dblOut == 5.0 +end + +# If we forget the mandatory flag, we should get wrong results. +@testset "TestRunBindingNoFlag" begin + _, dblOut, intOut, _, _, _, _, _, _, strOut, _, _, _, _ = + test_julia_binding(4.0, 12, "hello") + + @test strOut != "hello2" + @test intOut != 13 + @test dblOut != 5.0 +end + +# If we give the wrong string, we should get wrong results. +@testset "TestRunBindingWrongString" begin + _, _, _, _, _, _, _, _, _, strOut, _, _, _, _ = + test_julia_binding(4.0, 12, "goodbye", + flag1=true) + + @test strOut != "hello2" +end + +# If we give the wrong int, we should get wrong results. +@testset "TestRunBindingWrongInt" begin + _, _, intOut, _, _, _, _, _, _, _, _, _, _, _ = + test_julia_binding(4.0, 15, "hello", + flag1=true) + + @test intOut != 13 +end + +# If we give the wrong double, we should get wrong results. +@testset "TestRunBindingWrongDouble" begin + _, dblOut, _, _, _, _, _, _, _, _, _, _, _, _ = + test_julia_binding(2.0, 12, "hello", + flag1=true) + + @test dblOut != 5.0 +end + +# If we give the second flag, this should fail. +@testset "TestRunBadFlag" begin + _, dblOut, intOut, _, _, _, _, _, _, strOut, _, _, _, _ = + test_julia_binding(4.0, 12, "hello", + flag1=true, + flag2=true) + + @test strOut != "hello2" + @test intOut != 13 + @test dblOut != 5.0 +end + +# The matrix we pass in, we should get back with the third dimension doubled and +# the fifth forgotten. +@testset "TestMatrix" begin + x = rand(100, 5) + + _, _, _, _, matOut, _, _, _, _, _, _, _, _, _ = + test_julia_binding(4.0, 12, "hello", + matrix_in=x, + points_are_rows=true) + + @test size(matOut, 1) == 100 + @test size(matOut, 2) == 4 + @test typeof(matOut[1, 1]) == Float64 + for i in [0, 1, 3] + for j in 1:100 + @test matOut[j, i + 1] == x[j, i + 1] + end + end + + for j in 1:100 + @test matOut[j, 3] == 2 * x[j, 3] + end +end + +# The matrix we pass in, we should get back with the third dimension doubled and +# the fifth forgotten. This test is column major. +@testset "TestMatrixColMajor" begin + x = rand(5, 100) + + _, _, _, _, matOut, _, _, _, _, _, _, _, _, _ = + test_julia_binding(4.0, 12, "hello", + matrix_in=x, + points_are_rows=false) + + @test size(matOut, 1) == 4 + @test size(matOut, 2) == 100 + @test typeof(matOut[1, 1]) == Float64 + for i in 1:100 + for j in [0, 1, 3] + @test matOut[j + 1, i] == x[j + 1, i] + end + end + + for j in 1:100 + @test matOut[3, j] == 2 * x[3, j] + end +end + +# Same as TestMatrix but with an unsigned matrix. +@testset "TestUMatrix" begin + # Generate a random matrix of integers. + x = convert(Array{Int, 2}, rand(1:500, (100, 5))) + + _, _, _, _, _, _, _, _, _, _, _, umatOut, _, _ = + test_julia_binding(4.0, 12, "hello", + umatrix_in=x, + points_are_rows=true) + + @test size(umatOut, 1) == 100 + @test size(umatOut, 2) == 4 + @test typeof(umatOut[1, 1]) == Int + for i in [0, 1, 3] + for j in 1:100 + @test umatOut[j, i + 1] == x[j, i + 1] + end + end + + for j in 1;100 + # Since we subtract one when we convert to C++, and then add one when we + # convert back, we get a slightly different result here. + @test umatOut[j, 3] == 2 * x[j, 3] - 1 + end +end + +# Same as TestMatrix but with an unsigned column major matrix. +@testset "TestUMatrixColMajor" begin + # Generate a random matrix of integers. + x = convert(Array{Int, 2}, rand(1:500, (5, 100))) + + _, _, _, _, _, _, _, _, _, _, _, umatOut, _, _ = + test_julia_binding(4.0, 12, "hello", + umatrix_in=x, + points_are_rows=false) + + @test size(umatOut, 1) == 4 + @test size(umatOut, 2) == 100 + @test typeof(umatOut[1, 1]) == Int + for i in 1:100 + for j in [0, 1, 3] + @test umatOut[j + 1, i] == x[j + 1, i] + end + end + + for j in 1;100 + # Since we subtract one when we convert to C++, and then add one when we + # convert back, we get a slightly different result here. + @test umatOut[3, j] == 2 * x[3, j] - 1 + end +end + +# Test a column vector input parameter. +@testset "TestCol" begin + x = rand(100) + + colOut, _, _, _, _, _, _, _, _, _, _, _, _, _ = + test_julia_binding(4.0, 12, "hello", + col_in=x) + + @test size(colOut, 1) == 100 + @test typeof(colOut) == Array{Float64, 1} + + for i in 1:100 + @test colOut[i] == 2 * x[i] + end +end + +# Test an unsigned column vector input parameter. +@testset "TestUCol" begin + x = convert(Array{Int, 1}, rand(1:500, 100)) + + _, _, _, _, _, _, _, _, _, _, ucolOut, _, _, _ = + test_julia_binding(4.0, 12, "hello", + ucol_in=x) + + @test size(ucolOut, 1) == 100 + @test typeof(ucolOut) == Array{Int, 1} + for i in 1:100 + # Since we subtract one when we convert to C++, and then add one when we + # convert back, we get a slightly different result here. + @test ucolOut[i] == 2 * x[i] - 1 + end +end + +# Test a row vector input parameter. +@testset "TestRow" begin + x = rand(100) + + _, _, _, _, _, _, _, rowOut, _, _, _, _, _, _ = + test_julia_binding(4.0, 12, "hello", + row_in=x) + + @test size(rowOut, 1) == 100 + @test typeof(rowOut) == Array{Float64, 1} + for i in 1:100 + @test rowOut[i] == 2 * x[i] + end +end + +# Test an unsigned row vector input parameter. +@testset "TestURow" begin + x = convert(Array{Int, 1}, rand(1:500, 100)) + + _, _, _, _, _, _, _, _, _, _, _, _, urowOut, _ = + test_julia_binding(4.0, 12, "hello", + urow_in=x) + + @test size(urowOut, 1) == 100 + @test typeof(urowOut) == Array{Int, 1} + for i in 1:100 + # Since we subtract one when we convert to C++, and then add one when we + # convert back, we get a slightly different result here. + @test urowOut[i] == 2 * x[i] - 1 + end +end + +# Test that we can pass a matrix with all numeric features. +@testset "TestMatrixAndInfo" begin + x = rand(Float64, (10, 100)) + # Dimension information. + dims = [false, false, false, false, false, false, false, false, false, false] + z = x + + _, _, _, matrix_and_info_out, _, _, _, _, _, _, _, _, _, _ = + test_julia_binding(4.0, 12, "hello", + matrix_and_info_in=(dims, z), + points_are_rows=false) + + @test size(matrix_and_info_out, 1) == 10 + @test size(matrix_and_info_out, 2) == 100 + + for i in 1:100 + for j in 1:10 + @test matrix_and_info_out[j, i] == 2.0 * z[j, i] + end + end +end + +# Test that we can pass a matrix with all numeric features. +@testset "TestMatrixAndInfoRowMajor" begin + x = rand(Float64, (100, 10)) + # Dimension information. + dims = [false, false, false, false, false, false, false, false, false, false] + z = x + + _, _, _, matrix_and_info_out, _, _, _, _, _, _, _, _, _, _ = + test_julia_binding(4.0, 12, "hello", + matrix_and_info_in=(dims, z), + points_are_rows=true) + + @test size(matrix_and_info_out, 1) == 100 + @test size(matrix_and_info_out, 2) == 10 + + for i in 1:100 + for j in 1:10 + @test matrix_and_info_out[i, j] == 2.0 * z[i, j] + end + end +end + +# Test that we can pass a vector of ints and get back that same vector but with +# the last element removed. +@testset "TestIntVector" begin + x = [1, 2, 3, 4, 5] + + _, _, _, _, _, _, _, _, _, _, _, _, _, vecOut = + test_julia_binding(4.0, 12, "hello", + vector_in=x) + + @test vecOut == [1, 2, 3, 4] +end + +# Test that we can pass a vector of strings and get back that same vector but +# with the last element removed. +@testset "TestStringVector" begin + x = ["one", "two", "three", "four", "five"] + + _, _, _, _, _, _, _, _, strVecOut, _, _, _, _, _ = + test_julia_binding(4.0, 12, "hello", + str_vector_in=x) + + @test strVecOut == ["one", "two", "three", "four"] +end + +# First create a GaussianKernel object, then send it back and make sure we get +# the right double value. +@testset "TestModel" begin + _, _, _, _, _, _, modelOut, _, _, _, _, _, _, _ = + test_julia_binding(4.0, 12, "hello", + build_model=true) + + _, _, _, _, _, bwOut, _, _, _, _, _, _, _, _ = + test_julia_binding(4.0, 12, "hello", + model_in=modelOut) + + @test bwOut == 20.0 +end diff -Nru mlpack-3.2.2/src/mlpack/bindings/julia/tests/test_julia_binding_main.cpp mlpack-3.3.0/src/mlpack/bindings/julia/tests/test_julia_binding_main.cpp --- mlpack-3.2.2/src/mlpack/bindings/julia/tests/test_julia_binding_main.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/julia/tests/test_julia_binding_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,190 @@ +/** + * @file julia_binding_test.cpp + * @author Ryan Curtin + * + * A binding test for Julia. + * + * 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 + +using namespace std; +using namespace mlpack; +using namespace mlpack::kernel; + +PROGRAM_INFO("Julia binding test", + "A simple program to test Julia binding functionality.", + "A simple program to test Julia binding functionality. You can build " + "mlpack with the BUILD_TESTS option set to off, and this binding will " + "no longer be built."); + +PARAM_STRING_IN_REQ("string_in", "Input string, must be 'hello'.", "s"); +PARAM_INT_IN_REQ("int_in", "Input int, must be 12.", "i"); +PARAM_DOUBLE_IN_REQ("double_in", "Input double, must be 4.0.", "d"); +PARAM_FLAG("flag1", "Input flag, must be specified.", "f"); +PARAM_FLAG("flag2", "Input flag, must not be specified.", "F"); +PARAM_MATRIX_IN("matrix_in", "Input matrix.", "m"); +PARAM_UMATRIX_IN("umatrix_in", "Input unsigned matrix.", "u"); +PARAM_COL_IN("col_in", "Input column.", "c"); +PARAM_UCOL_IN("ucol_in", "Input unsigned column.", ""); +PARAM_ROW_IN("row_in", "Input row.", ""); +PARAM_UROW_IN("urow_in", "Input unsigned row.", ""); +PARAM_MATRIX_AND_INFO_IN("matrix_and_info_in", "Input matrix and info.", ""); +PARAM_VECTOR_IN(int, "vector_in", "Input vector of numbers.", ""); +PARAM_VECTOR_IN(string, "str_vector_in", "Input vector of strings.", ""); +PARAM_MODEL_IN(GaussianKernel, "model_in", "Input model.", ""); +PARAM_FLAG("build_model", "If true, a model will be returned.", ""); + +PARAM_STRING_OUT("string_out", "Output string, will be 'hello2'.", "S"); +PARAM_INT_OUT("int_out", "Output int, will be 13."); +PARAM_DOUBLE_OUT("double_out", "Output double, will be 5.0."); +PARAM_MATRIX_OUT("matrix_out", "Output matrix.", "M"); +PARAM_UMATRIX_OUT("umatrix_out", "Output unsigned matrix.", "U"); +PARAM_COL_OUT("col_out", "Output column. 2x input column", ""); +PARAM_UCOL_OUT("ucol_out", "Output unsigned column. 2x input column.", ""); +PARAM_ROW_OUT("row_out", "Output row. 2x input row.", ""); +PARAM_UROW_OUT("urow_out", "Output unsigned row. 2x input row.", ""); +PARAM_MATRIX_OUT("matrix_and_info_out", "Output matrix and info; all numeric " + "elements multiplied by 3.", ""); +PARAM_VECTOR_OUT(int, "vector_out", "Output vector.", ""); +PARAM_VECTOR_OUT(string, "str_vector_out", "Output string vector.", ""); +PARAM_MODEL_OUT(GaussianKernel, "model_out", "Output model, with twice the " + "bandwidth.", ""); +PARAM_DOUBLE_OUT("model_bw_out", "The bandwidth of the model."); + +static void mlpackMain() +{ + const string s = CLI::GetParam("string_in"); + const int i = CLI::GetParam("int_in"); + const double d = CLI::GetParam("double_in"); + + CLI::GetParam("string_out") = "wrong"; + CLI::GetParam("int_out") = 11; + CLI::GetParam("double_out") = 3.0; + + // Check that everything is right on the input, and then set output + // accordingly. + if (!CLI::HasParam("flag2") && CLI::HasParam("flag1")) + { + if (s == "hello") + CLI::GetParam("string_out") = "hello2"; + + if (i == 12) + CLI::GetParam("int_out") = 13; + + if (d == 4.0) + CLI::GetParam("double_out") = 5.0; + } + + // Input matrices should be at least 5 rows; the 5th row will be dropped and + // the 3rd row will be multiplied by two. + if (CLI::HasParam("matrix_in")) + { + arma::mat out = move(CLI::GetParam("matrix_in")); + out.shed_row(4); + out.row(2) *= 2.0; + + CLI::GetParam("matrix_out") = move(out); + } + + // Input matrices should be at least 5 rows; the 5th row will be dropped and + // the 3rd row will be multiplied by two. + if (CLI::HasParam("umatrix_in")) + { + arma::Mat out = + move(CLI::GetParam>("umatrix_in")); + out.shed_row(4); + out.row(2) *= 2; + + CLI::GetParam>("umatrix_out") = move(out); + } + + // An input column or row should have all elements multiplied by two. + if (CLI::HasParam("col_in")) + { + arma::vec out = move(CLI::GetParam("col_in")); + out *= 2.0; + + CLI::GetParam("col_out") = move(out); + } + + if (CLI::HasParam("ucol_in")) + { + arma::Col out = + move(CLI::GetParam>("ucol_in")); + out *= 2; + + CLI::GetParam>("ucol_out") = move(out); + } + + if (CLI::HasParam("row_in")) + { + arma::rowvec out = move(CLI::GetParam("row_in")); + out *= 2.0; + + CLI::GetParam("row_out") = move(out); + } + + if (CLI::HasParam("urow_in")) + { + arma::Row out = + move(CLI::GetParam>("urow_in")); + out *= 2; + + CLI::GetParam>("urow_out") = move(out); + } + + // Vector arguments should have the last element removed. + if (CLI::HasParam("vector_in")) + { + vector out = move(CLI::GetParam>("vector_in")); + out.pop_back(); + + CLI::GetParam>("vector_out") = move(out); + } + + if (CLI::HasParam("str_vector_in")) + { + vector out = move(CLI::GetParam>("str_vector_in")); + out.pop_back(); + + CLI::GetParam>("str_vector_out") = move(out); + } + + // All numeric elements should be multiplied by 3. + if (CLI::HasParam("matrix_and_info_in")) + { + typedef tuple TupleType; + TupleType tuple = move(CLI::GetParam("matrix_and_info_in")); + + const data::DatasetInfo& di = std::get<0>(tuple); + arma::mat& m = std::get<1>(tuple); + + for (size_t i = 0; i < m.n_rows; ++i) + { + if (di.Type(i) == data::Datatype::numeric) + m.row(i) *= 2.0; + } + + CLI::GetParam("matrix_and_info_out") = move(m); + } + + // If we got a request to build a model, then build it. + if (CLI::HasParam("build_model")) + { + CLI::GetParam("model_out") = new GaussianKernel(10.0); + } + + // If we got an input model, double the bandwidth and output that. + if (CLI::HasParam("model_in")) + { + CLI::GetParam("model_bw_out") = + CLI::GetParam("model_in")->Bandwidth() * 2.0; + } +} diff -Nru mlpack-3.2.2/src/mlpack/bindings/markdown/default_param.hpp mlpack-3.3.0/src/mlpack/bindings/markdown/default_param.hpp --- mlpack-3.2.2/src/mlpack/bindings/markdown/default_param.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/markdown/default_param.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -18,6 +18,7 @@ #include #include +#include namespace mlpack { namespace bindings { @@ -42,6 +43,16 @@ *((std::string*) output) = python::DefaultParamImpl::type>(data); } + else if (BindingInfo::Language() == "julia") + { + *((std::string*) output) = + julia::DefaultParamImpl::type>(data); + } + else + { + throw std::invalid_argument("DefaultParam(): unknown " + "BindingInfo::Language() " + BindingInfo::Language() + "!"); + } } } // namespace markdown diff -Nru mlpack-3.2.2/src/mlpack/bindings/markdown/get_binding_name.cpp mlpack-3.3.0/src/mlpack/bindings/markdown/get_binding_name.cpp --- mlpack-3.2.2/src/mlpack/bindings/markdown/get_binding_name.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/markdown/get_binding_name.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -32,6 +32,11 @@ // For Python bindings, the name is unchanged. return name; } + else if (language == "julia") + { + // For Julia bindings, the name is unchanged. + return name; + } else { throw std::invalid_argument("Don't know how to compute binding name for " diff -Nru mlpack-3.2.2/src/mlpack/bindings/markdown/get_printable_type.hpp mlpack-3.3.0/src/mlpack/bindings/markdown/get_printable_type.hpp --- mlpack-3.2.2/src/mlpack/bindings/markdown/get_printable_type.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/markdown/get_printable_type.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -17,6 +17,7 @@ #include #include +#include namespace mlpack { namespace bindings { @@ -41,6 +42,11 @@ *((std::string*) output) = python::GetPrintableType::type>(data); } + else if (BindingInfo::Language() == "julia") + { + *((std::string*) output) = + julia::GetPrintableType::type>(data); + } else { throw std::invalid_argument("GetPrintableType(): unknown " diff -Nru mlpack-3.2.2/src/mlpack/bindings/markdown/print_doc_functions_impl.hpp mlpack-3.3.0/src/mlpack/bindings/markdown/print_doc_functions_impl.hpp --- mlpack-3.2.2/src/mlpack/bindings/markdown/print_doc_functions_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/markdown/print_doc_functions_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -20,6 +20,7 @@ #include #include +#include namespace mlpack { namespace bindings { @@ -39,6 +40,10 @@ { return python::GetBindingName(bindingName); } + else if (BindingInfo::Language() == "julia") + { + return julia::GetBindingName(bindingName); + } else { throw std::invalid_argument("PrintValue(): unknown " @@ -59,6 +64,10 @@ { return "Python"; } + else if (language == "julia") + { + return "Julia"; + } else { throw std::invalid_argument("PrintLanguage(): unknown " @@ -79,6 +88,10 @@ { return python::PrintImport(bindingName); } + else if (BindingInfo::Language() == "julia") + { + return julia::PrintImport(bindingName); + } else { throw std::invalid_argument("PrintImport(): unknown " @@ -99,6 +112,10 @@ { return python::PrintOutputOptionInfo(); } + else if (BindingInfo::Language() == "julia") + { + return julia::PrintOutputOptionInfo(); + } else { throw std::invalid_argument("PrintOutputOptionInfo(): unknown " @@ -125,6 +142,8 @@ { std::string ret(str); std::replace(ret.begin(), ret.end(), ' ', '_'); + std::replace(ret.begin(), ret.end(), '{', '_'); + std::replace(ret.begin(), ret.end(), '}', '_'); return ret; } @@ -318,6 +337,10 @@ { result = python::PrintValue(value, quotes); } + else if (BindingInfo::Language() == "julia") + { + result = julia::PrintValue(value, quotes); + } else { throw std::invalid_argument("PrintValue(): unknown " @@ -353,6 +376,10 @@ { oss << python::PrintDefault(paramName); } + else if (BindingInfo::Language() == "julia") + { + oss << julia::PrintDefault(paramName); + } else { throw std::invalid_argument("PrintDefault: unknown " @@ -377,6 +404,10 @@ { result = python::PrintDataset(dataset); } + else if (BindingInfo::Language() == "julia") + { + result = julia::PrintDataset(dataset); + } else { throw std::invalid_argument("PrintDataset(): unknown " @@ -400,6 +431,10 @@ { result = python::PrintModel(model); } + else if (BindingInfo::Language() == "julia") + { + result = julia::PrintModel(model); + } else { throw std::invalid_argument("PrintModel(): unknown " @@ -416,23 +451,32 @@ template std::string ProgramCall(const std::string& programName, Args... args) { - std::string s = "```"; + std::string s; if (BindingInfo::Language() == "cli") { - s += "bash\n"; + s += "```bash\n"; s += cli::ProgramCall(programName, args...); } else if (BindingInfo::Language() == "python") { - s += "python\n"; + s += "```python\n"; s += python::ProgramCall(programName, args...); } + else if (BindingInfo::Language() == "julia") + { + // Julia's ProgramCall() with a set of arguments will automatically enclose + // the text in Markdown code, so we don't need to. + s += julia::ProgramCall(programName, args...); + } else { throw std::invalid_argument("ProgramCall(): unknown " "BindingInfo::Language(): " + BindingInfo::Language() + "!"); } - s += "\n```"; + + // Close the Markdown code block, but only if we opened one. + if (BindingInfo::Language() != "julia") + s += "\n```"; return s; } @@ -458,6 +502,14 @@ s += ">>> " + import + "\n"; s += python::ProgramCall(programName); } + else if (BindingInfo::Language() == "julia") + { + s += "julia\n"; + std::string import = PrintImport(programName); + if (import.size() > 0) + s += "julia> " + import + "\n"; + s += julia::ProgramCall(programName); + } else { throw std::invalid_argument("ProgramCall(): unknown " @@ -487,6 +539,10 @@ { s = python::ParamString(paramName); } + else if (BindingInfo::Language() == "julia") + { + s = julia::ParamString(paramName); + } else { throw std::invalid_argument("ParamString(): unknown " @@ -526,6 +582,10 @@ { return python::IgnoreCheck(t); } + else if (BindingInfo::Language() == "julia") + { + return julia::IgnoreCheck(t); + } else { throw std::invalid_argument("IgnoreCheck(): unknown " diff -Nru mlpack-3.2.2/src/mlpack/bindings/markdown/print_docs.cpp mlpack-3.3.0/src/mlpack/bindings/markdown/print_docs.cpp --- mlpack-3.2.2/src/mlpack/bindings/markdown/print_docs.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/markdown/print_docs.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -126,7 +126,8 @@ cout << "| "; cout << ParamString(it->second.name) << " | "; cout << ParamType(it->second) << " | "; - cout << it->second.desc; // just a string + string desc = boost::replace_all_copy(it->second.desc, "|", "\\|"); + cout << desc; // just a string // Print whether or not it's a "special" language-only parameter. if (it->second.name == "copy_all_inputs" || it->second.name == "help" || it->second.name == "info" || it->second.name == "version") @@ -180,7 +181,9 @@ cout << "{: #" << languages[i] << "_" << bindingName << "_detailed-documentation }" << endl; cout << endl; - cout << programDoc.documentation() << endl; + string doc = boost::replace_all_copy(programDoc.documentation(), + "|", "\\|"); + cout << doc << endl; cout << endl; cout << "### See also" << endl; diff -Nru mlpack-3.2.2/src/mlpack/bindings/markdown/print_type_doc.hpp mlpack-3.3.0/src/mlpack/bindings/markdown/print_type_doc.hpp --- mlpack-3.2.2/src/mlpack/bindings/markdown/print_type_doc.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/markdown/print_type_doc.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -17,6 +17,7 @@ #include #include +#include namespace mlpack { namespace bindings { @@ -37,6 +38,10 @@ { return python::PrintTypeDoc::type>(data); } + else if (BindingInfo::Language() == "julia") + { + return julia::PrintTypeDoc::type>(data); + } else { throw std::invalid_argument("PrintTypeDoc(): unknown " diff -Nru mlpack-3.2.2/src/mlpack/bindings/python/CMakeLists.txt mlpack-3.3.0/src/mlpack/bindings/python/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/bindings/python/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/python/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -215,8 +215,9 @@ -DGENERATE_CPP_OUT=${CMAKE_BINARY_DIR}/src/mlpack/bindings/python/generate_pyx_${name}.cpp -DPROGRAM_MAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/${name}_main.cpp -DPROGRAM_NAME=${name} - -P ${CMAKE_SOURCE_DIR}/CMake/ConfigureGeneratePYX.cmake - DEPENDS ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/python/generate_pyx.cpp.in) + -P ${CMAKE_SOURCE_DIR}/CMake/ConfigureGenerate.cmake + DEPENDS ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/python/generate_pyx.cpp.in + ${CMAKE_SOURCE_DIR}/CMake/ConfigureGenerate.cmake) add_executable(generate_pyx_${name} ${CMAKE_BINARY_DIR}/src/mlpack/bindings/python/generate_pyx_${name}.cpp diff -Nru mlpack-3.2.2/src/mlpack/bindings/python/ConfigureSetup.cmake mlpack-3.3.0/src/mlpack/bindings/python/ConfigureSetup.cmake --- mlpack-3.2.2/src/mlpack/bindings/python/ConfigureSetup.cmake 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/python/ConfigureSetup.cmake 2020-04-07 13:17:16.000000000 +0000 @@ -43,4 +43,4 @@ endif () endif () -configure_file("${SETUP_PY_IN}" "${SETUP_PY_OUT}") +configure_file(${SETUP_PY_IN} ${SETUP_PY_OUT}) diff -Nru mlpack-3.2.2/src/mlpack/bindings/python/setup.py.in mlpack-3.3.0/src/mlpack/bindings/python/setup.py.in --- mlpack-3.2.2/src/mlpack/bindings/python/setup.py.in 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/bindings/python/setup.py.in 2020-04-07 13:17:16.000000000 +0000 @@ -30,9 +30,12 @@ else: extra_link_args=['${OpenMP_CXX_FLAGS}'] -# Get list of library dirs. +# Get list of library dirs. Note that for the list of directories, any +# directories with a (valid) space in the name will be given to us as '\ '; so, +# in order to split these right, we first convert all spaces to ';', then +# convert '\;' back to ' ', then split on ';'. library_dirs = list(filter(None, ['${MLPACK_LIBDIR}'] + - '${Boost_LIBRARY_DIRS}'.split(' '))) + '${Boost_LIBRARY_DIRS}'.replace(' ', ';').replace('\;', ' ').split(' '))) # We'll link with the exact paths to each library using extra_objects, instead # of linking with 'libraries' and 'library_dirs', because of differences in @@ -73,7 +76,9 @@ include_dirs=[ \ np.get_include(), \ '${OUTPUT_DIR}/src/mlpack/bindings/python/'] + - '${CYTHON_INCLUDE_DIRECTORIES}'.split(' '), + '${CYTHON_INCLUDE_DIRECTORIES}'.replace(' ', ';') + .replace('\;', ' ') + .split(';'), library_dirs=library_dirs, # CMAKE_CXX_FLAGS seems to have an extra space. extra_compile_args=extra_args, @@ -89,7 +94,9 @@ include_dirs=[ \ np.get_include(), \ '${OUTPUT_DIR}/src/mlpack/bindings/python/'] + - '${CYTHON_INCLUDE_DIRECTORIES}'.split(' '), + '${CYTHON_INCLUDE_DIRECTORIES}'.replace(' ', ';') + .replace('\;', ' ') + .split(';'), library_dirs=library_dirs, # CMAKE_CXX_FLAGS seems to have an extra space. extra_compile_args=extra_args, diff -Nru mlpack-3.2.2/src/mlpack/CMakeLists.txt mlpack-3.3.0/src/mlpack/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -44,7 +44,7 @@ set_target_properties(mlpack PROPERTIES - VERSION 3.2 + VERSION 3.3 SOVERSION 3 ) @@ -122,19 +122,19 @@ PROPERTY INCLUDE_DIRECTORIES) add_custom_target(python_configure COMMAND ${CMAKE_COMMAND} - -D SETUP_PY_IN="${CMAKE_SOURCE_DIR}/src/mlpack/bindings/python/setup.py.in" - -D SETUP_PY_OUT="${CMAKE_BINARY_DIR}/src/mlpack/bindings/python/setup.py" + -D SETUP_PY_IN=${CMAKE_SOURCE_DIR}/src/mlpack/bindings/python/setup.py.in + -D SETUP_PY_OUT=${CMAKE_BINARY_DIR}/src/mlpack/bindings/python/setup.py -D PACKAGE_VERSION="${PACKAGE_VERSION}" -D Boost_SERIALIZATION_LIBRARY="${Boost_SERIALIZATION_LIBRARY_RELEASE}" -D Boost_LIBRARY_DIRS="${Boost_LIBRARY_DIRS}" -D ARMADILLO_LIBRARIES="${ARMADILLO_LIBRARIES}" - -D MLPACK_LIBRARY="$" - -D MLPACK_LIBDIR="$" + -D MLPACK_LIBRARY=$ + -D MLPACK_LIBDIR=$ -D MLPACK_PYXS="${MLPACK_PYXS}" -D OpenMP_CXX_FLAGS="${OpenMP_CXX_FLAGS}" -D DISABLE_CFLAGS="${DISABLE_CFLAGS}" -D CYTHON_INCLUDE_DIRECTORIES="${CYTHON_INCLUDE_DIRECTORIES}" - -D OUTPUT_DIR="${CMAKE_BINARY_DIR}" + -D OUTPUT_DIR=${CMAKE_BINARY_DIR} -P "${CMAKE_SOURCE_DIR}/src/mlpack/bindings/python/ConfigureSetup.cmake" BYPRODUCTS "${CMAKE_BINARY_DIR}/src/mlpack/bindings/python/setup.py" COMMENT "Configuring setup.py...") @@ -146,6 +146,14 @@ "__version__='${PACKAGE_VERSION}'\n") endif () +# If we are building Julia bindings, we have to end the 'module' declaration in +# mlpack.jl +if (BUILD_JULIA_BINDINGS) + file(APPEND + "${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/mlpack.jl" + "\nend\ninclude(\"functions.jl\")\nend\n") +endif () + # If we are building Markdown documentation, we have to run some setup after we # recurse into methods/. If not, this function is empty. post_markdown_setup() diff -Nru mlpack-3.2.2/src/mlpack/core/arma_extend/arma_extend.hpp mlpack-3.3.0/src/mlpack/core/arma_extend/arma_extend.hpp --- mlpack-3.2.2/src/mlpack/core/arma_extend/arma_extend.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/arma_extend/arma_extend.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -36,6 +36,12 @@ #endif #endif +// Force definition of old HDF5 API. Thanks to Mike Roberts for helping find +// this workaround. +#if !defined(H5_USE_110_API) + #define H5_USE_110_API +#endif + // Include everything we'll need for serialize(). #include #include diff -Nru mlpack-3.2.2/src/mlpack/core/arma_extend/Cube_extra_meat.hpp mlpack-3.3.0/src/mlpack/core/arma_extend/Cube_extra_meat.hpp --- mlpack-3.2.2/src/mlpack/core/arma_extend/Cube_extra_meat.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/arma_extend/Cube_extra_meat.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -19,6 +19,9 @@ // mem_state will always be 0 on load, so we don't need to save it. if (Archive::is_loading::value) { + // Clean any mat pointers. + delete_mat(); + // Don't free if local memory is being used. if (mem_state == 0 && mem != NULL && old_n_elem > arma_config::mat_prealloc) { diff -Nru mlpack-3.2.2/src/mlpack/core/boost_backport/boost_backport_math.hpp mlpack-3.3.0/src/mlpack/core/boost_backport/boost_backport_math.hpp --- mlpack-3.2.2/src/mlpack/core/boost_backport/boost_backport_math.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/boost_backport/boost_backport_math.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -/** - * @file boost_backport.hpp - * @author Yannis Mentekidis - * - * Centralized control of what boost files to include. We have backported the - * following boost functionality here: - * - * * trigamma and polygamma function evaluation (added in boost 1.58.0) - * - * For versions 1.56, 1.57 we include the backported polygamma and trigamma - * functions. Anything newer, we include from Boost. - */ -#ifndef MLPACK_CORE_BOOST_BACKPORT_MATH_HPP -#define MLPACK_CORE_BOOST_BACKPORT_MATH_HPP - -#include - -#if BOOST_VERSION < 105800 - // Backported trigamma and polygamma. - #include "mlpack/core/boost_backport/trigamma.hpp" - #include "mlpack/core/boost_backport/polygamma.hpp" -#else - // Boost's version. - #include - #include -#endif - -#endif // MLPACK_CORE_BOOST_BACKPORT_HPP - diff -Nru mlpack-3.2.2/src/mlpack/core/boost_backport/boost_backport_serialization.hpp mlpack-3.3.0/src/mlpack/core/boost_backport/boost_backport_serialization.hpp --- mlpack-3.2.2/src/mlpack/core/boost_backport/boost_backport_serialization.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/boost_backport/boost_backport_serialization.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -16,14 +16,7 @@ #define MLPACK_CORE_BOOST_BACKPORT_SERIALIZATION_HPP #include - -#if BOOST_VERSION < 105600 - // Backported unordered_map. - #include "mlpack/core/boost_backport/unordered_map.hpp" -#else - // Boost's version. - #include -#endif +#include #if BOOST_VERSION == 105800 /** diff -Nru mlpack-3.2.2/src/mlpack/core/boost_backport/boost_backport_string_view.hpp mlpack-3.3.0/src/mlpack/core/boost_backport/boost_backport_string_view.hpp --- mlpack-3.2.2/src/mlpack/core/boost_backport/boost_backport_string_view.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/boost_backport/boost_backport_string_view.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,43 @@ +/** + * @file boost_backport_string_view.hpp + * @author Jeffin Sam + * + * Centralized control of what boost files to include. We have backported the + * following boost functionality here: + * + * * string_view support (added in boost 1.61.0) + * * hash function support (added in boost 1.69.0) + * + * If the detected boost version is greater or equal to 1.61.0, we include the + * normal serialization functions (not the backported ones). For all older + * versions we include the backported headers. + */ +#ifndef MLPACK_CORE_BOOST_BACKPORT_STRING_VIEW_HPP +#define MLPACK_CORE_BOOST_BACKPORT_STRING_VIEW_HPP + +#include +#include + +#if BOOST_VERSION < 106100 + // Backported unordered_map. + #include "mlpack/core/boost_backport/string_view.hpp" +#else + // Boost's version. + #include +#endif + +#if BOOST_VERSION < 106900 + namespace boost + { + template<> + struct hash + { + std::size_t operator()(boost::string_view str) const + { + return boost::hash_range(str.begin(), str.end()); + } + }; + } +#endif + +#endif // MLPACK_CORE_BOOST_BACKPORT_STRING_VIEW_HPP diff -Nru mlpack-3.2.2/src/mlpack/core/boost_backport/CMakeLists.txt mlpack-3.3.0/src/mlpack/core/boost_backport/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/core/boost_backport/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/boost_backport/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -2,21 +2,20 @@ # Anything not in this list will not be compiled into mlpack. set(SOURCES bernoulli.hpp - boost_backport_math.hpp boost_backport_serialization.hpp detail/bernoulli_details.hpp detail/polygamma.hpp detail/unchecked_bernoulli.hpp math_fwd.hpp policy.hpp - polygamma.hpp - trigamma.hpp unordered_collections_load_imp.hpp unordered_collections_save_imp.hpp - unordered_map.hpp vector.hpp + string_view.hpp + string_view_fwd.hpp collections_load_imp.hpp collections_save_imp.hpp + boost_backport_string_view.hpp ) # add directory name to sources diff -Nru mlpack-3.2.2/src/mlpack/core/boost_backport/polygamma.hpp mlpack-3.3.0/src/mlpack/core/boost_backport/polygamma.hpp --- mlpack-3.2.2/src/mlpack/core/boost_backport/polygamma.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/boost_backport/polygamma.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ - -/////////////////////////////////////////////////////////////////////////////// -// Copyright 2013 Nikhar Agrawal -// Copyright 2013 Christopher Kormanyos -// Copyright 2014 John Maddock -// Copyright 2013 Paul Bristow -// Distributed under the Boost -// Software License, Version 1.0. (See accompanying file -// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#ifndef _BOOST_POLYGAMMA_2013_07_30_HPP_ - #define _BOOST_POLYGAMMA_2013_07_30_HPP_ - -#include "detail/polygamma.hpp" -#include "trigamma.hpp" -#include - -// Forward declarations -namespace boost { namespace math { - template - inline typename tools::promote_args::type - trigamma(T x, const Policy&); - - template - inline typename tools::promote_args::type - trigamma(T x); -}} - -namespace boost { namespace math { - - - template - inline typename tools::promote_args::type polygamma(const int n, T x, const Policy& pol) - { - // - // Filter off special cases right at the start: - // - if(n == 0) - return boost::math::digamma(x, pol); - if(n == 1) - return boost::math::trigamma(x, pol); - // - // We've found some standard library functions to misbehave if any FPU exception flags - // are set prior to their call, this code will clear those flags, then reset them - // on exit: - // - BOOST_FPU_EXCEPTION_GUARD - // - // The type of the result - the common type of T and U after - // any integer types have been promoted to double: - // - typedef typename tools::promote_args::type result_type; - // - // The type used for the calculation. This may be a wider type than - // the result in order to ensure full precision: - // - typedef typename policies::evaluation::type value_type; - // - // The type of the policy to forward to the actual implementation. - // We disable promotion of float and double as that's [possibly] - // happened already in the line above. Also reset to the default - // any policies we don't use (reduces code bloat if we're called - // multiple times with differing policies we don't actually use). - // Also normalise the type, again to reduce code bloat in case we're - // called multiple times with functionally identical policies that happen - // to be different types. - // - typedef typename policies::normalise< - Policy, - policies::promote_float, - policies::promote_double, - policies::discrete_quantile<>, - policies::assert_undefined<> >::type forwarding_policy; - // - // Whew. Now we can make the actual call to the implementation. - // Arguments are explicitly cast to the evaluation type, and the result - // passed through checked_narrowing_cast which handles things like overflow - // according to the policy passed: - // - return policies::checked_narrowing_cast( - detail::polygamma_imp(n, static_cast(x), forwarding_policy()), - "boost::math::polygamma<%1%>(int, %1%)"); - } - - template - inline typename tools::promote_args::type polygamma(const int n, T x) - { - return boost::math::polygamma(n, x, policies::policy<>()); - } - -} } // namespace boost::math - -#endif // _BOOST_BERNOULLI_2013_05_30_HPP_ - diff -Nru mlpack-3.2.2/src/mlpack/core/boost_backport/string_view_fwd.hpp mlpack-3.3.0/src/mlpack/core/boost_backport/string_view_fwd.hpp --- mlpack-3.2.2/src/mlpack/core/boost_backport/string_view_fwd.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/boost_backport/string_view_fwd.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,39 @@ +/* + Copyright (c) Marshall Clow 2012-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + For more information, see http://www.boost.org + + Based on the StringRef implementation in LLVM (http://llvm.org) and + N3422 by Jeffrey Yasskin + http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html + Updated July 2015 to reflect the Library Fundamentals TS + http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4480.html + +*/ + +#ifndef BOOST_STRING_VIEW_FWD_HPP +#define BOOST_STRING_VIEW_FWD_HPP + +#include +#include + +namespace boost { + + template > class basic_string_view; + typedef basic_string_view > string_view; + typedef basic_string_view > wstring_view; + +#ifndef BOOST_NO_CXX11_CHAR16_T + typedef basic_string_view > u16string_view; +#endif + +#ifndef BOOST_NO_CXX11_CHAR32_T + typedef basic_string_view > u32string_view; +#endif + +} + +#endif \ No newline at end of file diff -Nru mlpack-3.2.2/src/mlpack/core/boost_backport/string_view.hpp mlpack-3.3.0/src/mlpack/core/boost_backport/string_view.hpp --- mlpack-3.2.2/src/mlpack/core/boost_backport/string_view.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/boost_backport/string_view.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,698 @@ +/* + Copyright (c) Marshall Clow 2012-2015. + Copyright (c) Beman Dawes 2015 + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + For more information, see http://www.boost.org + + Based on the StringRef implementation in LLVM (http://llvm.org) and + N3422 by Jeffrey Yasskin + http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html + Updated July 2015 to reflect the Library Fundamentals TS + http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4480.html +*/ + +#ifndef BOOST_STRING_VIEW_HPP +#define BOOST_STRING_VIEW_HPP + +#include +#include +#include +#include + +#if BOOST_VERSION < 106100 + // Backported unordered_map. + #include "mlpack/core/boost_backport/string_view_fwd.hpp" +#else + // Boost's version. + #include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || (defined(BOOST_GCC) && ((BOOST_GCC+0) / 100) <= 406) +// GCC 4.6 cannot handle a defaulted function with noexcept specifier +#define BOOST_STRING_VIEW_NO_CXX11_DEFAULTED_NOEXCEPT_FUNCTIONS +#endif + +namespace boost { + + namespace detail { + // A helper functor because sometimes we don't have lambdas + template + class string_view_traits_eq { + public: + string_view_traits_eq ( charT ch ) : ch_(ch) {} + bool operator()( charT val ) const { return traits::eq (ch_, val); } + charT ch_; + }; + } + + template // traits defaulted in string_view_fwd.hpp + class basic_string_view { + public: + // types + typedef traits traits_type; + typedef charT value_type; + typedef charT* pointer; + typedef const charT* const_pointer; + typedef charT& reference; + typedef const charT& const_reference; + typedef const_pointer const_iterator; // impl-defined + typedef const_iterator iterator; + typedef std::reverse_iterator const_reverse_iterator; + typedef const_reverse_iterator reverse_iterator; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + static BOOST_CONSTEXPR_OR_CONST size_type npos = size_type(-1); + + // construct/copy + BOOST_CONSTEXPR basic_string_view() BOOST_NOEXCEPT + : ptr_(NULL), len_(0) {} + + // by defaulting these functions, basic_string_ref becomes + // trivially copy/move constructible. + BOOST_CONSTEXPR basic_string_view(const basic_string_view &rhs) BOOST_NOEXCEPT +#ifndef BOOST_STRING_VIEW_NO_CXX11_DEFAULTED_NOEXCEPT_FUNCTIONS + = default; +#else + : ptr_(rhs.ptr_), len_(rhs.len_) {} +#endif + + basic_string_view& operator=(const basic_string_view &rhs) BOOST_NOEXCEPT +#ifndef BOOST_STRING_VIEW_NO_CXX11_DEFAULTED_NOEXCEPT_FUNCTIONS + = default; +#else + { + ptr_ = rhs.ptr_; + len_ = rhs.len_; + return *this; + } +#endif + + template + basic_string_view(const std::basic_string& str) BOOST_NOEXCEPT + : ptr_(str.data()), len_(str.length()) {} + +// #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) +// // Constructing a string_view from a temporary string is a bad idea +// template +// basic_string_view( std::basic_string&&) +// = delete; +// #endif + + BOOST_CONSTEXPR basic_string_view(const charT* str) + : ptr_(str), len_(traits::length(str)) {} + + BOOST_CONSTEXPR basic_string_view(const charT* str, size_type len) + : ptr_(str), len_(len) {} + + // iterators + BOOST_CONSTEXPR const_iterator begin() const BOOST_NOEXCEPT { return ptr_; } + BOOST_CONSTEXPR const_iterator cbegin() const BOOST_NOEXCEPT { return ptr_; } + BOOST_CONSTEXPR const_iterator end() const BOOST_NOEXCEPT { return ptr_ + len_; } + BOOST_CONSTEXPR const_iterator cend() const BOOST_NOEXCEPT { return ptr_ + len_; } + const_reverse_iterator rbegin() const BOOST_NOEXCEPT { return const_reverse_iterator(end()); } + const_reverse_iterator crbegin() const BOOST_NOEXCEPT { return const_reverse_iterator(end()); } + const_reverse_iterator rend() const BOOST_NOEXCEPT { return const_reverse_iterator(begin()); } + const_reverse_iterator crend() const BOOST_NOEXCEPT { return const_reverse_iterator(begin()); } + + // capacity + BOOST_CONSTEXPR size_type size() const BOOST_NOEXCEPT { return len_; } + BOOST_CONSTEXPR size_type length() const BOOST_NOEXCEPT { return len_; } + BOOST_CONSTEXPR size_type max_size() const BOOST_NOEXCEPT { return len_; } + BOOST_CONSTEXPR bool empty() const BOOST_NOEXCEPT { return len_ == 0; } + + // element access + BOOST_CONSTEXPR const_reference operator[](size_type pos) const BOOST_NOEXCEPT { return ptr_[pos]; } + + BOOST_CONSTEXPR const_reference at(size_t pos) const { + return pos >= len_ ? BOOST_THROW_EXCEPTION(std::out_of_range("boost::string_view::at")), ptr_[0] : ptr_[pos]; + } + + BOOST_CONSTEXPR const_reference front() const { return ptr_[0]; } + BOOST_CONSTEXPR const_reference back() const { return ptr_[len_-1]; } + BOOST_CONSTEXPR const_pointer data() const BOOST_NOEXCEPT { return ptr_; } + + // modifiers + void clear() BOOST_NOEXCEPT { len_ = 0; } // Boost extension + + BOOST_CXX14_CONSTEXPR void remove_prefix(size_type n) { + if ( n > len_ ) + n = len_; + ptr_ += n; + len_ -= n; + } + + BOOST_CXX14_CONSTEXPR void remove_suffix(size_type n) { + if ( n > len_ ) + n = len_; + len_ -= n; + } + + BOOST_CXX14_CONSTEXPR void swap(basic_string_view& s) BOOST_NOEXCEPT { + std::swap(ptr_, s.ptr_); + std::swap(len_, s.len_); + } + + // basic_string_view string operations +#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS + template + explicit operator std::basic_string() const { + return std::basic_string(begin(), end()); + } +#endif + +#ifndef BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS + template > + std::basic_string to_string(const Allocator& a = Allocator()) const { + return std::basic_string(begin(), end(), a); + } +#else + std::basic_string to_string() const { + return std::basic_string(begin(), end()); + } + + template + std::basic_string to_string(const Allocator& a) const { + return std::basic_string(begin(), end(), a); + } +#endif + + size_type copy(charT* s, size_type n, size_type pos=0) const { + if (pos > size()) + BOOST_THROW_EXCEPTION(std::out_of_range("string_view::copy" )); + size_type rlen = (std::min)(n, len_ - pos); + traits_type::copy(s, data() + pos, rlen); + return rlen; + } + + BOOST_CXX14_CONSTEXPR basic_string_view substr(size_type pos, size_type n=npos) const { + if ( pos > size()) + BOOST_THROW_EXCEPTION( std::out_of_range ( "string_view::substr" ) ); + return basic_string_view(data() + pos, (std::min)(size() - pos, n)); + } + + BOOST_CXX14_CONSTEXPR int compare(basic_string_view x) const BOOST_NOEXCEPT { + const int cmp = traits::compare(ptr_, x.ptr_, (std::min)(len_, x.len_)); + return cmp != 0 ? cmp : (len_ == x.len_ ? 0 : len_ < x.len_ ? -1 : 1); + } + + BOOST_CXX14_CONSTEXPR int compare(size_type pos1, size_type n1, basic_string_view x) + const BOOST_NOEXCEPT { + return substr(pos1, n1).compare(x); + } + + BOOST_CXX14_CONSTEXPR int compare(size_type pos1, size_type n1, + basic_string_view x, size_type pos2, size_type n2) const { + return substr(pos1, n1).compare(x.substr(pos2, n2)); + } + + BOOST_CXX14_CONSTEXPR int compare(const charT* x) const { + return compare(basic_string_view(x)); + } + + BOOST_CXX14_CONSTEXPR int compare(size_type pos1, size_type n1, const charT* x) const { + return substr(pos1, n1).compare(basic_string_view(x)); + } + + BOOST_CXX14_CONSTEXPR int compare(size_type pos1, size_type n1, + const charT* x, size_type n2) const { + return substr(pos1, n1).compare(basic_string_view(x, n2)); + } + + // Searches + BOOST_CONSTEXPR bool starts_with(charT c) const BOOST_NOEXCEPT { // Boost extension + return !empty() && traits::eq(c, front()); + } + + BOOST_CONSTEXPR bool starts_with(basic_string_view x) const BOOST_NOEXCEPT { // Boost extension + return len_ >= x.len_ && traits::compare(ptr_, x.ptr_, x.len_) == 0; + } + + BOOST_CONSTEXPR bool ends_with(charT c) const BOOST_NOEXCEPT { // Boost extension + return !empty() && traits::eq(c, back()); + } + + BOOST_CONSTEXPR bool ends_with(basic_string_view x) const BOOST_NOEXCEPT { // Boost extension + return len_ >= x.len_ && + traits::compare(ptr_ + len_ - x.len_, x.ptr_, x.len_) == 0; + } + + // find + BOOST_CXX14_CONSTEXPR size_type find(basic_string_view s, size_type pos = 0) const BOOST_NOEXCEPT { + if (pos > size()) + return npos; + if (s.empty()) + return pos; + const_iterator iter = std::search(this->cbegin() + pos, this->cend(), + s.cbegin (), s.cend (), traits::eq); + return iter == this->cend () ? npos : std::distance(this->cbegin (), iter); + } + BOOST_CXX14_CONSTEXPR size_type find(charT c, size_type pos = 0) const BOOST_NOEXCEPT + { return find(basic_string_view(&c, 1), pos); } + BOOST_CXX14_CONSTEXPR size_type find(const charT* s, size_type pos, size_type n) const BOOST_NOEXCEPT + { return find(basic_string_view(s, n), pos); } + BOOST_CXX14_CONSTEXPR size_type find(const charT* s, size_type pos = 0) const BOOST_NOEXCEPT + { return find(basic_string_view(s), pos); } + + // rfind + BOOST_CXX14_CONSTEXPR size_type rfind(basic_string_view s, size_type pos = npos) const BOOST_NOEXCEPT { + if (len_ < s.len_) + return npos; + if (pos > len_ - s.len_) + pos = len_ - s.len_; + if (s.len_ == 0u) // an empty string is always found + return pos; + for (const charT* cur = ptr_ + pos; ; --cur) { + if (traits::compare(cur, s.ptr_, s.len_) == 0) + return cur - ptr_; + if (cur == ptr_) + return npos; + }; + } + BOOST_CXX14_CONSTEXPR size_type rfind(charT c, size_type pos = npos) const BOOST_NOEXCEPT + { return rfind(basic_string_view(&c, 1), pos); } + BOOST_CXX14_CONSTEXPR size_type rfind(const charT* s, size_type pos, size_type n) const BOOST_NOEXCEPT + { return rfind(basic_string_view(s, n), pos); } + BOOST_CXX14_CONSTEXPR size_type rfind(const charT* s, size_type pos = npos) const BOOST_NOEXCEPT + { return rfind(basic_string_view(s), pos); } + + // find_first_of + BOOST_CXX14_CONSTEXPR size_type find_first_of(basic_string_view s, size_type pos = 0) const BOOST_NOEXCEPT { + if (pos >= len_ || s.len_ == 0) + return npos; + const_iterator iter = std::find_first_of + (this->cbegin () + pos, this->cend (), s.cbegin (), s.cend (), traits::eq); + return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); + } + BOOST_CXX14_CONSTEXPR size_type find_first_of(charT c, size_type pos = 0) const BOOST_NOEXCEPT + { return find_first_of(basic_string_view(&c, 1), pos); } + BOOST_CXX14_CONSTEXPR size_type find_first_of(const charT* s, size_type pos, size_type n) const BOOST_NOEXCEPT + { return find_first_of(basic_string_view(s, n), pos); } + BOOST_CXX14_CONSTEXPR size_type find_first_of(const charT* s, size_type pos = 0) const BOOST_NOEXCEPT + { return find_first_of(basic_string_view(s), pos); } + + // find_last_of + BOOST_CXX14_CONSTEXPR size_type find_last_of(basic_string_view s, size_type pos = npos) const BOOST_NOEXCEPT { + if (s.len_ == 0u) + return npos; + if (pos >= len_) + pos = 0; + else + pos = len_ - (pos+1); + const_reverse_iterator iter = std::find_first_of + ( this->crbegin () + pos, this->crend (), s.cbegin (), s.cend (), traits::eq ); + return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter); + } + BOOST_CXX14_CONSTEXPR size_type find_last_of(charT c, size_type pos = npos) const BOOST_NOEXCEPT + { return find_last_of(basic_string_view(&c, 1), pos); } + BOOST_CXX14_CONSTEXPR size_type find_last_of(const charT* s, size_type pos, size_type n) const BOOST_NOEXCEPT + { return find_last_of(basic_string_view(s, n), pos); } + BOOST_CXX14_CONSTEXPR size_type find_last_of(const charT* s, size_type pos = npos) const BOOST_NOEXCEPT + { return find_last_of(basic_string_view(s), pos); } + + // find_first_not_of + BOOST_CXX14_CONSTEXPR size_type find_first_not_of(basic_string_view s, size_type pos = 0) const BOOST_NOEXCEPT { + if (pos >= len_) + return npos; + if (s.len_ == 0) + return pos; + const_iterator iter = find_not_of ( this->cbegin () + pos, this->cend (), s ); + return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); + } + BOOST_CXX14_CONSTEXPR size_type find_first_not_of(charT c, size_type pos = 0) const BOOST_NOEXCEPT + { return find_first_not_of(basic_string_view(&c, 1), pos); } + BOOST_CXX14_CONSTEXPR size_type find_first_not_of(const charT* s, size_type pos, size_type n) const BOOST_NOEXCEPT + { return find_first_not_of(basic_string_view(s, n), pos); } + BOOST_CXX14_CONSTEXPR size_type find_first_not_of(const charT* s, size_type pos = 0) const BOOST_NOEXCEPT + { return find_first_not_of(basic_string_view(s), pos); } + + // find_last_not_of + BOOST_CXX14_CONSTEXPR size_type find_last_not_of(basic_string_view s, size_type pos = npos) const BOOST_NOEXCEPT { + if (pos >= len_) + pos = len_ - 1; + if (s.len_ == 0u) + return pos; + pos = len_ - (pos+1); + const_reverse_iterator iter = find_not_of ( this->crbegin () + pos, this->crend (), s ); + return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter ); + } + BOOST_CXX14_CONSTEXPR size_type find_last_not_of(charT c, size_type pos = npos) const BOOST_NOEXCEPT + { return find_last_not_of(basic_string_view(&c, 1), pos); } + BOOST_CXX14_CONSTEXPR size_type find_last_not_of(const charT* s, size_type pos, size_type n) const BOOST_NOEXCEPT + { return find_last_not_of(basic_string_view(s, n), pos); } + BOOST_CXX14_CONSTEXPR size_type find_last_not_of(const charT* s, size_type pos = npos) const BOOST_NOEXCEPT + { return find_last_not_of(basic_string_view(s), pos); } + + private: + template + size_type reverse_distance(r_iter first, r_iter last) const BOOST_NOEXCEPT { + // Portability note here: std::distance is not NOEXCEPT, but calling it with a string_view::reverse_iterator will not throw. + return len_ - 1 - std::distance ( first, last ); + } + + template + Iterator find_not_of(Iterator first, Iterator last, basic_string_view s) const BOOST_NOEXCEPT { + for (; first != last ; ++first) + if ( 0 == traits::find(s.ptr_, s.len_, *first)) + return first; + return last; + } + + const charT *ptr_; + std::size_t len_; + }; + + +// Comparison operators +// Equality + template + inline bool operator==(basic_string_view x, + basic_string_view y) BOOST_NOEXCEPT { + if (x.size () != y.size ()) return false; + return x.compare(y) == 0; + } + +// Inequality + template + inline bool operator!=(basic_string_view x, + basic_string_view y) BOOST_NOEXCEPT { + if ( x.size () != y.size ()) return true; + return x.compare(y) != 0; + } + +// Less than + template + inline bool operator<(basic_string_view x, + basic_string_view y) BOOST_NOEXCEPT { + return x.compare(y) < 0; + } + +// Greater than + template + inline bool operator>(basic_string_view x, + basic_string_view y) BOOST_NOEXCEPT { + return x.compare(y) > 0; + } + +// Less than or equal to + template + inline bool operator<=(basic_string_view x, + basic_string_view y) BOOST_NOEXCEPT { + return x.compare(y) <= 0; + } + +// Greater than or equal to + template + inline bool operator>=(basic_string_view x, + basic_string_view y) BOOST_NOEXCEPT { + return x.compare(y) >= 0; + } + +// "sufficient additional overloads of comparison functions" + template + inline bool operator==(basic_string_view x, + const std::basic_string & y) BOOST_NOEXCEPT { + return x == basic_string_view(y); + } + + template + inline bool operator==(const std::basic_string & x, + basic_string_view y) BOOST_NOEXCEPT { + return basic_string_view(x) == y; + } + + template + inline bool operator==(basic_string_view x, + const charT * y) BOOST_NOEXCEPT { + return x == basic_string_view(y); + } + + template + inline bool operator==(const charT * x, + basic_string_view y) BOOST_NOEXCEPT { + return basic_string_view(x) == y; + } + + template + inline bool operator!=(basic_string_view x, + const std::basic_string & y) BOOST_NOEXCEPT { + return x != basic_string_view(y); + } + + template + inline bool operator!=(const std::basic_string & x, + basic_string_view y) BOOST_NOEXCEPT { + return basic_string_view(x) != y; + } + + template + inline bool operator!=(basic_string_view x, + const charT * y) BOOST_NOEXCEPT { + return x != basic_string_view(y); + } + + template + inline bool operator!=(const charT * x, + basic_string_view y) BOOST_NOEXCEPT { + return basic_string_view(x) != y; + } + + template + inline bool operator<(basic_string_view x, + const std::basic_string & y) BOOST_NOEXCEPT { + return x < basic_string_view(y); + } + + template + inline bool operator<(const std::basic_string & x, + basic_string_view y) BOOST_NOEXCEPT { + return basic_string_view(x) < y; + } + + template + inline bool operator<(basic_string_view x, + const charT * y) BOOST_NOEXCEPT { + return x < basic_string_view(y); + } + + template + inline bool operator<(const charT * x, + basic_string_view y) BOOST_NOEXCEPT { + return basic_string_view(x) < y; + } + + template + inline bool operator>(basic_string_view x, + const std::basic_string & y) BOOST_NOEXCEPT { + return x > basic_string_view(y); + } + + template + inline bool operator>(const std::basic_string & x, + basic_string_view y) BOOST_NOEXCEPT { + return basic_string_view(x) > y; + } + + template + inline bool operator>(basic_string_view x, + const charT * y) BOOST_NOEXCEPT { + return x > basic_string_view(y); + } + + template + inline bool operator>(const charT * x, + basic_string_view y) BOOST_NOEXCEPT { + return basic_string_view(x) > y; + } + + template + inline bool operator<=(basic_string_view x, + const std::basic_string & y) BOOST_NOEXCEPT { + return x <= basic_string_view(y); + } + + template + inline bool operator<=(const std::basic_string & x, + basic_string_view y) BOOST_NOEXCEPT { + return basic_string_view(x) <= y; + } + + template + inline bool operator<=(basic_string_view x, + const charT * y) BOOST_NOEXCEPT { + return x <= basic_string_view(y); + } + + template + inline bool operator<=(const charT * x, + basic_string_view y) BOOST_NOEXCEPT { + return basic_string_view(x) <= y; + } + + template + inline bool operator>=(basic_string_view x, + const std::basic_string & y) BOOST_NOEXCEPT { + return x >= basic_string_view(y); + } + + template + inline bool operator>=(const std::basic_string & x, + basic_string_view y) BOOST_NOEXCEPT { + return basic_string_view(x) >= y; + } + + template + inline bool operator>=(basic_string_view x, + const charT * y) BOOST_NOEXCEPT { + return x >= basic_string_view(y); + } + + template + inline bool operator>=(const charT * x, + basic_string_view y) BOOST_NOEXCEPT { + return basic_string_view(x) >= y; + } + + namespace detail { + + template + inline void sv_insert_fill_chars(std::basic_ostream& os, std::size_t n) { + enum { chunk_size = 8 }; + charT fill_chars[chunk_size]; + std::fill_n(fill_chars, static_cast< std::size_t >(chunk_size), os.fill()); + for (; n >= chunk_size && os.good(); n -= chunk_size) + os.write(fill_chars, static_cast< std::size_t >(chunk_size)); + if (n > 0 && os.good()) + os.write(fill_chars, n); + } + + template + void sv_insert_aligned(std::basic_ostream& os, const basic_string_view& str) { + const std::size_t size = str.size(); + const std::size_t alignment_size = static_cast< std::size_t >(os.width()) - size; + const bool align_left = (os.flags() & std::basic_ostream::adjustfield) == std::basic_ostream::left; + if (!align_left) { + detail::sv_insert_fill_chars(os, alignment_size); + if (os.good()) + os.write(str.data(), size); + } + else { + os.write(str.data(), size); + if (os.good()) + detail::sv_insert_fill_chars(os, alignment_size); + } + } + + } // namespace detail + + // Inserter + template + inline std::basic_ostream& + operator<<(std::basic_ostream& os, + const basic_string_view& str) { + if (os.good()) { + const std::size_t size = str.size(); + const std::size_t w = static_cast< std::size_t >(os.width()); + if (w <= size) + os.write(str.data(), size); + else + detail::sv_insert_aligned(os, str); + os.width(0); + } + return os; + } + +#if 0 + // numeric conversions + // + // These are short-term implementations. + // In a production environment, I would rather avoid the copying. + // + inline int stoi (string_view str, size_t* idx=0, int base=10) { + return std::stoi ( std::string(str), idx, base ); + } + + inline long stol (string_view str, size_t* idx=0, int base=10) { + return std::stol ( std::string(str), idx, base ); + } + + inline unsigned long stoul (string_view str, size_t* idx=0, int base=10) { + return std::stoul ( std::string(str), idx, base ); + } + + inline long long stoll (string_view str, size_t* idx=0, int base=10) { + return std::stoll ( std::string(str), idx, base ); + } + + inline unsigned long long stoull (string_view str, size_t* idx=0, int base=10) { + return std::stoull ( std::string(str), idx, base ); + } + + inline float stof (string_view str, size_t* idx=0) { + return std::stof ( std::string(str), idx ); + } + + inline double stod (string_view str, size_t* idx=0) { + return std::stod ( std::string(str), idx ); + } + + inline long double stold (string_view str, size_t* idx=0) { + return std::stold ( std::string(str), idx ); + } + + inline int stoi (wstring_view str, size_t* idx=0, int base=10) { + return std::stoi ( std::wstring(str), idx, base ); + } + + inline long stol (wstring_view str, size_t* idx=0, int base=10) { + return std::stol ( std::wstring(str), idx, base ); + } + + inline unsigned long stoul (wstring_view str, size_t* idx=0, int base=10) { + return std::stoul ( std::wstring(str), idx, base ); + } + + inline long long stoll (wstring_view str, size_t* idx=0, int base=10) { + return std::stoll ( std::wstring(str), idx, base ); + } + + inline unsigned long long stoull (wstring_view str, size_t* idx=0, int base=10) { + return std::stoull ( std::wstring(str), idx, base ); + } + + inline float stof (wstring_view str, size_t* idx=0) { + return std::stof ( std::wstring(str), idx ); + } + + inline double stod (wstring_view str, size_t* idx=0) { + return std::stod ( std::wstring(str), idx ); + } + + inline long double stold (wstring_view str, size_t* idx=0) { + return std::stold ( std::wstring(str), idx ); + } +#endif + +} + +#if 0 +namespace std { + // Hashing + template<> struct hash; + template<> struct hash; + template<> struct hash; + template<> struct hash; +} +#endif + +#endif diff -Nru mlpack-3.2.2/src/mlpack/core/boost_backport/trigamma.hpp mlpack-3.3.0/src/mlpack/core/boost_backport/trigamma.hpp --- mlpack-3.2.2/src/mlpack/core/boost_backport/trigamma.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/boost_backport/trigamma.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,469 +0,0 @@ -// (C) Copyright John Maddock 2006. -// Use, modification and distribution are subject to the -// Boost Software License, Version 1.0. (See accompanying file -// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_MATH_SF_TRIGAMMA_HPP -#define BOOST_MATH_SF_TRIGAMMA_HPP - -#ifdef _MSC_VER -#pragma once -#endif - -#include "math_fwd.hpp" -#include "polygamma.hpp" -#include -#include -#include -#include -#include -#include -#include - -namespace boost{ -namespace math{ -namespace detail{ - -template -T polygamma_imp(const int n, T x, const Policy &pol); - -template -T trigamma_prec(T x, const mpl::int_<53>*, const Policy&) -{ - // Max error in interpolated form: 3.736e-017 - static const T offset = BOOST_MATH_BIG_CONSTANT(T, 53, 2.1093254089355469); - static const T P_1_2[] = { - BOOST_MATH_BIG_CONSTANT(T, 53, -1.1093280605946045), - BOOST_MATH_BIG_CONSTANT(T, 53, -3.8310674472619321), - BOOST_MATH_BIG_CONSTANT(T, 53, -3.3703848401898283), - BOOST_MATH_BIG_CONSTANT(T, 53, 0.28080574467981213), - BOOST_MATH_BIG_CONSTANT(T, 53, 1.6638069578676164), - BOOST_MATH_BIG_CONSTANT(T, 53, 0.64468386819102836), - }; - static const T Q_1_2[] = { - BOOST_MATH_BIG_CONSTANT(T, 53, 1.0), - BOOST_MATH_BIG_CONSTANT(T, 53, 3.4535389668541151), - BOOST_MATH_BIG_CONSTANT(T, 53, 4.5208926987851437), - BOOST_MATH_BIG_CONSTANT(T, 53, 2.7012734178351534), - BOOST_MATH_BIG_CONSTANT(T, 53, 0.64468798399785611), - BOOST_MATH_BIG_CONSTANT(T, 53, -0.20314516859987728e-6), - }; - // Max error in interpolated form: 1.159e-017 - static const T P_2_4[] = { - BOOST_MATH_BIG_CONSTANT(T, 53, -0.13803835004508849e-7), - BOOST_MATH_BIG_CONSTANT(T, 53, 0.50000049158540261), - BOOST_MATH_BIG_CONSTANT(T, 53, 1.6077979838469348), - BOOST_MATH_BIG_CONSTANT(T, 53, 2.5645435828098254), - BOOST_MATH_BIG_CONSTANT(T, 53, 2.0534873203680393), - BOOST_MATH_BIG_CONSTANT(T, 53, 0.74566981111565923), - }; - static const T Q_2_4[] = { - BOOST_MATH_BIG_CONSTANT(T, 53, 1.0), - BOOST_MATH_BIG_CONSTANT(T, 53, 2.8822787662376169), - BOOST_MATH_BIG_CONSTANT(T, 53, 4.1681660554090917), - BOOST_MATH_BIG_CONSTANT(T, 53, 2.7853527819234466), - BOOST_MATH_BIG_CONSTANT(T, 53, 0.74967671848044792), - BOOST_MATH_BIG_CONSTANT(T, 53, -0.00057069112416246805), - }; - // Maximum Deviation Found: 6.896e-018 - // Expected Error Term : -6.895e-018 - // Maximum Relative Change in Control Points : 8.497e-004 - static const T P_4_inf[] = { - static_cast(0.68947581948701249e-17L), - static_cast(0.49999999999998975L), - static_cast(1.0177274392923795L), - static_cast(2.498208511343429L), - static_cast(2.1921221359427595L), - static_cast(1.5897035272532764L), - static_cast(0.40154388356961734L), - }; - static const T Q_4_inf[] = { - static_cast(1.0L), - static_cast(1.7021215452463932L), - static_cast(4.4290431747556469L), - static_cast(2.9745631894384922L), - static_cast(2.3013614809773616L), - static_cast(0.28360399799075752L), - static_cast(0.022892987908906897L), - }; - - if(x <= 2) - { - return (offset + boost::math::tools::evaluate_polynomial(P_1_2, x) / tools::evaluate_polynomial(Q_1_2, x)) / (x * x); - } - else if(x <= 4) - { - T y = 1 / x; - return (1 + tools::evaluate_polynomial(P_2_4, y) / tools::evaluate_polynomial(Q_2_4, y)) / x; - } - T y = 1 / x; - return (1 + tools::evaluate_polynomial(P_4_inf, y) / tools::evaluate_polynomial(Q_4_inf, y)) / x; -} - -template -T trigamma_prec(T x, const mpl::int_<64>*, const Policy&) -{ - // Max error in interpolated form: 1.178e-020 - static const T offset_1_2 = BOOST_MATH_BIG_CONSTANT(T, 64, 2.109325408935546875); - static const T P_1_2[] = { - BOOST_MATH_BIG_CONSTANT(T, 64, -1.10932535608960258341), - BOOST_MATH_BIG_CONSTANT(T, 64, -4.18793841543017129052), - BOOST_MATH_BIG_CONSTANT(T, 64, -4.63865531898487734531), - BOOST_MATH_BIG_CONSTANT(T, 64, -0.919832884430500908047), - BOOST_MATH_BIG_CONSTANT(T, 64, 1.68074038333180423012), - BOOST_MATH_BIG_CONSTANT(T, 64, 1.21172611429185622377), - BOOST_MATH_BIG_CONSTANT(T, 64, 0.259635673503366427284), - }; - static const T Q_1_2[] = { - BOOST_MATH_BIG_CONSTANT(T, 64, 1.0), - BOOST_MATH_BIG_CONSTANT(T, 64, 3.77521119359546982995), - BOOST_MATH_BIG_CONSTANT(T, 64, 5.664338024578956321), - BOOST_MATH_BIG_CONSTANT(T, 64, 4.25995134879278028361), - BOOST_MATH_BIG_CONSTANT(T, 64, 1.62956638448940402182), - BOOST_MATH_BIG_CONSTANT(T, 64, 0.259635512844691089868), - BOOST_MATH_BIG_CONSTANT(T, 64, 0.629642219810618032207e-8), - }; - // Max error in interpolated form: 3.912e-020 - static const T P_2_8[] = { - BOOST_MATH_BIG_CONSTANT(T, 64, -0.387540035162952880976e-11), - BOOST_MATH_BIG_CONSTANT(T, 64, 0.500000000276430504), - BOOST_MATH_BIG_CONSTANT(T, 64, 3.21926880986360957306), - BOOST_MATH_BIG_CONSTANT(T, 64, 10.2550347708483445775), - BOOST_MATH_BIG_CONSTANT(T, 64, 18.9002075150709144043), - BOOST_MATH_BIG_CONSTANT(T, 64, 21.0357215832399705625), - BOOST_MATH_BIG_CONSTANT(T, 64, 13.4346512182925923978), - BOOST_MATH_BIG_CONSTANT(T, 64, 3.98656291026448279118), - }; - static const T Q_2_8[] = { - BOOST_MATH_BIG_CONSTANT(T, 64, 1.0), - BOOST_MATH_BIG_CONSTANT(T, 64, 6.10520430478613667724), - BOOST_MATH_BIG_CONSTANT(T, 64, 18.475001060603645512), - BOOST_MATH_BIG_CONSTANT(T, 64, 31.7087534567758405638), - BOOST_MATH_BIG_CONSTANT(T, 64, 31.908814523890465398), - BOOST_MATH_BIG_CONSTANT(T, 64, 17.4175479039227084798), - BOOST_MATH_BIG_CONSTANT(T, 64, 3.98749106958394941276), - BOOST_MATH_BIG_CONSTANT(T, 64, -0.000115917322224411128566), - }; - // Maximum Deviation Found: 2.635e-020 - // Expected Error Term : 2.635e-020 - // Maximum Relative Change in Control Points : 1.791e-003 - static const T P_8_inf[] = { - BOOST_MATH_BIG_CONSTANT(T, 64, -0.263527875092466899848e-19), - BOOST_MATH_BIG_CONSTANT(T, 64, 0.500000000000000058145), - BOOST_MATH_BIG_CONSTANT(T, 64, 0.0730121433777364138677), - BOOST_MATH_BIG_CONSTANT(T, 64, 1.94505878379957149534), - BOOST_MATH_BIG_CONSTANT(T, 64, 0.0517092358874932620529), - BOOST_MATH_BIG_CONSTANT(T, 64, 1.07995383547483921121), - }; - static const T Q_8_inf[] = { - BOOST_MATH_BIG_CONSTANT(T, 64, 1.0), - BOOST_MATH_BIG_CONSTANT(T, 64, -0.187309046577818095504), - BOOST_MATH_BIG_CONSTANT(T, 64, 3.95255391645238842975), - BOOST_MATH_BIG_CONSTANT(T, 64, -1.14743283327078949087), - BOOST_MATH_BIG_CONSTANT(T, 64, 2.52989799376344914499), - BOOST_MATH_BIG_CONSTANT(T, 64, -0.627414303172402506396), - BOOST_MATH_BIG_CONSTANT(T, 64, 0.141554248216425512536), - }; - - if(x <= 2) - { - return (offset_1_2 + boost::math::tools::evaluate_polynomial(P_1_2, x) / tools::evaluate_polynomial(Q_1_2, x)) / (x * x); - } - else if(x <= 8) - { - T y = 1 / x; - return (1 + tools::evaluate_polynomial(P_2_8, y) / tools::evaluate_polynomial(Q_2_8, y)) / x; - } - T y = 1 / x; - return (1 + tools::evaluate_polynomial(P_8_inf, y) / tools::evaluate_polynomial(Q_8_inf, y)) / x; -} - -template -T trigamma_prec(T x, const mpl::int_<113>*, const Policy&) -{ - // Max error in interpolated form: 1.916e-035 - - static const T P_1_2[] = { - BOOST_MATH_BIG_CONSTANT(T, 113, -0.999999999999999082554457936871832533), - BOOST_MATH_BIG_CONSTANT(T, 113, -4.71237311120865266379041700054847734), - BOOST_MATH_BIG_CONSTANT(T, 113, -7.94125711970499027763789342500817316), - BOOST_MATH_BIG_CONSTANT(T, 113, -5.74657746697664735258222071695644535), - BOOST_MATH_BIG_CONSTANT(T, 113, -0.404213349456398905981223965160595687), - BOOST_MATH_BIG_CONSTANT(T, 113, 2.47877781178642876561595890095758896), - BOOST_MATH_BIG_CONSTANT(T, 113, 2.07714151702455125992166949812126433), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.858877899162360138844032265418028567), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.20499222604410032375789018837922397), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.0272103140348194747360175268778415049), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.0015764849020876949848954081173520686), - }; - static const T Q_1_2[] = { - BOOST_MATH_BIG_CONSTANT(T, 113, 1.0), - BOOST_MATH_BIG_CONSTANT(T, 113, 4.71237311120863419878375031457715223), - BOOST_MATH_BIG_CONSTANT(T, 113, 9.58619118655339853449127952145877467), - BOOST_MATH_BIG_CONSTANT(T, 113, 11.0940067269829372437561421279054968), - BOOST_MATH_BIG_CONSTANT(T, 113, 8.09075424749327792073276309969037885), - BOOST_MATH_BIG_CONSTANT(T, 113, 3.87705890159891405185343806884451286), - BOOST_MATH_BIG_CONSTANT(T, 113, 1.22758678701914477836330837816976782), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.249092040606385004109672077814668716), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.0295750413900655597027079600025569048), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.00157648490200498142247694709728858139), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.161264050344059471721062360645432809e-14), - }; - - // Max error in interpolated form: 8.958e-035 - static const T P_2_4[] = { - BOOST_MATH_BIG_CONSTANT(T, 113, -2.55843734739907925764326773972215085), - BOOST_MATH_BIG_CONSTANT(T, 113, -12.2830208240542011967952466273455887), - BOOST_MATH_BIG_CONSTANT(T, 113, -23.9195022162767993526575786066414403), - BOOST_MATH_BIG_CONSTANT(T, 113, -24.9256431504823483094158828285470862), - BOOST_MATH_BIG_CONSTANT(T, 113, -14.7979122765478779075108064826412285), - BOOST_MATH_BIG_CONSTANT(T, 113, -4.46654453928610666393276765059122272), - BOOST_MATH_BIG_CONSTANT(T, 113, -0.0191439033405649675717082465687845002), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.515412052554351265708917209749037352), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.195378348786064304378247325360320038), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.0334761282624174313035014426794245393), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.002373665205942206348500250056602687), - }; - static const T Q_2_4[] = { - BOOST_MATH_BIG_CONSTANT(T, 113, 1.0), - BOOST_MATH_BIG_CONSTANT(T, 113, 4.80098558454419907830670928248659245), - BOOST_MATH_BIG_CONSTANT(T, 113, 9.99220727843170133895059300223445265), - BOOST_MATH_BIG_CONSTANT(T, 113, 11.8896146167631330735386697123464976), - BOOST_MATH_BIG_CONSTANT(T, 113, 8.96613256683809091593793565879092581), - BOOST_MATH_BIG_CONSTANT(T, 113, 4.47254136149624110878909334574485751), - BOOST_MATH_BIG_CONSTANT(T, 113, 1.48600982028196527372434773913633152), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.319570735766764237068541501137990078), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.0407358345787680953107374215319322066), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.00237366520593271641375755486420859837), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.239554887903526152679337256236302116e-15), - BOOST_MATH_BIG_CONSTANT(T, 113, -0.294749244740618656265237072002026314e-17), - }; - - static const T y_offset_2_4 = BOOST_MATH_BIG_CONSTANT(T, 113, 3.558437347412109375); - - // Max error in interpolated form: 4.319e-035 - static const T P_4_8[] = { - BOOST_MATH_BIG_CONSTANT(T, 113, 0.166626112697021464248967707021688845e-16), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.499999999999997739552090249208808197), - BOOST_MATH_BIG_CONSTANT(T, 113, 6.40270945019053817915772473771553187), - BOOST_MATH_BIG_CONSTANT(T, 113, 41.3833374155000608013677627389343329), - BOOST_MATH_BIG_CONSTANT(T, 113, 166.803341854562809335667241074035245), - BOOST_MATH_BIG_CONSTANT(T, 113, 453.39964786925369319960722793414521), - BOOST_MATH_BIG_CONSTANT(T, 113, 851.153712317697055375935433362983944), - BOOST_MATH_BIG_CONSTANT(T, 113, 1097.70657567285059133109286478004458), - BOOST_MATH_BIG_CONSTANT(T, 113, 938.431232478455316020076349367632922), - BOOST_MATH_BIG_CONSTANT(T, 113, 487.268001604651932322080970189930074), - BOOST_MATH_BIG_CONSTANT(T, 113, 119.953445242335730062471193124820659), - }; - static const T Q_4_8[] = { - BOOST_MATH_BIG_CONSTANT(T, 113, 1.0), - BOOST_MATH_BIG_CONSTANT(T, 113, 12.4720855670474488978638945855932398), - BOOST_MATH_BIG_CONSTANT(T, 113, 78.6093129753298570701376952709727391), - BOOST_MATH_BIG_CONSTANT(T, 113, 307.470246050318322489781182863190127), - BOOST_MATH_BIG_CONSTANT(T, 113, 805.140686101151538537565264188630079), - BOOST_MATH_BIG_CONSTANT(T, 113, 1439.12019760292146454787601409644413), - BOOST_MATH_BIG_CONSTANT(T, 113, 1735.6105285756048831268586001383127), - BOOST_MATH_BIG_CONSTANT(T, 113, 1348.32500712856328019355198611280536), - BOOST_MATH_BIG_CONSTANT(T, 113, 607.225985860570846699704222144650563), - BOOST_MATH_BIG_CONSTANT(T, 113, 119.952317857277045332558673164517227), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.000140165918355036060868680809129436084), - }; - - // Maximum Deviation Found: 2.867e-035 - // Expected Error Term : 2.866e-035 - // Maximum Relative Change in Control Points : 2.662e-004 - static const T P_8_16[] = { - BOOST_MATH_BIG_CONSTANT(T, 113, -0.184828315274146610610872315609837439e-19), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.500000000000000004122475157735807738), - BOOST_MATH_BIG_CONSTANT(T, 113, 3.02533865247313349284875558880415875), - BOOST_MATH_BIG_CONSTANT(T, 113, 13.5995927517457371243039532492642734), - BOOST_MATH_BIG_CONSTANT(T, 113, 35.3132224283087906757037999452941588), - BOOST_MATH_BIG_CONSTANT(T, 113, 67.1639424550714159157603179911505619), - BOOST_MATH_BIG_CONSTANT(T, 113, 83.5767733658513967581959839367419891), - BOOST_MATH_BIG_CONSTANT(T, 113, 71.073491212235705900866411319363501), - BOOST_MATH_BIG_CONSTANT(T, 113, 35.8621515614725564575893663483998663), - BOOST_MATH_BIG_CONSTANT(T, 113, 8.72152231639983491987779743154333318), - }; - static const T Q_8_16[] = { - BOOST_MATH_BIG_CONSTANT(T, 113, 1.0), - BOOST_MATH_BIG_CONSTANT(T, 113, 5.71734397161293452310624822415866372), - BOOST_MATH_BIG_CONSTANT(T, 113, 25.293404179620438179337103263274815), - BOOST_MATH_BIG_CONSTANT(T, 113, 62.2619767967468199111077640625328469), - BOOST_MATH_BIG_CONSTANT(T, 113, 113.955048909238993473389714972250235), - BOOST_MATH_BIG_CONSTANT(T, 113, 130.807138328938966981862203944329408), - BOOST_MATH_BIG_CONSTANT(T, 113, 102.423146902337654110717764213057753), - BOOST_MATH_BIG_CONSTANT(T, 113, 44.0424772805245202514468199602123565), - BOOST_MATH_BIG_CONSTANT(T, 113, 8.89898032477904072082994913461386099), - BOOST_MATH_BIG_CONSTANT(T, 113, -0.0296627336872039988632793863671456398), - }; - // Maximum Deviation Found: 1.079e-035 - // Expected Error Term : -1.079e-035 - // Maximum Relative Change in Control Points : 7.884e-003 - static const T P_16_inf[] = { - BOOST_MATH_BIG_CONSTANT(T, 113, 0.0), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.500000000000000000000000000000087317), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.345625669885456215194494735902663968), - BOOST_MATH_BIG_CONSTANT(T, 113, 9.62895499360842232127552650044647769), - BOOST_MATH_BIG_CONSTANT(T, 113, 3.5936085382439026269301003761320812), - BOOST_MATH_BIG_CONSTANT(T, 113, 49.459599118438883265036646019410669), - BOOST_MATH_BIG_CONSTANT(T, 113, 7.77519237321893917784735690560496607), - BOOST_MATH_BIG_CONSTANT(T, 113, 74.4536074488178075948642351179304121), - BOOST_MATH_BIG_CONSTANT(T, 113, 2.75209340397069050436806159297952699), - BOOST_MATH_BIG_CONSTANT(T, 113, 23.9292359711471667884504840186561598), - }; - static const T Q_16_inf[] = { - BOOST_MATH_BIG_CONSTANT(T, 113, 1.0), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.357918006437579097055656138920742037), - BOOST_MATH_BIG_CONSTANT(T, 113, 19.1386039850709849435325005484512944), - BOOST_MATH_BIG_CONSTANT(T, 113, 0.874349081464143606016221431763364517), - BOOST_MATH_BIG_CONSTANT(T, 113, 98.6516097434855572678195488061432509), - BOOST_MATH_BIG_CONSTANT(T, 113, -16.1051972833382893468655223662534306), - BOOST_MATH_BIG_CONSTANT(T, 113, 154.316860216253720989145047141653727), - BOOST_MATH_BIG_CONSTANT(T, 113, -40.2026880424378986053105969312264534), - BOOST_MATH_BIG_CONSTANT(T, 113, 60.1679136674264778074736441126810223), - BOOST_MATH_BIG_CONSTANT(T, 113, -13.3414844622256422644504472438320114), - BOOST_MATH_BIG_CONSTANT(T, 113, 2.53795636200649908779512969030363442), - }; - - if(x <= 2) - { - return (2 + boost::math::tools::evaluate_polynomial(P_1_2, x) / tools::evaluate_polynomial(Q_1_2, x)) / (x * x); - } - else if(x <= 4) - { - return (y_offset_2_4 + boost::math::tools::evaluate_polynomial(P_2_4, x) / tools::evaluate_polynomial(Q_2_4, x)) / (x * x); - } - else if(x <= 8) - { - T y = 1 / x; - return (1 + tools::evaluate_polynomial(P_4_8, y) / tools::evaluate_polynomial(Q_4_8, y)) / x; - } - else if(x <= 16) - { - T y = 1 / x; - return (1 + tools::evaluate_polynomial(P_8_16, y) / tools::evaluate_polynomial(Q_8_16, y)) / x; - } - T y = 1 / x; - return (1 + tools::evaluate_polynomial(P_16_inf, y) / tools::evaluate_polynomial(Q_16_inf, y)) / x; -} - -template -T trigamma_imp(T x, const Tag* t, const Policy& pol) -{ - // - // This handles reflection of negative arguments, and all our - // error handling, then forwards to the T-specific approximation. - // - BOOST_MATH_STD_USING // ADL of std functions. - - T result = 0; - // - // Check for negative arguments and use reflection: - // - if(x <= 0) - { - // Reflect: - T z = 1 - x; - // Argument reduction for tan: - if(floor(x) == x) - { - return policies::raise_pole_error("boost::math::trigamma<%1%>(%1%)", 0, (1-x), pol); - } - T s = fabs(x) < fabs(z) ? boost::math::sin_pi(x, pol) : boost::math::sin_pi(z, pol); - return -trigamma_imp(z, t, pol) + boost::math::pow<2>(constants::pi()) / (s * s); - } - if(x < 1) - { - result = 1 / (x * x); - x += 1; - } - return result + trigamma_prec(x, t, pol); -} - -template -T trigamma_imp(T x, const mpl::int_<0>*, const Policy& pol) -{ - return polygamma_imp(1, x, pol); -} -// -// Initializer: ensure all our constants are initialized prior to the first call of main: -// -template -struct trigamma_initializer -{ - struct init - { - init() - { - typedef typename policies::precision::type precision_type; - do_init(mpl::bool_()); - } - void do_init(const mpl::true_&) - { - boost::math::trigamma(T(2.5), Policy()); - } - void do_init(const mpl::false_&){} - void force_instantiate()const{} - }; - static const init initializer; - static void force_instantiate() - { - initializer.force_instantiate(); - } -}; - -template -const typename trigamma_initializer::init trigamma_initializer::initializer; - -} // namespace detail - -template -inline typename tools::promote_args::type - trigamma(T x, const Policy&) -{ - typedef typename tools::promote_args::type result_type; - typedef typename policies::evaluation::type value_type; - typedef typename policies::precision::type precision_type; - typedef typename mpl::if_< - mpl::or_< - mpl::less_equal >, - mpl::greater > - >, - mpl::int_<0>, - typename mpl::if_< - mpl::less >, - mpl::int_<53>, - typename mpl::if_< - mpl::less >, - mpl::int_<64>, - mpl::int_<113> - >::type - >::type - >::type tag_type; - - typedef typename policies::normalise< - Policy, - policies::promote_float, - policies::promote_double, - policies::discrete_quantile<>, - policies::assert_undefined<> >::type forwarding_policy; - - // Force initialization of constants: - detail::trigamma_initializer::force_instantiate(); - - return policies::checked_narrowing_cast(detail::trigamma_imp( - static_cast(x), - static_cast(0), forwarding_policy()), "boost::math::trigamma<%1%>(%1%)"); -} - -template -inline typename tools::promote_args::type - trigamma(T x) -{ - return trigamma(x, policies::policy<>()); -} - -} // namespace math -} // namespace boost -#endif - diff -Nru mlpack-3.2.2/src/mlpack/core/boost_backport/unordered_map.hpp mlpack-3.3.0/src/mlpack/core/boost_backport/unordered_map.hpp --- mlpack-3.2.2/src/mlpack/core/boost_backport/unordered_map.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/boost_backport/unordered_map.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,234 +0,0 @@ -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_SERIALIZATION_UNORDERED_MAP_HPP -#define BOOST_SERIALIZATION_UNORDERED_MAP_HPP - -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 -// serialization/unordered_map.hpp: -// serialization for stl unordered_map templates - -// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . -// (C) Copyright 2014 Jim Bell -// Use, modification and distribution is subject to the Boost Software -// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -// See http://www.boost.org for updates, documentation, and revision history. - -#include - -#include - -#include -#include "unordered_collections_save_imp.hpp" -#include "unordered_collections_load_imp.hpp" -#include - -namespace boost { -namespace serialization { - -namespace stl { - -// map input -template -struct archive_input_unordered_map -{ - inline void operator()( - Archive &ar, - Container &s, - const unsigned int v - ){ - typedef typename Container::value_type type; - detail::stack_construct t(ar, v); - // borland fails silently w/o full namespace - ar >> boost::serialization::make_nvp("item", t.reference()); - std::pair result = - s.insert(t.reference()); - // note: the following presumes that the map::value_type was NOT tracked - // in the archive. This is the usual case, but here there is no way - // to determine that. - if(result.second){ - ar.reset_object_address( - & (result.first->second), - & t.reference().second - ); - } - } -}; - -// multimap input -template -struct archive_input_unordered_multimap -{ - inline void operator()( - Archive &ar, - Container &s, - const unsigned int v - ){ - typedef typename Container::value_type type; - detail::stack_construct t(ar, v); - // borland fails silently w/o full namespace - ar >> boost::serialization::make_nvp("item", t.reference()); - typename Container::const_iterator result - = s.insert(t.reference()); - // note: the following presumes that the map::value_type was NOT tracked - // in the archive. This is the usual case, but here there is no way - // to determine that. - ar.reset_object_address( - & result->second, - & t.reference() - ); - } -}; - -} // stl - -template< - class Archive, - class Key, - class HashFcn, - class EqualKey, - class Allocator -> -inline void save( - Archive & ar, - const std::unordered_map< - Key, HashFcn, EqualKey, Allocator - > &t, - const unsigned int /*file_version*/ -){ - boost::serialization::stl::save_unordered_collection< - Archive, - std::unordered_map< - Key, HashFcn, EqualKey, Allocator - > - >(ar, t); -} - -template< - class Archive, - class Key, - class HashFcn, - class EqualKey, - class Allocator -> -inline void load( - Archive & ar, - std::unordered_map< - Key, HashFcn, EqualKey, Allocator - > &t, - const unsigned int /*file_version*/ -){ - boost::serialization::stl::load_unordered_collection< - Archive, - std::unordered_map< - Key, HashFcn, EqualKey, Allocator - >, - boost::serialization::stl::archive_input_unordered_map< - Archive, - std::unordered_map< - Key, HashFcn, EqualKey, Allocator - > - > - >(ar, t); -} - -// split non-intrusive serialization function member into separate -// non intrusive save/load member functions -template< - class Archive, - class Key, - class HashFcn, - class EqualKey, - class Allocator -> -inline void serialize( - Archive & ar, - std::unordered_map< - Key, HashFcn, EqualKey, Allocator - > &t, - const unsigned int file_version -){ - boost::serialization::split_free(ar, t, file_version); -} - -// unordered_multimap -template< - class Archive, - class Key, - class HashFcn, - class EqualKey, - class Allocator -> -inline void save( - Archive & ar, - const std::unordered_multimap< - Key, HashFcn, EqualKey, Allocator - > &t, - const unsigned int /*file_version*/ -){ - boost::serialization::stl::save_unordered_collection< - Archive, - std::unordered_multimap< - Key, HashFcn, EqualKey, Allocator - > - >(ar, t); -} - -template< - class Archive, - class Key, - class HashFcn, - class EqualKey, - class Allocator -> -inline void load( - Archive & ar, - std::unordered_multimap< - Key, HashFcn, EqualKey, Allocator - > &t, - const unsigned int /*file_version*/ -){ - boost::serialization::stl::load_unordered_collection< - Archive, - std::unordered_multimap< - Key, HashFcn, EqualKey, Allocator - >, - boost::serialization::stl::archive_input_unordered_multimap< - Archive, - std::unordered_multimap< - Key, HashFcn, EqualKey, Allocator - > - > - >(ar, t); -} - -// split non-intrusive serialization function member into separate -// non intrusive save/load member functions -template< - class Archive, - class Key, - class HashFcn, - class EqualKey, - class Allocator -> -inline void serialize( - Archive & ar, - std::unordered_multimap< - Key, HashFcn, EqualKey, Allocator - > &t, - const unsigned int file_version -){ - boost::serialization::split_free(ar, t, file_version); -} - -} // namespace serialization -} // namespace boost - -#endif // BOOST_SERIALIZATION_UNORDERED_MAP_HPP diff -Nru mlpack-3.2.2/src/mlpack/core/cv/metrics/CMakeLists.txt mlpack-3.3.0/src/mlpack/core/cv/metrics/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/core/cv/metrics/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/cv/metrics/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -13,6 +13,8 @@ precision_impl.hpp recall.hpp recall_impl.hpp + r2_score.hpp + r2_score_impl.hpp ) # Add directory name to sources. diff -Nru mlpack-3.2.2/src/mlpack/core/cv/metrics/r2_score.hpp mlpack-3.3.0/src/mlpack/core/cv/metrics/r2_score.hpp --- mlpack-3.2.2/src/mlpack/core/cv/metrics/r2_score.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/cv/metrics/r2_score.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,76 @@ +/** + * @file r2_score.hpp + * @author Bisakh Mondal + * + * The R^2 (Coefficient of determination) regression metric. + * + * 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_CV_METRICS_R2SCORE_HPP +#define MLPACK_CORE_CV_METRICS_R2SCORE_HPP + +#include + +namespace mlpack { +namespace cv { + +/** + * The R2 Score is a metric of performance for regression algorithms + * that represents the proportion of variance (here y) that has been + * explained by the independent variables in the model. It provides + * an indication of goodness of fit and therefore a measure of how + * well unseen samples are likely to be predicted by the model, + * through the proportion of explained variance. + * As R2 Score is dataset dependent it can have wide range of values. The + * best possible score is @f$R^2 =1.0@f$. Values of R2 outside the range + * 0 to 1 can occur when the model fits the data worse than a horizontal + * hyperplane. This would occur when the wrong model was chosen, or + * nonsensical constraints were applied by mistake. A model which + * predicts exactly the expected value of y, disregarding the input + * features, gets a R2 Score equals to 0.0. + * If a model predicts @f$ \hat{y}_i $@f of the @f$ i $@f-th sample for a true + * @f$ y_i $@f for total n samples, the R2 Score is calculated by + * @f{eqnarray*}{ + * R^{2} \left( y, \hat{y} \right) &=& 1-\frac{\sum_{i=1}^{n} + * \left( y_i - \hat{y_i} \right)^2 } + * {\sum_{i=1}^{n} \left( y_i - \bar{y}\right)^2}\\ + * @f} + * + * where @f$ \bar{y} = frac{1}{y}\sum_{i=1}^{n} y_i $@f. + * For example, a model having R2Score = 0.85, explains 85 \% variability of + * the response data around its mean. + */ +class R2Score +{ + public: + /** + * Run prediction and calculate the R squared error. + * + * @param model A regression model. + * @param data Column-major data containing test items. + * @param responses Ground truth (correct) target values for the test items, + * should be either a row vector or a column-major matrix. + * @return calculated R2 Score. + */ + template + static double Evaluate(MLAlgorithm& model, + const DataType& data, + const ResponsesType& responses); + + /** + * Information for hyper-parameter tuning code. It indicates that we want + * to maximize the measurement. + */ + static const bool NeedsMinimization = false; +}; + +} // namespace cv +} // namespace mlpack + +// Include implementation. +#include "r2_score_impl.hpp" + +#endif diff -Nru mlpack-3.2.2/src/mlpack/core/cv/metrics/r2_score_impl.hpp mlpack-3.3.0/src/mlpack/core/cv/metrics/r2_score_impl.hpp --- mlpack-3.2.2/src/mlpack/core/cv/metrics/r2_score_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/cv/metrics/r2_score_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,55 @@ +/** + * @file r2_score_impl.hpp + * @author Bisakh Mondal + * + * The implementation of the class R2Score. + * + * 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_CV_METRICS_R2SCORE_IMPL_HPP +#define MLPACK_CORE_CV_METRICS_R2SCORE_IMPL_HPP + +namespace mlpack { +namespace cv { + +template +double R2Score::Evaluate(MLAlgorithm& model, + const DataType& data, + const ResponsesType& responses) +{ + if (data.n_cols != responses.n_cols) + { + std::ostringstream oss; + oss << "R2Score::Evaluate(): number of points (" << data.n_cols << ") " + << "does not match number of responses (" << responses.n_cols << ")!" + << std::endl; + throw std::invalid_argument(oss.str()); + } + + ResponsesType predictedResponses; + // Taking Predicted Output from the model. + model.Predict(data, predictedResponses); + // Mean value of response. + double meanResponses = arma::mean(responses); + + // Calculate the numerator i.e. residual sum of squares. + double residualSumSquared = arma::accu(arma::square(responses - + predictedResponses)); + + // Calculate the denominator i.e.total sum of squares. + double totalSumSquared = arma::accu(arma::square(responses - meanResponses)); + + // Handling undefined R2 Score when both denominator and numerator is 0.0. + if (residualSumSquared == 0.0) + return totalSumSquared ? 1.0 : DBL_MIN; + + return 1 - residualSumSquared / totalSumSquared; +} + +} // namespace cv +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/core/data/CMakeLists.txt mlpack-3.3.0/src/mlpack/core/data/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/core/data/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -11,6 +11,7 @@ load_csv.cpp load.hpp load_image_impl.hpp + load_image.cpp load_model_impl.hpp load_vec_impl.hpp load_impl.hpp @@ -21,10 +22,14 @@ normalize_labels_impl.hpp save.hpp save_impl.hpp + save_image.cpp serialization_template_version.hpp split_data.hpp imputer.hpp binarize.hpp + string_encoding.hpp + string_encoding_dictionary.hpp + string_encoding_impl.hpp confusion_matrix.hpp one_hot_encoding.hpp one_hot_encoding_impl.hpp @@ -39,7 +44,8 @@ # Add subdirectories. add_subdirectory(imputation_methods) add_subdirectory(map_policies) -add_subdirectory(scaler_methods) +add_subdirectory(string_encoding_policies) +add_subdirectory(tokenizers) # Append sources (with directory name) to list of all mlpack sources (used at # parent scope). diff -Nru mlpack-3.2.2/src/mlpack/core/data/image_info.hpp mlpack-3.3.0/src/mlpack/core/data/image_info.hpp --- mlpack-3.2.2/src/mlpack/core/data/image_info.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/image_info.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -13,28 +13,12 @@ #ifndef MLPACK_CORE_DATA_IMAGE_INFO_HPP #define MLPACK_CORE_DATA_IMAGE_INFO_HPP - #include - #include "extension.hpp" -#ifdef HAS_STB // Compile this only if stb is present. - -#define STB_IMAGE_STATIC -#define STB_IMAGE_IMPLEMENTATION -#include - -#define STB_IMAGE_WRITE_STATIC -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include - -#endif - namespace mlpack { namespace data { -#ifdef HAS_STB // Compile this only if stb is present. - /** * Checks if the given image filename is supported. * @@ -44,8 +28,6 @@ inline bool ImageFormatSupported(const std::string& fileName, const bool save = false); -#endif - /** * Implements meta-data of images required by data::Load and * data::Save for loading and saving images into arma::Mat. @@ -87,6 +69,15 @@ //! Modify the image quality. size_t& Quality() { return quality; } + template + void serialize(Archive& ar, const unsigned int /* version */) + { + ar & BOOST_SERIALIZATION_NVP(width); + ar & BOOST_SERIALIZATION_NVP(channels); + ar & BOOST_SERIALIZATION_NVP(height); + ar & BOOST_SERIALIZATION_NVP(quality); + } + private: // To store the image width. size_t width; diff -Nru mlpack-3.2.2/src/mlpack/core/data/load.hpp mlpack-3.3.0/src/mlpack/core/data/load.hpp --- mlpack-3.2.2/src/mlpack/core/data/load.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/load.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -291,7 +291,6 @@ /** * Image load/save interfaces. */ -#ifdef HAS_STB /** * Load the image file into the given matrix. @@ -300,15 +299,13 @@ * @param matrix Matrix to load the image into. * @param info An object of ImageInfo class. * @param fatal If an error should be reported as fatal (default false). - * @param transpose If true, transpose the matrix after loading. * @return Boolean value indicating success or failure of load. */ template bool Load(const std::string& filename, arma::Mat& matrix, ImageInfo& info, - const bool fatal = false, - const bool transpose = true); + const bool fatal = false); /** * Load the image file into the given matrix. @@ -324,10 +321,13 @@ bool Load(const std::vector& files, arma::Mat& matrix, ImageInfo& info, - const bool fatal = false, - const bool transpose = true); + const bool fatal = false); -#endif // HAS_STB. +// Implementation found in load_image.cpp. +bool LoadImage(const std::string& filename, + arma::Mat& matrix, + ImageInfo& info, + const bool fatal = false); } // namespace data } // namespace mlpack diff -Nru mlpack-3.2.2/src/mlpack/core/data/load_image.cpp mlpack-3.3.0/src/mlpack/core/data/load_image.cpp --- mlpack-3.2.2/src/mlpack/core/data/load_image.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/load_image.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,129 @@ +/** + * @file load_image.cpp + * @author Mehul Kumar Nirala + * + * Implementation of image loading functionality via STB. + * + * 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 "load.hpp" +#include "image_info.hpp" + +#ifdef HAS_STB + +// The definition of STB_IMAGE_IMPLEMENTATION means that the implementation will +// be included here directly. +#define STB_IMAGE_STATIC +#define STB_IMAGE_IMPLEMENTATION + +#include + +namespace mlpack { +namespace data { + +bool LoadImage(const std::string& filename, + arma::Mat& matrix, + ImageInfo& info, + const bool fatal) +{ + unsigned char* image; + + if (!ImageFormatSupported(filename)) + { + std::ostringstream oss; + oss << "Load(): file type " << Extension(filename) << " not supported. "; + oss << "Currently it supports: "; + for (auto extension : loadFileTypes) + oss << " " << extension; + oss << "." << std::endl; + + if (fatal) + { + Log::Fatal << oss.str(); + } + else + { + Log::Warn << oss.str(); + } + + return false; + } + + // Temporary variables needed as stb_image.h supports int parameters. + int tempWidth, tempHeight, tempChannels; + + // For grayscale images. + if (info.Channels() == 1) + { + image = stbi_load(filename.c_str(), &tempWidth, &tempHeight, &tempChannels, + STBI_grey); + } + else + { + image = stbi_load(filename.c_str(), &tempWidth, &tempHeight, &tempChannels, + STBI_rgb); + } + + if (!image) + { + if (fatal) + { + Log::Fatal << "Load(): failed to load image '" << filename << "': " + << stbi_failure_reason() << std::endl; + } + else + { + Log::Warn << "Load(): failed to load image '" << filename << "': " + << stbi_failure_reason() << std::endl; + } + + return false; + } + + info.Width() = tempWidth; + info.Height() = tempHeight; + info.Channels() = tempChannels; + + // Copy image into armadillo Mat. + matrix = arma::Mat(image, info.Width() * info.Height() * + info.Channels(), 1, true, true); + + // Free the image pointer. + free(image); + return true; +} + +} // namespace data +} // namespace mlpack + +#else + +namespace mlpack { +namespace data { + +bool LoadImage(const std::string& /* filename */, + arma::Mat& /* matrix */, + ImageInfo& /* info */, + const bool fatal) +{ + if (fatal) + { + Log::Fatal << "Load(): mlpack was not compiled with STB support, so images " + << "cannot be loaded!" << std::endl; + } + else + { + Log::Warn << "Load(): mlpack was not compiled with STB support, so images " + << "cannot be loaded!" << std::endl; + } + + return false; +} + +} // namespace data +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/core/data/load_image_impl.hpp mlpack-3.3.0/src/mlpack/core/data/load_image_impl.hpp --- mlpack-3.2.2/src/mlpack/core/data/load_image_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/load_image_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -19,68 +19,28 @@ namespace mlpack { namespace data { -#ifdef HAS_STB // Compile this only if stb is present. - // Image loading API. template bool Load(const std::string& filename, arma::Mat& matrix, ImageInfo& info, - const bool /* fatal */, - const bool transpose) + const bool fatal) { Timer::Start("loading_image"); - unsigned char* image; - if (!ImageFormatSupported(filename)) - { - std::ostringstream oss; - oss << "File type " << Extension(filename) << " not supported.\n"; - oss << "Currently it supports "; - for (auto extension : loadFileTypes) - oss << " " << extension; - oss << std::endl; - throw std::runtime_error(oss.str()); - return false; - } + // STB loads into unsigned char matrices, so we may have to convert once + // loaded. + arma::Mat tempMatrix; + const bool result = LoadImage(filename, tempMatrix, info, fatal); - stbi_set_flip_vertically_on_load(transpose); - - // Temporary variables needed as stb_image.h supports int parameters. - int tempWidth, tempHeight, tempChannels; - - // For grayscale images. - if (info.Channels() == 1) - { - image = stbi_load(filename.c_str(), &tempWidth, &tempHeight, &tempChannels, - STBI_grey); - } - else + // If fatal is true, then the program will have already thrown an exception. + if (!result) { - image = stbi_load(filename.c_str(), &tempWidth, &tempHeight, &tempChannels, - STBI_rgb); - } - - if (tempWidth <= 0 || tempHeight <= 0) - { - std::ostringstream oss; - oss << "Image '" << filename << "' not found." << std::endl; - free(image); - throw std::runtime_error(oss.str()); - + Timer::Stop("loading_image"); return false; } - info.Width() = tempWidth; - info.Height() = tempHeight; - info.Channels() = tempChannels; - - // Copy image into armadillo Mat. - matrix = arma::Mat(image, info.Width() * info.Height() * - info.Channels(), 1, true, true); - - // Free the image pointer. - free(image); + matrix = arma::conv_to>::from(tempMatrix); Timer::Stop("loading_image"); return true; } @@ -90,57 +50,45 @@ bool Load(const std::vector& files, arma::Mat& matrix, ImageInfo& info, - const bool fatal, - const bool transpose) + const bool fatal) { if (files.size() == 0) { std::ostringstream oss; - oss << "Files vector is empty." << std::endl; + oss << "Load(): vector of image files is empty." << std::endl; + + if (fatal) + Log::Fatal << oss.str(); + else + Log::Warn << oss.str(); - throw std::runtime_error(oss.str()); return false; } arma::Mat img; - bool status = Load(files[0], img, info, fatal, transpose); + bool status = LoadImage(files[0], img, info, fatal); + + if (!status) + return false; // Decide matrix dimension using the image height and width. - matrix.set_size(info.Width() * info.Height() * info.Channels(), files.size()); - matrix.col(0) = img; + arma::Mat tmpMatrix( + info.Width() * info.Height() * info.Channels(), files.size()); + tmpMatrix.col(0) = img; for (size_t i = 1; i < files.size() ; i++) { - arma::Mat colImg(matrix.colptr(i), matrix.n_rows, 1, + arma::Mat colImg(tmpMatrix.colptr(i), tmpMatrix.n_rows, 1, false, true); - status &= Load(files[i], colImg, info, fatal, transpose); - } - return status; -} + status = LoadImage(files[i], colImg, info, fatal); -#else // No STB. -template -bool Load(const std::string& filename, - arma::Mat& matrix, - ImageInfo& info, - const bool fatal = false, - const bool transpose = true) -{ - throw std::runtime_error("Load(): HAS_STB is not defined, " - "so STB is not available and images cannot be loaded!"); -} + if (!status) + return false; + } -template -bool Load(const std::vector& files, - arma::Mat& matrix, - ImageInfo& info, - const bool fatal = false, - const bool transpose = true) -{ - throw std::runtime_error("Load(): HAS_STB is not defined, " - "so STB is not available and images cannot be loaded!"); + matrix = arma::conv_to>::from(tmpMatrix); + return true; } -#endif // HAS_STB. } // namespace data } // namespace mlpack diff -Nru mlpack-3.2.2/src/mlpack/core/data/load_impl.hpp mlpack-3.3.0/src/mlpack/core/data/load_impl.hpp --- mlpack-3.2.2/src/mlpack/core/data/load_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/load_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -34,7 +34,7 @@ namespace details{ template -std::vector ToTokens(Tokenizer &lineTok) +std::vector ToTokens(Tokenizer& lineTok) { std::vector tokens; std::transform(std::begin(lineTok), std::end(lineTok), @@ -51,7 +51,7 @@ inline void TransposeTokens(std::vector> const &input, - std::vector &output, + std::vector& output, size_t index) { output.clear(); diff -Nru mlpack-3.2.2/src/mlpack/core/data/save.hpp mlpack-3.3.0/src/mlpack/core/data/save.hpp --- mlpack-3.2.2/src/mlpack/core/data/save.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/save.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -91,8 +91,6 @@ const bool fatal = false, format f = format::autodetect); -#ifdef HAS_STB - /** * Save the image file from the given matrix. * @@ -107,8 +105,7 @@ bool Save(const std::string& filename, arma::Mat& matrix, ImageInfo& info, - const bool fatal = false, - const bool transpose = true); + const bool fatal = false); /** * Save the image file from the given matrix. @@ -124,10 +121,15 @@ bool Save(const std::vector& files, arma::Mat& matrix, ImageInfo& info, - const bool fatal = false, - const bool transpose = true); + const bool fatal = false); -#endif // HAS_STB. +/** + * Helper function to save files. Implementation in save_image.cpp. + */ +bool SaveImage(const std::string& filename, + arma::Mat& image, + ImageInfo& info, + const bool fatal = false); } // namespace data } // namespace mlpack diff -Nru mlpack-3.2.2/src/mlpack/core/data/save_image.cpp mlpack-3.3.0/src/mlpack/core/data/save_image.cpp --- mlpack-3.2.2/src/mlpack/core/data/save_image.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/save_image.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,152 @@ +/** + * @file save_image.cpp + * @author Mehul Kumar Nirala + * + * Implementation of image saving functionality via STB. + * + * 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 "save.hpp" + +#ifdef HAS_STB + +// The implementation of the functions is included directly, so we need to make +// sure it doesn't get included twice. This is to work around a bug in old +// versions of STB where not all functions were correctly marked static. +#define STB_IMAGE_WRITE_STATIC +#ifndef STB_IMAGE_WRITE_IMPLEMENTATION + #define STB_IMAGE_WRITE_IMPLEMENTATION +#else + #undef STB_IMAGE_WRITE_IMPLEMENTATION +#endif +#include +#ifndef STB_IMAGE_WRITE_IMPLEMENTATION + #define STB_IMAGE_WRITE_IMPLEMENTATION +#endif + +namespace mlpack { +namespace data { + +bool SaveImage(const std::string& filename, + arma::Mat& image, + ImageInfo& info, + const bool fatal) +{ + // Check to see if the file type is supported. + if (!ImageFormatSupported(filename, true)) + { + std::ostringstream oss; + oss << "Save(): file type " << Extension(filename) << " not supported.\n"; + oss << "Currently image saving supports "; + for (auto extension : saveFileTypes) + oss << ", " << extension; + oss << "." << std::endl; + + if (fatal) + { + Log::Fatal << oss.str(); + } + else + { + Log::Warn << oss.str(); + } + + return false; + } + + // Ensure the shape of the matrix is correct. + if (image.n_cols > 1) + { + Log::Warn << "Save(): given input image matrix contains more than 1 image." + << std::endl; + Log::Warn << "Only the first image will be saved!" << std::endl; + } + + if (info.Width() * info.Height() * info.Channels() != image.n_elem) + { + Log::Fatal << "data::Save(): The given image dimensions do not match the " + << "dimensions of the matrix to be saved!" << std::endl; + } + + bool status = false; + unsigned char* imageMem = image.memptr(); + + if ("png" == Extension(filename)) + { + status = stbi_write_png(filename.c_str(), info.Width(), info.Height(), + info.Channels(), imageMem, info.Width() * info.Channels()); + } + else if ("bmp" == Extension(filename)) + { + status = stbi_write_bmp(filename.c_str(), info.Width(), info.Height(), + info.Channels(), imageMem); + } + else if ("tga" == Extension(filename)) + { + status = stbi_write_tga(filename.c_str(), info.Width(), info.Height(), + info.Channels(), imageMem); + } + else if ("hdr" == Extension(filename)) + { + // We'll have to convert to float... + arma::fmat tmpImage = arma::conv_to::from(image); + status = stbi_write_hdr(filename.c_str(), info.Width(), info.Height(), + info.Channels(), tmpImage.memptr()); + } + else if ("jpg" == Extension(filename)) + { + status = stbi_write_jpg(filename.c_str(), info.Width(), info.Height(), + info.Channels(), imageMem, info.Quality()); + } + + if (!status) + { + if (fatal) + { + Log::Fatal << "Save(): error saving image to '" << filename << "'." + << std::endl; + } + else + { + Log::Warn << "Save(): error saving image to '" << filename << "'." + << std::endl; + } + } + + return status; +} + +} // namespace data +} // namespace mlpack + +#else + +namespace mlpack { +namespace data { + +bool SaveImage(const std::string& /* filename */, + arma::Mat& /* image */, + ImageInfo& /* info */, + const bool fatal) +{ + if (fatal) + { + Log::Fatal << "Save(): mlpack was not compiled with STB support, so images " + << "cannot be saved!" << std::endl; + } + else + { + Log::Warn << "Save(): mlpack was not compiled with STB support, so images " + << "cannot be saved!" << std::endl; + } + + return false; +} + +} // namespace data +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/core/data/save_impl.hpp mlpack-3.3.0/src/mlpack/core/data/save_impl.hpp --- mlpack-3.2.2/src/mlpack/core/data/save_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/save_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -283,86 +283,25 @@ } } -#ifdef HAS_STB -// Image saving API. +/** + * Save the given image to the given filename. + * + * @param filename Filename to save to. + * @param matrix Matrix containing image to be saved. + * @param info Information about the image (width/height/channels/etc.). + * @param fatal Whether an exception should be thrown on save failure. + */ template bool Save(const std::string& filename, arma::Mat& matrix, ImageInfo& info, - const bool fatal, - const bool transpose) + const bool fatal) { - Timer::Start("saving_image"); - // We transpose by default. So, un-transpose if necessary. - if (!transpose) - matrix = arma::trans(matrix); - - int tempWidth, tempHeight, tempChannels, tempQuality; - - tempWidth = info.Width(); - tempHeight = info.Height(); - tempChannels = info.Channels(); - tempQuality = info.Quality(); + arma::Mat tmpMatrix = + arma::conv_to>::from(matrix); - if (!ImageFormatSupported(filename, true)) - { - std::ostringstream oss; - oss << "File type " << Extension(filename) << " not supported.\n"; - oss << "Currently it supports "; - for (auto extension : saveFileTypes) - oss << ", " << extension; - oss << std::endl; - throw std::runtime_error(oss.str()); - return false; - } - if (matrix.n_cols > 1) - { - std::cout << "Input Matrix contains more than 1 image." << std::endl; - std::cout << "Only the firstimage will be saved!" << std::endl; - } - stbi_flip_vertically_on_write(transpose); - - bool status = false; - try - { - unsigned char* image = matrix.memptr(); - - if ("png" == Extension(filename)) - { - status = stbi_write_png(filename.c_str(), tempWidth, tempHeight, - tempChannels, image, tempWidth * tempChannels); - } - else if ("bmp" == Extension(filename)) - { - status = stbi_write_bmp(filename.c_str(), tempWidth, tempHeight, - tempChannels, image); - } - else if ("tga" == Extension(filename)) - { - status = stbi_write_tga(filename.c_str(), tempWidth, tempHeight, - tempChannels, image); - } - else if ("hdr" == Extension(filename)) - { - status = stbi_write_hdr(filename.c_str(), tempWidth, tempHeight, - tempChannels, reinterpret_cast(image)); - } - else if ("jpg" == Extension(filename)) - { - status = stbi_write_jpg(filename.c_str(), tempWidth, tempHeight, - tempChannels, image, tempQuality); - } - } - catch (std::exception& e) - { - Timer::Stop("saving_image"); - if (fatal) - Log::Fatal << e.what() << std::endl; - Log::Warn << e.what() << std::endl; - return false; - } - Timer::Stop("saving_image"); - return status; + // Call out to .cpp implementation. + return SaveImage(filename, tmpMatrix, info, fatal); } // Image saving API for multiple files. @@ -370,59 +309,36 @@ bool Save(const std::vector& files, arma::Mat& matrix, ImageInfo& info, - const bool fatal, - const bool transpose) + const bool fatal) { if (files.size() == 0) { - std::ostringstream oss; - oss << "Files vector is empty." << std::endl; + if (fatal) + { + Log::Fatal << "Save(): vector of image files is empty; nothing to save." + << std::endl; + } + else + { + Log::Warn << "Save(): vector of image files is empty; nothing to save." + << std::endl; + } - throw std::runtime_error(oss.str()); return false; } - // We transpose by default. So, un-transpose if necessary. - if (!transpose) - matrix = arma::trans(matrix); arma::Mat img; - bool status = Save(files[0], img, info, fatal, transpose); - - // Decide matrix dimension using the image height and width. - matrix.set_size(info.Width() * info.Height() * info.Channels(), files.size()); - matrix.col(0) = img; + bool status = true; - for (size_t i = 1; i < files.size() ; i++) + for (size_t i = 0; i < files.size() ; i++) { - arma::Mat colImg(matrix.colptr(i), matrix.n_rows, 1, + arma::Mat colImg(matrix.colptr(i), matrix.n_rows, 1, false, true); - status &= Save(files[i], colImg, info, fatal, transpose); + status &= Save(files[i], colImg, info, fatal); } - return status; -} -#else -template -bool Save(const std::string& filename, - arma::Mat& matrix, - ImageInfo& info, - const bool fatal = false, - const bool transpose = true) -{ - throw std::runtime_error("Save(): HAS_STB is not defined, " - "so STB is not available and images cannot be saved!"); -} -template -bool Save(const std::vector& files, - arma::Mat& matrix, - ImageInfo& info, - const bool fatal = false, - const bool transpose = true) -{ - throw std::runtime_error("Save(): HAS_STB is not defined, " - "so STB is not available and images cannot be saved!"); + return status; } -#endif // HAS_STB. } // namespace data } // namespace mlpack diff -Nru mlpack-3.2.2/src/mlpack/core/data/scaler_methods/zca_whitening.hpp mlpack-3.3.0/src/mlpack/core/data/scaler_methods/zca_whitening.hpp --- mlpack-3.2.2/src/mlpack/core/data/scaler_methods/zca_whitening.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/scaler_methods/zca_whitening.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -52,10 +52,7 @@ * * @param eps Regularization parameter. */ - ZCAWhitening(double eps = 0.00005) - { - pca = new data::PCAWhitening(eps); - } + ZCAWhitening(double eps = 0.00005) : pca(eps) { } /** * Function to fit features, to find out the min max and scale. @@ -65,7 +62,7 @@ template void Fit(const MatType& input) { - pca->Fit(input); + pca.Fit(input); } /** @@ -77,8 +74,8 @@ template void Transform(const MatType& input, MatType& output) { - pca->Transform(input, output); - output = pca->EigenVectors() * output; + pca.Transform(input, output); + output = pca.EigenVectors() * output; } /** @@ -90,19 +87,19 @@ template void InverseTransform(const MatType& input, MatType& output) { - output = inv(pca->EigenVectors()) * arma::diagmat(arma::sqrt( - pca->EigenValues())) * inv(pca->EigenVectors().t()) * input; - output = (output.each_col() + pca->ItemMean()); + output = inv(pca.EigenVectors()) * arma::diagmat(arma::sqrt( + pca.EigenValues())) * inv(pca.EigenVectors().t()) * input; + output = (output.each_col() + pca.ItemMean()); } //! Get the mean row vector. - const arma::vec& ItemMean() const { return pca->ItemMean(); } + const arma::vec& ItemMean() const { return pca.ItemMean(); } //! Get the eigenvalues vector. - const arma::vec& EigenValues() const { return pca->EigenValues(); } + const arma::vec& EigenValues() const { return pca.EigenValues(); } //! Get the eigenvector. - const arma::mat& EigenVectors() const { return pca->EigenVectors(); } + const arma::mat& EigenVectors() const { return pca.EigenVectors(); } //! Get the regularization parameter. - double Epsilon() const { return pca->Epsilon(); } + double Epsilon() const { return pca.Epsilon(); } template void serialize(Archive& ar, const unsigned int /* version */) @@ -112,7 +109,7 @@ private: // A pointer to PcaWhitening Class. - PCAWhitening* pca; + PCAWhitening pca; }; // class ZCAWhitening } // namespace data diff -Nru mlpack-3.2.2/src/mlpack/core/data/string_encoding_dictionary.hpp mlpack-3.3.0/src/mlpack/core/data/string_encoding_dictionary.hpp --- mlpack-3.2.2/src/mlpack/core/data/string_encoding_dictionary.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/string_encoding_dictionary.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,348 @@ +/** + * @file string_encoding_dictionary.hpp + * @author Jeffin Sam + * @author Mikhail Lozhnikov + * + * Definition of the StringEncodingDictionary 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_DATA_STRING_ENCODING_DICTIONARY_HPP +#define MLPACK_CORE_DATA_STRING_ENCODING_DICTIONARY_HPP + +#include +#include +#include +#include +#include + +namespace mlpack { +namespace data { + +/** + * This class provides a dictionary interface for the purpose of string + * encoding. It works like an adapter to the internal dictionary. + * + * @tparam Token Type of the token that the dictionary stores. + */ +template +class StringEncodingDictionary +{ + public: + //! A convenient alias for the internal type of the map. + using MapType = std::unordered_map; + + //! The type of the token that the dictionary stores. + using TokenType = Token; + + /** + * The function returns true if the dictionary contains the given token. + * + * @param token The given token. + */ + bool HasToken(const Token& token) const + { + return mapping.find(token) != mapping.end(); + } + + /** + * The function adds the given token to the dictionary and assigns a label + * to the token. The label is equal to the resulting size of the dictionary. + * The function returns the assigned label. + * + * @param token The given token. + */ + template + size_t AddToken(T&& token) + { + size_t size = mapping.size(); + + mapping[std::forward(token)] = ++size; + + return size; + } + + /** + * The function returns the label assigned to the given token. The function + * throws std::out_of_range if no such token is found. + * + * @param token The given token. + */ + size_t Value(const Token& token) const + { + return mapping.at(token); + } + + //! Get the size of the dictionary. + size_t Size() const { return mapping.size(); } + + //! Clear the dictionary. + void Clear() + { + mapping.clear(); + } + + //! Get the mapping. + const MapType& Mapping() const { return mapping; } + //! Modify the mapping. + MapType& Mapping() { return mapping; } + + /** + * Serialize the class to the given archive. + */ + template + void serialize(Archive& ar, const unsigned int /* version */) + { + ar & BOOST_SERIALIZATION_NVP(mapping); + } + + private: + //! The dictionary itself. + MapType mapping; +}; + +/* + * Specialization of the StringEncodingDictionary class for boost::string_view. + */ +template<> +class StringEncodingDictionary +{ + public: + //! A convenient alias for the internal type of the map. + using MapType = std::unordered_map< + boost::string_view, + size_t, + boost::hash>; + + //! The type of the token that the dictionary stores. + using TokenType = boost::string_view; + + //! Construct the default class. + StringEncodingDictionary() = default; + + //! Copy the class from the given object. + StringEncodingDictionary(const StringEncodingDictionary& other) : + tokens(other.tokens) + { + for (const std::string& token : tokens) + mapping[token] = other.mapping.at(token); + } + + //! Standard move constructor. + StringEncodingDictionary(StringEncodingDictionary&& other) = default; + + //! Copy the class from the given object. + StringEncodingDictionary& operator=(const StringEncodingDictionary& other) + { + tokens = other.tokens; + mapping.clear(); + + for (const std::string& token : tokens) + mapping[token] = other.mapping.at(token); + + return *this; + } + + //! Standard move assignment operator. + StringEncodingDictionary& operator=( + StringEncodingDictionary&& other) = default; + + /** + * The function returns true if the dictionary contains the given token. + * + * @param token The given token. + */ + bool HasToken(const boost::string_view token) const + { + return mapping.find(token) != mapping.end(); + } + + /** + * The function adds the given token to the dictionary and assigns a label + * to the token. The label is equal to the resulting size of the dictionary. + * The function returns the assigned label. + * + * @param token The given token. + */ + size_t AddToken(const boost::string_view token) + { + tokens.emplace_back(token); + + size_t size = mapping.size(); + + mapping[tokens.back()] = ++size; + + return size; + } + + /** + * The function returns the label assigned to the given token. The function + * throws std::out_of_range if no such token is found. + * + * @param token The given token. + */ + size_t Value(const boost::string_view token) const + { + return mapping.at(token); + } + + //! Get the size of the dictionary. + size_t Size() const { return mapping.size(); } + + //! Clear the dictionary. + void Clear() + { + mapping.clear(); + tokens.clear(); + } + + //! Get the tokens. + const std::deque& Tokens() const { return tokens; } + //! Modify the tokens. + std::deque& Tokens() { return tokens; } + + //! Get the mapping. + const MapType& Mapping() const { return mapping; } + //! Modify the mapping. + MapType& Mapping() { return mapping; } + + /** + * Serialize the class to the given archive. + */ + template + void serialize(Archive& ar, const unsigned int /* version */) + { + size_t numTokens = tokens.size(); + + ar & BOOST_SERIALIZATION_NVP(numTokens); + + if (Archive::is_loading::value) + { + tokens.resize(numTokens); + + for (std::string& token : tokens) + { + ar & BOOST_SERIALIZATION_NVP(token); + + size_t tokenValue = 0; + ar & BOOST_SERIALIZATION_NVP(tokenValue); + mapping[token] = tokenValue; + } + } + if (Archive::is_saving::value) + { + for (std::string& token : tokens) + { + ar & BOOST_SERIALIZATION_NVP(token); + + size_t tokenValue = mapping.at(token); + ar & BOOST_SERIALIZATION_NVP(tokenValue); + } + } + } + + private: + //! The tokens that the dictionary stores. + std::deque tokens; + + //! The mapping itself. + MapType mapping; +}; + +template<> +class StringEncodingDictionary +{ + public: + //! A convenient alias for the internal type of the map. + using MapType = std::array; + + //! The type of the token that the dictionary stores. + using TokenType = int; + + //! Construct the default class. + StringEncodingDictionary() : + size(0) + { + mapping.fill(0); + } + + /** + * The function returns true if the dictionary contains the given token. + * The token must belong to [0, 255]; otherwise the behavior is undefined. + * + * @param token The given token. + */ + bool HasToken(const int token) const + { + return mapping[token] > 0; + } + + /** + * The function adds the given token to the dictionary and assigns a label + * to the token. The token must belong to [0, 255]; otherwise the behavior + * is undefined. The label is equal to the resulting size of the dictionary. + * The function returns the assigned label. + * + * @param token The given token. + */ + size_t AddToken(const int token) + { + mapping[token] = ++size; + + return size; + } + + /** + * The function returns the label assigned to the given token. The function + * doesn't verify that the dictionary contains the token. The token must + * belong to [0, 255]; otherwise the behavior is undefined. + * + * @param token The given token. + */ + size_t Value(const int token) const + { + return mapping[token]; + } + + //! Get the size of the dictionary. + size_t Size() const + { + return size; + } + + //! Clear the dictionary. + void Clear() + { + mapping.fill(0); + } + + //! Get the mapping. + const MapType& Mapping() const { return mapping; } + //! Modify the mapping. + MapType& Mapping() { return mapping; } + + /** + * Serialize the class to the given archive. + */ + template + void serialize(Archive& ar, const unsigned int /* version */) + { + ar & BOOST_SERIALIZATION_NVP(mapping); + ar & BOOST_SERIALIZATION_NVP(size); + } + + private: + //! The mapping itself. + MapType mapping; + + //! The size of the dictionary. + size_t size; +}; + +} // namespace data +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/core/data/string_encoding.hpp mlpack-3.3.0/src/mlpack/core/data/string_encoding.hpp --- mlpack-3.2.2/src/mlpack/core/data/string_encoding.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/string_encoding.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,218 @@ +/** + * @file string_encoding.hpp + * @author Jeffin Sam + * @author Mikhail Lozhnikov + * + * Definition of the StringEncoding 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_DATA_STRING_ENCODING_HPP +#define MLPACK_CORE_DATA_STRING_ENCODING_HPP + +#include +#include +#include +#include +#include + +namespace mlpack { +namespace data { + +/** + * The class translates a set of strings into numbers using various encoding + * algorithms. The encoder writes data either in the column-major order or + * in the row-major order depending on the output data type. + * + * @tparam EncodingPolicyType Type of the encoding algorithm itself. + * @tparam DictionaryType Type of the dictionary. + */ +template +class StringEncoding +{ + public: + /** + * Pass the given arguments to the policy constructor and create + * the StringEncoding object using the policy. + */ + template + StringEncoding(ArgTypes&& ... args); + + /** + * Construct the class from the given encoding policy. + * + * @param encodingPolicy The given encoding policy. + */ + StringEncoding(EncodingPolicyType encodingPolicy); + + /** + * A variant of the copy constructor for non-constant objects. + */ + StringEncoding(StringEncoding&); + + //! Default copy-constructor. + StringEncoding(const StringEncoding&); + + //! Default copy assignment operator. + StringEncoding& operator=(const StringEncoding&) = default; + + //! Default move-constructor. + StringEncoding(StringEncoding&&); + + //! Default move assignment operator. + StringEncoding& operator=(StringEncoding&&) = default; + + /** + * Initialize the dictionary using the given corpus. + * + * @tparam TokenizerType Type of the tokenizer. + * + * @param input Corpus of text to encode. + * @param tokenizer The tokenizer object. + * + * The tokenization algorithm has to be an object with two public methods: + * 1. operator() which accepts a reference to boost::string_view, extracts + * the next token from the given view, removes the prefix containing + * the extracted token and returns the token; + * 2. IsTokenEmpty() that accepts a token and returns true if the given + * token is empty. + */ + template + void CreateMap(const std::string& input, + const TokenizerType& tokenizer); + + /** + * Clear the dictionary. + */ + void Clear(); + + /** + * Encode the given text and write the result to the given output. The encoder + * writes data in the column-major order or in the row-major order depending + * on the output data type. + * + * If the output type is either arma::mat or arma::sp_mat then the function + * writes it in the column-major order. If the output type is 2D std::vector + * then the function writes it in the row major order. + * + * @tparam OutputType Type of the output container. The function supports + * the following types: arma::mat, arma::sp_mat, + * std::vector>. + * @tparam TokenizerType Type of the tokenizer. + * + * @param input Corpus of text to encode. + * @param output Output container to store the result. + * @param tokenizer The tokenizer object. + * + * The tokenization algorithm has to be an object with two public methods: + * 1. operator() which accepts a reference to boost::string_view, extracts + * the next token from the given view, removes the prefix containing + * the extracted token and returns the token; + * 2. IsTokenEmpty() that accepts a token and returns true if the given + * token is empty. + */ + template + void Encode(const std::vector& input, + OutputType& output, + const TokenizerType& tokenizer); + + //! Return the dictionary. + const DictionaryType& Dictionary() const { return dictionary; } + //! Modify the dictionary. + DictionaryType& Dictionary() { return dictionary; } + + //! Return the encoding policy object. + const EncodingPolicyType& EncodingPolicy() const { return encodingPolicy; } + //! Modify the encoding policy object. + EncodingPolicyType& EncodingPolicy() { return encodingPolicy; } + + /** + * Serialize the class to the given archive. + */ + template + void serialize(Archive& ar, const unsigned int /* version */); + + private: + /** + * A helper function to encode the given text and write the result to + * the given output. The encoder writes data in the column-major order or + * in the row-major order depending on the output data type. + * + * If the output type is either arma::mat or arma::sp_mat then the function + * writes it in the column-major order. If the output type is 2D std::vector + * then the function writes it in the row major order. + * + * @tparam OutputType Type of the output container. The function supports + * the following types: arma::mat, arma::sp_mat, + * std::vector>. + * @tparam TokenizerType Type of the tokenizer. + * @tparam PolicyType The type of the encoding policy. It has to be + * equal to EncodingPolicyType. + * + * @param input Corpus of text to encode. + * @param output Output container to store the result. + * @param tokenizer The tokenizer object. + * @param policy The policy object. + * + * The tokenization algorithm has to be an object with two public methods: + * 1. operator() which accepts a reference to boost::string_view, extracts + * the next token from the given view, removes the prefix containing + * the extracted token and returns the token; + * 2. IsTokenEmpty() that accepts a token and returns true if the given + * token is empty. + */ + template + void EncodeHelper(const std::vector& input, + OutputType& output, + const TokenizerType& tokenizer, + PolicyType& policy); + + /** + * A helper function to encode the given text and write the result to + * the given output. This is an optimized overload for policies that support + * the one pass encoding algorithm. The encoder writes data in the row-major + * order. + * + * @tparam TokenizerType Type of the tokenizer. + * @tparam PolicyType The type of the encoding policy. It has to be + * equal to EncodingPolicyType. + * @tparam ElemType Type of the output values. + * + * @param input Corpus of text to encode. + * @param output Output container to store the result. + * @param tokenizer The tokenizer object. + * @param policy The policy object. + * + * The tokenization algorithm has to be an object with two public methods: + * 1. operator() which accepts a reference to boost::string_view, extracts + * the next token from the given view, removes the prefix containing + * the extracted token and returns the token; + * 2. IsTokenEmpty() that accepts a token and returns true if the given + * token is empty. + */ + template + void EncodeHelper(const std::vector& input, + std::vector>& output, + const TokenizerType& tokenizer, + PolicyType& policy, + typename std::enable_if::onePassEncoding>::type* = 0); + + private: + //! The encoding policy object. + EncodingPolicyType encodingPolicy; + //! The dictionary that contains the tokens and their labels. + DictionaryType dictionary; +}; + +} // namespace data +} // namespace mlpack + +// Include implementation. +#include "string_encoding_impl.hpp" + +#endif diff -Nru mlpack-3.2.2/src/mlpack/core/data/string_encoding_impl.hpp mlpack-3.3.0/src/mlpack/core/data/string_encoding_impl.hpp --- mlpack-3.2.2/src/mlpack/core/data/string_encoding_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/string_encoding_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,211 @@ +/** + * @file string_encoding_impl.hpp + * @author Jeffin Sam + * @author Mikhail Lozhnikov + * + * Implementation of the StringEncoding 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_DATA_STRING_ENCODING_IMPL_HPP +#define MLPACK_CORE_DATA_STRING_ENCODING_IMPL_HPP + +// In case it hasn't been included yet. +#include "string_encoding.hpp" +#include + +namespace mlpack { +namespace data { + +template +template +StringEncoding::StringEncoding( + ArgTypes&& ... args) : + encodingPolicy(std::forward(args)...) +{ } + +template +StringEncoding::StringEncoding( + EncodingPolicyType encodingPolicy) : + encodingPolicy(std::move(encodingPolicy)) +{ } + +template +StringEncoding::StringEncoding( + StringEncoding& other) : + encodingPolicy(other.encodingPolicy), + dictionary(other.dictionary) +{ } + +template +StringEncoding::StringEncoding( + const StringEncoding& other) : + encodingPolicy(other.encodingPolicy), + dictionary(other.dictionary) +{ } + +template +StringEncoding::StringEncoding( + StringEncoding&& other) : + encodingPolicy(std::move(other.encodingPolicy)), + dictionary(std::move(other.dictionary)) +{ } + +template +void StringEncoding::Clear() +{ + dictionary.Clear(); +} + +template +template +void StringEncoding::CreateMap( + const std::string& input, + const TokenizerType& tokenizer) +{ + boost::string_view strView(input); + auto token = tokenizer(strView); + + static_assert( + std::is_same::type, + typename std::remove_reference::type>::value, + "The dictionary token type doesn't match the return value type " + "of the tokenizer."); + + // The loop below adds the extracted tokens to the dictionary. + while (!tokenizer.IsTokenEmpty(token)) + { + if (!dictionary.HasToken(token)) + dictionary.AddToken(std::move(token)); + + token = tokenizer(strView); + } +} + +template +template +void StringEncoding::Encode( + const std::vector& input, + OutputType& output, + const TokenizerType& tokenizer) +{ + EncodeHelper(input, output, tokenizer, encodingPolicy); +} + + +template +template +void StringEncoding:: +EncodeHelper(const std::vector& input, + MatType& output, + const TokenizerType& tokenizer, + PolicyType& policy) +{ + size_t numColumns = 0; + + policy.Reset(); + + // The first pass adds the extracted tokens to the dictionary. + for (size_t i = 0; i < input.size(); i++) + { + boost::string_view strView(input[i]); + auto token = tokenizer(strView); + + static_assert( + std::is_same::type, + typename std::remove_reference::type>::value, + "The dictionary token type doesn't match the return value type " + "of the tokenizer."); + + size_t numTokens = 0; + + while (!tokenizer.IsTokenEmpty(token)) + { + if (!dictionary.HasToken(token)) + dictionary.AddToken(std::move(token)); + + policy.PreprocessToken(i, numTokens, dictionary.Value(token)); + + token = tokenizer(strView); + numTokens++; + } + + numColumns = std::max(numColumns, numTokens); + } + + policy.InitMatrix(output, input.size(), numColumns, dictionary.Size()); + + // The second pass writes the encoded values to the output. + for (size_t i = 0; i < input.size(); i++) + { + boost::string_view strView(input[i]); + auto token = tokenizer(strView); + size_t numTokens = 0; + + while (!tokenizer.IsTokenEmpty(token)) + { + policy.Encode(output, dictionary.Value(token), i, numTokens); + token = tokenizer(strView); + numTokens++; + } + } +} + +template +template +void StringEncoding:: +EncodeHelper(const std::vector& input, + std::vector>& output, + const TokenizerType& tokenizer, + PolicyType& policy, + typename std::enable_if::onePassEncoding>::type*) +{ + policy.Reset(); + + // The loop below extracts the tokens and writes the encoded values + // at once. + for (size_t i = 0; i < input.size(); i++) + { + boost::string_view strView(input[i]); + auto token = tokenizer(strView); + + static_assert( + std::is_same::type, + typename std::remove_reference::type>::value, + "The dictionary token type doesn't match the return value type " + "of the tokenizer."); + + output.emplace_back(); + + while (!tokenizer.IsTokenEmpty(token)) + { + if (dictionary.HasToken(token)) + policy.Encode(output[i], dictionary.Value(token)); + else + policy.Encode(output[i], dictionary.AddToken(std::move(token))); + + token = tokenizer(strView); + } + } +} + +template +template +void StringEncoding::serialize( + Archive& ar, const unsigned int /* version */) +{ + ar & BOOST_SERIALIZATION_NVP(encodingPolicy); + ar & BOOST_SERIALIZATION_NVP(dictionary); +} + +} // namespace data +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/core/data/string_encoding_policies/bag_of_words_encoding_policy.hpp mlpack-3.3.0/src/mlpack/core/data/string_encoding_policies/bag_of_words_encoding_policy.hpp --- mlpack-3.2.2/src/mlpack/core/data/string_encoding_policies/bag_of_words_encoding_policy.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/string_encoding_policies/bag_of_words_encoding_policy.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,171 @@ +/** + * @file bag_of_words_encoding_policy.hpp + * @author Jeffin Sam + * @author Mikhail Lozhnikov + * + * Definition of the BagOfWordsEncodingPolicy 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_DATA_STR_ENCODING_POLICIES_BAG_OF_WORDS_ENCODING_POLICY_HPP +#define MLPACK_CORE_DATA_STR_ENCODING_POLICIES_BAG_OF_WORDS_ENCODING_POLICY_HPP + +#include +#include +#include + +namespace mlpack { +namespace data { + +/** + * Definition of the BagOfWordsEncodingPolicy class. + * + * BagOfWords is used as a helper class for StringEncoding. The encoder maps + * each dataset item to a vector of size N, where N is equal to the total unique + * number of tokens. The i-th coordinate of the output vector is equal to + * the number of times when the i-th token occurs in the corresponding dataset + * item. The order in which the tokens are labeled is defined by the dictionary + * used by the StringEncoding class. The encoder writes data either in the + * column-major order or in the row-major order depending on the output data + * type. + */ +class BagOfWordsEncodingPolicy +{ + public: + /** + * Clear the necessary internal variables. + */ + static void Reset() + { + // Nothing to do. + } + + /** + * The function initializes the output matrix. The encoder writes data + * in the column-major order. + * + * @tparam MatType The output matrix type. + * + * @param output Output matrix to store the encoded results (sp_mat or mat). + * @param datasetSize The number of strings in the input dataset. + * @param maxNumTokens The maximum number of tokens in the strings of the + * input dataset (not used). + * @param dictionarySize The size of the dictionary. + */ + template + static void InitMatrix(MatType& output, + const size_t datasetSize, + const size_t /* maxNumTokens */, + const size_t dictionarySize) + { + output.zeros(dictionarySize, datasetSize); + } + + /** + * The function initializes the output matrix. The encoder writes data + * in the row-major order. + * + * Overloaded function to save the result in vector>. + * + * @tparam ElemType Type of the output values. + * + * @param output Output matrix to store the encoded results. + * @param datasetSize The number of strings in the input dataset. + * @param maxNumTokens The maximum number of tokens in the strings of the + * input dataset (not used). + * @param dictionarySize The size of the dictionary. + */ + template + static void InitMatrix(std::vector>& output, + const size_t datasetSize, + const size_t /* maxNumTokens */, + const size_t dictionarySize) + { + output.resize(datasetSize, std::vector(dictionarySize)); + } + + /** + * The function performs the bag of words encoding algorithm i.e. it writes + * the encoded token to the output. The encoder writes data in the + * column-major order. + * + * @tparam MatType The output matrix type. + * + * @param output Output matrix to store the encoded results (sp_mat or mat). + * @param value The encoded token. + * @param line The line number at which the encoding is performed. + * @param index The token index in the line. + */ + template + static void Encode(MatType& output, + const size_t value, + const size_t line, + const size_t /* index */) + { + // The labels are assigned sequentially starting from one. + output(value - 1, line) += 1; + } + + /** + * The function performs the bag of words encoding algorithm i.e. it writes + * the encoded token to the output. The encoder writes data in the + * row-major order. + * + * Overloaded function to accept vector> as the output + * type. + * + * @tparam ElemType Type of the output values. + * + * @param output Output matrix to store the encoded results. + * @param value The encoded token. + * @param line The line number at which the encoding is performed. + * @param index The line token number at which the encoding is performed. + */ + template + static void Encode(std::vector>& output, + const size_t value, + const size_t line, + const size_t /* index */) + { + // The labels are assigned sequentially starting from one. + output[line][value - 1] += 1; + } + + /** + * The function is not used by the bag of words encoding policy. + * + * @param line The line number at which the encoding is performed. + * @param index The token sequence number in the line. + * @param value The encoded token. + */ + static void PreprocessToken(size_t /* line */, + size_t /* index */, + size_t /* value */) + { } + + /** + * Serialize the class to the given archive. + */ + template + void serialize(Archive& /* ar */, const unsigned int /* version */) + { + // Nothing to serialize. + } +}; + +/** + * A convenient alias for the StringEncoding class with BagOfWordsEncodingPolicy + * and the default dictionary for the given token type. + * + * @tparam TokenType Type of the tokens. + */ +template +using BagOfWordsEncoding = StringEncoding>; +} // namespace data +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/core/data/string_encoding_policies/CMakeLists.txt mlpack-3.3.0/src/mlpack/core/data/string_encoding_policies/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/core/data/string_encoding_policies/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/string_encoding_policies/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,18 @@ +# Define the files that we need to compile. +# Anything not in this list will not be compiled into mlpack. +set(SOURCES + bag_of_words_encoding_policy.hpp + dictionary_encoding_policy.hpp + policy_traits.hpp + tf_idf_encoding_policy.hpp +) + +# 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 +# parent scope). +set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) diff -Nru mlpack-3.2.2/src/mlpack/core/data/string_encoding_policies/dictionary_encoding_policy.hpp mlpack-3.3.0/src/mlpack/core/data/string_encoding_policies/dictionary_encoding_policy.hpp --- mlpack-3.2.2/src/mlpack/core/data/string_encoding_policies/dictionary_encoding_policy.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/string_encoding_policies/dictionary_encoding_policy.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,150 @@ +/** + * @file dictionary_encoding_policy.hpp + * @author Jeffin Sam + * @author Mikhail Lozhnikov + * + * Definition of the DictionaryEncodingPolicy 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_DATA_STRING_ENCODING_POLICIES_DICTIONARY_ENCODING_POLICY_HPP +#define MLPACK_CORE_DATA_STRING_ENCODING_POLICIES_DICTIONARY_ENCODING_POLICY_HPP + +#include +#include +#include + +namespace mlpack { +namespace data { + +/** + * DicitonaryEnocdingPolicy is used as a helper class for StringEncoding. + * The encoder assigns a positive integer number to each unique token and treats + * the dataset as categorical. The numbers are assigned sequentially starting + * from one. The order in which the tokens are labeled is defined by + * the dictionary used by the StringEncoding class. The encoder writes data + * either in the column-major order or in the row-major order depending on + * the output data type. + */ +class DictionaryEncodingPolicy +{ + public: + /** + * Clear the necessary internal variables. + */ + static void Reset() + { + // Nothing to do. + } + + /** + * The function initializes the output matrix. The encoder writes data + * in the column-major order. + * + * @tparam MatType The output matrix type. + * + * @param output Output matrix to store the encoded results (sp_mat or mat). + * @param datasetSize The number of strings in the input dataset. + * @param maxNumTokens The maximum number of tokens in the strings of the + * input dataset. + * @param dictionarySize The size of the dictionary (not used). + */ + template + static void InitMatrix(MatType& output, + const size_t datasetSize, + const size_t maxNumTokens, + const size_t /* dictionarySize */) + { + output.zeros(maxNumTokens, datasetSize); + } + + /** + * The function performs the dictionary encoding algorithm i.e. it writes + * the encoded token to the output. The encoder writes data in the + * column-major order. + * + * @tparam MatType The output matrix type. + * + * @param output Output matrix to store the encoded results (sp_mat or mat). + * @param value The encoded token. + * @param line The line number at which the encoding is performed. + * @param index The token index in the line. + */ + template + static void Encode(MatType& output, + const size_t value, + const size_t line, + const size_t index) + { + output(index, line) = value; + } + + /** + * The function performs the dictionary encoding algorithm i.e. it writes + * the encoded token to the output. This is an overloaded function which saves + * the result into the given vector to avoid padding. The encoder writes data + * in the row-major order. + * + * @tparam ElemType Type of the output values. + * + * @param output Output vector to store the encoded line. + * @param value The encoded token. + */ + template + static void Encode(std::vector& output, size_t value) + { + output.push_back(value); + } + + /** + * The function is not used by the dictionary encoding policy. + * + * @param line The line number at which the encoding is performed. + * @param index The token sequence number in the line. + * @param value The encoded token. + */ + static void PreprocessToken(const size_t /* line */, + const size_t /* index */, + const size_t /* value */) + { } + + /** + * Serialize the class to the given archive. + */ + template + void serialize(Archive& /* ar */, const unsigned int /* version */) + { + // Nothing to serialize. + } +}; + +/** + * The specialization provides some information about the dictionary encoding + * policy. + */ +template<> +struct StringEncodingPolicyTraits +{ + /** + * Indicates if the policy is able to encode the token at once without + * any information about other tokens as well as the total tokens count. + */ + static const bool onePassEncoding = true; +}; + +/** + * A convenient alias for the StringEncoding class with DictionaryEncodingPolicy + * and the default dictionary for the given token type. + * + * @tparam TokenType Type of the tokens. + */ +template +using DictionaryEncoding = StringEncoding>; +} // namespace data +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/core/data/string_encoding_policies/policy_traits.hpp mlpack-3.3.0/src/mlpack/core/data/string_encoding_policies/policy_traits.hpp --- mlpack-3.2.2/src/mlpack/core/data/string_encoding_policies/policy_traits.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/string_encoding_policies/policy_traits.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,39 @@ +/** + * @file policy_traits.hpp + * @author Jeffin Sam + * @author Mikhail Lozhnikov + * + * This provides the StringEncodingPolicyTraits struct, a template struct to + * get information about various encoding policies. + * + * 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_DATA_STRING_ENCODING_POLICIES_POLICY_TRAITS_HPP +#define MLPACK_CORE_DATA_STRING_ENCODING_POLICIES_POLICY_TRAITS_HPP + +#include + +namespace mlpack { +namespace data { + +/** + * This is a template struct that provides some information about various + * encoding policies. + */ +template +struct StringEncodingPolicyTraits +{ + /** + * Indicates if the policy is able to encode the token at once without + * any information about other tokens as well as the total tokens count. + */ + static const bool onePassEncoding = false; +}; + +} // namespace data +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/core/data/string_encoding_policies/tf_idf_encoding_policy.hpp mlpack-3.3.0/src/mlpack/core/data/string_encoding_policies/tf_idf_encoding_policy.hpp --- mlpack-3.2.2/src/mlpack/core/data/string_encoding_policies/tf_idf_encoding_policy.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/string_encoding_policies/tf_idf_encoding_policy.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,349 @@ +/** + * @file tf_idf_encoding_policy.hpp + * @author Jeffin Sam + * @author Mikhail Lozhnikov + * + * Definition of the TfIdfEncodingPolicy 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_DATA_STRING_ENCODING_POLICIES_TF_IDF_ENCODING_POLICY_HPP +#define MLPACK_CORE_DATA_STRING_ENCODING_POLICIES_TF_IDF_ENCODING_POLICY_HPP + +#include +#include +#include + +namespace mlpack { +namespace data { + +/** + * Definition of the TfIdfEncodingPolicy class. TfIdfEncodingPolicy is used + * as a helper class for StringEncoding. + * + * Tf-idf is a weighting scheme that takes into account the importance of + * encoded tokens. The tf-idf statistics is equal to term frequency (tf) + * multiplied by inverse document frequency (idf). + * The encoder assigns the corresponding tf-idf value to each token. The order + * in which the tokens are labeled is defined by the dictionary used by the + * StringEncoding class. The encoder writes data either in the column-major + * order or in the row-major order depending on the output data type. + */ +class TfIdfEncodingPolicy +{ + public: + /** + * Enum class used to identify the type of the term frequency statistics. + * + * The present implementation supports the following types: + * BINARY Term frequency equals 1 if the row contains the encoded + * token and 0 otherwise. + * RAW_COUNT Term frequency equals the number of times when the encoded + * token occurs in the row. + * TERM_FREQUENCY Term frequency equals the number of times when the encoded + * token occurs in the row divided by the total number of + * tokens in the row. + * SUBLINEAR_TF Term frequency equals \f$ 1 + log(rawCount), \f$ where + * rawCount is equal to the number of times when the encoded + * token occurs in the row. + */ + enum class TfTypes + { + BINARY, + RAW_COUNT, + TERM_FREQUENCY, + SUBLINEAR_TF, + }; + + /** + * Construct this using the term frequency type and the inverse document + * frequency type. + * + * @param tfType Type of the term frequency statistics. + * @param smoothIdf Used to indicate whether to use smooth idf or not. + * If idf is smooth it's calculated by the following formula: + * \f$ idf(T) = \log \frac{1 + N}{1 + df(T)} + 1, \f$ where + * \f$ N \f$ is the total number of strings in the document, + * \f$ T \f$ is the current encoded token, \f$ df(T) \f$ + * equals the number of strings which contain the token. + * If idf isn't smooth then the following rule applies: + * \f$ idf(T) = \log \frac{N}{df(T)} + 1. \f$ + */ + TfIdfEncodingPolicy(const TfTypes tfType = TfTypes::RAW_COUNT, + const bool smoothIdf = true) : + tfType(tfType), + smoothIdf(smoothIdf) + { } + + /** + * Clear the necessary internal variables. + */ + void Reset() + { + tokensFrequences.clear(); + numContainingStrings.clear(); + linesSizes.clear(); + } + + /** + * The function initializes the output matrix. The encoder writes data + * in the row-major order. + * + * @tparam MatType The output matrix type. + * + * @param output Output matrix to store the encoded results (sp_mat or mat). + * @param datasetSize The number of strings in the input dataset. + * @param maxNumTokens The maximum number of tokens in the strings of the + * input dataset (not used). + * @param dictionarySize The size of the dictionary. + */ + template + static void InitMatrix(MatType& output, + const size_t datasetSize, + const size_t /* maxNumTokens */, + const size_t dictionarySize) + { + output.zeros(dictionarySize, datasetSize); + } + + /** + * The function initializes the output matrix. The encoder writes data + * in the row-major order. + * + * Overloaded function to save the result in vector>. + * + * @tparam ElemType Type of the output values. + * + * @param output Output matrix to store the encoded results. + * @param datasetSize The number of strings in the input dataset. + * @param maxNumTokens The maximum number of tokens in the strings of the + * input dataset (not used). + * @param dictionarySize The size of the dictionary. + */ + template + static void InitMatrix(std::vector>& output, + const size_t datasetSize, + const size_t /* maxNumTokens */, + const size_t dictionarySize) + { + output.resize(datasetSize, std::vector(dictionarySize)); + } + + /** + * The function performs the TfIdf encoding algorithm i.e. it writes + * the encoded token to the output. The encoder writes data in the + * column-major order. + * + * @tparam MatType The output matrix type. + * + * @param output Output matrix to store the encoded results (sp_mat or mat). + * @param value The encoded token. + * @param line The line number at which the encoding is performed. + * @param index The token index in the line. + */ + template + void Encode(MatType& output, + const size_t value, + const size_t line, + const size_t /* index */) + { + const typename MatType::elem_type tf = + TermFrequency( + tokensFrequences[line][value], linesSizes[line]); + + const typename MatType::elem_type idf = + InverseDocumentFrequency( + output.n_cols, numContainingStrings[value]); + + output(value - 1, line) = tf * idf; + } + + /** + * The function performs the TfIdf encoding algorithm i.e. it writes + * the encoded token to the output. The encoder writes data in the + * row-major order. + * + * Overloaded function to accept vector> as the output + * type. + * + * @tparam ElemType Type of the output values. + * + * @param output Output matrix to store the encoded results. + * @param value The encoded token. + * @param line The line number at which the encoding is performed. + * @param index The token index in the line. + */ + template + void Encode(std::vector>& output, + const size_t value, + const size_t line, + const size_t /* index */) + { + const ElemType tf = TermFrequency( + tokensFrequences[line][value], linesSizes[line]); + + const ElemType idf = InverseDocumentFrequency( + output.size(), numContainingStrings[value]); + + output[line][value - 1] = tf * idf; + } + + /* + * The function calculates the necessary statistics for the purpose + * of the tf-idf algorithm during the first pass through the dataset. + * + * @param line The line number at which the encoding is performed. + * @param index The token sequence number in the line. + * @param value The encoded token. + */ + void PreprocessToken(const size_t line, + const size_t /* index */, + const size_t value) + { + if (line >= tokensFrequences.size()) + { + linesSizes.resize(line + 1); + tokensFrequences.resize(line + 1); + } + + tokensFrequences[line][value]++; + + if (tokensFrequences[line][value] == 1) + numContainingStrings[value]++; + + linesSizes[line]++; + } + + //! Return token frequencies. + const std::vector>& + TokensFrequences() const { return tokensFrequences; } + //! Modify token frequencies. + std::vector>& TokensFrequences() + { + return tokensFrequences; + } + + //! Get the number of containing strings depending on the given token. + const std::unordered_map& NumContainingStrings() const + { + return numContainingStrings; + } + + //! Modify the number of containing strings depending on the given token. + std::unordered_map& NumContainingStrings() + { + return numContainingStrings; + } + + //! Return the lines sizes. + const std::vector& LinesSizes() const { return linesSizes; } + //! Modify the lines sizes. + std::vector& LinesSizes() { return linesSizes; } + + //! Return the term frequency type. + TfTypes TfType() const { return tfType; } + //! Modify the term frequency type. + TfTypes& TfType() { return tfType; } + + //! Determine the idf algorithm type (whether it's smooth or not). + bool SmoothIdf() const { return smoothIdf; } + //! Modify the idf algorithm type (whether it's smooth or not). + bool& SmoothIdf() { return smoothIdf; } + + /** + * Serialize the class to the given archive. + */ + template + void serialize(Archive& ar, const unsigned int /* version */) + { + ar & BOOST_SERIALIZATION_NVP(tfType); + ar & BOOST_SERIALIZATION_NVP(smoothIdf); + } + + private: + /** + * The function calculates the term frequency statistics. + * + * @tparam ValueType Type of the returned value. + * + * @param numOccurrences The number of the given token occurrences in + * the line. + * @param numTokens The total number of tokens in the line. + */ + template + ValueType TermFrequency(const size_t numOccurrences, + const size_t numTokens) + { + switch (tfType) + { + case TfTypes::BINARY: + return numOccurrences > 0; + case TfTypes::RAW_COUNT: + return numOccurrences; + case TfTypes::TERM_FREQUENCY: + return static_cast(numOccurrences) / numTokens; + case TfTypes::SUBLINEAR_TF: + return std::log(static_cast(numOccurrences)) + 1; + default: + Log::Fatal << "Incorrect term frequency type!"; + return 0; + } + } + + /** + * The function calculates the inverse document frequency statistics. + * + * @tparam ValueType Type of the returned value. + * + * @param totalNumLines The total number of strings in the input dataset. + * @param numOccurrences The number of strings in the input dataset + * which contain the current token. + */ + template + ValueType InverseDocumentFrequency(const size_t totalNumLines, + const size_t numOccurrences) + { + if (smoothIdf) + { + return std::log(static_cast(totalNumLines + 1) / + (1 + numOccurrences)) + 1.0; + } + else + { + return std::log(static_cast(totalNumLines) / + numOccurrences) + 1.0; + } + } + + private: + //! Used to store the total number of tokens for each line. + std::vector> tokensFrequences; + /** + * Used to store the number of strings which contain a token depending + * on the given token. + */ + std::unordered_map numContainingStrings; + //! Used to store the number of tokens in each line. + std::vector linesSizes; + //! Type of the term frequency scheme. + TfTypes tfType; + //! Indicates whether the idf scheme is smooth or not. + bool smoothIdf; +}; + +/** + * A convenient alias for the StringEncoding class with TfIdfEncodingPolicy + * and the default dictionary for the given token type. + * + * @tparam TokenType Type of the tokens. + */ +template +using TfIdfEncoding = StringEncoding>; +} // namespace data +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/core/data/tokenizers/char_extract.hpp mlpack-3.3.0/src/mlpack/core/data/tokenizers/char_extract.hpp --- mlpack-3.2.2/src/mlpack/core/data/tokenizers/char_extract.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/tokenizers/char_extract.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,65 @@ +/** + * @file char_extract.hpp + * @author Jeffin Sam + * @author Mikhail Lozhnikov + * + * Definition of the CharExtract class which tokenizes a string into + * characters. + * + * 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_DATA_TOKENIZERS_CHAR_EXTRACT_HPP +#define MLPACK_CORE_DATA_TOKENIZERS_CHAR_EXTRACT_HPP + +#include + +namespace mlpack { +namespace data { + +/** + * The class is used to split a string into characters. + */ +class CharExtract +{ + public: + //! The type of the token which the tokenizer extracts. + using TokenType = int; + + /** + * The function extracts the first character from the given string view and + * removes it from the view. Each charecter is casted to unsigned char i.e. + * it belongs to [0, 255]. The functon returns EOF provided that the input + * string is empty. + * + * @param str String view to retrieve the next token from. + */ + int operator()(boost::string_view& str) const + { + if (str.empty()) + return EOF; + + const int retval = static_cast(str[0]); + + str.remove_prefix(1); + + return retval; + } + + /** + * The function returns true if the given token is equal to EOF. + * + * @param token The given token. + */ + static bool IsTokenEmpty(const int token) + { + return token == EOF; + } +}; + +} // namespace data +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/core/data/tokenizers/CMakeLists.txt mlpack-3.3.0/src/mlpack/core/data/tokenizers/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/core/data/tokenizers/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/tokenizers/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,16 @@ +# Define the files that we need to compile. +# Anything not in this list will not be compiled into mlpack. +set(SOURCES + char_extract.hpp + split_by_any_of.hpp +) + +# 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 +# parent scope). +set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) diff -Nru mlpack-3.2.2/src/mlpack/core/data/tokenizers/split_by_any_of.hpp mlpack-3.3.0/src/mlpack/core/data/tokenizers/split_by_any_of.hpp --- mlpack-3.2.2/src/mlpack/core/data/tokenizers/split_by_any_of.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/data/tokenizers/split_by_any_of.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,114 @@ +/** + * @file split_by_any_of.hpp + * @author Jeffin Sam + * @author Mikhail Lozhnikov + * + * Definition of the SplitByAnyOf 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_DATA_TOKENIZERS_SPLIT_BY_ANY_OF_HPP +#define MLPACK_CORE_DATA_TOKENIZERS_SPLIT_BY_ANY_OF_HPP + +#include +#include +#include + +namespace mlpack { +namespace data { + +/** + * The SplitByAnyOf class tokenizes a string using a set of delimiters. + */ +class SplitByAnyOf +{ + public: + //! The type of the token which the tokenizer extracts. + using TokenType = boost::string_view; + + //! A convenient alias for the mask type. + using MaskType = std::array; + + /** + * Construct the object from the given delimiters. + * + * @param delimiters The given delimiters. + */ + SplitByAnyOf(const boost::string_view delimiters) + { + mask.fill(false); + + for (char symbol : delimiters) + mask[static_cast(symbol)] = true; + } + + /** + * The function extracts the first token from the given string view and + * then removes the prefix containing the token from the view. + * + * @param str String view to retrieve the token from. + */ + boost::string_view operator()(boost::string_view& str) const + { + boost::string_view retval; + + while (retval.empty()) + { + const std::size_t pos = FindFirstDelimiter(str); + if (pos == str.npos) + { + retval = str; + str.clear(); + return retval; + } + retval = str.substr(0, pos); + str.remove_prefix(pos + 1); + } + return retval; + } + + /** + * The function returns true if the given token is empty. + * + * @param token The given token. + */ + static bool IsTokenEmpty(const boost::string_view token) + { + return token.empty(); + } + + //! Return the mask. + const MaskType& Mask() const { return mask; } + //! Modify the mask. + MaskType& Mask() { return mask; } + + private: + /** + * The function finds the first character in the given string view equal to + * any of the delimiters and returns the position of the character or + * boost::string_view::npos if no such character is found. + * + * @param str String where to find the character. + */ + size_t FindFirstDelimiter(const boost::string_view str) const + { + for (size_t pos = 0; pos < str.size(); pos++) + { + if (mask[static_cast(str[pos])]) + return pos; + } + return str.npos; + } + + private: + //! The mask that corresponds to the delimiters. + MaskType mask; +}; + +} // namespace data +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/core/dists/gamma_distribution.cpp mlpack-3.3.0/src/mlpack/core/dists/gamma_distribution.cpp --- mlpack-3.2.2/src/mlpack/core/dists/gamma_distribution.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/dists/gamma_distribution.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -11,8 +11,8 @@ * http://www.opensource.org/licenses/BSD-3-Clause for more information. */ #include "gamma_distribution.hpp" -// This will include digamma and trigamma. -#include +#include +#include using namespace mlpack; using namespace mlpack::distribution; diff -Nru mlpack-3.2.2/src/mlpack/core/dists/gaussian_distribution.cpp mlpack-3.3.0/src/mlpack/core/dists/gaussian_distribution.cpp --- mlpack-3.2.2/src/mlpack/core/dists/gaussian_distribution.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/dists/gaussian_distribution.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -39,8 +39,11 @@ void GaussianDistribution::FactorCovariance() { // On Armadillo < 4.500, the "lower" option isn't available. - covLower = arma::chol(covariance, "lower"); + if (!arma::chol(covLower, covariance, "lower")) + { + Log::Fatal << "Cholesky decomposition failed." << std::endl; + } // Comment from rcurtin: // // I think the use of the word "interpret" in the Armadillo documentation diff -Nru mlpack-3.2.2/src/mlpack/core/math/lin_alg.cpp mlpack-3.3.0/src/mlpack/core/math/lin_alg.cpp --- mlpack-3.2.2/src/mlpack/core/math/lin_alg.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/math/lin_alg.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -74,32 +74,6 @@ } /** - * Whitens a matrix using the eigendecomposition of the covariance matrix. - * Whitening means the covariance matrix of the result is the identity matrix. - */ -void mlpack::math::WhitenUsingEig(const arma::mat& x, - arma::mat& xWhitened, - arma::mat& whiteningMatrix) -{ - arma::mat diag, eigenvectors; - arma::vec eigenvalues; - - // Get eigenvectors of covariance of input matrix. - eig_sym(eigenvalues, eigenvectors, mlpack::math::ColumnCovariance(x)); - - // Generate diagonal matrix using 1 / sqrt(eigenvalues) for each value. - VectorPower(eigenvalues, -0.5); - diag.zeros(eigenvalues.n_elem, eigenvalues.n_elem); - diag.diag() = eigenvalues; - - // Our whitening matrix is diag(1 / sqrt(eigenvectors)) * eigenvalues. - whiteningMatrix = diag * trans(eigenvectors); - - // Now apply the whitening matrix. - xWhitened = whiteningMatrix * x; -} - -/** * Overwrites a dimension-N vector to a random vector on the unit sphere in R^N. */ void mlpack::math::RandVector(arma::vec& v) diff -Nru mlpack-3.2.2/src/mlpack/core/math/lin_alg.hpp mlpack-3.3.0/src/mlpack/core/math/lin_alg.hpp --- mlpack-3.2.2/src/mlpack/core/math/lin_alg.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/math/lin_alg.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -45,13 +45,6 @@ arma::mat& xWhitened, arma::mat& whiteningMatrix); -/** - * Whitens a matrix using the eigendecomposition of the covariance matrix. - * Whitening means the covariance matrix of the result is the identity matrix. - */ -void WhitenUsingEig(const arma::mat& x, - arma::mat& xWhitened, - arma::mat& whiteningMatrix); /** * Overwrites a dimension-N vector to a random vector on the unit sphere in R^N. diff -Nru mlpack-3.2.2/src/mlpack/core/metrics/ip_metric_impl.hpp mlpack-3.3.0/src/mlpack/core/metrics/ip_metric_impl.hpp --- mlpack-3.2.2/src/mlpack/core/metrics/ip_metric_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/metrics/ip_metric_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -49,7 +49,7 @@ template IPMetric::IPMetric(const IPMetric& other) : - kernel(other.kernel), + kernel(!other.kernelOwner ? other.kernel : new KernelType(*other.kernel)), kernelOwner(other.kernelOwner) { // Nothing to do. @@ -90,7 +90,11 @@ // If we're loading, we need to allocate space for the kernel, and we will own // the kernel. if (Archive::is_loading::value) + { + if (kernelOwner) + delete kernel; kernelOwner = true; + } ar & BOOST_SERIALIZATION_NVP(kernel); } diff -Nru mlpack-3.2.2/src/mlpack/core/metrics/lmetric.hpp mlpack-3.3.0/src/mlpack/core/metrics/lmetric.hpp --- mlpack-3.2.2/src/mlpack/core/metrics/lmetric.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/metrics/lmetric.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -63,7 +63,7 @@ class LMetric { public: - /*** + /** * Default constructor does nothing, but is required to satisfy the Metric * policy. */ diff -Nru mlpack-3.2.2/src/mlpack/core/metrics/mahalanobis_distance.hpp mlpack-3.3.0/src/mlpack/core/metrics/mahalanobis_distance.hpp --- mlpack-3.2.2/src/mlpack/core/metrics/mahalanobis_distance.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/metrics/mahalanobis_distance.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -1,4 +1,4 @@ -/*** +/** * @file mahalanobis_distance.hpp * @author Ryan Curtin * diff -Nru mlpack-3.2.2/src/mlpack/core/metrics/mahalanobis_distance_impl.hpp mlpack-3.3.0/src/mlpack/core/metrics/mahalanobis_distance_impl.hpp --- mlpack-3.2.2/src/mlpack/core/metrics/mahalanobis_distance_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/metrics/mahalanobis_distance_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -1,4 +1,4 @@ -/*** +/** * @file mahalanobis_distance_impl.hpp * @author Ryan Curtin * diff -Nru mlpack-3.2.2/src/mlpack/core/tree/binary_space_tree/binary_space_tree.hpp mlpack-3.3.0/src/mlpack/core/tree/binary_space_tree/binary_space_tree.hpp --- mlpack-3.2.2/src/mlpack/core/tree/binary_space_tree/binary_space_tree.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/tree/binary_space_tree/binary_space_tree.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -273,7 +273,7 @@ * Create a binary space tree by copying the other tree. Be careful! This * can take a long time and use a lot of memory. * - * @param other Tree to be replicated. + * @param other Tree to be copied. */ BinarySpaceTree(const BinarySpaceTree& other); @@ -284,6 +284,20 @@ BinarySpaceTree(BinarySpaceTree&& other); /** + * Copy the given BinarySaceTree. + * + * @param other The tree to be copied. + */ + BinarySpaceTree& operator=(const BinarySpaceTree& other); + + /** + * Take ownership of the given BinarySpaceTree. + * + * @param other The tree to take ownership of. + */ + BinarySpaceTree& operator=(BinarySpaceTree&& other); + + /** * Initialize the tree from a boost::serialization archive. * * @param ar Archive to load tree from. Must be an iarchive, not an oarchive. diff -Nru mlpack-3.2.2/src/mlpack/core/tree/binary_space_tree/binary_space_tree_impl.hpp mlpack-3.3.0/src/mlpack/core/tree/binary_space_tree/binary_space_tree_impl.hpp --- mlpack-3.2.2/src/mlpack/core/tree/binary_space_tree/binary_space_tree_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/tree/binary_space_tree/binary_space_tree_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -341,6 +341,7 @@ stat(other.stat), parentDistance(other.parentDistance), furthestDescendantDistance(other.furthestDescendantDistance), + minimumBoundDistance(other.minimumBoundDistance), // Copy matrix, but only if we are the root. dataset((other.parent == NULL) ? new MatType(*other.dataset) : NULL) { @@ -380,6 +381,126 @@ } /** + * Copy assignment operator: copy the given other tree. + */ +template class BoundType, + template + class SplitType> +BinarySpaceTree& +BinarySpaceTree:: +operator=(const BinarySpaceTree& other) +{ + // Return if it's the same tree. + if (this == &other) + return *this; + + // Freeing memory that will not be used anymore. + delete dataset; + delete left; + delete right; + + left = NULL; + right = NULL; + parent = other.Parent(); + begin = other.Begin(); + count = other.Count(); + bound = other.bound; + stat = other.stat; + parentDistance = other.ParentDistance(); + furthestDescendantDistance = other.FurthestDescendantDistance(); + minimumBoundDistance = other.MinimumBoundDistance(); + // Copy matrix, but only if we are the root. + dataset = ((other.parent == NULL) ? new MatType(*other.dataset) : NULL); + + // Create left and right children (if any). + if (other.Left()) + { + left = new BinarySpaceTree(*other.Left()); + left->Parent() = this; // Set parent to this, not other tree. + } + + if (other.Right()) + { + right = new BinarySpaceTree(*other.Right()); + right->Parent() = this; // Set parent to this, not other tree. + } + + // Propagate matrix, but only if we are the root. + if (parent == NULL) + { + std::queue queue; + if (left) + queue.push(left); + if (right) + queue.push(right); + while (!queue.empty()) + { + BinarySpaceTree* node = queue.front(); + queue.pop(); + + node->dataset = dataset; + if (node->left) + queue.push(node->left); + if (node->right) + queue.push(node->right); + } + } + + return *this; +} + +/** + * Move assignment operator: take ownership of the given tree. + */ +template class BoundType, + template + class SplitType> +BinarySpaceTree& +BinarySpaceTree:: +operator=(BinarySpaceTree&& other) +{ + // Return if it's the same tree. + if (this == &other) + return *this; + + // Freeing memory that will not be used anymore. + delete dataset; + delete left; + delete right; + + parent = other.Parent(); + left = other.Left(); + right = other.Right(); + begin = other.Begin(); + count = other.Count(); + bound = std::move(other.bound); + stat = std::move(other.stat); + parentDistance = other.ParentDistance(); + furthestDescendantDistance = other.FurthestDescendantDistance(); + minimumBoundDistance = other.MinimumBoundDistance(); + dataset = other.dataset; + + other.left = NULL; + other.right = NULL; + other.parent = NULL; + other.begin = 0; + other.count = 0; + other.parentDistance = 0.0; + other.furthestDescendantDistance = 0.0; + other.minimumBoundDistance = 0.0; + other.dataset = NULL; + + return *this; +} + + +/** * Move constructor. */ template& subIndices) : - dataset(parentNode.GetDataset()), + dataset(&parentNode.GetDataset()), parent(&parentNode), left(NULL), right(NULL), - numColumns(subIndices.size()) + numColumns(subIndices.size()), + localDataset(false) { // Initialize sizes of column indices and l2 norms. indices.resize(numColumns); @@ -76,10 +78,11 @@ CosineTree::CosineTree(const arma::mat& dataset, const double epsilon, const double delta) : - dataset(dataset), + dataset(&dataset), delta(delta), left(NULL), - right(NULL) + right(NULL), + localDataset(false) { // Declare the cosine tree priority queue. CosineNodeQueue treeQueue; @@ -150,8 +153,214 @@ ConstructBasis(treeQueue); } +//! Copy the given tree. +CosineTree::CosineTree(const CosineTree& other) : + // Copy matrix, but only if we are the root. + dataset((other.parent == NULL) ? new arma::mat(*other.dataset) : NULL), + delta(other.delta), + parent(NULL), + left(NULL), + right(NULL), + indices(other.indices), + l2NormsSquared(other.l2NormsSquared), + centroid(other.centroid), + basisVector(other.basisVector), + splitPointIndex(other.SplitPointIndex()), + numColumns(other.NumColumns()), + l2Error(other.L2Error()), + frobNormSquared(other.FrobNormSquared()), + localDataset(other.parent == NULL) +{ + // Create left and right children (if any). + if (other.Left()) + { + left = new CosineTree(*other.Left()); + left->Parent() = this; // Set parent to this, not other tree. + } + + if (other.Right()) + { + right = new CosineTree(*other.Right()); + right->Parent() = this; // Set parent to this, not other tree. + } + + // Propagate matrix, but only if we are the root. + if (parent == NULL && localDataset) + { + std::queue queue; + if (left) + queue.push(left); + if (right) + queue.push(right); + while (!queue.empty()) + { + CosineTree* node = queue.front(); + queue.pop(); + + node->dataset = dataset; + if (node->left) + queue.push(node->left); + if (node->right) + queue.push(node->right); + } + } +} + +//! Copy assignment operator: copy the given other tree. +CosineTree& CosineTree::operator=(const CosineTree& other) +{ + // Return if it's the same tree. + if (this == &other) + return *this; + + // Freeing memory that will not be used anymore. + if (localDataset) + delete dataset; + + delete left; + delete right; + + // Performing a deep copy of the dataset. + dataset = (other.parent == NULL) ? new arma::mat(*other.dataset) : NULL; + + delta = other.delta; + parent = other.Parent(); + left = other.Left(); + right = other.Right(); + indices = other.indices; + l2NormsSquared = other.l2NormsSquared; + centroid = other.centroid; + basisVector = other.basisVector; + splitPointIndex = other.SplitPointIndex(); + numColumns = other.NumColumns(); + l2Error = other.L2Error(); + localDataset = (other.parent == NULL) ? true : false; + frobNormSquared = other.FrobNormSquared(); + + // Create left and right children (if any). + if (other.Left()) + { + left = new CosineTree(*other.Left()); + left->Parent() = this; // Set parent to this, not other tree. + } + + if (other.Right()) + { + right = new CosineTree(*other.Right()); + right->Parent() = this; // Set parent to this, not other tree. + } + + // Propagate matrix, but only if we are the root. + if (parent == NULL && localDataset) + { + std::queue queue; + if (left) + queue.push(left); + if (right) + queue.push(right); + while (!queue.empty()) + { + CosineTree* node = queue.front(); + queue.pop(); + + node->dataset = dataset; + if (node->left) + queue.push(node->left); + if (node->right) + queue.push(node->right); + } + } + + return *this; +} + +//! Move the given tree. +CosineTree::CosineTree(CosineTree&& other) : + dataset(other.dataset), + delta(std::move(other.delta)), + parent(other.parent), + left(other.left), + right(other.right), + indices(std::move(other.indices)), + l2NormsSquared(std::move(other.l2NormsSquared)), + centroid(std::move(other.centroid)), + basisVector(std::move(other.basisVector)), + splitPointIndex(other.splitPointIndex), + numColumns(other.numColumns), + l2Error(other.l2Error), + frobNormSquared(other.frobNormSquared), + localDataset(other.localDataset) +{ + // Now we are a clone of the other tree. But we must also clear the other + // tree's contents, so it doesn't delete anything when it is destructed. + other.dataset = NULL; + other.parent = NULL; + other.left = NULL; + other.right = NULL; + other.splitPointIndex = 0; + other.numColumns = 0; + other.l2Error = -1; + other.localDataset = false; + other.frobNormSquared = 0; + // Set new parent. + if (left) + left->parent = this; + if (right) + right->parent = this; +} + +//! Move assignment operator: take ownership of the given tree. +CosineTree& CosineTree::operator=(CosineTree&& other) +{ + // Return if it's the same tree. + if (this == &other) + return *this; + + // Freeing memory that will not be used anymore. + if (localDataset) + delete dataset; + delete left; + delete right; + + dataset = other.dataset; + delta = std::move(other.delta); + parent = other.Parent(); + left = other.Left(); + right = other.Right(); + indices = std::move(other.indices); + l2NormsSquared = std::move(other.l2NormsSquared); + centroid = std::move(other.centroid); + basisVector = std::move(other.basisVector); + splitPointIndex = other.SplitPointIndex(); + numColumns = other.NumColumns(); + l2Error = other.L2Error(); + localDataset = other.localDataset; + frobNormSquared = other.FrobNormSquared(); + + // Now we are a clone of the other tree. But we must also clear the other + // tree's contents, so it doesn't delete anything when it is destructed. + other.dataset = NULL; + other.parent = NULL; + other.left = NULL; + other.right = NULL; + other.splitPointIndex = 0; + other.numColumns = 0; + other.l2Error = -1; + other.localDataset = false; + other.frobNormSquared = 0; + // Set new parent. + if (left) + left->parent = this; + if (right) + right->parent = this; + + return *this; +} + CosineTree::~CosineTree() { + if (localDataset) + delete dataset; if (left) delete left; if (right) @@ -206,7 +415,7 @@ node->ColumnSamplesLS(sampledIndices, probabilities, numSamples); // Get pointer to the original dataset. - arma::mat dataset = node->GetDataset(); + const arma::mat& dataset = node->GetDataset(); // Initialize weighted projection magnitudes as zeros. arma::vec weightedMagnitudes; @@ -280,7 +489,7 @@ void CosineTree::ConstructBasis(CosineNodeQueue& treeQueue) { // Initialize basis as matrix of zeros. - basis.zeros(dataset.n_rows, treeQueue.size()); + basis.zeros(dataset->n_rows, treeQueue.size()); // Variables for iterating through the priority queue. CosineTree *currentNode; @@ -435,8 +644,8 @@ else { cosines(i) = - std::abs(arma::norm_dot(dataset.col(indices[splitPointIndex]), - dataset.col(indices[i]))); + std::abs(arma::norm_dot(dataset->col(indices[splitPointIndex]), + dataset->col(indices[i]))); } } } @@ -444,12 +653,12 @@ void CosineTree::CalculateCentroid() { // Initialize centroid as vector of zeros. - centroid.zeros(dataset.n_rows); + centroid.zeros(dataset->n_rows); // Calculate centroid of columns in the node. for (size_t i = 0; i < numColumns; i++) { - centroid += dataset.col(indices[i]); + centroid += dataset->col(indices[i]); } centroid /= numColumns; } diff -Nru mlpack-3.2.2/src/mlpack/core/tree/cosine_tree/cosine_tree.hpp mlpack-3.3.0/src/mlpack/core/tree/cosine_tree/cosine_tree.hpp --- mlpack-3.2.2/src/mlpack/core/tree/cosine_tree/cosine_tree.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/tree/cosine_tree/cosine_tree.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -69,6 +69,35 @@ const double delta); /** + * Copy the given tree. Be careful! This may use a lot of memory. + * + * @param other Tree to copy from. + */ + CosineTree(const CosineTree& other); + + /** + * Move the given tree. The tree passed as a parameter will be emptied and + * will not be usable after this call. + * + * @param other Tree to move. + */ + CosineTree(CosineTree&& other); + + /** + * Copy the given Cosine Tree. + * + * @param other The tree to be copied. + */ + CosineTree& operator=(const CosineTree& other); + + /** + * Take ownership of the given Cosine Tree. + * + * @param other The tree to take ownership of. + */ + CosineTree& operator=(CosineTree&& other); + + /** * Clean up the CosineTree: release allocated memory (including children). */ ~CosineTree(); @@ -169,7 +198,7 @@ void GetFinalBasis(arma::mat& finalBasis) { finalBasis = basis; } //! Get pointer to the dataset matrix. - const arma::mat& GetDataset() const { return dataset; } + const arma::mat& GetDataset() const { return *dataset; } //! Get the indices of columns in the node. std::vector& VectorIndices() { return indices; } @@ -214,7 +243,7 @@ private: //! Matrix for which cosine tree is constructed. - const arma::mat& dataset; + const arma::mat* dataset; //! Cumulative probability for Monte Carlo error lower bound. double delta; //! Subspace basis of the input dataset. @@ -241,6 +270,8 @@ double l2Error; //! Frobenius norm squared of columns in the node. double frobNormSquared; + //! If true, we own the dataset and need to destroy it in the destructor. + bool localDataset; }; class CompareCosineNode diff -Nru mlpack-3.2.2/src/mlpack/core/tree/cover_tree/cover_tree_impl.hpp mlpack-3.3.0/src/mlpack/core/tree/cover_tree/cover_tree_impl.hpp --- mlpack-3.2.2/src/mlpack/core/tree/cover_tree/cover_tree_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/tree/cover_tree/cover_tree_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -548,7 +548,7 @@ } } -// Copy Assignment. +// Copy assignment operator: copy the given other tree. template< typename MetricType, typename StatisticType, @@ -658,7 +658,7 @@ other.metric = NULL; } -// Move Assignment. +// Move assignment operator: take ownership of the given tree. template< typename MetricType, typename StatisticType, diff -Nru mlpack-3.2.2/src/mlpack/core/tree/hollow_ball_bound_impl.hpp mlpack-3.3.0/src/mlpack/core/tree/hollow_ball_bound_impl.hpp --- mlpack-3.2.2/src/mlpack/core/tree/hollow_ball_bound_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/tree/hollow_ball_bound_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -80,6 +80,9 @@ HollowBallBound& HollowBallBound:: operator=(const HollowBallBound& other) { + if (ownsMetric) + delete metric; + radii = other.radii; center = other.center; hollowCenter = other.hollowCenter; diff -Nru mlpack-3.2.2/src/mlpack/core/tree/octree/octree.hpp mlpack-3.3.0/src/mlpack/core/tree/octree/octree.hpp --- mlpack-3.2.2/src/mlpack/core/tree/octree/octree.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/tree/octree/octree.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -221,6 +221,20 @@ Octree(Octree&& other); /** + * Copy the given Octree. + * + * @param other The tree to be copied. + */ + Octree& operator=(const Octree& other); + + /** + * Take ownership of the given Octree. + * + * @param other The tree to take ownership of. + */ + Octree& operator=(Octree&& other); + + /** * Initialize the tree from a boost::serialization archive. * * @param ar Archive to load tree from. Must be an iarchive, not an oarchive. diff -Nru mlpack-3.2.2/src/mlpack/core/tree/octree/octree_impl.hpp mlpack-3.3.0/src/mlpack/core/tree/octree/octree_impl.hpp --- mlpack-3.2.2/src/mlpack/core/tree/octree/octree_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/tree/octree/octree_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -363,6 +363,43 @@ } } +//! Copy assignment operator: copy the given other tree. +template +Octree& +Octree:: +operator=(const Octree& other) +{ + // Return if it's the same tree. + if (this == &other) + return *this; + + // Freeing memory that will not be used anymore. + delete dataset; + for (size_t i = 0; i < children.size(); ++i) + delete children[i]; + children.clear(); + + begin = other.Begin(); + count = other.Count(); + bound = other.bound; + dataset = ((other.parent == NULL) ? new MatType(*other.dataset) : NULL); + parent = NULL; + stat = other.stat; + parentDistance = other.ParentDistance(); + furthestDescendantDistance = other.FurthestDescendantDistance(); + metric = other.metric; + + // If we have any children, we need to create them, and then ensure that their + // parent links are set right. + for (size_t i = 0; i < other.NumChildren(); ++i) + { + children.push_back(new Octree(other.Child(i))); + children[i]->parent = this; + children[i]->dataset = this->dataset; + } + return *this; +} + //! Move the given tree. template Octree::Octree(Octree&& other) : @@ -389,6 +426,48 @@ other.parent = NULL; } +//! Move assignment operator: take ownership of the given tree. +template +Octree& +Octree:: +operator=(Octree&& other) +{ + // Return if it's the same tree. + if (this == &other) + return *this; + + // Freeing memory that will not be used anymore. + delete dataset; + for (size_t i = 0; i < children.size(); ++i) + delete children[i]; + children.clear(); + + children = std::move(other.children); + begin = other.Begin(); + count = other.Count(); + bound = std::move(other.bound); + dataset = other.dataset; + parent = other.Parent(); + stat = std::move(other.stat); + parentDistance = other.ParentDistance(); + furthestDescendantDistance = other.furthestDescendantDistance(); + metric = std::move(other.metric); + + // Update the parent pointers of the direct children. + for (size_t i = 0; i < children.size(); ++i) + children[i]->parent = this; + + other.begin = 0; + other.count = 0; + other.dataset = new MatType(); + other.parentDistance = 0.0; + other.numDescendants = 0; + other.furthestDescendantDistance = 0.0; + other.parent = NULL; + + return *this; +} + template Octree::Octree() : begin(0), diff -Nru mlpack-3.2.2/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp mlpack-3.3.0/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp --- mlpack-3.2.2/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/tree/rectangle_tree/rectangle_tree_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -183,6 +183,7 @@ maxLeafSize(other.MaxLeafSize()), minLeafSize(other.MinLeafSize()), bound(other.bound), + stat(other.stat), parentDistance(other.ParentDistance()), dataset(deepCopy ? (parent ? parent->dataset : new MatType(*other.dataset)) : @@ -203,6 +204,9 @@ children = other.children; } +/** + * Move constructor. + */ templateparent = this; } + // Now we are a clone of the other tree. But we must also clear the other + // tree's contents, so it doesn't delete anything when it is destructed. other.maxNumChildren = 0; other.minNumChildren = 0; other.numChildren = 0; @@ -256,6 +263,9 @@ other.ownsDataset = false; } +/** + * Copy assignment operator: copy the given other tree. + */ template -template -struct IsVector > -{ - const static bool value = true; -}; +#if ((ARMA_VERSION_MAJOR >= 10) || \ + ((ARMA_VERSION_MAJOR == 9) && (ARMA_VERSION_MINOR >= 869))) + + // Armadillo 9.869+ has SpSubview_col and SpSubview_row + + template + struct IsVector > + { + const static bool value = true; + }; + + template + struct IsVector > + { + const static bool value = true; + }; + +#else + + // fallback for older Armadillo versions + + template + struct IsVector > + { + const static bool value = true; + }; + +#endif #endif diff -Nru mlpack-3.2.2/src/mlpack/core/util/mlpack_main.hpp mlpack-3.3.0/src/mlpack/core/util/mlpack_main.hpp --- mlpack-3.2.2/src/mlpack/core/util/mlpack_main.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/util/mlpack_main.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -21,6 +21,7 @@ #define BINDING_TYPE_CLI 0 #define BINDING_TYPE_TEST 1 #define BINDING_TYPE_PYX 2 +#define BINDING_TYPE_JL 3 #define BINDING_TYPE_MARKDOWN 128 #define BINDING_TYPE_UNKNOWN -1 @@ -237,6 +238,49 @@ // Nothing else needs to be defined---the binding will use mlpackMain() as-is. +#elif(BINDING_TYPE == BINDING_TYPE_JL) // This is a Julia binding. + +// Matrices are transposed on load/save. +#define BINDING_MATRIX_TRANSPOSED true + +#include +#include + +#define PRINT_PARAM_STRING mlpack::bindings::julia::ParamString +#define PRINT_PARAM_VALUE mlpack::bindings::julia::PrintValue +#define PRINT_DATASET mlpack::bindings::julia::PrintDataset +#define PRINT_MODEL mlpack::bindings::julia::PrintModel +#define PRINT_CALL mlpack::bindings::julia::ProgramCall +#define BINDING_IGNORE_CHECK mlpack::bindings::julia::IgnoreCheck + +namespace mlpack { +namespace util { + +template +using Option = mlpack::bindings::julia::JuliaOption; + +} +} + +static const std::string testName = ""; +#include + +#undef PROGRAM_INFO +#define PROGRAM_INFO(NAME, SHORT_DESC, DESC, ...) static \ + mlpack::util::ProgramDoc \ + cli_programdoc_dummy_object = mlpack::util::ProgramDoc(NAME, SHORT_DESC, \ + []() { return DESC; }, { __VA_ARGS__ }); \ + namespace mlpack { \ + namespace bindings { \ + namespace julia { \ + std::string programName = NAME; \ + } \ + } \ + } + +PARAM_FLAG("verbose", "Display informational messages and the full list of " + "parameters and timers at the end of execution.", "v"); + #elif BINDING_TYPE == BINDING_TYPE_MARKDOWN // We use BINDING_NAME in PROGRAM_INFO() so it needs to be defined. @@ -244,6 +288,9 @@ #error "BINDING_NAME must be defined when BINDING_TYPE is Markdown!" #endif +// This value doesn't actually matter, but it needs to be defined as something. +#define BINDING_MATRIX_TRANSPOSED true + #include #include diff -Nru mlpack-3.2.2/src/mlpack/core/util/param.hpp mlpack-3.3.0/src/mlpack/core/util/param.hpp --- mlpack-3.2.2/src/mlpack/core/util/param.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/util/param.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -886,9 +886,9 @@ * * @code * DatasetInfo d = std::move( - * CLI::GetParam>("matrix").get<0>()); + * CLI::GetParam>("matrix").get<0>()); * arma::mat m = std::move( - * CLI::GetParam>("matrix").get<1>()); + * CLI::GetParam>("matrix").get<1>()); * @endcode * * @param ID Name of the parameter. diff -Nru mlpack-3.2.2/src/mlpack/core/util/prefixedoutstream.hpp mlpack-3.3.0/src/mlpack/core/util/prefixedoutstream.hpp --- mlpack-3.2.2/src/mlpack/core/util/prefixedoutstream.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/util/prefixedoutstream.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -124,7 +124,7 @@ private: /** * Conducts the base logic required in all the operator << overloads. Mostly - * just a good idea to reduce copy-pasta. + * just a good idea to reduce copy-paste. * * This overload is for non-Armadillo objects, which need special handling * during printing. @@ -138,7 +138,7 @@ /** * Conducts the base logic required in all the operator << overloads. Mostly - * just a good idea to reduce copy-pasta. + * just a good idea to reduce copy-paste. * * This overload is for Armadillo objects, which need special handling during * printing. diff -Nru mlpack-3.2.2/src/mlpack/core/util/version.hpp mlpack-3.3.0/src/mlpack/core/util/version.hpp --- mlpack-3.2.2/src/mlpack/core/util/version.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/core/util/version.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -17,8 +17,8 @@ // The version of mlpack. If this is a git repository, this will be a version // with higher number than the most recent release. #define MLPACK_VERSION_MAJOR 3 -#define MLPACK_VERSION_MINOR 2 -#define MLPACK_VERSION_PATCH 2 +#define MLPACK_VERSION_MINOR 3 +#define MLPACK_VERSION_PATCH 0 // The name of the version (for use by --version). namespace mlpack { diff -Nru mlpack-3.2.2/src/mlpack/methods/adaboost/adaboost.hpp mlpack-3.3.0/src/mlpack/methods/adaboost/adaboost.hpp --- mlpack-3.2.2/src/mlpack/methods/adaboost/adaboost.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/adaboost/adaboost.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -30,7 +30,7 @@ #include #include -#include +#include namespace mlpack { namespace adaboost { @@ -150,10 +150,24 @@ * Classify the given test points. * * @param test Testing data. - * @param predictedLabels Vector in which to the predicted labels of the test + * @param predictedLabels Vector in which the predicted labels of the test * set will be stored. + * @param probabilities matrix to store the predicted class probabilities for + * each point in the test set. */ - void Classify(const MatType& test, arma::Row& predictedLabels); + void Classify(const MatType& test, + arma::Row& predictedLabels, + arma::mat& probabilities); + + /** + * Classify the given test points. + * + * @param test Testing data. + * @param predictedLabels Vector in which the predicted labels of the test + * set will be stored. + */ + void Classify(const MatType& test, + arma::Row& predictedLabels); /** * Serialize the AdaBoost model. diff -Nru mlpack-3.2.2/src/mlpack/methods/adaboost/adaboost_impl.hpp mlpack-3.3.0/src/mlpack/methods/adaboost/adaboost_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/adaboost/adaboost_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/adaboost/adaboost_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -211,9 +211,23 @@ arma::Row& predictedLabels) { arma::Row tempPredictedLabels(test.n_cols); - arma::mat cMatrix(numClasses, test.n_cols); + arma::mat probabilities; - cMatrix.zeros(); + Classify(test, predictedLabels, probabilities); +} + +/** + * Classify the given test points. + */ +template +void AdaBoost::Classify( + const MatType& test, + arma::Row& predictedLabels, + arma::mat& probabilities) +{ + arma::Row tempPredictedLabels(test.n_cols); + + probabilities.zeros(numClasses, test.n_cols); predictedLabels.set_size(test.n_cols); for (size_t i = 0; i < wl.size(); i++) @@ -221,16 +235,17 @@ wl[i].Classify(test, tempPredictedLabels); for (size_t j = 0; j < tempPredictedLabels.n_cols; j++) - cMatrix(tempPredictedLabels(j), j) += alpha[i]; + probabilities(tempPredictedLabels(j), j) += alpha[i]; } - arma::colvec cMRow; + arma::colvec pRow; arma::uword maxIndex = 0; for (size_t i = 0; i < predictedLabels.n_cols; i++) { - cMRow = cMatrix.unsafe_col(i); - cMRow.max(maxIndex); + probabilities.col(i) /= arma::accu(probabilities.col(i)); + pRow = probabilities.unsafe_col(i); + pRow.max(maxIndex); predictedLabels(i) = maxIndex; } } diff -Nru mlpack-3.2.2/src/mlpack/methods/adaboost/adaboost_main.cpp mlpack-3.3.0/src/mlpack/methods/adaboost/adaboost_main.cpp --- mlpack-3.2.2/src/mlpack/methods/adaboost/adaboost_main.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/adaboost/adaboost_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -42,7 +42,7 @@ using namespace std; using namespace arma; using namespace mlpack::adaboost; -using namespace mlpack::decision_stump; +using namespace mlpack::tree; using namespace mlpack::perceptron; using namespace mlpack::util; @@ -121,6 +121,8 @@ // PARAM_UROW_OUT("output") is deprecated and will be removed in mlpack 4.0.0. PARAM_UROW_OUT("output", "Predicted labels for the test set.", "o"); PARAM_UROW_OUT("predictions", "Predicted labels for the test set.", "P"); +PARAM_MATRIX_OUT("probabilities", "Predicted class probabilities for each " + "point in the test set.", "p"); // Training options. PARAM_INT_IN("iterations", "The maximum number of boosting iterations to be run" @@ -233,9 +235,20 @@ << m->Dimensionality() << ")!" << endl; Row predictedLabels(testingData.n_cols); - Timer::Start("adaboost_classification"); - m->Classify(testingData, predictedLabels); - Timer::Stop("adaboost_classification"); + mat probabilities; + + if (CLI::HasParam("probabilities")) + { + Timer::Start("adaboost_classification"); + m->Classify(testingData, predictedLabels, probabilities); + Timer::Stop("adaboost_classification"); + } + else + { + Timer::Start("adaboost_classification"); + m->Classify(testingData, predictedLabels); + Timer::Stop("adaboost_classification"); + } Row results; data::RevertLabels(predictedLabels, m->Mappings(), results); @@ -245,6 +258,8 @@ CLI::GetParam>("output") = results; if (CLI::HasParam("predictions")) CLI::GetParam>("predictions") = std::move(results); + if (CLI::HasParam("probabilities")) + CLI::GetParam("probabilities") = std::move(probabilities); } CLI::GetParam("output_model") = m; diff -Nru mlpack-3.2.2/src/mlpack/methods/adaboost/adaboost_model.cpp mlpack-3.3.0/src/mlpack/methods/adaboost/adaboost_model.cpp --- mlpack-3.2.2/src/mlpack/methods/adaboost/adaboost_model.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/adaboost/adaboost_model.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -16,7 +16,7 @@ using namespace std; using namespace arma; using namespace mlpack::adaboost; -using namespace mlpack::decision_stump; +using namespace mlpack::tree; using namespace mlpack::perceptron; //! Create an empty AdaBoost model. @@ -47,7 +47,7 @@ mappings(other.mappings), weakLearnerType(other.weakLearnerType), dsBoost(other.dsBoost == NULL ? NULL : - new AdaBoost>(*other.dsBoost)), + new AdaBoost(*other.dsBoost)), pBoost(other.pBoost == NULL ? NULL : new AdaBoost>(*other.pBoost)), dimensionality(other.dimensionality) @@ -77,7 +77,7 @@ delete dsBoost; dsBoost = (other.dsBoost == NULL) ? NULL : - new AdaBoost>(*other.dsBoost); + new AdaBoost(*other.dsBoost); delete pBoost; pBoost = (other.pBoost == NULL) ? NULL : @@ -105,13 +105,13 @@ if (weakLearnerType == WeakLearnerTypes::DECISION_STUMP) { delete dsBoost; - - DecisionStump<> ds(data, labels, max(labels) + 1); - dsBoost = new AdaBoost>(data, labels, numClasses, ds, + ID3DecisionStump ds(data, labels, max(labels) + 1); + dsBoost = new AdaBoost(data, labels, numClasses, ds, iterations, tolerance); } else if (weakLearnerType == WeakLearnerTypes::PERCEPTRON) { + delete pBoost; Perceptron<> p(data, labels, max(labels) + 1); pBoost = new AdaBoost>(data, labels, numClasses, p, iterations, tolerance); @@ -119,7 +119,19 @@ } //! Classify test points. -void AdaBoostModel::Classify(const mat& testData, Row& predictions) +void AdaBoostModel::Classify(const mat& testData, + Row& predictions, + mat& probabilities) +{ + if (weakLearnerType == WeakLearnerTypes::DECISION_STUMP) + dsBoost->Classify(testData, predictions, probabilities); + else if (weakLearnerType == WeakLearnerTypes::PERCEPTRON) + pBoost->Classify(testData, predictions, probabilities); +} + +//! Classify test points. +void AdaBoostModel::Classify(const mat& testData, + Row& predictions) { if (weakLearnerType == WeakLearnerTypes::DECISION_STUMP) dsBoost->Classify(testData, predictions); diff -Nru mlpack-3.2.2/src/mlpack/methods/adaboost/adaboost_model.hpp mlpack-3.3.0/src/mlpack/methods/adaboost/adaboost_model.hpp --- mlpack-3.2.2/src/mlpack/methods/adaboost/adaboost_model.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/adaboost/adaboost_model.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -38,7 +38,7 @@ //! The type of weak learner. size_t weakLearnerType; //! Non-NULL if using decision stumps. - AdaBoost>* dsBoost; + AdaBoost* dsBoost; //! Non-NULL if using perceptrons. AdaBoost>* pBoost; //! Number of dimensions in training data. @@ -79,7 +79,7 @@ //! Modify the dimensionality of the model. size_t& Dimensionality() { return dimensionality; } - //! Train the model. + //! Train the model, treat the data is all of the numeric type. void Train(const arma::mat& data, const arma::Row& labels, const size_t numClasses, @@ -87,7 +87,13 @@ const double tolerance); //! Classify test points. - void Classify(const arma::mat& testData, arma::Row& predictions); + void Classify(const arma::mat& testData, + arma::Row& predictions); + + //! Classify test points. + void Classify(const arma::mat& testData, + arma::Row& predictions, + arma::mat& probabilities); //! Serialize the model. template diff -Nru mlpack-3.2.2/src/mlpack/methods/adaboost/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/adaboost/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/adaboost/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/adaboost/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -18,4 +18,5 @@ add_cli_executable(adaboost) add_python_binding(adaboost) -add_markdown_docs(adaboost "cli;python" "classification") +add_julia_binding(adaboost) +add_markdown_docs(adaboost "cli;python;julia" "classification") diff -Nru mlpack-3.2.2/src/mlpack/methods/amf/init_rules/average_init.hpp mlpack-3.3.0/src/mlpack/methods/amf/init_rules/average_init.hpp --- mlpack-3.2.2/src/mlpack/methods/amf/init_rules/average_init.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/amf/init_rules/average_init.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -1,5 +1,5 @@ /** - * @file averge_init.hpp + * @file average_init.hpp * @author Sumedh Ghaisas * * Initialization rule for Alternating Matrix Factorization. @@ -49,7 +49,6 @@ const size_t m = V.n_cols; double avgV = 0; - size_t count = 0; double min = DBL_MAX; // Iterate over all elements in the matrix (for sparse matrices, this only @@ -57,7 +56,6 @@ for (typename MatType::const_row_col_iterator it = V.begin(); it != V.end(); ++it) { - ++count; avgV += *it; // Track the minimum value. if (*it < min) @@ -70,8 +68,53 @@ W.randu(n, r); H.randu(r, m); - W = W + avgV; - H = H + avgV; + W += avgV; + H += + avgV; + } + + /** + * Initialize the matrix W or H to the average value of V with uniform + * random noise added. + * + * @param V Input matrix. + * @param r Rank of matrix. + * @param M W or H matrix, to be initialized to the average value of V + * with uniform random noise added. + * @param whichMatrix If true, initialize W. Otherwise, initialize H. + */ + template + inline static void InitializeOne(const MatType& V, + const size_t r, + arma::mat& M, + const bool whichMatrix = true) + { + const size_t n = V.n_rows; + const size_t m = V.n_cols; + + double avgV = 0; + double min = DBL_MAX; + + // Iterate over all elements in the matrix (for sparse matrices, this only + // iterates over nonzeros). + for (typename MatType::const_row_col_iterator it = V.begin(); + it != V.end(); ++it) + { + avgV += *it; + // Track the minimum value. + if (*it < min) + min = *it; + } + if (whichMatrix) + { + // Initialize W to random values + M.randu(n, r); + } + else + { + // Initialize H to random values + M.randu(r, m); + } + M += sqrt(((avgV / (n * m)) - min) / r); } //! Serialize the object (in this case, there is nothing to do). diff -Nru mlpack-3.2.2/src/mlpack/methods/amf/init_rules/given_init.hpp mlpack-3.3.0/src/mlpack/methods/amf/init_rules/given_init.hpp --- mlpack-3.2.2/src/mlpack/methods/amf/init_rules/given_init.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/amf/init_rules/given_init.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -1,5 +1,5 @@ /** - * @file given_initialization.hpp + * @file given_init.hpp * @author Ryan Curtin * * Initialization rule for alternating matrix factorization (AMF). This simple @@ -28,25 +28,62 @@ { public: // Empty constructor required for the InitializeRule template. - GivenInitialization() { } + GivenInitialization() : wIsGiven(false), hIsGiven(false) { } // Initialize the GivenInitialization object with the given matrices. - GivenInitialization(const arma::mat& w, const arma::mat& h) : w(w), h(h) { } + GivenInitialization(const arma::mat& w, const arma::mat& h) : + w(w), h(h), wIsGiven(true), hIsGiven(true) { } // Initialize the GivenInitialization object, taking control of the given // matrices. GivenInitialization(const arma::mat&& w, const arma::mat&& h) : w(std::move(w)), - h(std::move(h)) + h(std::move(h)), + wIsGiven(true), + hIsGiven(true) { } + // Initialize either H or W with the given matrix. + GivenInitialization(const arma::mat& m, const bool whichMatrix = true) + { + if (whichMatrix) + { + w = m; + wIsGiven = true; + hIsGiven = false; + } + else + { + h = m; + wIsGiven = false; + hIsGiven = true; + } + } + + // Initialize either H or W, taking control of the given matrix. + GivenInitialization(const arma::mat&& m, const bool whichMatrix = true) + { + if (whichMatrix) + { + w = std::move(m); + wIsGiven = true; + hIsGiven = false; + } + else + { + h = std::move(m); + wIsGiven = false; + hIsGiven = true; + } + } + /** - * Fill W and H with random uniform noise. + * Fill W and H with given matrices. * * @param V Input matrix. * @param r Rank of decomposition. - * @param W W matrix, to be filled with random noise. - * @param H H matrix, to be filled with random noise. + * @param W W matrix, to be initialized to given matrix. + * @param H H matrix, to be initialized to given matrix. */ template inline void Initialize(const MatType& V, @@ -54,6 +91,16 @@ arma::mat& W, arma::mat& H) { + // Make sure the initial W, H matrices are given + if (!wIsGiven) + { + Log::Fatal << "Initial W matrix is not given!" << std::endl; + } + if (!hIsGiven) + { + Log::Fatal << "Initial H matrix is not given!" << std::endl; + } + // Make sure the initial W, H matrices have correct size. if (w.n_rows != V.n_rows) { @@ -85,6 +132,72 @@ H = h; } + /** + * Fill W or H with given matrix. + * + * @param V Input matrix. + * @param r Rank of decomposition. + * @param M W or H matrix, to be initialized to given matrix. + * @param whichMatrix If true, initialize W. Otherwise, initialize H. + */ + template + inline void InitializeOne(const MatType& V, + const size_t r, + arma::mat& M, + const bool whichMatrix = true) + { + if (whichMatrix) + { + // Make sure the initial W matrix is given. + if (!wIsGiven) + { + Log::Fatal << "Initial W matrix is not given!" << std::endl; + } + + // Make sure the initial W matrix has correct size. + if (w.n_rows != V.n_rows) + { + Log::Fatal << "The number of rows in given W (" << w.n_rows + << ") doesn't equal the number of rows in V (" << V.n_rows + << ") !" << std::endl; + } + if (w.n_cols != r) + { + Log::Fatal << "The number of columns in given W (" << w.n_cols + << ") doesn't equal the rank of factorization (" << r + << ") !" << std::endl; + } + + // Initialize W to the given matrix. + M = w; + } + else + { + // Make sure the initial H matrix is given. + if (!hIsGiven) + { + Log::Fatal << "Initial H matrix is not given!" << std::endl; + } + + // Make sure the initial H matrix has correct size. + if (h.n_cols != V.n_cols) + { + Log::Fatal << "The number of columns in given H (" << h.n_cols + << ") doesn't equal the number of columns in V (" << V.n_cols + << ") !" << std::endl; + } + if (h.n_rows != r) + { + Log::Fatal << "The number of rows in given H (" << h.n_rows + << ") doesn't equal the rank of factorization (" << r + << ") !"<< std::endl; + } + + // Initialize H to the given matrix. + M = h; + } + } + //! Serialize the object (in this case, there is nothing to serialize). template void serialize(Archive& ar, const unsigned int /* version */) @@ -98,6 +211,10 @@ arma::mat w; //! The H matrix for initialization. arma::mat h; + //! Whether initial W is given. + bool wIsGiven; + //! Whether initial H is given. + bool hIsGiven; }; } // namespace amf diff -Nru mlpack-3.2.2/src/mlpack/methods/amf/init_rules/merge_init.hpp mlpack-3.3.0/src/mlpack/methods/amf/init_rules/merge_init.hpp --- mlpack-3.2.2/src/mlpack/methods/amf/init_rules/merge_init.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/amf/init_rules/merge_init.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,69 @@ +/** + * @file merge_init.hpp + * @author Ziyang Jiang + * + * Initialization rule for alternating matrix factorization (AMF). This simple + * initialization is performed by assigning a given matrix to W or H and a + * random matrix to another one. + * + * 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_AMF_MERGE_INIT_HPP +#define MLPACK_METHODS_AMF_MERGE_INIT_HPP + +#include + +namespace mlpack { +namespace amf { + +/** + * This initialization rule for AMF simply takes in two initialization rules, + * and initialize W with the first rule and H with the second rule. + */ +template +class MergeInitialization +{ + public: + // Empty constructor required for the InitializeRule template + MergeInitialization() { } + + // Initialize the MergeInitialization object with existing initialization + // rules. + MergeInitialization(const WInitializationRuleType& wInitRule, + const HInitializationRuleType& hInitRule) : + wInitializationRule(wInitRule), + hInitializationRule(hInitRule) + { } + + /** + * Initialize W and H with the corresponding initialization rules. + * + * @param V Input matrix. + * @param r Rank of decomposition. + * @param W W matrix, to be initialized to given matrix. + * @param H H matrix, to be initialized to given matrix. + */ + template + inline void Initialize(const MatType& V, + const size_t r, + arma::mat& W, + arma::mat& H) + { + wInitializationRule.InitializeOne(V, r, W); + hInitializationRule.InitializeOne(V, r, H, false); + } + + private: + // Initialization rule for W matrix + WInitializationRuleType wInitializationRule; + // Initialization rule for H matrix + HInitializationRuleType hInitializationRule; +}; + +} // namespace amf +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/amf/init_rules/random_init.hpp mlpack-3.3.0/src/mlpack/methods/amf/init_rules/random_init.hpp --- mlpack-3.2.2/src/mlpack/methods/amf/init_rules/random_init.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/amf/init_rules/random_init.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -51,6 +51,35 @@ H.randu(r, m); } + /** + * Fill W or H with random uniform noise. + * + * @param V Input matrix. + * @param r Rank of decomposition. + * @param M W or H matrix, to be filled with random noise. + * @param whichMatrix If true, initialize W. Otherwise, initialize H. + */ + template + inline void InitializeOne(const MatType& V, + const size_t r, + arma::mat& M, + const bool whichMatrix = true) + { + // Simple implementation (left in the header file due to its simplicity). + const size_t n = V.n_rows; + const size_t m = V.n_cols; + + // Initialize W or H to random values + if (whichMatrix) + { + M.randu(n, r); + } + else + { + M.randu(r, m); + } + } + //! Serialize the object (in this case, there is nothing to serialize). template void serialize(Archive& /* ar */, const unsigned int /* version */) { } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/activation_functions/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/ann/activation_functions/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/ann/activation_functions/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/activation_functions/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -8,6 +8,9 @@ rectifier_function.hpp softplus_function.hpp swish_function.hpp + mish_function.hpp + lisht_function.hpp + gelu_function.hpp ) # Add directory name to sources. diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/activation_functions/gelu_function.hpp mlpack-3.3.0/src/mlpack/methods/ann/activation_functions/gelu_function.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/activation_functions/gelu_function.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/activation_functions/gelu_function.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,92 @@ +/** + * @file gelu_function.hpp + * @author Himanshu Pathak + * + * Definition and implementation of the Gaussian Error Linear Unit (GELU) + * 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_ACTIVATION_FUNCTIONS_GELU_FUNCTION_HPP +#define MLPACK_METHODS_ANN_ACTIVATION_FUNCTIONS_GELU_FUNCTION_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * The GELU function, defined by + * + * @f{eqnarray*}{ + * f(x) = 0.5 * x * {1 + tanh[(2/pi)^(1/2) * (x + 0.044715 * x^3)]} \\ + * f'(x) = 0.5 * tanh(0.0356774 * x^3) + 0.797885 * x) + + * (0.0535161x^3 + 0.398942 * x) * + * sech^2(0.0356774 * x^3+0.797885 * x) + 0.5\\ + * @f} + */ +class GELUFunction +{ + public: + /** + * Computes the GELU function. + * + * @param x Input data. + * @return f(x). + */ + static double Fn(const double x) + { + return 0.5 * x * (1 + std::tanh(std::sqrt(2 / M_PI) * + (x + 0.044715 * std::pow(x, 3)))); + } + + /** + * Computes the GELU function. + * + * @param x Input data. + * @param y The resulting output activation. + */ + template + static void Fn(const InputVecType& x, OutputVecType& y) + { + y = 0.5 * x % (1 + arma::tanh(std::sqrt(2 / M_PI) * + (x + 0.044715 * arma::pow(x, 3)))); + } + + /** + * Computes the first derivative of the GELU function. + * + * @param y Input data. + * @return f'(x) + */ + static double Deriv(const double y) + { + return 0.5 * std::tanh(0.0356774 * std::pow(y, 3) + 0.797885 * y) + + (0.0535161 * std::pow(y, 3) + 0.398942 * y) * + std::pow(1 / std::cosh(0.0356774 * std::pow(y, 3) + + 0.797885 * y), 2) + 0.5; + } + + /** + * Computes the first derivatives of the GELU function. + * + * @param y Input data. + * @param x The resulting derivatives. + */ + template + static void Deriv(const InputVecType& y, OutputVecType& x) + { + x = 0.5 * arma::tanh(0.0356774 * arma::pow(y, 3) + 0.797885 * y) + + (0.0535161 * arma::pow(y, 3) + 0.398942 * y) % + arma::pow(1 / arma::cosh(0.0356774 * arma::pow(y, 3) + + 0.797885 * y), 2) + 0.5; + } +}; // class GELUFunction + +} // namespace ann +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/activation_functions/lisht_function.hpp mlpack-3.3.0/src/mlpack/methods/ann/activation_functions/lisht_function.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/activation_functions/lisht_function.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/activation_functions/lisht_function.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,95 @@ +/** + * @file lisht_function.hpp + * @author Kartik Dutt + * + * Definition and implementation of the LiSHT function as described by + * Swalpa K. Roy, Suvojit Manna, Shiv Ram Dubey and Bidyut B. Chaudhuri. + * + * For more information, see the following paper. + * + * @code + * @misc{ + * author = {Swalpa K. Roy, Suvojit Manna, Shiv R. Dubey and + * Bidyut B. Chaudhuri}, + * title = {LiSHT: Non-Parametric Linearly Scaled Hyperbolic Tangent + * Activation Function for Neural Networks}, + * year = {2019} + * } + * @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_LISHT_FUNCTION_HPP +#define MLPACK_METHODS_ANN_ACTIVATION_FUNCTIONS_LISHT_FUNCTION_HPP + +#include +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * The LiSHT function, defined by + * + * @f{eqnarray*}{ + * f(x) = x * tanh(x) + * f'(x) = tanh(x) + x * (1 - tanh^{2}(x)) + * @f} + */ +class LiSHTFunction +{ + public: + /** + * Computes the LiSHT function. + * + * @param x Input data. + * @return f(x). + */ + static double Fn(const double x) + { + return x * std::tanh(x); + } + + /** + * Computes the LiSHT function. + * + * @param x Input data. + * @param y The resulting output activation. + */ + template + static void Fn(const InputVecType &x, OutputVecType &y) + { + y = x % arma::tanh(x); + } + + /** + * Computes the first derivative of the LiSHT function. + * + * @param y Input data. + * @return f'(x) + */ + static double Deriv(const double y) + { + return std::tanh(y) + y * (1 - std::pow(std::tanh(y), 2)); + } + + /** + * Computes the first derivatives of the LiSHT function. + * + * @param y Input activations. + * @param x The resulting derivatives. + */ + template + static void Deriv(const InputVecType &y, OutputVecType &x) + { + x = arma::tanh(y) + y % (1 - arma::pow(arma::tanh(y), 2)); + } +}; // class LishtFunction + +} // namespace ann +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/activation_functions/mish_function.hpp mlpack-3.3.0/src/mlpack/methods/ann/activation_functions/mish_function.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/activation_functions/mish_function.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/activation_functions/mish_function.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,99 @@ +/** + * @file mish_function.hpp + * @author Kartik Dutt + * + * Definition and implementation of the Mish function as described by + * Diganta Misra. + * + * For more information, see the following paper. + * + * @code + * @misc{ + * author = {Diganta Misra}, + * title = {Mish: Self Regularized Non-Monotonic Neural Activation Function}, + * year = {2019} + * } + * @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_MISH_FUNCTION_HPP +#define MLPACK_METHODS_ANN_ACTIVATION_FUNCTIONS_MISH_FUNCTION_HPP + +#include +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * The Mish function, defined by + * + * @f{eqnarray*}{ + * f(x) = x * tanh(ln(1+e^x)) + * f'(x) = tanh(ln(1+e^x)) + x * ((1 - tanh^2(ln(1+e^x))) * frac{1}{1 + e^{-x}}) + * } + */ +class MishFunction +{ + public: + /** + * Computes the Mish function. + * + * @param x Input data. + * @return f(x). + */ + static double Fn(const double x) + { + return x * (std::exp(2 * x) + 2 * std::exp(x)) / + (2 + 2 * std::exp(x) + std::exp(2 * x)); + } + + /** + * Computes the Mish function. + * + * @param x Input data. + * @param y The resulting output activation. + */ + template + static void Fn(const InputVecType &x, OutputVecType &y) + { + y = x % (arma::exp(2 * x) + 2 * arma::exp(x)) / + (2 + 2 * arma::exp(x) + arma::exp(2 * x)); + } + + /** + * Computes the first derivative of the Mish function. + * + * @param y Input data. + * @return f'(x) + */ + static double Deriv(const double y) + { + return std::exp(y) * (4 * (y + 1) + std::exp(y) * (4 * y + 6) + + 4 * std::exp(2 * y) + std::exp(3 * y)) / + std::pow(std::exp(2 * y) + 2 * std::exp(y) + 2, 2); + } + + /** + * Computes the first derivatives of the Mish function. + * + * @param y Input activations. + * @param x The resulting derivatives. + */ + template + static void Deriv(const InputVecType &y, OutputVecType &x) + { + x = arma::exp(y) % (4 * (y + 1) + arma::exp(y) % (4 * y + 6) + + 4 * arma::exp(2 * y) + arma::exp(3 * y)) / + arma::pow(arma::exp(2 * y) + 2 * arma::exp(y) + 2, 2); + } +}; // class MishFunction + +} // namespace ann +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/activation_functions/softsign_function.hpp mlpack-3.3.0/src/mlpack/methods/ann/activation_functions/softsign_function.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/activation_functions/softsign_function.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/activation_functions/softsign_function.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -35,11 +35,11 @@ * * @f{eqnarray*}{ * f(x) &=& \frac{x}{1 + |x|} \\ - * f'(x) &=& (1 - |x|)^2 \\ + * f'(x) &=& (1 - |f(x)|)^2 \\ * f(x) &=& \left\{ * \begin{array}{lr} - * -\frac{y}{y-1} & : x > 0 \\ - * \frac{x}{1 + x} & : x \le 0 + * -\frac{x}{1 - x} & : x \le 0 \\ + * \frac{x}{1 + x} & : x > 0 * \end{array} * \right. * @f} diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/brnn.hpp mlpack-3.3.0/src/mlpack/methods/ann/brnn.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/brnn.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/brnn.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -24,6 +24,7 @@ #include "init_rules/network_init.hpp" #include #include +#include #include #include @@ -72,10 +73,41 @@ BRNN(const size_t rho, const bool single = false, OutputLayerType outputLayer = OutputLayerType(), - MergeLayerType mergeLayer = MergeLayerType(), - MergeOutputType mergeOutput = MergeOutputType(), + MergeLayerType* mergeLayer = new MergeLayerType(), + MergeOutputType* mergeOutput = new MergeOutputType(), InitializationRuleType initializeRule = InitializationRuleType()); + ~BRNN(); + + /** + * Check if the optimizer has MaxIterations() parameter, if it does + * then check if it's value is less than the number of datapoints + * in the dataset. + * + * @tparam OptimizerType Type of optimizer to use to train the model. + * @param optimizer optimizer used in the training process. + * @param samples Number of datapoints in the dataset. + */ + template + typename std::enable_if< + HasMaxIterations + ::value, void>::type + WarnMessageMaxIterations(OptimizerType& optimizer, size_t samples) const; + + /** + * Check if the optimizer has MaxIterations() parameter, if it + * doesn't then simply return from the function. + * + * @tparam OptimizerType Type of optimizer to use to train the model. + * @param optimizer optimizer used in the training process. + * @param samples Number of datapoints in the dataset. + */ + template + typename std::enable_if< + !HasMaxIterations + ::value, void>::type + WarnMessageMaxIterations(OptimizerType& optimizer, size_t samples) const; + /** * Train the bidirectional recurrent neural network on the given input data * using the given optimizer. diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/brnn_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/brnn_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/brnn_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/brnn_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -39,13 +39,13 @@ const size_t rho, const bool single, OutputLayerType outputLayer, - MergeLayerType mergeLayer, - MergeOutputType mergeOutput, + MergeLayerType* mergeLayer, + MergeOutputType* mergeOutput, InitializationRuleType initializeRule) : rho(rho), outputLayer(std::move(outputLayer)), - mergeLayer(new MergeLayerType(mergeLayer)), - mergeOutput(new MergeOutputType(mergeOutput)), + mergeLayer(mergeLayer), + mergeOutput(mergeOutput), initializeRule(std::move(initializeRule)), inputSize(0), outputSize(0), @@ -63,6 +63,61 @@ template +BRNN::~BRNN() +{ + // Remove the last layers from the forward and backward RNNs, as they are held + // in mergeLayer. So, when we use DeleteVisitor with mergeLayer, those two + // layers will be properly (and not doubly) freed. + forwardRNN.network.pop_back(); + backwardRNN.network.pop_back(); + + // Clean up layers that we allocated. + boost::apply_visitor(DeleteVisitor(), mergeLayer); + boost::apply_visitor(DeleteVisitor(), mergeOutput); +} + +template +template +typename std::enable_if< + HasMaxIterations + ::value, void>::type +BRNN::WarnMessageMaxIterations +(OptimizerType& optimizer, size_t samples) const +{ + if (optimizer.MaxIterations() < samples && + optimizer.MaxIterations() != 0) + { + Log::Warn << "The optimizer's maximum number of iterations " + << "is less than the size of the dataset; the " + << "optimizer will not pass over the entire " + << "dataset. To fix this, modify the maximum " + << "number of iterations to be at least equal " + << "to the number of points of your dataset " + << "(" << samples << ")." << std::endl; + } +} + +template +template +typename std::enable_if< + !HasMaxIterations + ::value, void>::type +BRNN::WarnMessageMaxIterations +(OptimizerType& optimizer, size_t samples) const +{ + return; +} + +template template double BRNN::Train( @@ -83,6 +138,8 @@ ResetParameters(); } + WarnMessageMaxIterations(optimizer, this->predictors.n_cols); + // Train the model. Timer::Start("BRNN_optimization"); const double out = optimizer.Optimize(*this, parameter); @@ -117,6 +174,8 @@ OptimizerType optimizer; + WarnMessageMaxIterations(optimizer, this->predictors.n_cols); + // Train the model. const double out = optimizer.Optimize(*this, parameter); @@ -166,34 +225,34 @@ size_t(predictors.n_cols - begin)); for (size_t seqNum = 0; seqNum < rho; ++seqNum) { - forwardRNN.Forward(std::move(arma::mat( + forwardRNN.Forward(arma::mat( predictors.slice(seqNum).colptr(begin), - predictors.n_rows, effectiveBatchSize, false, true))); + predictors.n_rows, effectiveBatchSize, false, true)); backwardRNN.Forward(std::move(arma::mat( predictors.slice(rho - seqNum - 1).colptr(begin), predictors.n_rows, effectiveBatchSize, false, true))); - boost::apply_visitor(SaveOutputParameterVisitor( - std::move(results1)), forwardRNN.network.back()); - boost::apply_visitor(SaveOutputParameterVisitor( - std::move(results2)), backwardRNN.network.back()); + boost::apply_visitor(SaveOutputParameterVisitor(results1), + forwardRNN.network.back()); + boost::apply_visitor(SaveOutputParameterVisitor(results2), + backwardRNN.network.back()); } reverse(results1.begin(), results1.end()); // Forward outputs from both RNN's through merge layer for each time step. for (size_t seqNum = 0; seqNum < rho; ++seqNum) { - boost::apply_visitor(LoadOutputParameterVisitor( - std::move(results1)), forwardRNN.network.back()); - boost::apply_visitor(LoadOutputParameterVisitor( - std::move(results2)), backwardRNN.network.back()); + boost::apply_visitor(LoadOutputParameterVisitor(results1), + forwardRNN.network.back()); + boost::apply_visitor(LoadOutputParameterVisitor(results2), + backwardRNN.network.back()); - boost::apply_visitor(ForwardVisitor(std::move(input), - std::move(boost::apply_visitor(outputParameterVisitor, mergeLayer))), + boost::apply_visitor(ForwardVisitor(input, + boost::apply_visitor(outputParameterVisitor, mergeLayer)), mergeLayer); boost::apply_visitor(ForwardVisitor( - std::move(boost::apply_visitor(outputParameterVisitor, mergeLayer)), - std::move(boost::apply_visitor(outputParameterVisitor, mergeOutput))), + boost::apply_visitor(outputParameterVisitor, mergeLayer), + boost::apply_visitor(outputParameterVisitor, mergeOutput)), mergeOutput); results.slice(seqNum).submat(0, begin, results.n_rows - 1, begin + effectiveBatchSize - 1) = @@ -243,17 +302,17 @@ std::vector results1, results2; for (size_t seqNum = 0; seqNum < rho; ++seqNum) { - forwardRNN.Forward(std::move(arma::mat( + forwardRNN.Forward(arma::mat( predictors.slice(seqNum).colptr(begin), - predictors.n_rows, batchSize, false, true))); - backwardRNN.Forward(std::move(arma::mat( + predictors.n_rows, batchSize, false, true)); + backwardRNN.Forward(arma::mat( predictors.slice(rho - seqNum - 1).colptr(begin), - predictors.n_rows, batchSize, false, true))); + predictors.n_rows, batchSize, false, true)); - boost::apply_visitor(SaveOutputParameterVisitor( - std::move(results1)), forwardRNN.network.back()); - boost::apply_visitor(SaveOutputParameterVisitor( - std::move(results2)), backwardRNN.network.back()); + boost::apply_visitor(SaveOutputParameterVisitor(results1), + forwardRNN.network.back()); + boost::apply_visitor(SaveOutputParameterVisitor(results2), + backwardRNN.network.back()); } if (outputSize == 0) { @@ -271,22 +330,22 @@ { responseSeq = seqNum; } - boost::apply_visitor(LoadOutputParameterVisitor( - std::move(results1)), forwardRNN.network.back()); - boost::apply_visitor(LoadOutputParameterVisitor( - std::move(results2)), backwardRNN.network.back()); + boost::apply_visitor(LoadOutputParameterVisitor(results1), + forwardRNN.network.back()); + boost::apply_visitor(LoadOutputParameterVisitor(results2), + backwardRNN.network.back()); - boost::apply_visitor(ForwardVisitor(std::move(input), - std::move(boost::apply_visitor(outputParameterVisitor, mergeLayer))), + boost::apply_visitor(ForwardVisitor(input, + boost::apply_visitor(outputParameterVisitor, mergeLayer)), mergeLayer); boost::apply_visitor(ForwardVisitor( - std::move(boost::apply_visitor(outputParameterVisitor, mergeLayer)), - std::move(boost::apply_visitor(outputParameterVisitor, mergeOutput))), - mergeOutput); - performance += outputLayer.Forward(std::move( + boost::apply_visitor(outputParameterVisitor, mergeLayer), boost::apply_visitor(outputParameterVisitor, mergeOutput)), - std::move(arma::mat(responses.slice(responseSeq).colptr(begin), - responses.n_rows, batchSize, false, true))); + mergeOutput); + performance += outputLayer.Forward( + boost::apply_visitor(outputParameterVisitor, mergeOutput), + arma::mat(responses.slice(responseSeq).colptr(begin), + responses.n_rows, batchSize, false, true)); } return performance; } @@ -361,24 +420,24 @@ std::vector results1, results2; for (size_t seqNum = 0; seqNum < rho; ++seqNum) { - forwardRNN.Forward(std::move(arma::mat( + forwardRNN.Forward(arma::mat( predictors.slice(seqNum).colptr(begin), - predictors.n_rows, batchSize, false, true))); - backwardRNN.Forward(std::move(arma::mat( + predictors.n_rows, batchSize, false, true)); + backwardRNN.Forward(arma::mat( predictors.slice(rho - seqNum - 1).colptr(begin), - predictors.n_rows, batchSize, false, true))); + predictors.n_rows, batchSize, false, true)); for (size_t l = 0; l < networkSize; ++l) { boost::apply_visitor(SaveOutputParameterVisitor( - std::move(forwardRNNOutputParameter)), forwardRNN.network[l]); + forwardRNNOutputParameter), forwardRNN.network[l]); boost::apply_visitor(SaveOutputParameterVisitor( - std::move(backwardRNNOutputParameter)), backwardRNN.network[l]); + backwardRNNOutputParameter), backwardRNN.network[l]); } - boost::apply_visitor(SaveOutputParameterVisitor( - std::move(results1)), forwardRNN.network.back()); - boost::apply_visitor(SaveOutputParameterVisitor( - std::move(results2)), backwardRNN.network.back()); + boost::apply_visitor(SaveOutputParameterVisitor(results1), + forwardRNN.network.back()); + boost::apply_visitor(SaveOutputParameterVisitor(results2), + backwardRNN.network.back()); } if (outputSize == 0) { @@ -410,18 +469,18 @@ responseSeq = seqNum; } boost::apply_visitor(LoadOutputParameterVisitor( - std::move(results1)), forwardRNN.network.back()); + results1), forwardRNN.network.back()); boost::apply_visitor(LoadOutputParameterVisitor( - std::move(results2)), backwardRNN.network.back()); - boost::apply_visitor(ForwardVisitor(std::move(input), - std::move(boost::apply_visitor(outputParameterVisitor, mergeLayer))), + results2), backwardRNN.network.back()); + boost::apply_visitor(ForwardVisitor(input, + boost::apply_visitor(outputParameterVisitor, mergeLayer)), mergeLayer); boost::apply_visitor(ForwardVisitor( - std::move(boost::apply_visitor(outputParameterVisitor, mergeLayer)), - std::move(results.slice(seqNum))), mergeOutput); - performance += outputLayer.Forward(std::move(results.slice(seqNum)), - std::move(arma::mat(responses.slice(responseSeq).colptr(begin), - responses.n_rows, batchSize, false, true))); + boost::apply_visitor(outputParameterVisitor, mergeLayer), + results.slice(seqNum)), mergeOutput); + performance += outputLayer.Forward(results.slice(seqNum), + arma::mat(responses.slice(responseSeq).colptr(begin), + responses.n_rows, batchSize, false, true)); } // Calculate and storing delta parameters from output for t = 1 to T. @@ -436,25 +495,25 @@ } else if (single && seqNum == 0) { - outputLayer.Backward(std::move(results.slice(seqNum)), - std::move(arma::mat(responses.slice(0).colptr(begin), - responses.n_rows, batchSize, false, true)), std::move(error)); + outputLayer.Backward(results.slice(seqNum), + arma::mat(responses.slice(0).colptr(begin), + responses.n_rows, batchSize, false, true), error); } else { - outputLayer.Backward(std::move(results.slice(seqNum)), - std::move(arma::mat(responses.slice(seqNum).colptr(begin), - responses.n_rows, batchSize, false, true)), std::move(error)); + outputLayer.Backward(results.slice(seqNum), + arma::mat(responses.slice(seqNum).colptr(begin), + responses.n_rows, batchSize, false, true), error); } - boost::apply_visitor(BackwardVisitor(std::move(results.slice(seqNum)), - std::move(error), std::move(delta)), mergeOutput); + boost::apply_visitor(BackwardVisitor(results.slice(seqNum), error, delta), + mergeOutput); allDelta.push_back(arma::mat(delta)); } // BPTT ForwardRNN from t = T to 1. totalGradient = arma::mat(gradient.memptr(), - parameter.n_elem/2, 1, false, false); + parameter.n_elem / 2, 1, false, false); forwardGradient.zeros(); forwardRNN.ResetGradients(forwardGradient); @@ -467,32 +526,32 @@ for (size_t l = 0; l < networkSize; ++l) { boost::apply_visitor(LoadOutputParameterVisitor( - std::move(forwardRNNOutputParameter)), + forwardRNNOutputParameter), forwardRNN.network[networkSize - 1 - l]); } - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, forwardRNN.network.back())), - std::move(allDelta[rho - seqNum - 1]), std::move(delta), 0), + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, forwardRNN.network.back()), + allDelta[rho - seqNum - 1], delta, 0), mergeLayer); for (size_t i = 2; i < networkSize; ++i) { boost::apply_visitor(BackwardVisitor( - std::move(boost::apply_visitor(outputParameterVisitor, - forwardRNN.network[networkSize - i])), - std::move(boost::apply_visitor(deltaVisitor, - forwardRNN.network[networkSize - i + 1])), std::move( + boost::apply_visitor(outputParameterVisitor, + forwardRNN.network[networkSize - i]), boost::apply_visitor(deltaVisitor, - forwardRNN.network[networkSize - i]))), + forwardRNN.network[networkSize - i + 1]), + boost::apply_visitor(deltaVisitor, + forwardRNN.network[networkSize - i])), forwardRNN.network[networkSize - i]); } - forwardRNN.Gradient(std::move( + forwardRNN.Gradient( arma::mat(predictors.slice(rho - seqNum - 1).colptr(begin), - predictors.n_rows, batchSize, false, true))); + predictors.n_rows, batchSize, false, true)); boost::apply_visitor(GradientVisitor( - std::move(boost::apply_visitor(outputParameterVisitor, - forwardRNN.network[networkSize - 2])), - std::move(allDelta[rho - seqNum - 1]), 0), mergeLayer); + boost::apply_visitor(outputParameterVisitor, + forwardRNN.network[networkSize - 2]), + allDelta[rho - seqNum - 1], 0), mergeLayer); totalGradient += forwardGradient; } @@ -506,31 +565,31 @@ for (size_t l = 0; l < networkSize; ++l) { boost::apply_visitor(LoadOutputParameterVisitor( - std::move(backwardRNNOutputParameter)), + backwardRNNOutputParameter), backwardRNN.network[networkSize - 1 - l]); } - boost::apply_visitor(BackwardVisitor(std::move( + boost::apply_visitor(BackwardVisitor( boost::apply_visitor(outputParameterVisitor, - backwardRNN.network.back())), - std::move(allDelta[seqNum]), std::move(delta), 1), mergeLayer); + backwardRNN.network.back()), + allDelta[seqNum], delta, 1), mergeLayer); for (size_t i = 2; i < networkSize; ++i) { boost::apply_visitor(BackwardVisitor( - std::move(boost::apply_visitor(outputParameterVisitor, - backwardRNN.network[networkSize - i])), std::move(boost::apply_visitor( - deltaVisitor, backwardRNN.network[networkSize - i + 1])), std::move( + boost::apply_visitor(outputParameterVisitor, + backwardRNN.network[networkSize - i]), boost::apply_visitor( + deltaVisitor, backwardRNN.network[networkSize - i + 1]), boost::apply_visitor(deltaVisitor, - backwardRNN.network[networkSize - i]))), + backwardRNN.network[networkSize - i])), backwardRNN.network[networkSize - i]); } - backwardRNN.Gradient(std::move( + backwardRNN.Gradient( arma::mat(predictors.slice(seqNum).colptr(begin), - predictors.n_rows, batchSize, false, true))); + predictors.n_rows, batchSize, false, true)); boost::apply_visitor(GradientVisitor( std::move(boost::apply_visitor(outputParameterVisitor, backwardRNN.network[networkSize - 2])), - std::move(allDelta[seqNum]), 1), mergeLayer); + allDelta[seqNum], 1), mergeLayer); totalGradient += backwardGradient; } return performance; @@ -592,6 +651,8 @@ { if (!reset) { + // TODO: what if we call ResetParameters() multiple times? Do we have to + // remove any existing mergeLayer? boost::apply_visitor(AddVisitor( forwardRNN.network.back()), mergeLayer); boost::apply_visitor(AddVisitor( @@ -665,6 +726,8 @@ ar & BOOST_SERIALIZATION_NVP(parameter); ar & BOOST_SERIALIZATION_NVP(backwardRNN); ar & BOOST_SERIALIZATION_NVP(forwardRNN); + + // TODO: are there more parameters to be serialized? } } // namespace ann diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/dists/bernoulli_distribution.hpp mlpack-3.3.0/src/mlpack/methods/ann/dists/bernoulli_distribution.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/dists/bernoulli_distribution.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/dists/bernoulli_distribution.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -60,7 +60,7 @@ * @param eps The minimum value used for computing logarithms and * denominators. */ - BernoulliDistribution(const DataType&& param, + BernoulliDistribution(const DataType& param, const bool applyLogistic = true, const double eps = 1e-10); @@ -69,7 +69,7 @@ * * @param observation The observation matrix. */ - double Probability(const DataType&& observation) const + double Probability(const DataType& observation) const { return std::exp(LogProbability(observation)); } @@ -79,7 +79,7 @@ * * @param observation The observation matrix. */ - double LogProbability(const DataType&& observation) const; + double LogProbability(const DataType& observation) const; /** * Stores the gradient of the log probabilities of the observations in the @@ -88,7 +88,7 @@ * @param observation The observation matrix. * @param output The output matrix where the gradients are stored. */ - void LogProbBackward(const DataType&& observation, DataType&& output) const; + void LogProbBackward(const DataType& observation, DataType& output) const; /** * Return a matrix of randomly generated samples according to the diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/dists/bernoulli_distribution_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/dists/bernoulli_distribution_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/dists/bernoulli_distribution_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/dists/bernoulli_distribution_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -28,7 +28,7 @@ template BernoulliDistribution::BernoulliDistribution( - const DataType&& param, + const DataType& param, const bool applyLogistic, const double eps) : logits(param), @@ -36,7 +36,9 @@ eps(eps) { if (applyLogistic) + { LogisticFunction::Fn(logits, probability); + } else { probability = arma::mat(logits.memptr(), logits.n_rows, @@ -58,7 +60,7 @@ template double BernoulliDistribution::LogProbability( - const DataType&& observation) const + const DataType& observation) const { return arma::accu(arma::log(probability + eps) % observation + arma::log(1 - probability + eps) % (1 - observation)) / @@ -67,7 +69,7 @@ template void BernoulliDistribution::LogProbBackward( - const DataType&& observation, DataType&& output) const + const DataType& observation, DataType& output) const { if (!applyLogistic) { diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/ffn.hpp mlpack-3.3.0/src/mlpack/methods/ann/ffn.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/ffn.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/ffn.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -30,6 +30,7 @@ #include #include #include +#include #include namespace mlpack { @@ -83,6 +84,35 @@ ~FFN(); /** + * Check if the optimizer has MaxIterations() parameter, if it does + * then check if it's value is less than the number of datapoints + * in the dataset. + * + * @tparam OptimizerType Type of optimizer to use to train the model. + * @param optimizer optimizer used in the training process. + * @param samples Number of datapoints in the dataset. + */ + template + typename std::enable_if< + HasMaxIterations + ::value, void>::type + WarnMessageMaxIterations(OptimizerType& optimizer, size_t samples) const; + + /** + * Check if the optimizer has MaxIterations() parameter, if it + * doesn't then simply return from the function. + * + * @tparam OptimizerType Type of optimizer to use to train the model. + * @param optimizer optimizer used in the training process. + * @param samples Number of datapoints in the dataset. + */ + template + typename std::enable_if< + !HasMaxIterations + ::value, void>::type + WarnMessageMaxIterations(OptimizerType& optimizer, size_t samples) const; + + /** * Train the feedforward network on the given input data using the given * optimizer. * @@ -153,7 +183,9 @@ * @param predictors Input variables. * @param responses Target outputs for input variables. */ - double Evaluate(arma::mat predictors, arma::mat responses); + template + double Evaluate(const PredictorsType& predictors, + const ResponsesType& responses); /** * Evaluate the feedforward network with the given parameters. This function @@ -271,7 +303,9 @@ { return network; } - //! Modify the network model. + //! Modify the network model. Be careful! If you change the structure of the + //! network or parameters for layers, its state may become invalid, so be sure + //! to call ResetParameters() afterwards. std::vector >& Model() { return network; } //! Return the number of separable functions (the number of predictor points). @@ -311,7 +345,8 @@ * @param inputs The input data. * @param results The predicted results. */ - void Forward(arma::mat inputs, arma::mat& results); + template + void Forward(const PredictorsType& inputs, ResponsesType& results); /** * Perform a partial forward pass of the data. @@ -324,8 +359,9 @@ * @param begin The index of the first layer. * @param end The index of the last layer. */ - void Forward(arma::mat inputs, - arma::mat& results, + template + void Forward(const PredictorsType& inputs , + ResponsesType& results, const size_t begin, const size_t end); @@ -340,7 +376,12 @@ * @param gradients Computed gradients. * @return Training error of the current pass. */ - double Backward(arma::mat targets, arma::mat& gradients); + template + double Backward(const PredictorsType& inputs, + const TargetsType& targets, + GradientsType& gradients); private: // Helper functions. @@ -350,7 +391,8 @@ * * @param input Data sequence to compute probabilities for. */ - void Forward(arma::mat&& input); + template + void Forward(const InputType& input); /** * Prepare the network for the given data. @@ -371,7 +413,8 @@ * Iterate through all layer modules and update the the gradient using the * layer defined optimizer. */ - void Gradient(arma::mat&& input); + template + void Gradient(const InputType& input); /** * Reset the module status by setting the current deterministic parameter @@ -425,9 +468,6 @@ //! The current error for the backward pass. arma::mat error; - //! THe current input of the forward/backward pass. - arma::mat currentInput; - //! Locally-stored delta visitor. DeltaVisitor deltaVisitor; @@ -494,7 +534,7 @@ struct version< mlpack::ann::FFN> { - BOOST_STATIC_CONSTANT(int, value = 1); + BOOST_STATIC_CONSTANT(int, value = 2); }; } // namespace serialization diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/ffn_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/ffn_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/ffn_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/ffn_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -41,7 +41,7 @@ numFunctions(0), deterministic(true) { - /* Nothing to do here */ + /* Nothing to do here. */ } template +template +typename std::enable_if< + HasMaxIterations + ::value, void>::type +FFN:: +WarnMessageMaxIterations(OptimizerType& optimizer, size_t samples) const +{ + if (optimizer.MaxIterations() < samples && + optimizer.MaxIterations() != 0) + { + Log::Warn << "The optimizer's maximum number of iterations " + << "is less than the size of the dataset; the " + << "optimizer will not pass over the entire " + << "dataset. To fix this, modify the maximum " + << "number of iterations to be at least equal " + << "to the number of points of your dataset " + << "(" << samples << ")." << std::endl; + } +} + +template +template +typename std::enable_if< + !HasMaxIterations + ::value, void>::type +FFN:: +WarnMessageMaxIterations(OptimizerType& /* optimizer */, size_t /* samples */) + const +{ + return; +} + +template template double FFN::Train( arma::mat predictors, @@ -78,6 +113,8 @@ { ResetData(std::move(predictors), std::move(responses)); + WarnMessageMaxIterations(optimizer, this->predictors.n_cols); + // Train the model. Timer::Start("ffn_optimization"); const double out = optimizer.Optimize(*this, parameter, callbacks...); @@ -100,6 +137,8 @@ OptimizerType optimizer; + WarnMessageMaxIterations(optimizer, this->predictors.n_cols); + // Train the model. Timer::Start("ffn_optimization"); const double out = optimizer.Optimize(*this, parameter, callbacks...); @@ -112,8 +151,9 @@ template +template void FFN::Forward( - arma::mat inputs, arma::mat& results) + const PredictorsType& inputs, ResponsesType& results) { if (parameter.is_empty()) ResetParameters(); @@ -124,25 +164,28 @@ ResetDeterministic(); } - currentInput = std::move(inputs); - Forward(std::move(currentInput)); + Forward(inputs); results = boost::apply_visitor(outputParameterVisitor, network.back()); } template +template void FFN::Forward( - arma::mat inputs, arma::mat& results, const size_t begin, const size_t end) + const PredictorsType& inputs, + ResponsesType& results, + const size_t begin, + const size_t end) { - boost::apply_visitor(ForwardVisitor(std::move(inputs), std::move( - boost::apply_visitor(outputParameterVisitor, network[begin]))), + boost::apply_visitor(ForwardVisitor(inputs, + boost::apply_visitor(outputParameterVisitor, network[begin])), network[begin]); for (size_t i = 1; i < end - begin + 1; ++i) { - boost::apply_visitor(ForwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network[begin + i - 1])), std::move( - boost::apply_visitor(outputParameterVisitor, network[begin + i]))), + boost::apply_visitor(ForwardVisitor(boost::apply_visitor( + outputParameterVisitor, network[begin + i - 1]), + boost::apply_visitor(outputParameterVisitor, network[begin + i])), network[begin + i]); } @@ -151,25 +194,28 @@ template +template double FFN::Backward( - arma::mat targets, arma::mat& gradients) + const PredictorsType& inputs, + const TargetsType& targets, + GradientsType& gradients) { - double res = outputLayer.Forward(std::move(boost::apply_visitor( - outputParameterVisitor, network.back())), std::move(targets)); + double res = outputLayer.Forward(boost::apply_visitor( + outputParameterVisitor, network.back()), targets); for (size_t i = 0; i < network.size(); ++i) { res += boost::apply_visitor(lossVisitor, network[i]); } - outputLayer.Backward(std::move(boost::apply_visitor(outputParameterVisitor, - network.back())), std::move(targets), std::move(error)); + outputLayer.Backward(boost::apply_visitor(outputParameterVisitor, + network.back()), targets, error); gradients = arma::zeros(parameter.n_rows, parameter.n_cols); Backward(); ResetGradients(gradients); - Gradient(std::move(currentInput)); + Gradient(inputs); return res; } @@ -189,8 +235,7 @@ } arma::mat resultsTemp; - Forward(std::move(arma::mat(predictors.colptr(0), - predictors.n_rows, 1, false, true))); + Forward(arma::mat(predictors.colptr(0), predictors.n_rows, 1, false, true)); resultsTemp = boost::apply_visitor(outputParameterVisitor, network.back()).col(0); @@ -199,8 +244,7 @@ for (size_t i = 1; i < predictors.n_cols; i++) { - Forward(std::move(arma::mat(predictors.colptr(i), - predictors.n_rows, 1, false, true))); + Forward(arma::mat(predictors.colptr(i), predictors.n_rows, 1, false, true)); resultsTemp = boost::apply_visitor(outputParameterVisitor, network.back()); @@ -210,8 +254,9 @@ template +template double FFN::Evaluate( - arma::mat predictors, arma::mat responses) + const PredictorsType& predictors, const ResponsesType& responses) { if (parameter.is_empty()) ResetParameters(); @@ -222,10 +267,10 @@ ResetDeterministic(); } - Forward(std::move(predictors)); + Forward(predictors); - double res = outputLayer.Forward(std::move(boost::apply_visitor( - outputParameterVisitor, network.back())), std::move(responses)); + double res = outputLayer.Forward(boost::apply_visitor( + outputParameterVisitor, network.back()), responses); for (size_t i = 0; i < network.size(); ++i) { @@ -264,10 +309,10 @@ ResetDeterministic(); } - Forward(std::move(predictors.cols(begin, begin + batchSize - 1))); + Forward(predictors.cols(begin, begin + batchSize - 1)); double res = outputLayer.Forward( - std::move(boost::apply_visitor(outputParameterVisitor, network.back())), - std::move(responses.cols(begin, begin + batchSize - 1))); + boost::apply_visitor(outputParameterVisitor, network.back()), + responses.cols(begin, begin + batchSize - 1)); for (size_t i = 0; i < network.size(); ++i) { @@ -325,10 +370,10 @@ ResetDeterministic(); } - Forward(std::move(predictors.cols(begin, begin + batchSize - 1))); + Forward(predictors.cols(begin, begin + batchSize - 1)); double res = outputLayer.Forward( - std::move(boost::apply_visitor(outputParameterVisitor, network.back())), - std::move(responses.cols(begin, begin + batchSize - 1))); + boost::apply_visitor(outputParameterVisitor, network.back()), + responses.cols(begin, begin + batchSize - 1)); for (size_t i = 0; i < network.size(); ++i) { @@ -336,13 +381,13 @@ } outputLayer.Backward( - std::move(boost::apply_visitor(outputParameterVisitor, network.back())), - std::move(responses.cols(begin, begin + batchSize - 1)), - std::move(error)); + boost::apply_visitor(outputParameterVisitor, network.back()), + responses.cols(begin, begin + batchSize - 1), + error); Backward(); ResetGradients(gradient); - Gradient(std::move(predictors.cols(begin, begin + batchSize - 1))); + Gradient(predictors.cols(begin, begin + batchSize - 1)); return res; } @@ -396,18 +441,19 @@ size_t offset = 0; for (size_t i = 0; i < network.size(); ++i) { - offset += boost::apply_visitor(GradientSetVisitor(std::move(gradient), - offset), network[i]); + offset += boost::apply_visitor(GradientSetVisitor(gradient, offset), + network[i]); } } template +template void FFN::Forward(arma::mat&& input) + CustomLayers...>::Forward(const InputType& input) { - boost::apply_visitor(ForwardVisitor(std::move(input), std::move( - boost::apply_visitor(outputParameterVisitor, network.front()))), + boost::apply_visitor(ForwardVisitor(input, + boost::apply_visitor(outputParameterVisitor, network.front())), network.front()); if (!reset) @@ -434,9 +480,9 @@ boost::apply_visitor(SetInputHeightVisitor(height), network[i]); } - boost::apply_visitor(ForwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network[i - 1])), std::move( - boost::apply_visitor(outputParameterVisitor, network[i]))), network[i]); + boost::apply_visitor(ForwardVisitor(boost::apply_visitor( + outputParameterVisitor, network[i - 1]), + boost::apply_visitor(outputParameterVisitor, network[i])), network[i]); if (!reset) { @@ -462,37 +508,38 @@ typename... CustomLayers> void FFN::Backward() { - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network.back())), std::move(error), std::move( - boost::apply_visitor(deltaVisitor, network.back()))), network.back()); + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, network.back()), error, + boost::apply_visitor(deltaVisitor, network.back())), network.back()); for (size_t i = 2; i < network.size(); ++i) { - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network[network.size() - i])), std::move( - boost::apply_visitor(deltaVisitor, network[network.size() - i + 1])), - std::move(boost::apply_visitor(deltaVisitor, - network[network.size() - i]))), network[network.size() - i]); + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, network[network.size() - i]), + boost::apply_visitor(deltaVisitor, network[network.size() - i + 1]), + boost::apply_visitor(deltaVisitor, network[network.size() - i])), + network[network.size() - i]); } } template +template void FFN::Gradient(arma::mat&& input) + CustomLayers...>::Gradient(const InputType& input) { - boost::apply_visitor(GradientVisitor(std::move(input), std::move( - boost::apply_visitor(deltaVisitor, network[1]))), network.front()); + boost::apply_visitor(GradientVisitor(input, + boost::apply_visitor(deltaVisitor, network[1])), network.front()); for (size_t i = 1; i < network.size() - 1; ++i) { - boost::apply_visitor(GradientVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network[i - 1])), std::move( - boost::apply_visitor(deltaVisitor, network[i + 1]))), network[i]); + boost::apply_visitor(GradientVisitor(boost::apply_visitor( + outputParameterVisitor, network[i - 1]), + boost::apply_visitor(deltaVisitor, network[i + 1])), network[i]); } - boost::apply_visitor(GradientVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network[network.size() - 2])), std::move(error)), + boost::apply_visitor(GradientVisitor(boost::apply_visitor( + outputParameterVisitor, network[network.size() - 2]), error), network[network.size() - 1]); } @@ -505,7 +552,13 @@ ar & BOOST_SERIALIZATION_NVP(parameter); ar & BOOST_SERIALIZATION_NVP(width); ar & BOOST_SERIALIZATION_NVP(height); - ar & BOOST_SERIALIZATION_NVP(currentInput); + + // Early versions used the currentInput member, which is now no longer needed. + if (version < 2) + { + arma::mat currentInput; // Temporary matrix to output. + ar & BOOST_SERIALIZATION_NVP(currentInput); + } // Earlier versions of the FFN code did not serialize whether or not the model // was reset. @@ -535,8 +588,8 @@ size_t offset = 0; for (size_t i = 0; i < network.size(); ++i) { - offset += boost::apply_visitor(WeightSetVisitor(std::move(parameter), - offset), network[i]); + offset += boost::apply_visitor(WeightSetVisitor(parameter, offset), + network[i]); boost::apply_visitor(resetVisitor, network[i]); } @@ -562,7 +615,6 @@ std::swap(parameter, network.parameter); std::swap(numFunctions, network.numFunctions); std::swap(error, network.error); - std::swap(currentInput, network.currentInput); std::swap(deterministic, network.deterministic); std::swap(delta, network.delta); std::swap(inputParameter, network.inputParameter); @@ -584,7 +636,6 @@ parameter(network.parameter), numFunctions(network.numFunctions), error(network.error), - currentInput(network.currentInput), deterministic(network.deterministic), delta(network.delta), inputParameter(network.inputParameter), @@ -613,7 +664,6 @@ parameter(std::move(network.parameter)), numFunctions(network.numFunctions), error(std::move(network.error)), - currentInput(std::move(network.currentInput)), deterministic(network.deterministic), delta(std::move(network.delta)), inputParameter(std::move(network.inputParameter)), diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/gan/gan.hpp mlpack-3.3.0/src/mlpack/methods/ann/gan/gan.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/gan/gan.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/gan/gan.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -289,7 +289,7 @@ * * @param input Sampled noise. */ - void Forward(arma::mat&& input); + void Forward(const arma::mat& input); /** * This function predicts the output of the network on the given input. diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/gan/gan_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/gan/gan_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/gan/gan_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/gan/gan_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -258,28 +258,27 @@ currentTarget = arma::mat(responses.memptr() + i, 1, batchSize, false, false); - discriminator.Forward(std::move(currentInput)); + discriminator.Forward(currentInput); double res = discriminator.outputLayer.Forward( - std::move(boost::apply_visitor( + boost::apply_visitor( outputParameterVisitor, - discriminator.network.back())), std::move(currentTarget)); + discriminator.network.back()), currentTarget); noise.imbue( [&]() { return noiseFunction();} ); - generator.Forward(std::move(noise)); + generator.Forward(noise); predictors.cols(numFunctions, numFunctions + batchSize - 1) = boost::apply_visitor(outputParameterVisitor, generator.network.back()); - discriminator.Forward(std::move(predictors.cols(numFunctions, - numFunctions + batchSize - 1))); + discriminator.Forward(predictors.cols(numFunctions, + numFunctions + batchSize - 1)); responses.cols(numFunctions, numFunctions + batchSize - 1) = arma::zeros(1, batchSize); currentTarget = arma::mat(responses.memptr() + numFunctions, 1, batchSize, false, false); res += discriminator.outputLayer.Forward( - std::move(boost::apply_visitor( - outputParameterVisitor, - discriminator.network.back())), std::move(currentTarget)); + boost::apply_visitor(outputParameterVisitor, + discriminator.network.back()), currentTarget); return res; } @@ -341,7 +340,7 @@ i, gradientDiscriminator, batchSize); noise.imbue( [&]() { return noiseFunction();} ); - generator.Forward(std::move(noise)); + generator.Forward(noise); predictors.cols(numFunctions, numFunctions + batchSize - 1) = boost::apply_visitor(outputParameterVisitor, generator.network.back()); responses.cols(numFunctions, numFunctions + batchSize - 1) = @@ -419,18 +418,18 @@ typename PolicyType > void GAN::Forward( - arma::mat&& input) + const arma::mat& input) { if (parameter.is_empty()) { Reset(); } - generator.Forward(std::move(input)); + generator.Forward(input); arma::mat ganOutput = boost::apply_visitor(outputParameterVisitor, generator.network.back()); - discriminator.Forward(std::move(ganOutput)); + discriminator.Forward(ganOutput); } template< @@ -453,7 +452,7 @@ ResetDeterministic(); } - Forward(std::move(input)); + Forward(input); output = boost::apply_visitor(outputParameterVisitor, discriminator.network.back()); @@ -502,8 +501,8 @@ size_t offset = 0; for (size_t i = 0; i < generator.network.size(); ++i) { - offset += boost::apply_visitor(WeightSetVisitor(std::move( - generator.parameter), offset), generator.network[i]); + offset += boost::apply_visitor(WeightSetVisitor( + generator.parameter, offset), generator.network[i]); boost::apply_visitor(resetVisitor, generator.network[i]); } @@ -511,8 +510,8 @@ offset = 0; for (size_t i = 0; i < discriminator.network.size(); ++i) { - offset += boost::apply_visitor(WeightSetVisitor(std::move( - discriminator.parameter), offset), discriminator.network[i]); + offset += boost::apply_visitor(WeightSetVisitor( + discriminator.parameter, offset), discriminator.network[i]); boost::apply_visitor(resetVisitor, discriminator.network[i]); } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/gan/wgan_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/gan/wgan_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/gan/wgan_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/gan/wgan_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -50,28 +50,28 @@ currentTarget = arma::mat(responses.memptr() + i, 1, batchSize, false, false); - discriminator.Forward(std::move(currentInput)); + discriminator.Forward(currentInput); double res = discriminator.outputLayer.Forward( - std::move(boost::apply_visitor( + boost::apply_visitor( outputParameterVisitor, - discriminator.network.back())), std::move(currentTarget)); + discriminator.network.back()), currentTarget); noise.imbue( [&]() { return noiseFunction();} ); - generator.Forward(std::move(noise)); + generator.Forward(noise); predictors.cols(numFunctions, numFunctions + batchSize - 1) = boost::apply_visitor(outputParameterVisitor, generator.network.back()); - discriminator.Forward(std::move(predictors.cols(numFunctions, - numFunctions + batchSize - 1))); + discriminator.Forward(predictors.cols(numFunctions, + numFunctions + batchSize - 1)); responses.cols(numFunctions, numFunctions + batchSize - 1) = -arma::ones(1, batchSize); currentTarget = arma::mat(responses.memptr() + numFunctions, 1, batchSize, false, false); res += discriminator.outputLayer.Forward( - std::move(boost::apply_visitor( + boost::apply_visitor( outputParameterVisitor, - discriminator.network.back())), std::move(currentTarget)); + discriminator.network.back()), currentTarget); return res; } @@ -132,7 +132,7 @@ i, gradientDiscriminator, batchSize); noise.imbue( [&]() { return noiseFunction();} ); - generator.Forward(std::move(noise)); + generator.Forward(noise); predictors.cols(numFunctions, numFunctions + batchSize - 1) = boost::apply_visitor(outputParameterVisitor, generator.network.back()); responses.cols(numFunctions, numFunctions + batchSize - 1) = diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/init_rules/network_init.hpp mlpack-3.3.0/src/mlpack/methods/ann/init_rules/network_init.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/init_rules/network_init.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/init_rules/network_init.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -92,8 +92,8 @@ // hold various other modules. for (size_t i = 0, offset = parameterOffset; i < network.size(); ++i) { - offset += boost::apply_visitor(WeightSetVisitor(std::move(parameter), - offset), network[i]); + offset += boost::apply_visitor(WeightSetVisitor(parameter, offset), + network[i]); boost::apply_visitor(resetVisitor, network[i]); } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/add.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/add.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/add.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/add.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -49,7 +49,7 @@ * @param output Resulting output activation. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -61,9 +61,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - const arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); /** * Calculate the gradient using the output delta and the input activation. @@ -73,9 +73,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(const arma::Mat&& /* input */, - arma::Mat&& error, - arma::Mat&& gradient); + void Gradient(const arma::Mat& /* input */, + const arma::Mat& error, + arma::Mat& gradient); //! Get the parameters. OutputDataType const& Parameters() const { return weights; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/add_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/add_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/add_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/add_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -29,7 +29,7 @@ template template void Add::Forward( - const arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { output = input; output.each_col() += weights; @@ -38,9 +38,9 @@ template template void Add::Backward( - const arma::Mat&& /* input */, - const arma::Mat&& gy, - arma::Mat&& g) + const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g) { g = gy; } @@ -48,9 +48,9 @@ template template void Add::Gradient( - const arma::Mat&& /* input */, - arma::Mat&& error, - arma::Mat&& gradient) + const arma::Mat& /* input */, + const arma::Mat& error, + arma::Mat& gradient) { gradient = error; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/add_merge.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/add_merge.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/add_merge.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/add_merge.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -50,6 +50,15 @@ */ AddMerge(const bool model = false, const bool run = true); + /** + * Create the AddMerge object using the specified parameters. + * + * @param model Expose all the network modules. + * @param run Call the Forward/Backward method before the output is merged. + * @param ownsLayers Delete the layers when this is deallocated. + */ + AddMerge(const bool model, const bool run, const bool ownsLayers); + //! Destructor to release allocated memory. ~AddMerge(); @@ -61,7 +70,7 @@ * @param output Resulting output activation. */ template - void Forward(InputType&& /* input */, OutputType&& output); + void Forward(const InputType& /* input */, OutputType& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -73,9 +82,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); /** * This is the overload of Backward() that runs only a specific layer with @@ -87,9 +96,9 @@ * @param The index of the layer to run. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g, + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g, const size_t index); /* @@ -100,9 +109,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient); + void Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient); /* * This is the overload of Gradient() that runs a specific layer with the @@ -114,9 +123,9 @@ * @param The index of the layer to run. */ template - void Gradient(arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient, + void Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient, const size_t index); /* @@ -184,8 +193,9 @@ //! before merging the output. bool run; - //! We need this to know whether we should delete the layer in the destructor. - bool ownsLayer; + //! We need this to know whether we should delete the internally-held layers + //! in the destructor. + bool ownsLayers; //! Locally-stored network modules. std::vector > network; @@ -221,6 +231,24 @@ } // namespace ann } // namespace mlpack +//! Set the serialization version of the AddMerge class. +namespace boost { +namespace serialization { + +template< + typename InputDataType, + typename OutputDataType, + typename... CustomLayers +> +struct version> +{ + BOOST_STATIC_CONSTANT(int, value = 1); +}; + +} // namespace serialization +} // namespace boost + // Include implementation. #include "add_merge_impl.hpp" diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/add_merge_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/add_merge_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/add_merge_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/add_merge_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -27,7 +27,16 @@ typename... CustomLayers> AddMerge::AddMerge( const bool model, const bool run) : - model(model), run(run), ownsLayer(!model) + model(model), run(run), ownsLayers(!model) +{ + // Nothing to do here. +} + +template +AddMerge::AddMerge( + const bool model, const bool run, const bool ownsLayers) : + model(model), run(run), ownsLayers(ownsLayers) { // Nothing to do here. } @@ -36,7 +45,7 @@ typename... CustomLayers> AddMerge::~AddMerge() { - if (ownsLayer) + if (!model && ownsLayers) { std::for_each(network.begin(), network.end(), boost::apply_visitor(deleteVisitor)); @@ -47,14 +56,14 @@ typename... CustomLayers> template void AddMerge::Forward( - InputType&& input, OutputType&& output) + const InputType& input, OutputType& output) { if (run) { for (size_t i = 0; i < network.size(); ++i) { - boost::apply_visitor(ForwardVisitor(std::move(input), std::move( - boost::apply_visitor(outputParameterVisitor, network[i]))), + boost::apply_visitor(ForwardVisitor(input, + boost::apply_visitor(outputParameterVisitor, network[i])), network[i]); } } @@ -70,15 +79,17 @@ typename... CustomLayers> template void AddMerge::Backward( - const arma::Mat&& /* input */, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g) { if (run) { for (size_t i = 0; i < network.size(); ++i) { - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network[i])), std::move(gy), std::move( - boost::apply_visitor(deltaVisitor, network[i]))), network[i]); + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, network[i]), gy, + boost::apply_visitor(deltaVisitor, network[i])), network[i]); } g = boost::apply_visitor(deltaVisitor, network[0]); @@ -95,12 +106,14 @@ typename... CustomLayers> template void AddMerge::Backward( - const arma::Mat&& /* input */, arma::Mat&& gy, arma::Mat&& g, + const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g, const size_t index) { - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network[index])), std::move(gy), std::move( - boost::apply_visitor(deltaVisitor, network[index]))), network[index]); + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, network[index]), gy, + boost::apply_visitor(deltaVisitor, network[index])), network[index]); g = boost::apply_visitor(deltaVisitor, network[index]); } @@ -108,16 +121,15 @@ typename... CustomLayers> template void AddMerge::Gradient( - arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& /* gradient */ ) + const arma::Mat& input, + const arma::Mat& error, + arma::Mat& /* gradient */ ) { if (run) { for (size_t i = 0; i < network.size(); ++i) { - boost::apply_visitor(GradientVisitor(std::move(input), std::move(error)), - network[i]); + boost::apply_visitor(GradientVisitor(input, error), network[i]); } } } @@ -126,20 +138,19 @@ typename... CustomLayers> template void AddMerge::Gradient( - arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& /* gradient */, + const arma::Mat& input, + const arma::Mat& error, + arma::Mat& /* gradient */, const size_t index) { - boost::apply_visitor(GradientVisitor(std::move(input), std::move(error)), - network[index]); + boost::apply_visitor(GradientVisitor(input, error), network[index]); } template template void AddMerge::serialize( - Archive& ar, const unsigned int /* version */) + Archive& ar, const unsigned int version) { // Be sure to clear other layers before loading. if (Archive::is_loading::value) @@ -148,7 +159,11 @@ ar & BOOST_SERIALIZATION_NVP(network); ar & BOOST_SERIALIZATION_NVP(model); ar & BOOST_SERIALIZATION_NVP(run); - ar & BOOST_SERIALIZATION_NVP(ownsLayer); + + if (version >= 1) + ar & BOOST_SERIALIZATION_NVP(ownsLayers); + else if (Archive::is_loading::value) + ownsLayers = !model; } } // namespace ann diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/alpha_dropout.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/alpha_dropout.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/alpha_dropout.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/alpha_dropout.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -35,7 +35,8 @@ * Andreas Mayr}, * title = {Self-Normalizing Neural Networks}, * journal = {Advances in Neural Information Processing Systems}, - * year = {2017} + * year = {2017}, + * url = {https://arxiv.org/abs/1706.02515} * } * @endcode * @@ -65,7 +66,7 @@ * @param output Resulting output activation. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of the alpha_dropout layer. @@ -75,9 +76,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); //! Get the output parameter. OutputDataType const& OutputParameter() const { return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/alpha_dropout_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/alpha_dropout_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/alpha_dropout_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/alpha_dropout_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -36,7 +36,7 @@ template template void AlphaDropout::Forward( - const arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { // The dropout mask will not be multiplied in the deterministic mode // (during testing). @@ -58,7 +58,7 @@ template template void AlphaDropout::Backward( - const arma::Mat&& /* input */, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g) { g = gy % mask * a; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/atrous_convolution.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/atrous_convolution.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/atrous_convolution.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/atrous_convolution.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -61,31 +61,31 @@ * * @param inSize The number of input maps. * @param outSize The number of output maps. - * @param kW Width of the filter/kernel. - * @param kH Height of the filter/kernel. - * @param dW Stride of filter application in the x direction. - * @param dH Stride of filter application in the y direction. + * @param kernelWidth Width of the filter/kernel. + * @param kernelHeight Height of the filter/kernel. + * @param strideWidth Stride of filter application in the x direction. + * @param strideHeight Stride of filter application in the y direction. * @param padW Padding width of the input. * @param padH Padding height of the input. * @param inputWidth The widht of the input data. * @param inputHeight The height of the input data. - * @param dilationW The space between the cells of filters in x direction. - * @param dilationH The space between the cells of filters in y direction. + * @param dilationWidth The space between the cells of filters in x direction. + * @param dilationHeight The space between the cells of filters in y direction. * @param paddingType The type of padding (Valid or Same). Defaults to None. */ AtrousConvolution(const size_t inSize, const size_t outSize, - const size_t kW, - const size_t kH, - const size_t dW = 1, - const size_t dH = 1, + const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth = 1, + const size_t strideHeight = 1, const size_t padW = 0, const size_t padH = 0, const size_t inputWidth = 0, const size_t inputHeight = 0, - const size_t dilationW = 1, - const size_t dilationH = 1, - const std::string paddingType = "None"); + const size_t dilationWidth = 1, + const size_t dilationHeight = 1, + const std::string& paddingType = "None"); /** * Create the AtrousConvolution object using the specified number of @@ -94,10 +94,10 @@ * * @param inSize The number of input maps. * @param outSize The number of output maps. - * @param kW Width of the filter/kernel. - * @param kH Height of the filter/kernel. - * @param dW Stride of filter application in the x direction. - * @param dH Stride of filter application in the y direction. + * @param kernelWidth Width of the filter/kernel. + * @param kernelHeight Height of the filter/kernel. + * @param strideWidth Stride of filter application in the x direction. + * @param strideHeight Stride of filter application in the y direction. * @param padW A two-value tuple indicating padding widths of the input. * First value is padding at left side. Second value is padding on * right side. @@ -106,23 +106,23 @@ * bottom. * @param inputWidth The widht of the input data. * @param inputHeight The height of the input data. - * @param dilationW The space between the cells of filters in x direction. - * @param dilationH The space between the cells of filters in y direction. - * @param paddingType The type of padding (Valid or Same). Defaults to None. + * @param dilationWidth The space between the cells of filters in x direction. + * @param dilationHeight The space between the cells of filters in y direction. + * @param paddingType The type of padding (Valid/Same/None). Defaults to None. */ AtrousConvolution(const size_t inSize, const size_t outSize, - const size_t kW, - const size_t kH, - const size_t dW, - const size_t dH, - const std::tuple padW, - const std::tuple padH, + const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth, + const size_t strideHeight, + const std::tuple& padW, + const std::tuple& padH, const size_t inputWidth = 0, const size_t inputHeight = 0, - const size_t dilationW = 1, - const size_t dilationH = 1, - const std::string paddingType = "None"); + const size_t dilationWidth = 1, + const size_t dilationHeight = 1, + const std::string& paddingType = "None"); /* * Set the weight and bias term. @@ -137,7 +137,7 @@ * @param output Resulting output activation. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -149,9 +149,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); /* * Calculate the gradient using the output delta and the input activation. @@ -161,55 +161,96 @@ * @param gradient The calculated gradient. */ template - void Gradient(const arma::Mat&& /* input */, - arma::Mat&& error, - arma::Mat&& gradient); + void Gradient(const arma::Mat& /* input */, + const arma::Mat& error, + arma::Mat& gradient); //! Get the parameters. - OutputDataType const& Parameters() const { return weights; } + const OutputDataType& Parameters() const { return weights; } //! Modify the parameters. OutputDataType& Parameters() { return weights; } //! Get the output parameter. - OutputDataType const& OutputParameter() const { return outputParameter; } + const OutputDataType& OutputParameter() const { return outputParameter; } //! Modify the output parameter. OutputDataType& OutputParameter() { return outputParameter; } //! Get the delta. - OutputDataType const& Delta() const { return delta; } + const OutputDataType& Delta() const { return delta; } //! Modify the delta. OutputDataType& Delta() { return delta; } //! Get the gradient. - OutputDataType const& Gradient() const { return gradient; } + const OutputDataType& Gradient() const { return gradient; } //! Modify the gradient. OutputDataType& Gradient() { return gradient; } //! Get the input width. - size_t const& InputWidth() const { return inputWidth; } + const size_t& InputWidth() const { return inputWidth; } //! Modify input the width. size_t& InputWidth() { return inputWidth; } //! Get the input height. - size_t const& InputHeight() const { return inputHeight; } + const size_t& InputHeight() const { return inputHeight; } //! Modify the input height. size_t& InputHeight() { return inputHeight; } //! Get the output width. - size_t const& OutputWidth() const { return outputWidth; } + const size_t& OutputWidth() const { return outputWidth; } //! Modify the output width. size_t& OutputWidth() { return outputWidth; } //! Get the output height. - size_t const& OutputHeight() const { return outputHeight; } + const size_t& OutputHeight() const { return outputHeight; } //! Modify the output height. size_t& OutputHeight() { return outputHeight; } + //! Get the input size. + const size_t& InputSize() const { return inSize; } + + //! Get the output size. + const size_t& OutputSize() const { return outSize; } + + //! Get the kernel width. + size_t KernelWidth() const { return kernelWidth; } + //! Modify the kernel width. + size_t& KernelWidth() { return kernelWidth; } + + //! Get the kernel height. + size_t KernelHeight() const { return kernelHeight; } + //! Modify the kernel height. + size_t& KernelHeight() { return kernelHeight; } + + //! Get the stride width. + size_t StrideWidth() const { return strideWidth; } + //! Modify the stride width. + size_t& StrideWidth() { return strideWidth; } + + //! Get the stride height. + size_t StrideHeight() const { return strideHeight; } + //! Modify the stride height. + size_t& StrideHeight() { return strideHeight; } + + //! Get the dilation rate on the X axis. + size_t DilationWidth() const { return dilationWidth; } + //! Modify the dilation rate on the X axis. + size_t& DilationWidth() { return dilationWidth; } + + //! Get the dilation rate on the Y axis. + size_t DilationHeight() const { return dilationHeight; } + //! Modify the dilation rate on the Y axis. + size_t& DilationHeight() { return dilationHeight; } + + //! Get the internal Padding layer. + const ann::Padding<>& Padding() const { return padding; } + //! Modify the internal Padding layer. + ann::Padding<>& Padding() { return padding; } + //! Modify the bias weights of the layer. arma::mat& Bias() { return bias; } /** - * Serialize the layer + * Serialize the layer. */ template void serialize(Archive& ar, const unsigned int /* version */); @@ -239,7 +280,10 @@ /* * Function to assign padding such that output size is same as input size. */ - void InitializeSamePadding(); + void InitializeSamePadding(size_t& padWLeft, + size_t& padWRight, + size_t& padHBottom, + size_t& padHTop) const; /* * Rotates a 3rd-order tensor counterclockwise by 180 degrees. @@ -280,28 +324,16 @@ size_t batchSize; //! Locally-stored filter/kernel width. - size_t kW; + size_t kernelWidth; //! Locally-stored filter/kernel height. - size_t kH; + size_t kernelHeight; //! Locally-stored stride of the filter in x-direction. - size_t dW; + size_t strideWidth; //! Locally-stored stride of the filter in y-direction. - size_t dH; - - //! Locally-stored left-side padding width. - size_t padWLeft; - - //! Locally-stored right-side padding width. - size_t padWRight; - - //! Locally-stored bottom padding height. - size_t padHBottom; - - //! Locally-stored top padding height. - size_t padHTop; + size_t strideHeight; //! Locally-stored weight object. OutputDataType weights; @@ -325,17 +357,14 @@ size_t outputHeight; //! Locally-stored width dilation factor. - size_t dilationW; + size_t dilationWidth; //! Locally-stored height dilation factor. - size_t dilationH; + size_t dilationHeight; //! Locally-stored transformed output parameter. arma::cube outputTemp; - //! Locally-stored transformed input parameter. - arma::cube inputTemp; - //! Locally-stored transformed padded input parameter. arma::cube inputPaddedTemp; @@ -346,7 +375,7 @@ arma::cube gradientTemp; //! Locally-stored padding layer. - Padding<>* padding; + ann::Padding<> padding; //! Locally-stored delta object. OutputDataType delta; @@ -377,13 +406,13 @@ BackwardConvolutionRule, GradientConvolutionRule, InputDataType, OutputDataType> > { - BOOST_STATIC_CONSTANT(int, value = 1); + BOOST_STATIC_CONSTANT(int, value = 2); }; } // namespace serialization } // namespace boost -// Include implementation +// Include implementation. #include "atrous_convolution_impl.hpp" #endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/atrous_convolution_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/atrous_convolution_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/atrous_convolution_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/atrous_convolution_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -53,54 +53,33 @@ >::AtrousConvolution( const size_t inSize, const size_t outSize, - const size_t kW, - const size_t kH, - const size_t dW, - const size_t dH, + const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth, + const size_t strideHeight, const size_t padW, const size_t padH, const size_t inputWidth, const size_t inputHeight, - const size_t dilationW, - const size_t dilationH, - const std::string paddingType) : - inSize(inSize), - outSize(outSize), - kW(kW), - kH(kH), - dW(dW), - dH(dH), - padWLeft(padW), - padWRight(padW), - padHBottom(padH), - padHTop(padH), - inputWidth(inputWidth), - inputHeight(inputHeight), - outputWidth(0), - outputHeight(0), - dilationW(dilationW), - dilationH(dilationH) + const size_t dilationWidth, + const size_t dilationHeight, + const std::string& paddingType) : + AtrousConvolution( + inSize, + outSize, + kernelWidth, + kernelHeight, + strideWidth, + strideHeight, + std::tuple(padW, padW), + std::tuple(padH, padH), + inputWidth, + inputHeight, + dilationWidth, + dilationHeight, + paddingType) { - weights.set_size((outSize * inSize * kW * kH) + outSize, 1); - - // Transform paddingType to lowercase. - std::string paddingTypeLow = paddingType; - std::transform(paddingType.begin(), paddingType.end(), paddingTypeLow.begin(), - [](unsigned char c){ return std::tolower(c); }); - - if (paddingTypeLow == "valid") - { - padWLeft = 0; - padWRight = 0; - padHTop = 0; - padHBottom = 0; - } - else if (paddingTypeLow == "same") - { - InitializeSamePadding(); - } - - padding = new Padding<>(padWLeft, padWRight, padHTop, padHBottom); + // Nothing to do here. } template< @@ -119,41 +98,42 @@ >::AtrousConvolution( const size_t inSize, const size_t outSize, - const size_t kW, - const size_t kH, - const size_t dW, - const size_t dH, - const std::tuple padW, - const std::tuple padH, + const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth, + const size_t strideHeight, + const std::tuple& padW, + const std::tuple& padH, const size_t inputWidth, const size_t inputHeight, - const size_t dilationW, - const size_t dilationH, - const std::string paddingType) : + const size_t dilationWidth, + const size_t dilationHeight, + const std::string& paddingType) : inSize(inSize), outSize(outSize), - kW(kW), - kH(kH), - dW(dW), - dH(dH), - padWLeft(std::get<0>(padW)), - padWRight(std::get<1>(padW)), - padHBottom(std::get<1>(padH)), - padHTop(std::get<0>(padH)), + kernelWidth(kernelWidth), + kernelHeight(kernelHeight), + strideWidth(strideWidth), + strideHeight(strideHeight), inputWidth(inputWidth), inputHeight(inputHeight), outputWidth(0), outputHeight(0), - dilationW(dilationW), - dilationH(dilationH) + dilationWidth(dilationWidth), + dilationHeight(dilationHeight) { - weights.set_size((outSize * inSize * kW * kH) + outSize, 1); + weights.set_size((outSize * inSize * kernelWidth * kernelHeight) + outSize, + 1); // Transform paddingType to lowercase. std::string paddingTypeLow = paddingType; std::transform(paddingType.begin(), paddingType.end(), paddingTypeLow.begin(), [](unsigned char c){ return std::tolower(c); }); + size_t padWLeft = std::get<0>(padW); + size_t padWRight = std::get<1>(padW); + size_t padHTop = std::get<0>(padH); + size_t padHBottom = std::get<1>(padH); if (paddingTypeLow == "valid") { padWLeft = 0; @@ -163,10 +143,10 @@ } else if (paddingTypeLow == "same") { - InitializeSamePadding(); + InitializeSamePadding(padWLeft, padWRight, padHTop, padHBottom); } - padding = new Padding<>(padWLeft, padWRight, padHTop, padHBottom); + padding = ann::Padding<>(padWLeft, padWRight, padHTop, padHBottom); } template< @@ -184,7 +164,7 @@ OutputDataType >::Reset() { - weight = arma::cube(weights.memptr(), kW, kH, + weight = arma::cube(weights.memptr(), kernelWidth, kernelHeight, outSize * inSize, false, false); bias = arma::mat(weights.memptr() + weight.n_elem, outSize, 1, false, false); @@ -204,28 +184,30 @@ GradientConvolutionRule, InputDataType, OutputDataType ->::Forward(const arma::Mat&& input, arma::Mat&& output) +>::Forward(const arma::Mat& input, arma::Mat& output) { batchSize = input.n_cols; - inputTemp = arma::cube(const_cast&&>(input).memptr(), + arma::cube inputTemp(const_cast&>(input).memptr(), inputWidth, inputHeight, inSize * batchSize, false, false); - if (padWLeft != 0 || padWRight != 0 || padHTop != 0 || padHBottom != 0) + if (padding.PadWLeft() != 0 || padding.PadWRight() != 0 || + padding.PadHTop() != 0 || padding.PadHBottom() != 0) { - inputPaddedTemp.set_size(inputTemp.n_rows + padWLeft + padWRight, - inputTemp.n_cols + padHTop + padHBottom, inputTemp.n_slices); + inputPaddedTemp.set_size( + inputTemp.n_rows + padding.PadWLeft() + padding.PadWRight(), + inputTemp.n_cols + padding.PadHTop() + padding.PadHBottom(), + inputTemp.n_slices); for (size_t i = 0; i < inputTemp.n_slices; ++i) { - padding->Forward(std::move(inputTemp.slice(i)), - std::move(inputPaddedTemp.slice(i))); + padding.Forward(inputTemp.slice(i), inputPaddedTemp.slice(i)); } } - size_t wConv = ConvOutSize(inputWidth, kW, dW, padWLeft, padWRight, - dilationW); - size_t hConv = ConvOutSize(inputHeight, kH, dH, padHTop, padHBottom, - dilationH); + size_t wConv = ConvOutSize(inputWidth, kernelWidth, strideWidth, + padding.PadWLeft(), padding.PadWRight(), dilationWidth); + size_t hConv = ConvOutSize(inputHeight, kernelHeight, strideHeight, + padding.PadHTop(), padding.PadHBottom(), dilationHeight); output.set_size(wConv * hConv * outSize, batchSize); outputTemp = arma::Cube(output.memptr(), wConv, hConv, @@ -245,17 +227,18 @@ { arma::Mat convOutput; - if (padWLeft != 0 || padWRight != 0 || padHTop != 0 || padHBottom != 0) + if (padding.PadWLeft() != 0 || padding.PadWRight() != 0 || + padding.PadHTop() != 0 || padding.PadHBottom() != 0) { ForwardConvolutionRule::Convolution(inputPaddedTemp.slice(inMap + - batchCount * inSize), weight.slice(outMapIdx), convOutput, dW, dH, - dilationW, dilationH); + batchCount * inSize), weight.slice(outMapIdx), convOutput, + strideWidth, strideHeight, dilationWidth, dilationHeight); } else { ForwardConvolutionRule::Convolution(inputTemp.slice(inMap + - batchCount * inSize), weight.slice(outMapIdx), convOutput, dW, dH, - dilationW, dilationH); + batchCount * inSize), weight.slice(outMapIdx), convOutput, + strideWidth, strideHeight, dilationWidth, dilationHeight); } outputTemp.slice(outMap) += convOutput; @@ -283,14 +266,14 @@ InputDataType, OutputDataType >::Backward( - const arma::Mat&& /* input */, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g) { - arma::cube mappedError(gy.memptr(), outputWidth, outputHeight, - outSize * batchSize, false, false); + arma::cube mappedError(((arma::Mat&) gy).memptr(), outputWidth, + outputHeight, outSize * batchSize, false, false); - g.set_size(inputTemp.n_rows * inputTemp.n_cols * inSize, batchSize); - gTemp = arma::Cube(g.memptr(), inputTemp.n_rows, - inputTemp.n_cols, inputTemp.n_slices, false, false); + g.set_size(inputWidth * inputHeight * inSize, batchSize); + gTemp = arma::Cube(g.memptr(), inputWidth, inputHeight, + inSize * batchSize, false, false); gTemp.zeros(); for (size_t outMap = 0, outMapIdx = 0, batchCount = 0; outMap < @@ -308,12 +291,16 @@ Rotate180(weight.slice(outMapIdx), rotatedFilter); BackwardConvolutionRule::Convolution(mappedError.slice(outMap), - rotatedFilter, output, dW, dH, dilationW, dilationH); + rotatedFilter, output, strideWidth, strideHeight, dilationWidth, + dilationHeight); - if (padWLeft != 0 || padWRight != 0 || padHTop != 0 || padHBottom != 0) + if (padding.PadWLeft() != 0 || padding.PadWRight() != 0 || + padding.PadHTop() != 0 || padding.PadHBottom() != 0) { - gTemp.slice(inMap + batchCount * inSize) += output.submat(padWLeft, - padHTop, padWLeft + gTemp.n_rows - 1, padHTop + gTemp.n_cols - 1); + gTemp.slice(inMap + batchCount * inSize) += + output.submat(padding.PadWLeft(), padding.PadHTop(), + padding.PadWLeft() + gTemp.n_rows - 1, + padding.PadHTop() + gTemp.n_cols - 1); } else { @@ -338,12 +325,14 @@ InputDataType, OutputDataType >::Gradient( - const arma::Mat&& /* input */, - arma::Mat&& error, - arma::Mat&& gradient) + const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient) { - arma::cube mappedError(error.memptr(), outputWidth, outputHeight, - outSize * batchSize, false, false); + arma::cube mappedError(((arma::Mat&) error).memptr(), outputWidth, + outputHeight, outSize * batchSize, false, false); + arma::cube inputTemp(const_cast&>(input).memptr(), + inputWidth, inputHeight, inSize * batchSize, false, false); gradient.set_size(weights.n_elem, 1); gradientTemp = arma::Cube(gradient.memptr(), weight.n_rows, @@ -362,7 +351,8 @@ for (size_t inMap = 0; inMap < inSize; inMap++, outMapIdx++) { arma::Mat inputSlice; - if (padWLeft != 0 || padWRight != 0 || padHTop != 0 || padHBottom != 0) + if (padding.PadWLeft() != 0 || padding.PadWRight() != 0 || + padding.PadHTop() != 0 || padding.PadHBottom() != 0) { inputSlice = inputPaddedTemp.slice(inMap + batchCount * inSize); } @@ -375,18 +365,18 @@ arma::Mat output; GradientConvolutionRule::Convolution(inputSlice, deltaSlice, - output, dW, dH, 1, 1); + output, strideWidth, strideHeight, 1, 1); - if (dilationH > 1) + if (dilationHeight > 1) { for (size_t i = 1; i < output.n_cols; i++){ - output.shed_cols(i, i + dilationH - 2); + output.shed_cols(i, i + dilationHeight - 2); } } - if (dilationW > 1) + if (dilationWidth > 1) { for (size_t i = 1; i < output.n_rows; i++){ - output.shed_rows(i, i + dilationW - 2); + output.shed_rows(i, i + dilationWidth - 2); } } @@ -432,26 +422,36 @@ ar & BOOST_SERIALIZATION_NVP(inSize); ar & BOOST_SERIALIZATION_NVP(outSize); ar & BOOST_SERIALIZATION_NVP(batchSize); - ar & BOOST_SERIALIZATION_NVP(kW); - ar & BOOST_SERIALIZATION_NVP(kH); - ar & BOOST_SERIALIZATION_NVP(dW); - ar & BOOST_SERIALIZATION_NVP(dH); - ar & BOOST_SERIALIZATION_NVP(padWLeft); - ar & BOOST_SERIALIZATION_NVP(padWRight); - ar & BOOST_SERIALIZATION_NVP(padHBottom); - ar & BOOST_SERIALIZATION_NVP(padHTop); + ar & BOOST_SERIALIZATION_NVP(kernelWidth); + ar & BOOST_SERIALIZATION_NVP(kernelHeight); + ar & BOOST_SERIALIZATION_NVP(strideWidth); + ar & BOOST_SERIALIZATION_NVP(strideHeight); + + // These are now stored in the padding layer. + if (version < 2 && Archive::is_loading::value) + { + size_t padWLeft, padWRight, padHBottom, padHTop; + ar & BOOST_SERIALIZATION_NVP(padWLeft); + ar & BOOST_SERIALIZATION_NVP(padWRight); + ar & BOOST_SERIALIZATION_NVP(padHBottom); + ar & BOOST_SERIALIZATION_NVP(padHTop); + } + ar & BOOST_SERIALIZATION_NVP(inputWidth); ar & BOOST_SERIALIZATION_NVP(inputHeight); ar & BOOST_SERIALIZATION_NVP(outputWidth); ar & BOOST_SERIALIZATION_NVP(outputHeight); - ar & BOOST_SERIALIZATION_NVP(dilationW); - ar & BOOST_SERIALIZATION_NVP(dilationH); + ar & BOOST_SERIALIZATION_NVP(dilationWidth); + ar & BOOST_SERIALIZATION_NVP(dilationHeight); if (version > 0) ar & BOOST_SERIALIZATION_NVP(padding); if (Archive::is_loading::value) - weights.set_size((outSize * inSize * kW * kH) + outSize, 1); + { + weights.set_size((outSize * inSize * kernelWidth * kernelHeight) + outSize, + 1); + } } template< @@ -467,15 +467,18 @@ GradientConvolutionRule, InputDataType, OutputDataType ->::InitializeSamePadding() +>::InitializeSamePadding(size_t& padWLeft, + size_t& padWRight, + size_t& padHTop, + size_t& padHBottom) const { /* * Using O = (W - F + 2P) / s + 1; */ - size_t totalVerticalPadding = (dW - 1) * inputWidth + kW - dW + (dilationW - - 1) * (kW - 1); - size_t totalHorizontalPadding = (dH - 1) * inputHeight + kH - dH + (dilationH - - 1) * (kH - 1); + size_t totalVerticalPadding = (strideWidth - 1) * inputWidth + kernelWidth - + strideWidth + (dilationWidth - 1) * (kernelWidth - 1); + size_t totalHorizontalPadding = (strideHeight - 1) * inputHeight + + kernelHeight - strideHeight + (dilationHeight - 1) * (kernelHeight - 1); padWLeft = totalVerticalPadding / 2; padWRight = totalVerticalPadding - totalVerticalPadding / 2; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/base_layer.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/base_layer.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/base_layer.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/base_layer.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -20,6 +20,10 @@ #include #include #include +#include +#include +#include +#include namespace mlpack { namespace ann /** Artificial Neural Network. */ { @@ -65,7 +69,7 @@ * @param output Resulting output activation. */ template - void Forward(const InputType&& input, OutputType&& output) + void Forward(const InputType& input, OutputType& output) { ActivationFunction::Fn(input, output); } @@ -80,9 +84,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& input, - arma::Mat&& gy, - arma::Mat&& g) + void Backward(const arma::Mat& input, + const arma::Mat& gy, + arma::Mat& g) { arma::Mat derivative; ActivationFunction::Deriv(input, derivative); @@ -184,6 +188,50 @@ using HardSigmoidLayer = BaseLayer< ActivationFunction, InputDataType, OutputDataType>; +/** + * Standard Swish-Layer using the Swish activation function. + */ +template < + class ActivationFunction = SwishFunction, + typename InputDataType = arma::mat, + typename OutputDataType = arma::mat +> +using SwishFunctionLayer = BaseLayer< + ActivationFunction, InputDataType, OutputDataType>; + +/** + * Standard Mish-Layer using the Mish activation function. + */ +template < + class ActivationFunction = MishFunction, + typename InputDataType = arma::mat, + typename OutputDataType = arma::mat +> +using MishFunctionLayer = BaseLayer< + ActivationFunction, InputDataType, OutputDataType>; + +/** + * Standard LiSHT-Layer using the LiSHT activation function. + */ +template < + class ActivationFunction = LiSHTFunction, + typename InputDataType = arma::mat, + typename OutputDataType = arma::mat +> +using LiSHTFunctionLayer = BaseLayer< + ActivationFunction, InputDataType, OutputDataType>; + +/** + * Standard GELU-Layer using the GELU activation function. + */ +template < + class ActivationFunction = GELUFunction, + typename InputDataType = arma::mat, + typename OutputDataType = arma::mat +> +using GELUFunctionLayer = BaseLayer< + ActivationFunction, InputDataType, OutputDataType>; + } // namespace ann } // namespace mlpack diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/batch_norm.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/batch_norm.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/batch_norm.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/batch_norm.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -81,7 +81,7 @@ * @param output Resulting output activations. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Backward pass through the layer. @@ -91,9 +91,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& input, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& input, + const arma::Mat& gy, + arma::Mat& g); /** * Calculate the gradient using the output delta and the input activations. @@ -103,9 +103,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(const arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient); + void Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient); //! Get the parameters. OutputDataType const& Parameters() const { return weights; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/batch_norm_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/batch_norm_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/batch_norm_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/batch_norm_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -63,7 +63,7 @@ template template void BatchNorm::Forward( - const arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { // Mean and variance over the entire training set will be used to compute // the forward pass when deterministic is set to true. @@ -106,7 +106,7 @@ template template void BatchNorm::Backward( - const arma::Mat&& input, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& input, const arma::Mat& gy, arma::Mat& g) { const arma::mat stdInv = 1.0 / arma::sqrt(variance + eps); @@ -130,9 +130,9 @@ template template void BatchNorm::Gradient( - const arma::Mat&& /* input */, - arma::Mat&& error, - arma::Mat&& gradient) + const arma::Mat& /* input */, + const arma::Mat& error, + arma::Mat& gradient) { gradient.set_size(size + size, 1); diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/bilinear_interpolation.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/bilinear_interpolation.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/bilinear_interpolation.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/bilinear_interpolation.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -65,7 +65,7 @@ * @param output The resulting interpolated output matrix. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -79,9 +79,9 @@ * @param output The resulting down-sampled output. */ template - void Backward(const arma::Mat&& /*input*/, - arma::Mat&& gradient, - arma::Mat&& output); + void Backward(const arma::Mat& /*input*/, + const arma::Mat& gradient, + arma::Mat& output); //! Get the output parameter. OutputDataType const& OutputParameter() const { return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/bilinear_interpolation_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/bilinear_interpolation_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/bilinear_interpolation_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/bilinear_interpolation_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -54,7 +54,7 @@ template template void BilinearInterpolation::Forward( - const arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { batchSize = input.n_cols; if (output.is_empty()) @@ -68,7 +68,7 @@ assert(inRowSize >= 2); assert(inColSize >= 2); - arma::cube inputAsCube(const_cast&&>(input).memptr(), + arma::cube inputAsCube(const_cast&>(input).memptr(), inRowSize, inColSize, depth * batchSize, false, false); arma::cube outputAsCube(output.memptr(), outRowSize, outColSize, depth * batchSize, false, true); @@ -114,9 +114,9 @@ template template void BilinearInterpolation::Backward( - const arma::Mat&& /*input*/, - arma::Mat&& gradient, - arma::Mat&& output) + const arma::Mat& /*input*/, + const arma::Mat& gradient, + arma::Mat& output) { if (output.is_empty()) output.set_size(inRowSize * inColSize * depth, batchSize); @@ -129,8 +129,8 @@ assert(outRowSize >= 2); assert(outColSize >= 2); - arma::cube gradientAsCube(gradient.memptr(), outRowSize, outColSize, - depth * batchSize, false, false); + arma::cube gradientAsCube(((arma::Mat&) gradient).memptr(), outRowSize, + outColSize, depth * batchSize, false, false); arma::cube outputAsCube(output.memptr(), inRowSize, inColSize, depth * batchSize, false, true); diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/celu.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/celu.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/celu.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/celu.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,143 @@ +/** + * @file celu.hpp + * @author Gaurav Singh + * + * Definition of the CELU activation function as described by Jonathan T. Barron. + * + * For more information, read the following paper. + * + * @code + * @article{ + * author = {Jonathan T. Barron}, + * title = {Continuously Differentiable Exponential Linear Units}, + * year = {2017}, + * url = {https://arxiv.org/pdf/1704.07483} + * } + * @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_LAYER_CELU_HPP +#define MLPACK_METHODS_ANN_LAYER_CELU_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * The CELU activation function, defined by + * + * @f{eqnarray*}{ + * f(x) &=& \left\{ + * \begin{array}{lr} + * x & : x \ge 0 \\ + * \alpha(e^(\frac{x}{\alpha}) - 1) & : x < 0 + * \end{array} + * \right. \\ + * f'(x) &=& \left\{ + * \begin{array}{lr} + * 1 & : x \ge 0 \\ + * (\frac{f(x)}{\alpha}) + 1 & : x < 0 + * \end{array} + * \right. + * @f} + * + * In the deterministic mode, there is no computation of the derivative. + * + * @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 CELU +{ + public: + /** + * Create the CELU object using the specified parameter. The non zero + * gradient for negative inputs can be adjusted by specifying the CELU + * hyperparameter alpha (alpha > 0). + * + * @param alpha Scale parameter for the negative factor (default = 1.0). + */ + CELU(const double alpha = 1.0); + + /** + * 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 f(x). + * @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 non zero gradient. + double const& Alpha() const { return alpha; } + //! Modify the non zero gradient. + double& Alpha() { return alpha; } + + //! Get the value of deterministic parameter. + bool Deterministic() const { return deterministic; } + //! Modify the value of deterministic parameter. + bool& Deterministic() { return deterministic; } + + /** + * Serialize the layer. + */ + template + void serialize(Archive& ar, const unsigned int /* version */); + + private: + //! Locally-stored delta object. + OutputDataType delta; + + //! Locally-stored output parameter object. + OutputDataType outputParameter; + + //! Locally stored first derivative of the activation function. + arma::mat derivative; + + //! CELU Hyperparameter (alpha > 0). + double alpha; + + //! If true the derivative computation is disabled, see notes above. + bool deterministic; +}; // class CELU + +} // namespace ann +} // namespace mlpack + +// Include implementation. +#include "celu_impl.hpp" + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/celu_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/celu_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/celu_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/celu_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,76 @@ +/** + * @file celu_impl.hpp + * @author Gaurav Singh + * + * Implementation of the CELU activation function as described by Jonathan T. Barron. + * + * 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_CELU_IMPL_HPP +#define MLPACK_METHODS_ANN_LAYER_CELU_IMPL_HPP + +// In case it hasn't yet been included. +#include "celu.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +CELU::CELU(const double alpha) : + alpha(alpha), + deterministic(false) +{ + if (alpha == 0) + { + Log::Fatal << "The value of alpha cannot be equal to 0, " + << "terminating the program." << std::endl; + } +} + +template +template +void CELU::Forward( + const InputType& input, OutputType& output) +{ + output = arma::ones(arma::size(input)); + for (size_t i = 0; i < input.n_elem; i++) + { + output(i) = (input(i) >= 0) ? input(i) : alpha * + (std::exp(input(i) / alpha) - 1); + } + + if (!deterministic) + { + derivative.set_size(arma::size(input)); + for (size_t i = 0; i < input.n_elem; i++) + { + derivative(i) = (input(i) >= 0) ? 1 : + (output(i) / alpha) + 1; + } + } +} + +template +template +void CELU::Backward( + const DataType& /* input */, const DataType& gy, DataType& g) +{ + g = gy % derivative; +} + +template +template +void CELU::serialize( + Archive& ar, + const unsigned int /* version */) +{ + ar & BOOST_SERIALIZATION_NVP(alpha); +} + +} // namespace ann +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/ann/layer/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/ann/layer/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -94,6 +94,12 @@ c_relu_impl.hpp weight_norm.hpp weight_norm_impl.hpp + hardshrink.hpp + hardshrink_impl.hpp + celu.hpp + celu_impl.hpp + softshrink.hpp + softshrink_impl.hpp ) # Add directory name to sources. diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/concatenate.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/concatenate.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/concatenate.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/concatenate.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -49,7 +49,7 @@ * @param output Resulting output activation. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -61,9 +61,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - const arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); //! Get the parameters. OutputDataType const& Parameters() const { return weights; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/concatenate_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/concatenate_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/concatenate_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/concatenate_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -28,7 +28,7 @@ template template void Concatenate::Forward( - const arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { if (concat.is_empty()) Log::Warn << "The concat matrix has not been provided." << std::endl; @@ -46,9 +46,9 @@ template template void Concatenate::Backward( - const arma::Mat&& /* input */, - const arma::Mat&& gy, - arma::Mat&& g) + const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g) { g = gy.submat(0, 0, inRows - 1, concat.n_cols - 1); } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/concat.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/concat.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/concat.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/concat.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -3,7 +3,7 @@ * @author Marcus Edel * @author Mehul Kumar Nirala * - * Definition of the Concat class, which acts as a concatenation contain. + * Definition of the Concat class, which acts as a concatenation container. * * 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 @@ -80,7 +80,7 @@ * @param output Resulting output activation. */ template - void Forward(arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, using 3rd-order tensors as @@ -92,9 +92,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); /** * This is the overload of Backward() that runs only a specific layer with @@ -106,9 +106,9 @@ * @param The index of the layer to run. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g, + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g, const size_t index); /* @@ -119,9 +119,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(arma::Mat&& /* input */, - arma::Mat&& error, - arma::Mat&& /* gradient */); + void Gradient(const arma::Mat& /* input */, + const arma::Mat& error, + arma::Mat& /* gradient */); /* * This is the overload of Gradient() that runs a specific layer with the @@ -133,9 +133,9 @@ * @param The index of the layer to run. */ template - void Gradient(arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient, + void Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient, const size_t index); /* diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/concat_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/concat_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/concat_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/concat_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -90,23 +90,26 @@ typename... CustomLayers> Concat::~Concat() { - // Clear memory. - std::for_each(network.begin(), network.end(), - boost::apply_visitor(deleteVisitor)); + if (!model) + { + // Clear memory. + std::for_each(network.begin(), network.end(), + boost::apply_visitor(deleteVisitor)); + } } template template void Concat::Forward( - arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { if (run) { for (size_t i = 0; i < network.size(); ++i) { - boost::apply_visitor(ForwardVisitor(std::move(input), std::move( - boost::apply_visitor(outputParameterVisitor, network[i]))), + boost::apply_visitor(ForwardVisitor(input, + boost::apply_visitor(outputParameterVisitor, network[i])), network[i]); } } @@ -134,13 +137,14 @@ typename... CustomLayers> template void Concat::Backward( - const arma::Mat&& /* input */, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g) { size_t rowCount = 0; if (run) { arma::Mat delta; - gy.reshape(gy.n_rows / channels, gy.n_cols * channels); + arma::Mat gyTmp(((arma::Mat&) gy).memptr(), gy.n_rows / channels, + gy.n_cols * channels, false, false); for (size_t i = 0; i < network.size(); ++i) { // Use rows from the error corresponding to the output from each layer. @@ -148,13 +152,13 @@ outputParameterVisitor, network[i]).n_rows; // Extract from gy the parameters for the i-th network. - delta = gy.rows(rowCount / channels, (rowCount + rows) / channels - 1); + delta = gyTmp.rows(rowCount / channels, (rowCount + rows) / channels - 1); delta.reshape(delta.n_rows * channels, delta.n_cols / channels); - boost::apply_visitor(BackwardVisitor(std::move( + boost::apply_visitor(BackwardVisitor( boost::apply_visitor(outputParameterVisitor, - network[i])), std::move(delta), std::move( - boost::apply_visitor(deltaVisitor, network[i]))), network[i]); + network[i]), delta, + boost::apply_visitor(deltaVisitor, network[i])), network[i]); rowCount += rows; } @@ -163,7 +167,6 @@ { g += boost::apply_visitor(deltaVisitor, network[i]); } - gy.reshape(gy.n_rows * channels, gy.n_cols / channels); } else { @@ -175,7 +178,9 @@ typename... CustomLayers> template void Concat::Backward( - const arma::Mat&& /* input */, arma::Mat&& gy, arma::Mat&& g, + const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g, const size_t index) { size_t rowCount = 0, rows = 0; @@ -188,18 +193,16 @@ rows = boost::apply_visitor(outputParameterVisitor, network[index]).n_rows; // Reshape gy to extract the i-th layer gy. - gy.reshape(gy.n_rows / channels, gy.n_cols * channels); + arma::Mat gyTmp(((arma::Mat&) gy).memptr(), gy.n_rows / channels, + gy.n_cols * channels, false, false); - arma::Mat delta = gy.rows(rowCount / channels, (rowCount + rows) / + arma::Mat delta = gyTmp.rows(rowCount / channels, (rowCount + rows) / channels - 1); delta.reshape(delta.n_rows * channels, delta.n_cols / channels); - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network[index])), std::move(delta), std::move( - boost::apply_visitor(deltaVisitor, network[index]))), network[index]); - - // Reshape gy to its original shape. - gy.reshape(gy.n_rows * channels, gy.n_cols / channels); + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, network[index]), delta, + boost::apply_visitor(deltaVisitor, network[index])), network[index]); g = boost::apply_visitor(deltaVisitor, network[index]); } @@ -208,32 +211,29 @@ typename... CustomLayers> template void Concat::Gradient( - arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& /* gradient */) + const arma::Mat& input, + const arma::Mat& error, + arma::Mat& /* gradient */) { if (run) { size_t rowCount = 0; // Reshape error to extract the i-th layer error. - error.reshape(error.n_rows / channels, error.n_cols * channels); + arma::Mat errorTmp(((arma::Mat&) error).memptr(), + error.n_rows / channels, error.n_cols * channels, false, false); for (size_t i = 0; i < network.size(); ++i) { size_t rows = boost::apply_visitor( outputParameterVisitor, network[i]).n_rows; // Extract from error the parameters for the i-th network. - arma::Mat err = error.rows(rowCount / channels, (rowCount + rows) / + arma::Mat err = errorTmp.rows(rowCount / channels, (rowCount + rows) / channels - 1); err.reshape(err.n_rows * channels, err.n_cols / channels); - boost::apply_visitor(GradientVisitor(std::move(input), - std::move(err)), network[i]); + boost::apply_visitor(GradientVisitor(input, err), network[i]); rowCount += rows; } - - // Reshape error to its original shape. - error.reshape(error.n_rows * channels, error.n_cols / channels); } } @@ -241,9 +241,9 @@ typename... CustomLayers> template void Concat::Gradient( - arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& /* gradient */, + const arma::Mat& input, + const arma::Mat& error, + arma::Mat& /* gradient */, const size_t index) { size_t rowCount = 0; @@ -255,15 +255,13 @@ size_t rows = boost::apply_visitor( outputParameterVisitor, network[index]).n_rows; - error.reshape(error.n_rows / channels, error.n_cols * channels); - arma::Mat err = error.rows(rowCount / channels, (rowCount + rows) / + arma::Mat errorTmp(((arma::Mat&) error).memptr(), + error.n_rows / channels, error.n_cols * channels, false, false); + arma::Mat err = errorTmp.rows(rowCount / channels, (rowCount + rows) / channels - 1); err.reshape(err.n_rows * channels, err.n_cols / channels); - boost::apply_visitor(GradientVisitor(std::move(input), - std::move(err)), network[index]); - - error.reshape(error.n_rows * channels, error.n_cols / channels); + boost::apply_visitor(GradientVisitor(input, err), network[index]); } template - double Forward(const arma::Mat&& input, arma::Mat&& target); + double Forward(const arma::Mat& input, arma::Mat& target); + /** * Ordinary feed backward pass of a neural network. The negative log * likelihood layer expectes that the input contains log-probabilities for @@ -68,9 +69,9 @@ * @param output The calculated error. */ template - void Backward(const arma::Mat&& input, - const arma::Mat&& target, - arma::Mat&& output); + void Backward(const arma::Mat& input, + const arma::Mat& target, + arma::Mat& output); //! Get the output parameter. OutputDataType& OutputParameter() const { return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/concat_performance_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/concat_performance_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/concat_performance_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/concat_performance_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -44,7 +44,7 @@ OutputLayerType, InputDataType, OutputDataType ->::Forward(const arma::Mat&& input, arma::Mat&& target) +>::Forward(const arma::Mat& input, arma::Mat& target) { const size_t elements = input.n_elem / inSize; @@ -52,7 +52,7 @@ for (size_t i = 0; i < input.n_elem; i+= elements) { arma::mat subInput = input.submat(i, 0, i + elements - 1, 0); - output += outputLayer.Forward(std::move(subInput), std::move(target)); + output += outputLayer.Forward(subInput, target); } return output; @@ -69,17 +69,16 @@ InputDataType, OutputDataType >::Backward( - const arma::Mat&& input, - const arma::Mat&& target, - arma::Mat&& output) + const arma::Mat& input, + const arma::Mat& target, + arma::Mat& output) { const size_t elements = input.n_elem / inSize; arma::mat subInput = input.submat(0, 0, elements - 1, 0); arma::mat subOutput; - outputLayer.Backward(std::move(subInput), std::move(target), - std::move(subOutput)); + outputLayer.Backward(subInput, target, subOutput); output = arma::zeros(subOutput.n_elem, inSize); output.col(0) = subOutput; @@ -87,8 +86,7 @@ for (size_t i = elements, j = 0; i < input.n_elem; i+= elements, j++) { subInput = input.submat(i, 0, i + elements - 1, 0); - outputLayer.Backward(std::move(subInput), std::move(target), - std::move(subOutput)); + outputLayer.Backward(subInput, target, subOutput); output.col(j) = subOutput; } @@ -104,9 +102,9 @@ OutputLayerType, InputDataType, OutputDataType ->::serialize(Archive& /* ar */, const unsigned int /* version */) +>::serialize(Archive& ar, const unsigned int /* version */) { - // Nothing to do here. + ar & BOOST_SERIALIZATION_NVP(inSize); } } // namespace ann diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/constant.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/constant.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/constant.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/constant.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -51,7 +51,7 @@ * @param output Resulting output activation. */ template - void Forward(const InputType&& input, OutputType&& output); + void Forward(const InputType& input, OutputType& output); /** * Ordinary feed backward pass of a neural network. The backward pass of the @@ -62,9 +62,9 @@ * @param g The calculated gradient. */ template - void Backward(const DataType&& /* input */, - DataType&& /* gy */, - DataType&& g); + void Backward(const DataType& /* input */, + const DataType& /* gy */, + DataType& g); //! Get the output parameter. OutputDataType& OutputParameter() const { return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/constant_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/constant_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/constant_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/constant_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -33,7 +33,7 @@ template template void Constant::Forward( - const InputType&& input, OutputType&& output) + const InputType& input, OutputType& output) { if (inSize == 0) { @@ -46,7 +46,7 @@ template template void Constant::Backward( - const DataType&& /* input */, DataType&& /* gy */, DataType&& g) + const DataType& /* input */, const DataType& /* gy */, DataType& g) { g = arma::zeros(inSize, 1); } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/convolution.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/convolution.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/convolution.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/convolution.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -56,10 +56,10 @@ * * @param inSize The number of input maps. * @param outSize The number of output maps. - * @param kW Width of the filter/kernel. - * @param kH Height of the filter/kernel. - * @param dW Stride of filter application in the x direction. - * @param dH Stride of filter application in the y direction. + * @param kernelWidth Width of the filter/kernel. + * @param kernelHeight Height of the filter/kernel. + * @param strideWidth Stride of filter application in the x direction. + * @param strideHeight Stride of filter application in the y direction. * @param padW Padding width of the input. * @param padH Padding height of the input. * @param inputWidth The width of the input data. @@ -68,15 +68,15 @@ */ Convolution(const size_t inSize, const size_t outSize, - const size_t kW, - const size_t kH, - const size_t dW = 1, - const size_t dH = 1, + const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth = 1, + const size_t strideHeight = 1, const size_t padW = 0, const size_t padH = 0, const size_t inputWidth = 0, const size_t inputHeight = 0, - const std::string paddingType = "None"); + const std::string& paddingType = "None"); /** * Create the Convolution object using the specified number of input maps, @@ -84,10 +84,10 @@ * * @param inSize The number of input maps. * @param outSize The number of output maps. - * @param kW Width of the filter/kernel. - * @param kH Height of the filter/kernel. - * @param dW Stride of filter application in the x direction. - * @param dH Stride of filter application in the y direction. + * @param kernelWidth Width of the filter/kernel. + * @param kernelHeight Height of the filter/kernel. + * @param strideWidth Stride of filter application in the x direction. + * @param strideHeight Stride of filter application in the y direction. * @param padW A two-value tuple indicating padding widths of the input. * First value is padding at left side. Second value is padding on * right side. @@ -100,15 +100,15 @@ */ Convolution(const size_t inSize, const size_t outSize, - const size_t kW, - const size_t kH, - const size_t dW, - const size_t dH, - const std::tuple padW, - const std::tuple padH, + const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth, + const size_t strideHeight, + const std::tuple& padW, + const std::tuple& padH, const size_t inputWidth = 0, const size_t inputHeight = 0, - const std::string paddingType = "None"); + const std::string& paddingType = "None"); /* * Set the weight and bias term. @@ -123,7 +123,7 @@ * @param output Resulting output activation. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -135,9 +135,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); /* * Calculate the gradient using the output delta and the input activation. @@ -147,60 +147,106 @@ * @param gradient The calculated gradient. */ template - void Gradient(const arma::Mat&& /* input */, - arma::Mat&& error, - arma::Mat&& gradient); + void Gradient(const arma::Mat& /* input */, + const arma::Mat& error, + arma::Mat& gradient); //! Get the parameters. - OutputDataType const& Parameters() const { return weights; } + const OutputDataType& Parameters() const { return weights; } //! Modify the parameters. OutputDataType& Parameters() { return weights; } //! Get the input parameter. - InputDataType const& InputParameter() const { return inputParameter; } + const InputDataType& InputParameter() const { return inputParameter; } //! Modify the input parameter. InputDataType& InputParameter() { return inputParameter; } //! Get the output parameter. - OutputDataType const& OutputParameter() const { return outputParameter; } + const OutputDataType& OutputParameter() const { return outputParameter; } //! Modify the output parameter. OutputDataType& OutputParameter() { return outputParameter; } //! Get the delta. - OutputDataType const& Delta() const { return delta; } + const OutputDataType& Delta() const { return delta; } //! Modify the delta. OutputDataType& Delta() { return delta; } //! Get the gradient. - OutputDataType const& Gradient() const { return gradient; } + const OutputDataType& Gradient() const { return gradient; } //! Modify the gradient. OutputDataType& Gradient() { return gradient; } //! Get the input width. - size_t const& InputWidth() const { return inputWidth; } + const size_t& InputWidth() const { return inputWidth; } //! Modify input the width. size_t& InputWidth() { return inputWidth; } //! Get the input height. - size_t const& InputHeight() const { return inputHeight; } + const size_t& InputHeight() const { return inputHeight; } //! Modify the input height. size_t& InputHeight() { return inputHeight; } //! Get the output width. - size_t const& OutputWidth() const { return outputWidth; } + const size_t& OutputWidth() const { return outputWidth; } //! Modify the output width. size_t& OutputWidth() { return outputWidth; } //! Get the output height. - size_t const& OutputHeight() const { return outputHeight; } + const size_t& OutputHeight() const { return outputHeight; } //! Modify the output height. size_t& OutputHeight() { return outputHeight; } + //! Get the input size. + size_t InputSize() const { return inSize; } + + //! Get the output size. + size_t OutputSize() const { return outSize; } + + //! Get the kernel width. + size_t KernelWidth() const { return kernelWidth; } + //! Modify the kernel width. + size_t& KernelWidth() { return kernelWidth; } + + //! Get the kernel height. + size_t KernelHeight() const { return kernelHeight; } + //! Modify the kernel height. + size_t& KernelHeight() { return kernelHeight; } + + //! Get the stride width. + size_t StrideWidth() const { return strideWidth; } + //! Modify the stride width. + size_t& StrideWidth() { return strideWidth; } + + //! Get the stride height. + size_t StrideHeight() const { return strideHeight; } + //! Modify the stride height. + size_t& StrideHeight() { return strideHeight; } + + //! Get the top padding height. + size_t PadHTop() const { return padHTop; } + //! Modify the top padding height. + size_t& PadHTop() { return padHTop; } + + //! Get the bottom padding height. + size_t PadHBottom() const { return padHBottom; } + //! Modify the bottom padding height. + size_t& PadHBottom() { return padHBottom; } + + //! Get the left padding width. + size_t PadWLeft() const { return padWLeft; } + //! Modify the left padding width. + size_t& PadWLeft() { return padWLeft; } + + //! Get the right padding width. + size_t PadWRight() const { return padWRight; } + //! Modify the right padding width. + size_t& PadWRight() { return padWRight; } + //! Modify the bias weights of the layer. arma::mat& Bias() { return bias; } /** - * Serialize the layer + * Serialize the layer. */ template void serialize(Archive& ar, const unsigned int /* version */); @@ -269,16 +315,16 @@ size_t batchSize; //! Locally-stored filter/kernel width. - size_t kW; + size_t kernelWidth; //! Locally-stored filter/kernel height. - size_t kH; + size_t kernelHeight; //! Locally-stored stride of the filter in x-direction. - size_t dW; + size_t strideWidth; //! Locally-stored stride of the filter in y-direction. - size_t dH; + size_t strideHeight; //! Locally-stored left-side padding width. size_t padWLeft; @@ -316,9 +362,6 @@ //! Locally-stored transformed output parameter. arma::cube outputTemp; - //! Locally-stored transformed input parameter. - arma::cube inputTemp; - //! Locally-stored transformed padded input parameter. arma::cube inputPaddedTemp; @@ -329,7 +372,7 @@ arma::cube gradientTemp; //! Locally-stored padding layer. - Padding<>* padding; + ann::Padding<> padding; //! Locally-stored delta object. OutputDataType delta; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/convolution_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/convolution_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/convolution_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/convolution_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -52,50 +52,29 @@ >::Convolution( const size_t inSize, const size_t outSize, - const size_t kW, - const size_t kH, - const size_t dW, - const size_t dH, + const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth, + const size_t strideHeight, const size_t padW, const size_t padH, const size_t inputWidth, const size_t inputHeight, - const std::string paddingType) : - inSize(inSize), - outSize(outSize), - kW(kW), - kH(kH), - dW(dW), - dH(dH), - padWLeft(padW), - padWRight(padW), - padHBottom(padH), - padHTop(padH), - inputWidth(inputWidth), - inputHeight(inputHeight), - outputWidth(0), - outputHeight(0) + const std::string& paddingType) : + Convolution( + inSize, + outSize, + kernelWidth, + kernelHeight, + strideWidth, + strideHeight, + std::tuple(padW, padW), + std::tuple(padH, padH), + inputWidth, + inputHeight, + paddingType) { - weights.set_size((outSize * inSize * kW * kH) + outSize, 1); - - // Transform paddingType to lowercase. - std::string paddingTypeLow = paddingType; - std::transform(paddingType.begin(), paddingType.end(), paddingTypeLow.begin(), - [](unsigned char c){ return std::tolower(c); }); - - if (paddingTypeLow == "valid") - { - padWLeft = 0; - padWRight = 0; - padHTop = 0; - padHBottom = 0; - } - else if (paddingTypeLow == "same") - { - InitializeSamePadding(); - } - - padding = new Padding<>(padWLeft, padWRight, padHTop, padHBottom); + // Nothing to do here. } template< @@ -114,21 +93,21 @@ >::Convolution( const size_t inSize, const size_t outSize, - const size_t kW, - const size_t kH, - const size_t dW, - const size_t dH, - const std::tuple padW, - const std::tuple padH, + const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth, + const size_t strideHeight, + const std::tuple& padW, + const std::tuple& padH, const size_t inputWidth, const size_t inputHeight, - const std::string paddingType) : + const std::string& paddingType) : inSize(inSize), outSize(outSize), - kW(kW), - kH(kH), - dW(dW), - dH(dH), + kernelWidth(kernelWidth), + kernelHeight(kernelHeight), + strideWidth(strideWidth), + strideHeight(strideHeight), padWLeft(std::get<0>(padW)), padWRight(std::get<1>(padW)), padHBottom(std::get<1>(padH)), @@ -138,7 +117,8 @@ outputWidth(0), outputHeight(0) { - weights.set_size((outSize * inSize * kW * kH) + outSize, 1); + weights.set_size((outSize * inSize * kernelWidth * kernelHeight) + outSize, + 1); // Transform paddingType to lowercase. std::string paddingTypeLow = paddingType; @@ -157,7 +137,7 @@ InitializeSamePadding(); } - padding = new Padding<>(padWLeft, padWRight, padHTop, padHBottom); + padding = ann::Padding<>(padWLeft, padWRight, padHTop, padHBottom); } template< @@ -175,7 +155,7 @@ OutputDataType >::Reset() { - weight = arma::cube(weights.memptr(), kW, kH, + weight = arma::cube(weights.memptr(), kernelWidth, kernelHeight, outSize * inSize, false, false); bias = arma::mat(weights.memptr() + weight.n_elem, outSize, 1, false, false); @@ -195,10 +175,10 @@ GradientConvolutionRule, InputDataType, OutputDataType ->::Forward(const arma::Mat&& input, arma::Mat&& output) +>::Forward(const arma::Mat& input, arma::Mat& output) { batchSize = input.n_cols; - inputTemp = arma::cube(const_cast&&>(input).memptr(), + arma::cube inputTemp(const_cast&>(input).memptr(), inputWidth, inputHeight, inSize * batchSize, false, false); if (padWLeft != 0 || padWRight != 0 || padHTop != 0 || padHBottom != 0) @@ -208,13 +188,14 @@ for (size_t i = 0; i < inputTemp.n_slices; ++i) { - padding->Forward(std::move(inputTemp.slice(i)), - std::move(inputPaddedTemp.slice(i))); + padding.Forward(inputTemp.slice(i), inputPaddedTemp.slice(i)); } } - size_t wConv = ConvOutSize(inputWidth, kW, dW, padWLeft, padWRight); - size_t hConv = ConvOutSize(inputHeight, kH, dH, padHTop, padHBottom); + size_t wConv = ConvOutSize(inputWidth, kernelWidth, strideWidth, padWLeft, + padWRight); + size_t hConv = ConvOutSize(inputHeight, kernelHeight, strideHeight, padHTop, + padHBottom); output.set_size(wConv * hConv * outSize, batchSize); outputTemp = arma::Cube(output.memptr(), wConv, hConv, @@ -237,12 +218,14 @@ if (padWLeft != 0 || padWRight != 0 || padHTop != 0 || padHBottom != 0) { ForwardConvolutionRule::Convolution(inputPaddedTemp.slice(inMap + - batchCount * inSize), weight.slice(outMapIdx), convOutput, dW, dH); + batchCount * inSize), weight.slice(outMapIdx), convOutput, + strideWidth, strideHeight); } else { ForwardConvolutionRule::Convolution(inputTemp.slice(inMap + - batchCount * inSize), weight.slice(outMapIdx), convOutput, dW, dH); + batchCount * inSize), weight.slice(outMapIdx), convOutput, + strideWidth, strideHeight); } outputTemp.slice(outMap) += convOutput; @@ -270,14 +253,14 @@ InputDataType, OutputDataType >::Backward( - const arma::Mat&& /* input */, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g) { - arma::cube mappedError(gy.memptr(), outputWidth, outputHeight, - outSize * batchSize, false, false); + arma::cube mappedError(((arma::Mat&) gy).memptr(), outputWidth, + outputHeight, outSize * batchSize, false, false); - g.set_size(inputTemp.n_rows * inputTemp.n_cols * inSize, batchSize); - gTemp = arma::Cube(g.memptr(), inputTemp.n_rows, - inputTemp.n_cols, inputTemp.n_slices, false, false); + g.set_size(inputWidth * inputHeight * inSize, batchSize); + gTemp = arma::Cube(g.memptr(), inputWidth, inputHeight, + inSize * batchSize, false, false); gTemp.zeros(); for (size_t outMap = 0, outMapIdx = 0, batchCount = 0; outMap < @@ -295,7 +278,7 @@ Rotate180(weight.slice(outMapIdx), rotatedFilter); BackwardConvolutionRule::Convolution(mappedError.slice(outMap), - rotatedFilter, output, dW, dH); + rotatedFilter, output, strideWidth, strideHeight); if (padWLeft != 0 || padWRight != 0 || padHTop != 0 || padHBottom != 0) { @@ -325,12 +308,14 @@ InputDataType, OutputDataType >::Gradient( - const arma::Mat&& /* input */, - arma::Mat&& error, - arma::Mat&& gradient) + const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient) { - arma::cube mappedError(error.memptr(), outputWidth, + arma::cube mappedError(((arma::Mat&) error).memptr(), outputWidth, outputHeight, outSize * batchSize, false, false); + arma::cube inputTemp(((arma::Mat&) input).memptr(), inputWidth, + inputHeight, inSize * batchSize, false, false); gradient.set_size(weights.n_elem, 1); gradientTemp = arma::Cube(gradient.memptr(), weight.n_rows, @@ -362,7 +347,7 @@ arma::Mat output; GradientConvolutionRule::Convolution(inputSlice, deltaSlice, - output, dW, dH); + output, strideWidth, strideHeight); if (gradientTemp.n_rows < output.n_rows || gradientTemp.n_cols < output.n_cols) @@ -406,10 +391,10 @@ ar & BOOST_SERIALIZATION_NVP(inSize); ar & BOOST_SERIALIZATION_NVP(outSize); ar & BOOST_SERIALIZATION_NVP(batchSize); - ar & BOOST_SERIALIZATION_NVP(kW); - ar & BOOST_SERIALIZATION_NVP(kH); - ar & BOOST_SERIALIZATION_NVP(dW); - ar & BOOST_SERIALIZATION_NVP(dH); + ar & BOOST_SERIALIZATION_NVP(kernelWidth); + ar & BOOST_SERIALIZATION_NVP(kernelHeight); + ar & BOOST_SERIALIZATION_NVP(strideWidth); + ar & BOOST_SERIALIZATION_NVP(strideHeight); ar & BOOST_SERIALIZATION_NVP(padWLeft); ar & BOOST_SERIALIZATION_NVP(padWRight); ar & BOOST_SERIALIZATION_NVP(padHBottom); @@ -423,7 +408,10 @@ ar & BOOST_SERIALIZATION_NVP(padding); if (Archive::is_loading::value) - weights.set_size((outSize * inSize * kW * kH) + outSize, 1); + { + weights.set_size((outSize * inSize * kernelWidth * kernelHeight) + outSize, + 1); + } } template< @@ -444,8 +432,10 @@ /* * Using O = (W - F + 2P) / s + 1; */ - size_t totalVerticalPadding = (dW - 1) * inputWidth + kW - dW; - size_t totalHorizontalPadding = (dH - 1) * inputHeight + kH - dH; + size_t totalVerticalPadding = (strideWidth - 1) * inputWidth + kernelWidth - + strideWidth; + size_t totalHorizontalPadding = (strideHeight - 1) * inputHeight + + kernelHeight - strideHeight; padWLeft = totalVerticalPadding / 2; padWRight = totalVerticalPadding - totalVerticalPadding / 2; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/c_relu.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/c_relu.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/c_relu.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/c_relu.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -33,7 +33,8 @@ * title = {Understanding and Improving Convolutional Neural Networks * via Concatenated Rectified Linear Units}, * author = {LWenling Shang, Kihyuk Sohn, Diogo Almeida, Honglak Lee}, - * year = {2016} + * year = {2016}, + * url = {https://arxiv.org/abs/1603.05201} * } * @endcode * @@ -57,13 +58,13 @@ /** * Ordinary feed forward pass of a neural network, evaluating the function * f(x) by propagating the activity forward through f. - * Works only for 2D Tenosrs. + * Works only for 2D Tensors. * * @param input Input data used for evaluating the specified function. * @param output Resulting output activation. */ template - void Forward(const InputType&& input, OutputType&& output); + void Forward(const InputType& input, OutputType& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -75,7 +76,7 @@ * @param g The calculated gradient. */ template - void Backward(const DataType&& input, DataType&& gy, DataType&& g); + void Backward(const DataType& input, const DataType& gy, DataType& g); //! Get the output parameter. OutputDataType const& OutputParameter() const { return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/c_relu_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/c_relu_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/c_relu_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/c_relu_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -27,7 +27,7 @@ template template void CReLU::Forward( - const InputType&& input, OutputType&& output) + const InputType& input, OutputType& output) { output = arma::join_cols(arma::max(input, 0.0 * input), arma::max( (-1 * input), 0.0 * input)); @@ -36,7 +36,7 @@ template template void CReLU::Backward( - const DataType&& input, DataType&& gy, DataType&& g) + const DataType& input, const DataType& gy, DataType& g) { DataType temp; temp = gy % (input >= 0.0); diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/dropconnect.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/dropconnect.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/dropconnect.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/dropconnect.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -46,7 +46,8 @@ * Learning(ICML - 13)}, * author = {Li Wan and Matthew Zeiler and Sixin Zhang and Yann L. Cun and * Rob Fergus}, - * year = {2013} + * year = {2013}, + * url = {http://proceedings.mlr.press/v28/wan13.pdf} * } * @endcode * @@ -77,16 +78,14 @@ const size_t outSize, const double ratio = 0.5); - ~DropConnect(); - /** - * Ordinary feed forward pass of the DropConnect layer. - * - * @param input Input data used for evaluating the specified function. - * @param output Resulting output activation. - */ + * Ordinary feed forward pass of the DropConnect layer. + * + * @param input Input data used for evaluating the specified function. + * @param output Resulting output activation. + */ template - void Forward(arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of the DropConnect layer. @@ -96,9 +95,9 @@ * @param g The calculated gradient. */ template - void Backward(arma::Mat&& input, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& input, + const arma::Mat& gy, + arma::Mat& g); /** * Calculate the gradient using the output delta and the input activation. @@ -108,9 +107,9 @@ * @param g The calculated gradient. */ template - void Gradient(arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& /* gradient */); + void Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& /* gradient */); //! Get the model modules. std::vector >& Model() { return network; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/dropconnect_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/dropconnect_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/dropconnect_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/dropconnect_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -48,40 +48,32 @@ network.push_back(baseLayer); } -template -DropConnect::~DropConnect() -{ - boost::apply_visitor(DeleteVisitor(), baseLayer); -} - template template void DropConnect::Forward( - arma::Mat&& input, - arma::Mat&& output) + const arma::Mat& input, + arma::Mat& output) { // The DropConnect mask will not be multiplied in the deterministic mode // (during testing). if (deterministic) { - boost::apply_visitor(ForwardVisitor(std::move(input), std::move(output)), - baseLayer); + boost::apply_visitor(ForwardVisitor(input, output), baseLayer); } else { // Save weights for denoising. - boost::apply_visitor(ParametersVisitor(std::move(denoise)), baseLayer); + boost::apply_visitor(ParametersVisitor(denoise), baseLayer); // Scale with input / (1 - ratio) and set values to zero with // probability ratio. mask = arma::randu >(denoise.n_rows, denoise.n_cols); mask.transform([&](double val) { return (val > ratio); }); - boost::apply_visitor(ParametersSetVisitor(std::move(denoise % mask)), - baseLayer); + arma::mat tmp = denoise % mask; + boost::apply_visitor(ParametersSetVisitor(tmp), baseLayer); - boost::apply_visitor(ForwardVisitor(std::move(input), std::move(output)), - baseLayer); + boost::apply_visitor(ForwardVisitor(input, output), baseLayer); output = output * scale; } @@ -90,26 +82,25 @@ template template void DropConnect::Backward( - arma::Mat&& input, - arma::Mat&& gy, - arma::Mat&& g) + const arma::Mat& input, + const arma::Mat& gy, + arma::Mat& g) { - boost::apply_visitor(BackwardVisitor(std::move(input), std::move(gy), - std::move(g)), baseLayer); + boost::apply_visitor(BackwardVisitor(input, gy, g), baseLayer); } template template void DropConnect::Gradient( - arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& /* gradient */) + const arma::Mat& input, + const arma::Mat& error, + arma::Mat& /* gradient */) { - boost::apply_visitor(GradientVisitor(std::move(input), std::move(error)), + boost::apply_visitor(GradientVisitor(input, error), baseLayer); // Denoise the weights. - boost::apply_visitor(ParametersSetVisitor(std::move(denoise)), baseLayer); + boost::apply_visitor(ParametersSetVisitor(denoise), baseLayer); } template diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/dropout.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/dropout.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/dropout.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/dropout.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -39,6 +39,7 @@ * journal = {CoRR}, * volume = {abs/1207.0580}, * year = {2012}, + * url = {https://arxiv.org/abs/1207.0580} * } * @endcode * @@ -66,7 +67,7 @@ * @param output Resulting output activation. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of the dropout layer. @@ -76,9 +77,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); //! Get the output parameter. OutputDataType const& OutputParameter() const { return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/dropout_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/dropout_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/dropout_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/dropout_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -32,8 +32,8 @@ template template void Dropout::Forward( - const arma::Mat&& input, - arma::Mat&& output) + const arma::Mat& input, + arma::Mat& output) { // The dropout mask will not be multiplied in the deterministic mode // (during testing). @@ -54,9 +54,9 @@ template template void Dropout::Backward( - const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g) + const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g) { g = gy % mask * scale; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/elu.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/elu.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/elu.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/elu.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -3,7 +3,7 @@ * @author Vivek Pal * @author Dakshit Agrawal * - * Definition of the ELU activation function as descibed by Djork-Arne Clevert, + * Definition of the ELU activation function as described by Djork-Arne Clevert, * Thomas Unterthiner and Sepp Hochreiter. * * Definition of the SELU function as introduced by @@ -56,7 +56,8 @@ * title = {Fast and Accurate Deep Network Learning by Exponential Linear * Units (ELUs)}, * journal = {CoRR}, - * year = {2015} + * year = {2015}, + * url = {https://arxiv.org/abs/1511.07289} * } * @endcode * @@ -86,7 +87,8 @@ * Andreas Mayr}, * title = {Self-Normalizing Neural Networks}, * journal = {Advances in Neural Information Processing Systems}, - * year = {2017} + * year = {2017}, + * url = {https://arxiv.org/abs/1706.02515} * } * @endcode * @@ -134,7 +136,7 @@ * @param output Resulting output activation. */ template - void Forward(const InputType&& input, OutputType&& output); + void Forward(const InputType& input, OutputType& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -146,7 +148,7 @@ * @param g The calculated gradient. */ template - void Backward(const DataType&& input, DataType&& gy, DataType&& g); + void Backward(const DataType& input, const DataType& gy, DataType& g); //! Get the output parameter. OutputDataType const& OutputParameter() const { return outputParameter; } @@ -163,6 +165,11 @@ //! Modify the non zero gradient. double& Alpha() { return alpha; } + //! Get the value of deterministic parameter. + bool Deterministic() const { return deterministic; } + //! Modify the value of deterministic parameter. + bool& Deterministic() { return deterministic; } + //! Get the lambda parameter. double const& Lambda() const { return lambda; } @@ -173,69 +180,6 @@ void serialize(Archive& ar, const unsigned int /* version */); private: - /** - * Computes the value of activation function. - * - * @param x Input data. - * @return f(x). - */ - double Fn(const double x) - { - if (x < DBL_MAX) - { - return (x > 0) ? lambda * x : lambda * alpha * (std::exp(x) - 1); - } - - return 1.0; - } - - /** - * Computes the value of activation function using a dense matrix as input. - * - * @param x Input data. - * @param y The resulting output activation. - */ - template - void Fn(const arma::Mat& x, arma::Mat& y) - { - y.set_size(arma::size(x)); - - for (size_t i = 0; i < x.n_elem; i++) - { - y(i) = Fn(x(i)); - } - } - - /** - * Computes the first derivative of the activation function. - * - * @param x Input data. - * @param y Propagated data f(x). - * @return f'(x) - */ - double Deriv(const double x, const double y) - { - return (x > 0) ? lambda : y + lambda * alpha; - } - - /** - * Computes the first derivative of the activation function. - * - * @param x Input data. - * @param y Output activations f(x). - * @param z The resulting derivatives. - */ - template - void Deriv(const InputType& x, OutputType& y) - { - derivative.set_size(arma::size(x)); - - for (size_t i = 0; i < x.n_elem; i++) - { - derivative(i) = Deriv(x(i), y(i)); - } - } - //! Locally-stored delta object. OutputDataType delta; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/elu_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/elu_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/elu_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/elu_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -3,7 +3,7 @@ * @author Vivek Pal * @author Dakshit Agrawal * - * Implementation of the ELU activation function as descibed by Djork-Arne + * Implementation of the ELU activation function as described by Djork-Arne * Clevert, Thomas Unterthiner and Sepp Hochreiter. * * Implementation of the SELU function as introduced by Klambauer et. al. in @@ -49,20 +49,33 @@ template template void ELU::Forward( - const InputType&& input, OutputType&& output) + const InputType& input, OutputType& output) { - Fn(input, output); - - if (!deterministic) + output = arma::ones(arma::size(input)); + for (size_t i = 0; i < input.n_elem; i++) { - Deriv(input, output); + if (input(i) < DBL_MAX) + { + output(i) = (input(i) > 0) ? lambda * input(i) : lambda * + alpha * (std::exp(input(i)) - 1); + } } + + if (!deterministic) + { + derivative.set_size(arma::size(input)); + for (size_t i = 0; i < input.n_elem; i++) + { + derivative(i) = (input(i) > 0) ? lambda : output(i) + + lambda * alpha; + } + } } template template void ELU::Backward( - const DataType&& /* input */, DataType&& gy, DataType&& g) + const DataType& /* input */, const DataType& gy, DataType& g) { g = gy % derivative; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/fast_lstm.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/fast_lstm.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/fast_lstm.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/fast_lstm.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -47,7 +47,8 @@ * author = {Hochreiter, Sepp and Schmidhuber, J\"{u}rgen}, * title = {Long Short-term Memory}, * journal = {Neural Comput.}, - * year = {1997} + * year = {1997}, + * url = {https://www.bioinf.jku.at/publications/older/2604.pdf} * } * @endcode * @@ -91,7 +92,7 @@ * @param output Resulting output activation. */ template - void Forward(InputType&& input, OutputType&& output); + void Forward(const InputType& input, OutputType& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -103,9 +104,9 @@ * @param g The calculated gradient. */ template - void Backward(const InputType&& input, - ErrorType&& gy, - GradientType&& g); + void Backward(const InputType& input, + const ErrorType& gy, + GradientType& g); /* * Reset the layer parameter. @@ -128,9 +129,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(InputType&& input, - ErrorType&& error, - GradientType&& gradient); + void Gradient(const InputType& input, + const ErrorType& error, + GradientType& gradient); //! Get the maximum number of steps to backpropagate through time (BPTT). size_t Rho() const { return rho; } @@ -171,7 +172,7 @@ * @param sigmoid The matrix to store the sigmoid approximation into. */ template - void FastSigmoid(InputType&& input, OutputType&& sigmoids) + void FastSigmoid(const InputType& input, OutputType& sigmoids) { for (size_t i = 0; i < input.n_elem; ++i) sigmoids(i) = FastSigmoid(input(i)); diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/fast_lstm_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/fast_lstm_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/fast_lstm_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/fast_lstm_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -112,7 +112,7 @@ template template void FastLSTM::Forward( - InputType&& input, OutputType&& output) + const InputType& input, OutputType& output) { // Check if the batch size changed, the number of cols is defines the input // batch size. @@ -128,9 +128,11 @@ forwardStep, forwardStep + batchStep); gate.cols(forwardStep, forwardStep + batchStep).each_col() += input2GateBias; - FastSigmoid(std::move( - gate.submat(0, forwardStep, 3 * outSize - 1, forwardStep + batchStep)), - std::move(gateActivation.cols(forwardStep, forwardStep + batchStep))); + arma::subview sigmoidOut = gateActivation.cols(forwardStep, + forwardStep + batchStep); + FastSigmoid( + gate.submat(0, forwardStep, 3 * outSize - 1, forwardStep + batchStep), + sigmoidOut); stateActivation.cols(forwardStep, forwardStep + batchStep) = arma::tanh( gate.submat(3 * outSize, forwardStep, 4 * outSize - 1, @@ -178,14 +180,20 @@ template template void FastLSTM::Backward( - const InputType&& /* input */, ErrorType&& gy, GradientType&& g) + const InputType& /* input */, const ErrorType& gy, GradientType& g) { + ErrorType gyLocal; if (gradientStepIdx > 0) { - gy += output2GateWeight.t() * prevError; + gyLocal = gy + output2GateWeight.t() * prevError; + } + else + { + gyLocal = ErrorType(((ErrorType&) gy).memptr(), gy.n_rows, gy.n_cols, false, + false); } - cellActivationError = gy % gateActivation.submat(outSize, + cellActivationError = gyLocal % gateActivation.submat(outSize, backwardStep - batchStep, 2 * outSize - 1, backwardStep) % (1 - arma::pow(cellActivation.cols(backwardStep - batchStep, backwardStep), 2)); @@ -225,7 +233,7 @@ prevError.submat(outSize, 0, 2 * outSize - 1, batchStep) = cellActivation.cols(backwardStep - batchStep, - backwardStep) % gy % gateActivation.submat( + backwardStep) % gyLocal % gateActivation.submat( outSize, backwardStep - batchStep, 2 * outSize - 1, backwardStep) % (1.0 - gateActivation.submat( outSize, backwardStep - batchStep, 2 * outSize - 1, backwardStep)); @@ -244,7 +252,9 @@ template template void FastLSTM::Gradient( - InputType&& input, ErrorType&& /* error */, GradientType&& gradient) + const InputType& input, + const ErrorType& /* error */, + GradientType& gradient) { // Gradient of the input to gate layer. gradient.submat(0, 0, input2GateWeight.n_elem - 1, 0) = diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/flexible_relu.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/flexible_relu.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/flexible_relu.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/flexible_relu.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -84,7 +84,7 @@ * @param output Resulting output activation. */ template - void Forward(const InputType&& input, OutputType&& output); + void Forward(const InputType& input, OutputType& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -96,7 +96,7 @@ * @param g The calculated gradient. */ template - void Backward(const DataType&& input, DataType&& gy, DataType&& g); + void Backward(const DataType& input, const DataType& gy, DataType& g); /** * Calculate the gradient using the output delta and the input activation. @@ -106,9 +106,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(const arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient); + void Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient); //! Get the parameters. OutputDataType const& Parameters() const { return alpha; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/flexible_relu_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/flexible_relu_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/flexible_relu_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/flexible_relu_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -41,7 +41,7 @@ template template void FlexibleReLU::Forward( - const InputType&& input, OutputType&& output) + const InputType& input, OutputType& output) { output = arma::clamp(input, 0.0, DBL_MAX) + alpha(0); } @@ -49,7 +49,7 @@ template template void FlexibleReLU::Backward( - const DataType&& input, DataType&& gy, DataType&& g) + const DataType& input, const DataType& gy, DataType& g) { //! Compute the first derivative of FlexibleReLU function. g = gy % arma::clamp(arma::sign(input), 0.0, 1.0); @@ -58,9 +58,9 @@ template template void FlexibleReLU::Gradient( - const arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient) + const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient) { if (gradient.n_elem == 0) { diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/glimpse.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/glimpse.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/glimpse.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/glimpse.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -15,6 +15,7 @@ * journal = {CoRR}, * volume = {abs/1406.6247}, * year = {2014}, + * url = {https://arxiv.org/abs/1406.6247} * } * @endcode * @@ -113,7 +114,7 @@ * @param output Resulting output activation. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of the glimpse layer. @@ -123,9 +124,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); //! Get the output parameter. OutputDataType& OutputParameter() const {return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/glimpse_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/glimpse_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/glimpse_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/glimpse_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -45,7 +45,7 @@ template template void Glimpse::Forward( - const arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { inputTemp = arma::cube(input.colptr(0), inputWidth, inputHeight, inSize); outputTemp = arma::Cube(size, size, depth * inputTemp.n_slices); @@ -129,7 +129,7 @@ template template void Glimpse::Backward( - const arma::Mat&& /* input */, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g) { // Generate a cube using the backpropagated error matrix. arma::Cube mappedError = arma::zeros(outputWidth, diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/gru.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/gru.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/gru.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/gru.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -13,7 +13,8 @@ Kyunghyun and Bengio, Yoshua}, * booktitle = {ICML}, * pages = {2067--2075}, - * year = {2015} + * year = {2015}, + * url = {https://arxiv.org/abs/1502.02367} * } * @endcode * @@ -72,11 +73,6 @@ const size_t rho = std::numeric_limits::max()); /** - * Delete the GRU and the layers it holds. - */ - ~GRU(); - - /** * Ordinary feed forward pass of a neural network, evaluating the function * f(x) by propagating the activity forward through f. * @@ -84,7 +80,7 @@ * @param output Resulting output activation. */ template - void Forward(arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -96,9 +92,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); /* * Calculate the gradient using the output delta and the input activation. @@ -108,9 +104,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(arma::Mat&& input, - arma::Mat&& /* error */, - arma::Mat&& /* gradient */); + void Gradient(const arma::Mat& input, + const arma::Mat& /* error */, + arma::Mat& /* gradient */); /* * Resets the cell to accept a new input. This breaks the BPTT chain starts a diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/gru_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/gru_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/gru_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/gru_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -77,20 +77,9 @@ } template -GRU::~GRU() -{ - boost::apply_visitor(deleteVisitor, input2GateModule); - boost::apply_visitor(deleteVisitor, output2GateModule); - boost::apply_visitor(deleteVisitor, outputHidden2GateModule); - boost::apply_visitor(deleteVisitor, inputGateModule); - boost::apply_visitor(deleteVisitor, forgetGateModule); - boost::apply_visitor(deleteVisitor, hiddenStateModule); -} - -template template void GRU::Forward( - arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { if (input.n_cols != batchSize) { @@ -114,13 +103,13 @@ } // Process the input linearly(zt, rt, ot). - boost::apply_visitor(ForwardVisitor(std::move(input), std::move( - boost::apply_visitor(outputParameterVisitor, input2GateModule))), + boost::apply_visitor(ForwardVisitor(input, + boost::apply_visitor(outputParameterVisitor, input2GateModule)), input2GateModule); // Process the output(zt, rt) linearly. - boost::apply_visitor(ForwardVisitor(std::move(*prevOutput), std::move( - boost::apply_visitor(outputParameterVisitor, output2GateModule))), + boost::apply_visitor(ForwardVisitor(*prevOutput, + boost::apply_visitor(outputParameterVisitor, output2GateModule)), output2GateModule); // Merge the outputs(zt and rt). @@ -129,22 +118,22 @@ boost::apply_visitor(outputParameterVisitor, output2GateModule)); // Pass the first outSize through inputGate(it). - boost::apply_visitor(ForwardVisitor(std::move(output.submat( - 0, 0, 1 * outSize - 1, batchSize - 1)), std::move(boost::apply_visitor( - outputParameterVisitor, inputGateModule))), inputGateModule); + boost::apply_visitor(ForwardVisitor(output.submat( + 0, 0, 1 * outSize - 1, batchSize - 1), boost::apply_visitor( + outputParameterVisitor, inputGateModule)), inputGateModule); // Pass the second through forgetGate. - boost::apply_visitor(ForwardVisitor(std::move(output.submat( - 1 * outSize, 0, 2 * outSize - 1, batchSize - 1)), std::move( - boost::apply_visitor(outputParameterVisitor, forgetGateModule))), + boost::apply_visitor(ForwardVisitor(output.submat( + 1 * outSize, 0, 2 * outSize - 1, batchSize - 1), + boost::apply_visitor(outputParameterVisitor, forgetGateModule)), forgetGateModule); arma::mat modInput = (boost::apply_visitor(outputParameterVisitor, forgetGateModule) % *prevOutput); // Pass that through the outputHidden2GateModule. - boost::apply_visitor(ForwardVisitor(std::move(modInput), std::move( - boost::apply_visitor(outputParameterVisitor, outputHidden2GateModule))), + boost::apply_visitor(ForwardVisitor(modInput, + boost::apply_visitor(outputParameterVisitor, outputHidden2GateModule)), outputHidden2GateModule); // Merge for ot. @@ -153,8 +142,8 @@ boost::apply_visitor(outputParameterVisitor, outputHidden2GateModule); // Pass it through hiddenGate. - boost::apply_visitor(ForwardVisitor(std::move(outputH), std::move( - boost::apply_visitor(outputParameterVisitor, hiddenStateModule))), + boost::apply_visitor(ForwardVisitor(outputH, + boost::apply_visitor(outputParameterVisitor, hiddenStateModule)), hiddenStateModule); // Update the output (nextOutput): cmul1 + cmul2 @@ -205,7 +194,7 @@ template template void GRU::Backward( - const arma::Mat&& input, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& input, const arma::Mat& gy, arma::Mat& g) { if (input.n_cols != batchSize) { @@ -228,9 +217,15 @@ gradIterator = outParameter.end(); } + arma::Mat gyLocal; if ((outParameter.size() - backwardStep - 1) % rho != 0 && backwardStep != 0) { - gy += boost::apply_visitor(deltaVisitor, output2GateModule); + gyLocal = gy + boost::apply_visitor(deltaVisitor, output2GateModule); + } + else + { + gyLocal = arma::Mat(((arma::Mat&) gy).memptr(), gy.n_rows, + gy.n_cols, false, false); } if (backIterator == outParameter.end()) @@ -239,31 +234,31 @@ } // Delta zt. - arma::mat dZt = gy % (*backIterator - + arma::mat dZt = gyLocal % (*backIterator - boost::apply_visitor(outputParameterVisitor, hiddenStateModule)); // Delta ot. - arma::mat dOt = gy % (arma::ones(outSize, batchSize) - + arma::mat dOt = gyLocal % (arma::ones(outSize, batchSize) - boost::apply_visitor(outputParameterVisitor, inputGateModule)); // Delta of input gate. - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, inputGateModule)), std::move(dZt), - std::move(boost::apply_visitor(deltaVisitor, inputGateModule))), + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, inputGateModule), dZt, + boost::apply_visitor(deltaVisitor, inputGateModule)), inputGateModule); // Delta of hidden gate. - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, hiddenStateModule)), std::move(dOt), - std::move(boost::apply_visitor(deltaVisitor, hiddenStateModule))), + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, hiddenStateModule), dOt, + boost::apply_visitor(deltaVisitor, hiddenStateModule)), hiddenStateModule); // Delta of outputHidden2GateModule. - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, outputHidden2GateModule)), - std::move(boost::apply_visitor(deltaVisitor, hiddenStateModule)), - std::move(boost::apply_visitor(deltaVisitor, outputHidden2GateModule))), + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, outputHidden2GateModule), + boost::apply_visitor(deltaVisitor, hiddenStateModule), + boost::apply_visitor(deltaVisitor, outputHidden2GateModule)), outputHidden2GateModule); // Delta rt. @@ -271,9 +266,9 @@ *backIterator; // Delta of forget gate. - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, forgetGateModule)), std::move(dRt), - std::move(boost::apply_visitor(deltaVisitor, forgetGateModule))), + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, forgetGateModule), dRt, + boost::apply_visitor(deltaVisitor, forgetGateModule)), forgetGateModule); // Put delta zt. @@ -289,10 +284,12 @@ boost::apply_visitor(deltaVisitor, hiddenStateModule); // Get delta ht - 1 for input gate and forget gate. - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, input2GateModule)), - std::move(prevError.submat(0, 0, 2 * outSize - 1, batchSize - 1)), - std::move(boost::apply_visitor(deltaVisitor, output2GateModule))), + arma::mat prevErrorSubview = prevError.submat(0, 0, 2 * outSize - 1, + batchSize - 1); + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, input2GateModule), + prevErrorSubview, + boost::apply_visitor(deltaVisitor, output2GateModule)), output2GateModule); // Add delta ht - 1 from hidden state. @@ -301,13 +298,13 @@ boost::apply_visitor(outputParameterVisitor, forgetGateModule); // Add delta ht - 1 from ht. - boost::apply_visitor(deltaVisitor, output2GateModule) += gy % + boost::apply_visitor(deltaVisitor, output2GateModule) += gyLocal % boost::apply_visitor(outputParameterVisitor, inputGateModule); // Get delta input. - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, input2GateModule)), std::move(prevError), - std::move(boost::apply_visitor(deltaVisitor, input2GateModule))), + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, input2GateModule), prevError, + boost::apply_visitor(deltaVisitor, input2GateModule)), input2GateModule); backwardStep++; @@ -319,9 +316,9 @@ template template void GRU::Gradient( - arma::Mat&& input, - arma::Mat&& /* error */, - arma::Mat&& /* gradient */) + const arma::Mat& input, + const arma::Mat& /* error */, + arma::Mat& /* gradient */) { if (input.n_cols != batchSize) { @@ -349,19 +346,18 @@ gradIterator = --(--outParameter.end()); } - boost::apply_visitor(GradientVisitor(std::move(input), std::move(prevError)), - input2GateModule); + boost::apply_visitor(GradientVisitor(input, prevError), input2GateModule); boost::apply_visitor(GradientVisitor( - std::move(*gradIterator), - std::move(prevError.submat(0, 0, 2 * outSize - 1, batchSize - 1))), + *gradIterator, + prevError.submat(0, 0, 2 * outSize - 1, batchSize - 1)), output2GateModule); boost::apply_visitor(GradientVisitor( *gradIterator % boost::apply_visitor(outputParameterVisitor, forgetGateModule), - std::move(prevError.submat(2 * outSize, 0, 3 * outSize - 1, - batchSize - 1))), outputHidden2GateModule); + prevError.submat(2 * outSize, 0, 3 * outSize - 1, batchSize - 1)), + outputHidden2GateModule); gradIterator--; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/hardshrink.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/hardshrink.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/hardshrink.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/hardshrink.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,123 @@ +/** + * @file hardshrink.hpp + * @author Lakshya Ojha + * + * Same as soft thresholding, if its amplitude is smaller than a predefined + * threshold, it will be set to zero (kill), otherwise it will be kept + * unchanged. + * In order to promote sparsity and to improve the approximation, the hard + * thresholding method is used as an alternative. + * + * 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_HARDSHRINK_HPP +#define MLPACK_METHODS_ANN_LAYER_HARDSHRINK_HPP + +#include + +namespace mlpack { +namespace ann /** Artifical Neural Network. */ { + + /** + * Hard Shrink operator is defined as, + * @f{eqnarray*}{ + * f(x) &=& \left\{ + * \begin{array}{lr} + * x & : x > lambda \\ + * x & : x < -lambda \\ + * 0 & : otherwise + * \end{array} \\ + * \right. + * f'(x) &=& \left\{ + * \begin{array}{lr} + * 1 & : x > lambda \\ + * 1 & : x < -lambda \\ + * 0 & : otherwise + * \end{array} + * \right. + * @f} + * lambda is set to 0.5 by default. + */ +template < + typename InputDataType = arma::mat, + typename OutputDataType = arma::mat +> +class HardShrink +{ + public: +/** + * Create HardShrink object using specified hyperparameter lambda. + * + * @param lambda Is calculated by multiplying the + * noise level sigma of the input(noisy image) and a + * coefficient 'a' which is one of the training parameters. + * Default value of lambda is 0.5. + */ + HardShrink(const double lambda = 0.5); + + /** + * 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 Hard Shrink 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 f(x). + * @param gy The backpropagated error. + * @param g The calculated gradient. + */ + template + void Backward(const DataType& input, + 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 hyperparameter lambda. + double const& Lambda() const { return lambda; } + //! Modify the hyperparameter lambda. + double& Lambda() { return lambda; } + + /** + * Serialize the layer. + */ + template + void serialize(Archive& ar, const unsigned int /* version */); + + private: + //! Locally-stored delta object. + OutputDataType delta; + + //! Locally-stored output parameter object. + OutputDataType outputParameter; + + //! Locally-stored hyperparameter lambda. + double lambda; +}; // class HardShrink + +} // namespace ann +} // namespace mlpack + +// Include implementation. +#include "hardshrink_impl.hpp" + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/hardshrink_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/hardshrink_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/hardshrink_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/hardshrink_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,60 @@ +/** + * @file hardshrink.hpp + * @author Lakshya Ojha + * + * Implementation of Hard Shrink activation 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_LAYER_HARDSHRINK_IMPL_HPP +#define MLPACK_METHODS_ANN_LAYER_HARDSHRINK_IMPL_HPP + +// In case it hasn't yet been included +#include "hardshrink.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +// This constructor is called for Hard Shrink activation function. +// 'lambda' is a hyperparameter. +template +HardShrink::HardShrink(const double lambda) : + lambda(lambda) +{ + // Nothing to do here. +} + +template +template +void HardShrink::Forward( + const InputType& input, OutputType& output) +{ + output = ((input > lambda) + (input < -lambda)) % input; +} + +template +template +void HardShrink::Backward( + const DataType& input, DataType& gy, DataType& g) +{ + DataType derivative; + derivative = (arma::ones(arma::size(input)) - (input == 0)); + g = gy % derivative; +} + +template +template +void HardShrink::serialize( + Archive& ar, + const unsigned int /* version */) +{ + ar & BOOST_SERIALIZATION_NVP(lambda); +} + +} // namespace ann +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/hard_tanh.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/hard_tanh.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/hard_tanh.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/hard_tanh.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -67,7 +67,7 @@ * @param output Resulting output activation. */ template - void Forward(const InputType&& input, OutputType&& output); + void Forward(const InputType& input, OutputType& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -79,9 +79,9 @@ * @param g The calculated gradient. */ template - void Backward(const DataType&& input, - DataType&& gy, - DataType&& g); + void Backward(const DataType& input, + const DataType& gy, + DataType& g); //! Get the output parameter. OutputDataType const& OutputParameter() const { return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/hard_tanh_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/hard_tanh_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/hard_tanh_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/hard_tanh_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -31,7 +31,7 @@ template template void HardTanH::Forward( - const InputType&& input, OutputType&& output) + const InputType& input, OutputType& output) { output = input; for (size_t i = 0; i < input.n_elem; i++) @@ -44,7 +44,7 @@ template template void HardTanH::Backward( - const DataType&& input, DataType&& gy, DataType&& g) + const DataType& input, const DataType& gy, DataType& g) { g = gy; for (size_t i = 0; i < input.n_elem; i++) diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/highway.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/highway.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/highway.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/highway.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -75,11 +75,6 @@ ~Highway(); /** - * Destroy all the modules added to the Highway object. - */ - void DeleteModules(); - - /** * Reset the layer parameter. */ void Reset(); @@ -92,7 +87,7 @@ * @param output Resulting output activation. */ template - void Forward(arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed-backward pass of a neural network, calculating the function @@ -104,9 +99,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); /** * Calculate the gradient using the output delta and the input activation. @@ -116,9 +111,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient); + void Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient); /** * Add a new module to the model. @@ -126,14 +121,22 @@ * @param args The layer parameter. */ template - void Add(Args... args) { network.push_back(new LayerType(args...)); } + void Add(Args... args) + { + network.push_back(new LayerType(args...)); + networkOwnerships.push_back(true); + } /** * Add a new module to the model. * * @param layer The Layer to be added to the model. */ - void Add(LayerTypes layer) { network.push_back(layer); } + void Add(LayerTypes layer) + { + network.push_back(layer); + networkOwnerships.push_back(false); + } //! Return the modules of the model. std::vector >& Model() @@ -190,6 +193,9 @@ //! Locally-stored network modules. std::vector > network; + //! The list of network modules we are responsible for. + std::vector networkOwnerships; + //! Locally-stored empty list of modules. std::vector > empty; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/highway_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/highway_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/highway_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/highway_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -57,23 +57,10 @@ { if (!model) { - for (LayerTypes& layer : network) + for (size_t i = 0; i < network.size(); ++i) { - boost::apply_visitor(deleteVisitor, layer); - } - } -} - -template -void Highway< - InputDataType, OutputDataType, CustomLayers...>::DeleteModules() -{ - if (model) - { - for (LayerTypes& layer : network) - { - boost::apply_visitor(deleteVisitor, layer); + if (networkOwnerships[i]) + boost::apply_visitor(deleteVisitor, network[i]); } } } @@ -91,10 +78,10 @@ typename... CustomLayers> template void Highway::Forward( - arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { - boost::apply_visitor(ForwardVisitor(std::move(input), std::move( - boost::apply_visitor(outputParameterVisitor, network.front()))), + boost::apply_visitor(ForwardVisitor(input, + boost::apply_visitor(outputParameterVisitor, network.front())), network.front()); if (!reset) @@ -121,9 +108,9 @@ boost::apply_visitor(SetInputHeightVisitor(height), network[i]); } - boost::apply_visitor(ForwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network[i - 1])), std::move( - boost::apply_visitor(outputParameterVisitor, network[i]))), + boost::apply_visitor(ForwardVisitor(boost::apply_visitor( + outputParameterVisitor, network[i - 1]), + boost::apply_visitor(outputParameterVisitor, network[i])), network[i]); if (!reset) @@ -167,23 +154,24 @@ typename... CustomLayers> template void Highway::Backward( - const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g) -{ - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network.back())), - std::move(gy % transformGateActivation), - std::move(boost::apply_visitor(deltaVisitor, network.back()))), + const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g) +{ + arma::Mat gyTransform = gy % transformGateActivation; + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, network.back()), + gyTransform, + boost::apply_visitor(deltaVisitor, network.back())), network.back()); for (size_t i = 2; i < network.size() + 1; ++i) { - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network[network.size() - i])), std::move( - boost::apply_visitor(deltaVisitor, network[network.size() - i + 1])), - std::move(boost::apply_visitor(deltaVisitor, - network[network.size() - i]))), network[network.size() - i]); + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, network[network.size() - i]), + boost::apply_visitor(deltaVisitor, network[network.size() - i + 1]), + boost::apply_visitor(deltaVisitor, + network[network.size() - i])), network[network.size() - i]); } g = boost::apply_visitor(deltaVisitor, network.front()); @@ -198,24 +186,25 @@ typename... CustomLayers> template void Highway::Gradient( - arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient) -{ - boost::apply_visitor(GradientVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network[network.size() - 2])), - std::move(error % transformGateActivation)), network.back()); + const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient) +{ + arma::Mat errorTransform = error % transformGateActivation; + boost::apply_visitor(GradientVisitor(boost::apply_visitor( + outputParameterVisitor, network[network.size() - 2]), + errorTransform), network.back()); for (size_t i = 2; i < network.size(); ++i) { - boost::apply_visitor(GradientVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network[network.size() - i - 1])), std::move( - boost::apply_visitor(deltaVisitor, network[network.size() - i + 1]))), + boost::apply_visitor(GradientVisitor(boost::apply_visitor( + outputParameterVisitor, network[network.size() - i - 1]), + boost::apply_visitor(deltaVisitor, network[network.size() - i + 1])), network[network.size() - i]); } - boost::apply_visitor(GradientVisitor(std::move(input), std::move( - boost::apply_visitor(deltaVisitor, network[1]))), network.front()); + boost::apply_visitor(GradientVisitor(input, + boost::apply_visitor(deltaVisitor, network[1])), network.front()); gradient.submat(0, 0, transformWeight.n_elem - 1, 0) = arma::vectorise( transformGateError * input.t()); diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/join.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/join.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/join.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/join.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -44,7 +44,7 @@ * @param output Resulting output activation. */ template - void Forward(const InputType&& input, OutputType&& output); + void Forward(const InputType& input, OutputType& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -56,9 +56,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); //! Get the output parameter. OutputDataType const& OutputParameter() const { return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/join_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/join_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/join_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/join_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -29,7 +29,7 @@ template template void Join::Forward( - const InputType&& input, OutputType&& output) + const InputType& input, OutputType& output) { inSizeRows = input.n_rows; inSizeCols = input.n_cols; @@ -39,11 +39,12 @@ template template void Join::Backward( - const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g) + const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g) { - g = arma::mat(gy.memptr(), inSizeRows, inSizeCols, false, false); + g = arma::mat(((arma::Mat&) gy).memptr(), inSizeRows, inSizeCols, false, + false); } template diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/layer.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/layer.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/layer.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/layer.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -12,32 +12,57 @@ #ifndef MLPACK_METHODS_ANN_LAYER_LAYER_HPP #define MLPACK_METHODS_ANN_LAYER_LAYER_HPP +#include "add.hpp" #include "add_merge.hpp" +#include "alpha_dropout.hpp" #include "atrous_convolution.hpp" +#include "base_layer.hpp" #include "batch_norm.hpp" +#include "bilinear_interpolation.hpp" +#include "c_relu.hpp" +#include "celu.hpp" #include "concat_performance.hpp" +#include "concat.hpp" +#include "concatenate.hpp" +#include "constant.hpp" #include "convolution.hpp" #include "dropconnect.hpp" +#include "dropout.hpp" +#include "elu.hpp" +#include "fast_lstm.hpp" +#include "flexible_relu.hpp" #include "glimpse.hpp" +#include "gru.hpp" +#include "hard_tanh.hpp" +#include "hardshrink.hpp" #include "highway.hpp" +#include "join.hpp" #include "layer_norm.hpp" #include "layer_types.hpp" +#include "leaky_relu.hpp" #include "linear.hpp" #include "linear_no_bias.hpp" +#include "log_softmax.hpp" +#include "lookup.hpp" #include "lstm.hpp" +#include "max_pooling.hpp" +#include "mean_pooling.hpp" #include "minibatch_discrimination.hpp" +#include "multiply_constant.hpp" #include "multiply_merge.hpp" #include "padding.hpp" -#include "gru.hpp" -#include "fast_lstm.hpp" -#include "recurrent.hpp" +#include "parametric_relu.hpp" #include "recurrent_attention.hpp" +#include "recurrent.hpp" +#include "reinforce_normal.hpp" #include "reparametrization.hpp" +#include "select.hpp" #include "sequential.hpp" +#include "softshrink.hpp" #include "subview.hpp" -#include "concat.hpp" -#include "vr_class_reward.hpp" #include "transposed_convolution.hpp" +#include "virtual_batch_norm.hpp" +#include "vr_class_reward.hpp" #include "weight_norm.hpp" #endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/layer_norm.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/layer_norm.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/layer_norm.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/layer_norm.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -90,7 +90,7 @@ * @param output Resulting output activations. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Backward pass through the layer. @@ -100,9 +100,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& input, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& input, + const arma::Mat& gy, + arma::Mat& g); /** * Calculate the gradient using the output delta and the input activations. @@ -112,9 +112,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(const arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient); + void Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient); //! Get the parameters. OutputDataType const& Parameters() const { return weights; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/layer_norm_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/layer_norm_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/layer_norm_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/layer_norm_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -57,7 +57,7 @@ template template void LayerNorm::Forward( - const arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { mean = arma::mean(input, 0); variance = arma::var(input, 1, 0); @@ -78,7 +78,7 @@ template template void LayerNorm::Backward( - const arma::Mat&& input, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& input, const arma::Mat& gy, arma::Mat& g) { const arma::mat stdInv = 1.0 / arma::sqrt(variance + eps); @@ -102,9 +102,9 @@ template template void LayerNorm::Gradient( - const arma::Mat&& /* input */, - arma::Mat&& error, - arma::Mat&& gradient) + const arma::Mat& /* input */, + const arma::Mat& error, + arma::Mat& gradient) { gradient.set_size(size + size, 1); diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/layer_traits.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/layer_traits.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/layer_traits.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/layer_traits.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -116,6 +116,10 @@ // can use with SFINAE to catch when a type has a Bias() function. HAS_MEM_FUNC(Bias, HasBiasCheck); +// This gives us a HasMaxIterationsC type (where U is a function pointer) +// we can use with SFINAE to catch when a type has a MaxIterations() function. +HAS_MEM_FUNC(MaxIterations, HasMaxIterations); + } // namespace ann } // namespace mlpack diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/layer_types.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/layer_types.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/layer_types.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/layer_types.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,9 @@ #include #include #include +#include +#include +#include // Convolution modules. #include @@ -242,6 +246,7 @@ Padding*, PReLU*, WeightNorm*, + CELU*, MoreTypes, CustomLayers*... >; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/leaky_relu.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/leaky_relu.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/leaky_relu.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/leaky_relu.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -61,7 +61,7 @@ * @param output Resulting output activation. */ template - void Forward(const InputType&& input, OutputType&& output); + void Forward(const InputType& input, OutputType& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -73,7 +73,7 @@ * @param g The calculated gradient. */ template - void Backward(const DataType&& input, DataType&& gy, DataType&& g); + void Backward(const DataType& input, const DataType& gy, DataType& g); //! Get the output parameter. OutputDataType const& OutputParameter() const { return outputParameter; } @@ -97,58 +97,6 @@ void serialize(Archive& ar, const unsigned int /* version */); private: - /** - * Computes the LeakyReLU function - * - * @param x Input data. - * @return f(x). - */ - double Fn(const double x) - { - return std::max(x, alpha * x); - } - - /** - * Computes the LeakyReLU function using a dense matrix as input. - * - * @param x Input data. - * @param y The resulting output activation. - */ - template - void Fn(const arma::Mat& x, arma::Mat& y) - { - y = arma::max(x, alpha * x); - } - - /** - * Computes the first derivative of the LeakyReLU function. - * - * @param x Input data. - * @return f'(x) - */ - double Deriv(const double x) - { - return (x >= 0) ? 1 : alpha; - } - - /** - * Computes the first derivative of the LeakyReLU function. - * - * @param x Input activations. - * @param y The resulting derivatives. - */ - - template - void Deriv(const InputType& x, OutputType& y) - { - y.set_size(arma::size(x)); - - for (size_t i = 0; i < x.n_elem; i++) - { - y(i) = Deriv(x(i)); - } - } - //! Locally-stored delta object. OutputDataType delta; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/leaky_relu_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/leaky_relu_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/leaky_relu_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/leaky_relu_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -30,18 +30,21 @@ template template void LeakyReLU::Forward( - const InputType&& input, OutputType&& output) + const InputType& input, OutputType& output) { - Fn(input, output); + output = arma::max(input, alpha * input); } template template void LeakyReLU::Backward( - const DataType&& input, DataType&& gy, DataType&& g) + const DataType& input, const DataType& gy, DataType& g) { DataType derivative; - Deriv(input, derivative); + derivative.set_size(arma::size(input)); + for (size_t i = 0; i < input.n_elem; i++) + derivative(i) = (input(i) >= 0) ? 1 : alpha; + g = gy % derivative; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/linear.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/linear.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/linear.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/linear.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -64,7 +64,7 @@ * @param output Resulting output activation. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -76,9 +76,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); /* * Calculate the gradient using the output delta and the input activation. @@ -88,9 +88,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(const arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient); + void Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient); //! Get the parameters. OutputDataType const& Parameters() const { return weights; } @@ -112,6 +112,12 @@ //! Modify the delta. OutputDataType& Delta() { return delta; } + //! Get the input size. + size_t InputSize() const { return inSize; } + + //! Get the output size. + size_t OutputSize() const { return outSize; } + //! Get the gradient. OutputDataType const& Gradient() const { return gradient; } //! Modify the gradient. diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/linear_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/linear_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/linear_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/linear_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -54,7 +54,7 @@ typename RegularizerType> template void Linear::Forward( - const arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { output = weight * input; output.each_col() += bias; @@ -64,7 +64,7 @@ typename RegularizerType> template void Linear::Backward( - const arma::Mat&& /* input */, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g) { g = weight.t() * gy; } @@ -73,9 +73,9 @@ typename RegularizerType> template void Linear::Gradient( - const arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient) + const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient) { gradient.submat(0, 0, weight.n_elem - 1, 0) = arma::vectorise( error * input.t()); diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/linear_no_bias.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/linear_no_bias.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/linear_no_bias.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/linear_no_bias.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -63,7 +63,7 @@ * @param output Resulting output activation. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -75,9 +75,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); /* * Calculate the gradient using the output delta and the input activation. @@ -87,9 +87,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(const arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient); + void Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient); //! Get the parameters. OutputDataType const& Parameters() const { return weights; } @@ -111,6 +111,12 @@ //! Modify the delta. OutputDataType& Delta() { return delta; } + //! Get the input size. + size_t InputSize() const { return inSize; } + + //! Get the output size. + size_t OutputSize() const { return outSize; } + //! Get the gradient. OutputDataType const& Gradient() const { return gradient; } //! Modify the gradient. diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/linear_no_bias_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/linear_no_bias_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/linear_no_bias_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/linear_no_bias_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -52,7 +52,7 @@ typename RegularizerType> template void LinearNoBias::Forward( - const arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { output = weight * input; } @@ -61,7 +61,7 @@ typename RegularizerType> template void LinearNoBias::Backward( - const arma::Mat&& /* input */, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g) { g = weight.t() * gy; } @@ -70,9 +70,9 @@ typename RegularizerType> template void LinearNoBias::Gradient( - const arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient) + const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient) { gradient.submat(0, 0, weight.n_elem - 1, 0) = arma::vectorise( error * input.t()); diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/log_softmax.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/log_softmax.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/log_softmax.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/log_softmax.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -49,7 +49,7 @@ * @param output Resulting output activation. */ template - void Forward(const InputType&& input, OutputType&& output); + void Forward(const InputType& input, OutputType& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -61,9 +61,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& input, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& input, + const arma::Mat& gy, + arma::Mat& g); //! Get the output parameter. OutputDataType& OutputParameter() const { return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/log_softmax_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/log_softmax_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/log_softmax_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/log_softmax_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -27,7 +27,7 @@ template template void LogSoftMax::Forward( - const InputType&& input, OutputType&& output) + const InputType& input, OutputType& output) { arma::mat maxInput = arma::repmat(arma::max(input), input.n_rows, 1); output = (maxInput - input); @@ -64,9 +64,9 @@ template template void LogSoftMax::Backward( - const arma::Mat&& input, - arma::Mat&& gy, - arma::Mat&& g) + const arma::Mat& input, + const arma::Mat& gy, + arma::Mat& g) { g = arma::exp(input) + gy; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/lookup.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/lookup.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/lookup.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/lookup.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -52,7 +52,7 @@ * @param output Resulting output activation. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -64,9 +64,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - const arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); /* * Calculate the gradient using the output delta and the input activation. @@ -76,9 +76,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(const arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient); + void Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient); //! Get the parameters. OutputDataType const& Parameters() const { return weights; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/lookup_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/lookup_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/lookup_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/lookup_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -32,7 +32,7 @@ template template void Lookup::Forward( - const arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { output = weights.cols(arma::conv_to::from(input) - 1); } @@ -40,9 +40,9 @@ template template void Lookup::Backward( - const arma::Mat&& /* input */, - const arma::Mat&& gy, - arma::Mat&& g) + const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g) { g = gy; } @@ -50,9 +50,9 @@ template template void Lookup::Gradient( - const arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient) + const arma::Mat& input, + 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; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/lstm.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/lstm.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/lstm.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/lstm.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -26,9 +26,9 @@ * i &=& sigmoid(W \cdot x + W \cdot h + W \cdot c + b) \\ * f &=& sigmoid(W \cdot x + W \cdot h + W \cdot c + b) \\ * z &=& tanh(W \cdot x + W \cdot h + b) \\ - * c &=& f \cdot c + i \cdot z \\ + * c &=& f \odot c + i \odot z \\ * o &=& sigmoid(W \cdot x + W \cdot h + W \cdot c + b) \\ - * h &=& o \cdot tanh(c) + * h &=& o \odot tanh(c) * @f} * * Note that if an LSTM layer is desired as the first layer of a neural network, @@ -84,7 +84,7 @@ * @param output Resulting output activation. */ template - void Forward(InputType&& input, OutputType&& output); + void Forward(const InputType& input, OutputType& output); /** * Ordinary feed-forward pass of a neural network, evaluating the function @@ -96,9 +96,9 @@ * @param useCellState Use the cellState passed in the LSTM cell. */ template - void Forward(InputType&& input, - OutputType&& output, - OutputType&& cellState, + void Forward(const InputType& input, + OutputType& output, + OutputType& cellState, bool useCellState = false); /** @@ -111,9 +111,9 @@ * @param g The calculated gradient. */ template - void Backward(const InputType&& input, - ErrorType&& gy, - GradientType&& g); + void Backward(const InputType& input, + const ErrorType& gy, + GradientType& g); /* * Reset the layer parameter. @@ -136,9 +136,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(InputType&& input, - ErrorType&& error, - GradientType&& gradient); + void Gradient(const InputType& input, + const ErrorType& error, + GradientType& gradient); //! Get the maximum number of steps to backpropagate through time (BPTT). size_t Rho() const { return rho; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/lstm_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/lstm_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/lstm_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/lstm_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -163,19 +163,19 @@ template template void LSTM::Forward( - InputType&& input, OutputType&& output) + const InputType& input, OutputType& output) { //! Locally-stored cellState. OutputType cellState; - Forward(std::move(input), std::move(output), std::move(cellState), false); + Forward(input, output, cellState, false); } // Forward when cellState is needed overloaded LSTM::Forward(). template template -void LSTM::Forward(InputType&& input, - OutputType&& output, - OutputType&& cellState, +void LSTM::Forward(const InputType& input, + OutputType& output, + OutputType& cellState, bool useCellState) { // Check if the batch size changed, the number of cols is defines the input @@ -288,20 +288,27 @@ template template void LSTM::Backward( - const InputType&& /* input */, ErrorType&& gy, GradientType&& g) + const InputType& /* input */, const ErrorType& gy, GradientType& g) { + ErrorType gyLocal; if (gradientStepIdx > 0) { - gy += prevError; + gyLocal = gy + prevError; + } + else + { + // Make an alias. + gyLocal = ErrorType(((ErrorType&) gy).memptr(), gy.n_rows, gy.n_cols, false, + false); } outputGateError = - gy % cellActivation.cols(backwardStep - batchStep, backwardStep) % + gyLocal % cellActivation.cols(backwardStep - batchStep, backwardStep) % (outputGateActivation.cols(backwardStep - batchStep, backwardStep) % (1.0 - outputGateActivation.cols(backwardStep - batchStep, backwardStep))); - OutputDataType cellError = gy % + OutputDataType cellError = gyLocal % outputGateActivation.cols(backwardStep - batchStep, backwardStep) % (1 - arma::pow(cellActivation.cols(backwardStep - batchStep, backwardStep), 2)) + outputGateError.each_col() % @@ -359,7 +366,9 @@ template template void LSTM::Gradient( - InputType&& input, ErrorType&& /* error */, GradientType&& gradient) + const InputType& input, + const ErrorType& /* error */, + GradientType& gradient) { // Input2GateOutputWeight and input2GateOutputBias gradients. gradient.submat(0, 0, input2GateOutputWeight.n_elem - 1, 0) = diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/max_pooling.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/max_pooling.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/max_pooling.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/max_pooling.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -58,16 +58,16 @@ /** * Create the MaxPooling object using the specified number of units. * - * @param kW Width of the pooling window. - * @param kH Height of the pooling window. - * @param dW Width of the stride operation. - * @param dH Width of the stride operation. + * @param kernelWidth Width of the pooling window. + * @param kernelHeight Height of the pooling window. + * @param strideWidth Width of the stride operation. + * @param strideHeight Width of the stride operation. * @param floor Rounding operator (floor or ceil). */ - MaxPooling(const size_t kW, - const size_t kH, - const size_t dW = 1, - const size_t dH = 1, + MaxPooling(const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth = 1, + const size_t strideHeight = 1, const bool floor = true); /** @@ -78,7 +78,7 @@ * @param output Resulting output activation. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, using 3rd-order tensors as @@ -90,40 +90,71 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); //! Get the output parameter. - OutputDataType const& OutputParameter() const { return outputParameter; } + const OutputDataType& OutputParameter() const { return outputParameter; } //! Modify the output parameter. OutputDataType& OutputParameter() { return outputParameter; } //! Get the delta. - OutputDataType const& Delta() const { return delta; } + const OutputDataType& Delta() const { return delta; } //! Modify the delta. OutputDataType& Delta() { return delta; } //! Get the width. - size_t const& InputWidth() const { return inputWidth; } + size_t InputWidth() const { return inputWidth; } //! Modify the width. size_t& InputWidth() { return inputWidth; } //! Get the height. - size_t const& InputHeight() const { return inputHeight; } + size_t InputHeight() const { return inputHeight; } //! Modify the height. size_t& InputHeight() { return inputHeight; } //! Get the width. - size_t const& OutputWidth() const { return outputWidth; } + size_t OutputWidth() const { return outputWidth; } //! Modify the width. size_t& OutputWidth() { return outputWidth; } //! Get the height. - size_t const& OutputHeight() const { return outputHeight; } + size_t OutputHeight() const { return outputHeight; } //! Modify the height. size_t& OutputHeight() { return outputHeight; } + //! Get the input size. + size_t InputSize() const { return inSize; } + + //! Get the output size. + size_t OutputSize() const { return outSize; } + + //! Get the kernel width. + size_t KernelWidth() const { return kernelWidth; } + //! Modify the kernel width. + size_t& KernelWidth() { return kernelWidth; } + + //! Get the kernel height. + size_t KernelHeight() const { return kernelHeight; } + //! Modify the kernel height. + size_t& KernelHeight() { return kernelHeight; } + + //! Get the stride width. + size_t StrideWidth() const { return strideWidth; } + //! Modify the stride width. + size_t& StrideWidth() { return strideWidth; } + + //! Get the stride height. + size_t StrideHeight() const { return strideHeight; } + //! Modify the stride height. + size_t& StrideHeight() { return strideHeight; } + + //! Get the value of the rounding operation. + bool Floor() const { return floor; } + //! Modify the value of the rounding operation. + bool& Floor() { return floor; } + //! Get the value of the deterministic parameter. bool Deterministic() const { return deterministic; } //! Modify the value of the deterministic parameter. @@ -148,12 +179,15 @@ arma::Mat& output, arma::Mat& poolingIndices) { - for (size_t j = 0, colidx = 0; j < output.n_cols; ++j, colidx += dW) + for (size_t j = 0, colidx = 0; j < output.n_cols; + ++j, colidx += strideHeight) { - for (size_t i = 0, rowidx = 0; i < output.n_rows; ++i, rowidx += dH) + for (size_t i = 0, rowidx = 0; i < output.n_rows; + ++i, rowidx += strideWidth) { - arma::mat subInput = input(arma::span(rowidx, rowidx + kW - 1 - offset), - arma::span(colidx, colidx + kH - 1 - offset)); + arma::mat subInput = input( + arma::span(rowidx, rowidx + kernelWidth - 1 - offset), + arma::span(colidx, colidx + kernelHeight - 1 - offset)); const size_t idx = pooling.Pooling(subInput); output(i, j) = subInput(idx); @@ -161,8 +195,8 @@ if (!deterministic) { arma::Mat subIndices = indices(arma::span(rowidx, - rowidx + kW - 1 - offset), - arma::span(colidx, colidx + kH - 1 - offset)); + rowidx + kernelWidth - 1 - offset), + arma::span(colidx, colidx + kernelHeight - 1 - offset)); poolingIndices(i, j) = subIndices(idx); } @@ -189,16 +223,16 @@ } //! Locally-stored width of the pooling window. - size_t kW; + size_t kernelWidth; //! Locally-stored height of the pooling window. - size_t kH; + size_t kernelHeight; //! Locally-stored width of the stride operation. - size_t dW; + size_t strideWidth; //! Locally-stored height of the stride operation. - size_t dH; + size_t strideHeight; //! Rounding operation used. bool floor; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/max_pooling_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/max_pooling_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/max_pooling_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/max_pooling_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -27,15 +27,15 @@ template MaxPooling::MaxPooling( - const size_t kW, - const size_t kH, - const size_t dW, - const size_t dH, + const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth, + const size_t strideHeight, const bool floor) : - kW(kW), - kH(kH), - dW(dW), - dH(dH), + kernelWidth(kernelWidth), + kernelHeight(kernelHeight), + strideWidth(strideWidth), + strideHeight(strideHeight), floor(floor), inSize(0), outSize(0), @@ -54,23 +54,27 @@ template template void MaxPooling::Forward( - const arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { batchSize = input.n_cols; inSize = input.n_elem / (inputWidth * inputHeight * batchSize); - inputTemp = arma::cube(const_cast&&>(input).memptr(), + inputTemp = arma::cube(const_cast&>(input).memptr(), inputWidth, inputHeight, batchSize * inSize, false, false); if (floor) { - outputWidth = std::floor((inputWidth - (double) kW) / (double) dW + 1); - outputHeight = std::floor((inputHeight - (double) kH) / (double) dH + 1); + outputWidth = std::floor((inputWidth - + (double) kernelWidth) / (double) strideWidth + 1); + outputHeight = std::floor((inputHeight - + (double) kernelHeight) / (double) strideHeight + 1); offset = 0; } else { - outputWidth = std::ceil((inputWidth - (double) kW) / (double) dW + 1); - outputHeight = std::ceil((inputHeight - (double) kH) / (double) dH + 1); + outputWidth = std::ceil((inputWidth - + (double) kernelWidth) / (double) strideWidth + 1); + outputHeight = std::ceil((inputHeight - + (double) kernelHeight) / (double) strideHeight + 1); offset = 1; } @@ -118,10 +122,10 @@ template template void MaxPooling::Backward( - const arma::Mat&& /* input */, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g) { - arma::cube mappedError = arma::cube(gy.memptr(), outputWidth, - outputHeight, outSize, false, false); + arma::cube mappedError = arma::cube(((arma::Mat&) gy).memptr(), + outputWidth, outputHeight, outSize, false, false); gTemp = arma::zeros(inputTemp.n_rows, inputTemp.n_cols, inputTemp.n_slices); @@ -143,10 +147,10 @@ Archive& ar, const unsigned int /* version */) { - ar & BOOST_SERIALIZATION_NVP(kW); - ar & BOOST_SERIALIZATION_NVP(kH); - ar & BOOST_SERIALIZATION_NVP(dW); - ar & BOOST_SERIALIZATION_NVP(dH); + ar & BOOST_SERIALIZATION_NVP(kernelWidth); + ar & BOOST_SERIALIZATION_NVP(kernelHeight); + ar & BOOST_SERIALIZATION_NVP(strideWidth); + ar & BOOST_SERIALIZATION_NVP(strideHeight); ar & BOOST_SERIALIZATION_NVP(batchSize); ar & BOOST_SERIALIZATION_NVP(floor); ar & BOOST_SERIALIZATION_NVP(inputWidth); diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/mean_pooling.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/mean_pooling.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/mean_pooling.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/mean_pooling.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -39,15 +39,15 @@ /** * Create the MeanPooling object using the specified number of units. * - * @param kW Width of the pooling window. - * @param kH Height of the pooling window. - * @param dW Width of the stride operation. - * @param dH Width of the stride operation. - */ - MeanPooling(const size_t kW, - const size_t kH, - const size_t dW = 1, - const size_t dH = 1, + * @param kernelWidth Width of the pooling window. + * @param kernelHeight Height of the pooling window. + * @param strideWidth Width of the stride operation. + * @param strideHeight Width of the stride operation. + */ + MeanPooling(const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth = 1, + const size_t strideHeight = 1, const bool floor = true); /** @@ -58,7 +58,7 @@ * @param output Resulting output activation. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, using 3rd-order tensors as @@ -70,9 +70,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); //! Get the output parameter. OutputDataType const& OutputParameter() const { return outputParameter; } @@ -104,6 +104,37 @@ //! Modify the height. size_t& OutputHeight() { return outputHeight; } + //! Get the input size. + size_t InputSize() const { return inSize; } + + //! Get the output size. + size_t OutputSize() const { return outSize; } + + //! Get the kernel width. + size_t KernelWidth() const { return kernelWidth; } + //! Modify the kernel width. + size_t& KernelWidth() { return kernelWidth; } + + //! Get the kernel height. + size_t KernelHeight() const { return kernelHeight; } + //! Modify the kernel height. + size_t& KernelHeight() { return kernelHeight; } + + //! Get the stride width. + size_t StrideWidth() const { return strideWidth; } + //! Modify the stride width. + size_t& StrideWidth() { return strideWidth; } + + //! Get the stride height. + size_t StrideHeight() const { return strideHeight; } + //! Modify the stride height. + size_t& StrideHeight() { return strideHeight; } + + //! Get the value of the rounding operation + bool const& Floor() const { return floor; } + //! Modify the value of the rounding operation + bool& Floor() { return floor; } + //! Get the value of the deterministic parameter. bool Deterministic() const { return deterministic; } //! Modify the value of the deterministic parameter. @@ -125,16 +156,15 @@ template void Pooling(const arma::Mat& input, arma::Mat& output) { - const size_t rStep = kW; - const size_t cStep = kH; - - for (size_t j = 0, colidx = 0; j < output.n_cols; ++j, colidx += dH) + for (size_t j = 0, colidx = 0; j < output.n_cols; + ++j, colidx += strideHeight) { - for (size_t i = 0, rowidx = 0; i < output.n_rows; ++i, rowidx += dW) + for (size_t i = 0, rowidx = 0; i < output.n_rows; + ++i, rowidx += strideWidth) { arma::mat subInput = input( - arma::span(rowidx, rowidx + rStep - 1 - offset), - arma::span(colidx, colidx + cStep - 1 - offset)); + arma::span(rowidx, rowidx + kernelWidth - 1 - offset), + arma::span(colidx, colidx + kernelHeight - 1 - offset)); output(i, j) = arma::mean(arma::mean(subInput)); } @@ -173,16 +203,16 @@ } //! Locally-stored width of the pooling window. - size_t kW; + size_t kernelWidth; //! Locally-stored height of the pooling window. - size_t kH; + size_t kernelHeight; //! Locally-stored width of the stride operation. - size_t dW; + size_t strideWidth; //! Locally-stored height of the stride operation. - size_t dH; + size_t strideHeight; //! Rounding operation used. bool floor; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/mean_pooling_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/mean_pooling_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/mean_pooling_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/mean_pooling_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -27,15 +27,15 @@ template MeanPooling::MeanPooling( - const size_t kW, - const size_t kH, - const size_t dW, - const size_t dH, + const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth, + const size_t strideHeight, const bool floor) : - kW(kW), - kH(kH), - dW(dW), - dH(dH), + kernelWidth(kernelWidth), + kernelHeight(kernelHeight), + strideWidth(strideWidth), + strideHeight(strideHeight), floor(floor), inSize(0), outSize(0), @@ -54,24 +54,28 @@ template template void MeanPooling::Forward( - const arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { batchSize = input.n_cols; inSize = input.n_elem / (inputWidth * inputHeight * batchSize); - inputTemp = arma::cube(const_cast&&>(input).memptr(), + inputTemp = arma::cube(const_cast&>(input).memptr(), inputWidth, inputHeight, batchSize * inSize, false, false); if (floor) { - outputWidth = std::floor((inputWidth - (double) kW) / (double) dW + 1); - outputHeight = std::floor((inputHeight - (double) kH) / (double) dH + 1); + outputWidth = std::floor((inputWidth - + (double) kernelWidth) / (double) strideWidth + 1); + outputHeight = std::floor((inputHeight - + (double) kernelHeight) / (double) strideHeight + 1); offset = 0; } else { - outputWidth = std::ceil((inputWidth - (double) kW) / (double) dW + 1); - outputHeight = std::ceil((inputHeight - (double) kH) / (double) dH + 1); + outputWidth = std::ceil((inputWidth - + (double) kernelWidth) / (double) strideWidth + 1); + outputHeight = std::ceil((inputHeight - + (double) kernelHeight) / (double) strideHeight + 1); offset = 1; } @@ -93,12 +97,12 @@ template template void MeanPooling::Backward( - const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g) + const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g) { - arma::cube mappedError = arma::cube(gy.memptr(), outputWidth, - outputHeight, outSize, false, false); + arma::cube mappedError = arma::cube(((arma::Mat&) gy).memptr(), + outputWidth, outputHeight, outSize, false, false); gTemp = arma::zeros(inputTemp.n_rows, inputTemp.n_cols, inputTemp.n_slices); @@ -117,10 +121,10 @@ Archive& ar, const unsigned int /* version */) { - ar & BOOST_SERIALIZATION_NVP(kW); - ar & BOOST_SERIALIZATION_NVP(kH); - ar & BOOST_SERIALIZATION_NVP(dW); - ar & BOOST_SERIALIZATION_NVP(dH); + ar & BOOST_SERIALIZATION_NVP(kernelWidth); + ar & BOOST_SERIALIZATION_NVP(kernelHeight); + ar & BOOST_SERIALIZATION_NVP(strideWidth); + ar & BOOST_SERIALIZATION_NVP(strideHeight); ar & BOOST_SERIALIZATION_NVP(batchSize); ar & BOOST_SERIALIZATION_NVP(floor); ar & BOOST_SERIALIZATION_NVP(inputWidth); diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/minibatch_discrimination.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/minibatch_discrimination.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/minibatch_discrimination.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/minibatch_discrimination.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -81,7 +81,7 @@ * @param output Resulting output activation. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed-backward pass of a neural network, calculating the function @@ -93,9 +93,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); /** * Calculate the gradient using the output delta and the input activation. @@ -105,9 +105,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(const arma::Mat&& input, - arma::Mat&& /* error */, - arma::Mat&& gradient); + void Gradient(const arma::Mat& input, + const arma::Mat& /* error */, + arma::Mat& gradient); //! Get the parameters. OutputDataType const& Parameters() const { return weights; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/minibatch_discrimination_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/minibatch_discrimination_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/minibatch_discrimination_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/minibatch_discrimination_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -52,7 +52,7 @@ template template void MiniBatchDiscrimination::Forward( - const arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { batchSize = input.n_cols; tempM = weight * input; @@ -88,7 +88,7 @@ template template void MiniBatchDiscrimination::Backward( - const arma::Mat&& /* input */, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g) { g = gy.head_rows(A); arma::Mat gM = gy.tail_rows(B); @@ -117,9 +117,9 @@ template template void MiniBatchDiscrimination::Gradient( - const arma::Mat&& input, - arma::Mat&& /* error */, - arma::Mat&& gradient) + const arma::Mat& input, + const arma::Mat& /* error */, + arma::Mat& gradient) { gradient = arma::vectorise(deltaTemp * input.t()); } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/multiply_constant.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/multiply_constant.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/multiply_constant.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/multiply_constant.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -47,7 +47,7 @@ * @param output Resulting output activation. */ template - void Forward(const InputType&& input, OutputType&& output); + void Forward(const InputType& input, OutputType& output); /** * Ordinary feed backward pass of a neural network. The backward pass @@ -58,7 +58,7 @@ * @param g The calculated gradient. */ template - void Backward(const DataType&& /* input */, DataType&& gy, DataType&& g); + void Backward(const DataType& /* input */, const DataType& gy, DataType& g); //! Get the output parameter. OutputDataType& OutputParameter() const { return outputParameter; } @@ -70,6 +70,11 @@ //! Modify the delta. OutputDataType& Delta() { return delta; } + //! Get the scalar multiplier. + double Scalar() const { return scalar; } + //! Modify the scalar multiplier. + double& Scalar() { return scalar; } + /** * Serialize the layer. */ diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/multiply_constant_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/multiply_constant_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/multiply_constant_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/multiply_constant_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -29,7 +29,7 @@ template template void MultiplyConstant::Forward( - const InputType&& input, OutputType&& output) + const InputType& input, OutputType& output) { output = input * scalar; } @@ -37,7 +37,7 @@ template template void MultiplyConstant::Backward( - const DataType&& /* input */, DataType&& gy, DataType&& g) + const DataType& /* input */, const DataType& gy, DataType& g) { g = gy * scalar; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/multiply_merge.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/multiply_merge.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/multiply_merge.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/multiply_merge.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -61,7 +61,7 @@ * @param output Resulting output activation. */ template - void Forward(InputType&& /* input */, OutputType&& output); + void Forward(const InputType& /* input */, OutputType& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -73,9 +73,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); /* * Calculate the gradient using the output delta and the input activation. @@ -85,9 +85,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient); + void Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient); /* * Add a new module to the model. diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/multiply_merge_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/multiply_merge_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/multiply_merge_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/multiply_merge_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -47,14 +47,14 @@ typename... CustomLayers> template void MultiplyMerge::Forward( - InputType&& input, OutputType&& output) + const InputType& input, OutputType& output) { if (run) { for (size_t i = 0; i < network.size(); ++i) { - boost::apply_visitor(ForwardVisitor(std::move(input), std::move( - boost::apply_visitor(outputParameterVisitor, network[i]))), + boost::apply_visitor(ForwardVisitor(input, + boost::apply_visitor(outputParameterVisitor, network[i])), network[i]); } } @@ -70,15 +70,15 @@ typename... CustomLayers> template void MultiplyMerge::Backward( - const arma::Mat&& /* input */, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g) { if (run) { for (size_t i = 0; i < network.size(); ++i) { - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network[i])), std::move(gy), std::move( - boost::apply_visitor(deltaVisitor, network[i]))), network[i]); + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, network[i]), gy, + boost::apply_visitor(deltaVisitor, network[i])), network[i]); } g = boost::apply_visitor(deltaVisitor, network[0]); @@ -95,16 +95,15 @@ typename... CustomLayers> template void MultiplyMerge::Gradient( - arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& /* gradient */ ) + const arma::Mat& input, + const arma::Mat& error, + arma::Mat& /* gradient */ ) { if (run) { for (size_t i = 0; i < network.size(); ++i) { - boost::apply_visitor(GradientVisitor(std::move(input), std::move(error)), - network[i]); + boost::apply_visitor(GradientVisitor(input, error), network[i]); } } } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/padding.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/padding.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/padding.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/padding.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -38,7 +38,7 @@ * Create the Padding object using the specified number of output units. * * @param padWLeft Left padding width of the input. - * @param padWLeft Right padding width of the input. + * @param padWRight Right padding width of the input. * @param padHTop Top padding height of the input. * @param padHBottom Bottom padding height of the input. */ @@ -55,7 +55,7 @@ * @param output Resulting output activation. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -67,9 +67,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - const arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); //! Get the output parameter. OutputDataType const& OutputParameter() const { return outputParameter; } @@ -81,6 +81,26 @@ //! Modify the delta. OutputDataType& Delta() { return delta; } + //! Get the left padding width. + size_t PadWLeft() const { return padWLeft; } + //! Modify the left padding width. + size_t& PadWLeft() { return padWLeft; } + + //! Get the right padding width. + size_t PadWRight() const { return padWRight; } + //! Modify the right padding width. + size_t& PadWRight() { return padWRight; } + + //! Get the top padding width. + size_t PadHTop() const { return padHTop; } + //! Modify the top padding width. + size_t& PadHTop() { return padHTop; } + + //! Get the bottom padding width. + size_t PadHBottom() const { return padHBottom; } + //! Modify the bottom padding width. + size_t& PadHBottom() { return padHBottom; } + /** * Serialize the layer. */ diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/padding_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/padding_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/padding_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/padding_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -38,7 +38,7 @@ template template void Padding::Forward( - const arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { nRows = input.n_rows; nCols = input.n_cols; @@ -51,9 +51,9 @@ template template void Padding::Backward( - const arma::Mat&& /* input */, - const arma::Mat&& gy, - arma::Mat&& g) + const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g) { g = gy.submat(padWLeft, padHTop, padWLeft + nRows - 1, padHTop + nCols - 1); diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/parametric_relu.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/parametric_relu.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/parametric_relu.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/parametric_relu.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -68,7 +68,7 @@ * @param output Resulting output activation. */ template - void Forward(const InputType&& input, OutputType&& output); + void Forward(const InputType& input, OutputType& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -80,7 +80,7 @@ * @param g The calculated gradient. */ template - void Backward(const DataType&& input, DataType&& gy, DataType&& g); + void Backward(const DataType& input, const DataType& gy, DataType& g); /** * Calculate the gradient using the output delta and the input activation. @@ -90,9 +90,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(const arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient); + void Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient); //! Get the parameters. OutputDataType const& Parameters() const { return alpha; } @@ -126,60 +126,6 @@ void serialize(Archive& ar, const unsigned int /* version */); private: - /** - * Computes the parametric ReLU function. - * - * @param x Input data. - * @return f(x). - */ - double Fn(const double x) - { - return std::max(x, alpha(0) * x); - } - - /** - * Computes the parametric ReLU function using a dense matrix as input. - * - * @param x Input data. - * @param y The resulting output activation. - */ - template - void Fn(const arma::Mat& x, arma::Mat& y) - { - y = x; - arma::uvec negative = arma::find(x < 0); - y(negative) = x(negative) * alpha(0); - } - - /** - * Computes the first derivative of the parametric ReLU function. - * - * @param x Input data. - * @return f'(x) - */ - double Deriv(const double x) - { - return (x >= 0) ? 1 : alpha(0); - } - - /** - * Computes the first derivative of the PReLU function. - * - * @param x Input activations. - * @param y The resulting derivatives. - */ - - template - void Deriv(const InputType& x, OutputType& y) - { - y.set_size(arma::size(x)); - - for (size_t i = 0; i < x.n_elem; i++) - { - y(i) = Deriv(x(i)); - } - } - //! Locally-stored delta object. OutputDataType delta; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/parametric_relu_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/parametric_relu_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/parametric_relu_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/parametric_relu_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -39,26 +39,34 @@ template template void PReLU::Forward( - const InputType&& input, OutputType&& output) + const InputType& input, OutputType& output) { - Fn(input, output); + output = input; + arma::uvec negative = arma::find(input < 0); + output(negative) = input(negative) * alpha(0); } template template void PReLU::Backward( - const DataType&& input, DataType&& gy, DataType&& g) + const DataType& input, const DataType& gy, DataType& g) { DataType derivative; - Deriv(input, derivative); + derivative.set_size(arma::size(input)); + for (size_t i = 0; i < input.n_elem; i++) + { + derivative(i) = (input(i) >= 0) ? 1 : alpha(0); + } + g = gy % derivative; } template template void PReLU::Gradient( - const arma::Mat&& input, arma::Mat&& error, - arma::Mat&& gradient) + const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient) { if (gradient.n_elem == 0) { diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/recurrent_attention.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/recurrent_attention.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/recurrent_attention.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/recurrent_attention.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -35,11 +35,12 @@ * * @code * @article{MnihHGK14, - * title={Recurrent Models of Visual Attention}, - * author={Volodymyr Mnih, Nicolas Heess, Alex Graves, Koray Kavukcuoglu}, - * journal={CoRR}, - * volume={abs/1406.6247}, - * year={2014} + * title = {Recurrent Models of Visual Attention}, + * author = {Volodymyr Mnih, Nicolas Heess, Alex Graves, Koray Kavukcuoglu}, + * journal = {CoRR}, + * volume = {abs/1406.6247}, + * year = {2014}, + * url = {https://arxiv.org/abs/1406.6247} * } * @endcode * @@ -64,9 +65,9 @@ /** * Create the RecurrentAttention object using the specified modules. * - * @param start The module output size. - * @param start The recurrent neural network module. - * @param start The action module. + * @param outSize The module output size. + * @param rnn The recurrent neural network module. + * @param action The action module. * @param rho Maximum number of steps to backpropagate through time (BPTT). */ template @@ -83,7 +84,7 @@ * @param output Resulting output activation. */ template - void Forward(arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -95,9 +96,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); /* * Calculate the gradient using the output delta and the input activation. @@ -107,9 +108,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(arma::Mat&& /* input */, - arma::Mat&& /* error */, - arma::Mat&& /* gradient */); + void Gradient(const arma::Mat& /* input */, + const arma::Mat& /* error */, + arma::Mat& /* gradient */); //! Get the model modules. std::vector>& Model() { return network; } @@ -154,19 +155,19 @@ // Gradient of the action module. if (backwardStep == (rho - 1)) { - boost::apply_visitor(GradientVisitor(std::move(initialInput), - std::move(actionError)), actionModule); + boost::apply_visitor(GradientVisitor(initialInput, actionError), + actionModule); } else { - boost::apply_visitor(GradientVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, actionModule)), std::move(actionError)), + boost::apply_visitor(GradientVisitor(boost::apply_visitor( + outputParameterVisitor, actionModule), actionError), actionModule); } // Gradient of the recurrent module. - boost::apply_visitor(GradientVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, rnnModule)), std::move(recurrentError)), + boost::apply_visitor(GradientVisitor(boost::apply_visitor( + outputParameterVisitor, rnnModule), recurrentError), rnnModule); attentionGradient += intermediateGradient; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/recurrent_attention_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/recurrent_attention_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/recurrent_attention_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/recurrent_attention_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -58,7 +58,7 @@ template template void RecurrentAttention::Forward( - arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { // Initialize the action input. if (initialInput.is_empty()) @@ -71,15 +71,15 @@ { if (forwardStep == 0) { - boost::apply_visitor(ForwardVisitor(std::move(initialInput), std::move( - boost::apply_visitor(outputParameterVisitor, actionModule))), + boost::apply_visitor(ForwardVisitor(initialInput, + boost::apply_visitor(outputParameterVisitor, actionModule)), actionModule); } else { - boost::apply_visitor(ForwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, rnnModule)), std::move(boost::apply_visitor( - outputParameterVisitor, actionModule))), actionModule); + boost::apply_visitor(ForwardVisitor(boost::apply_visitor( + outputParameterVisitor, rnnModule), boost::apply_visitor( + outputParameterVisitor, actionModule)), actionModule); } // Initialize the glimpse input. @@ -89,8 +89,8 @@ actionModule).n_elem - 1, 1) = boost::apply_visitor( outputParameterVisitor, actionModule); - boost::apply_visitor(ForwardVisitor(std::move(glimpseInput), - std::move(boost::apply_visitor(outputParameterVisitor, rnnModule))), + boost::apply_visitor(ForwardVisitor(glimpseInput, + boost::apply_visitor(outputParameterVisitor, rnnModule)), rnnModule); // Save the output parameter when training the module. @@ -99,7 +99,7 @@ for (size_t l = 0; l < network.size(); ++l) { boost::apply_visitor(SaveOutputParameterVisitor( - std::move(moduleOutputParameter)), network[l]); + moduleOutputParameter), network[l]); } } } @@ -113,9 +113,9 @@ template template void RecurrentAttention::Backward( - const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g) + const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g) { if (intermediateGradient.is_empty() && backwardStep == 0) { @@ -137,9 +137,9 @@ { size_t offset = 0; offset += boost::apply_visitor(GradientSetVisitor( - std::move(intermediateGradient), offset), rnnModule); + intermediateGradient, offset), rnnModule); boost::apply_visitor(GradientSetVisitor( - std::move(intermediateGradient), offset), actionModule); + intermediateGradient, offset), actionModule); attentionGradient.zeros(); } @@ -159,24 +159,24 @@ for (size_t l = 0; l < network.size(); ++l) { boost::apply_visitor(LoadOutputParameterVisitor( - std::move(moduleOutputParameter)), network[network.size() - 1 - l]); + moduleOutputParameter), network[network.size() - 1 - l]); } if (backwardStep == (rho - 1)) { - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, actionModule)), std::move(actionError), - std::move(actionDelta)), actionModule); + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, actionModule), actionError, + actionDelta), actionModule); } else { - boost::apply_visitor(BackwardVisitor(std::move(initialInput), - std::move(actionError), std::move(actionDelta)), actionModule); + boost::apply_visitor(BackwardVisitor(initialInput, actionError, + actionDelta), actionModule); } - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, rnnModule)), std::move(recurrentError), - std::move(rnnDelta)), rnnModule); + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, rnnModule), recurrentError, rnnDelta), + rnnModule); if (backwardStep == 0) { @@ -194,15 +194,15 @@ template template void RecurrentAttention::Gradient( - arma::Mat&& /* input */, - arma::Mat&& /* error */, - arma::Mat&& /* gradient */) + const arma::Mat& /* input */, + const arma::Mat& /* error */, + arma::Mat& /* gradient */) { size_t offset = 0; offset += boost::apply_visitor(GradientUpdateVisitor( - std::move(attentionGradient), offset), rnnModule); + attentionGradient, offset), rnnModule); boost::apply_visitor(GradientUpdateVisitor( - std::move(attentionGradient), offset), actionModule); + attentionGradient, offset), actionModule); } template diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/recurrent.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/recurrent.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/recurrent.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/recurrent.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -50,9 +50,6 @@ */ Recurrent(); - //! Destructor to release allocated memory. - ~Recurrent(); - //! Copy constructor. Recurrent(const Recurrent&); @@ -83,7 +80,7 @@ * @param output Resulting output activation. */ template - void Forward(arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -95,9 +92,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); /* * Calculate the gradient using the output delta and the input activation. @@ -107,9 +104,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& /* gradient */); + void Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& /* gradient */); //! Get the model modules. std::vector >& Model() { return network; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/recurrent_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/recurrent_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/recurrent_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/recurrent_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -37,19 +37,6 @@ // Nothing to do. } -template -Recurrent::~Recurrent() -{ - if (ownsLayer) - { - boost::apply_visitor(DeleteVisitor(), recurrentModule); - boost::apply_visitor(DeleteVisitor(), initialModule); - boost::apply_visitor(DeleteVisitor(), startModule); - network.clear(); - } -} - template template< @@ -76,8 +63,8 @@ ownsLayer(true) { initialModule = new Sequential<>(); - mergeModule = new AddMerge<>(false, false); - recurrentModule = new Sequential<>(false); + mergeModule = new AddMerge<>(false, false, false); + recurrentModule = new Sequential<>(false, false); boost::apply_visitor(AddVisitor(inputModule), initialModule); @@ -116,8 +103,8 @@ feedbackModule = boost::apply_visitor(copyVisitor, network.feedbackModule); transferModule = boost::apply_visitor(copyVisitor, network.transferModule); initialModule = new Sequential<>(); - mergeModule = new AddMerge<>(false, false); - recurrentModule = new Sequential<>(false); + mergeModule = new AddMerge<>(false, false, false); + recurrentModule = new Sequential<>(false, false); boost::apply_visitor(AddVisitor(inputModule), initialModule); @@ -143,26 +130,24 @@ typename... CustomLayers> template void Recurrent::Forward( - arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { if (forwardStep == 0) { - boost::apply_visitor(ForwardVisitor(std::move(input), std::move(output)), - initialModule); + boost::apply_visitor(ForwardVisitor(input, output), initialModule); } else { - boost::apply_visitor(ForwardVisitor(std::move(input), std::move( - boost::apply_visitor(outputParameterVisitor, inputModule))), + boost::apply_visitor(ForwardVisitor(input, + boost::apply_visitor(outputParameterVisitor, inputModule)), inputModule); - boost::apply_visitor(ForwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, transferModule)), std::move( - boost::apply_visitor(outputParameterVisitor, feedbackModule))), + boost::apply_visitor(ForwardVisitor(boost::apply_visitor( + outputParameterVisitor, transferModule), + boost::apply_visitor(outputParameterVisitor, feedbackModule)), feedbackModule); - boost::apply_visitor(ForwardVisitor(std::move(input), std::move(output)), - recurrentModule); + boost::apply_visitor(ForwardVisitor(input, output), recurrentModule); } output = boost::apply_visitor(outputParameterVisitor, transferModule); @@ -190,7 +175,7 @@ typename... CustomLayers> template void Recurrent::Backward( - const arma::Mat&& /* input */, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g) { if (!recurrentError.is_empty()) { @@ -203,26 +188,26 @@ if (backwardStep < (rho - 1)) { - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, recurrentModule)), std::move(recurrentError), - std::move(boost::apply_visitor(deltaVisitor, recurrentModule))), + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, recurrentModule), recurrentError, + boost::apply_visitor(deltaVisitor, recurrentModule)), recurrentModule); - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, inputModule)), std::move( - boost::apply_visitor(deltaVisitor, recurrentModule)), std::move(g)), + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, inputModule), + boost::apply_visitor(deltaVisitor, recurrentModule), g), inputModule); - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, feedbackModule)), std::move( - boost::apply_visitor(deltaVisitor, recurrentModule)), std::move( - boost::apply_visitor(deltaVisitor, feedbackModule))), feedbackModule); + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, feedbackModule), + boost::apply_visitor(deltaVisitor, recurrentModule), + boost::apply_visitor(deltaVisitor, feedbackModule)), feedbackModule); } else { - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, initialModule)), std::move(recurrentError), - std::move(g)), initialModule); + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, initialModule), recurrentError, g), + initialModule); } recurrentError = boost::apply_visitor(deltaVisitor, feedbackModule); @@ -233,22 +218,21 @@ typename... CustomLayers> template void Recurrent::Gradient( - arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& /* gradient */) + const arma::Mat& input, + const arma::Mat& error, + arma::Mat& /* gradient */) { if (gradientStep < (rho - 1)) { - boost::apply_visitor(GradientVisitor(std::move(input), std::move(error)), - recurrentModule); + boost::apply_visitor(GradientVisitor(input, error), recurrentModule); - boost::apply_visitor(GradientVisitor(std::move(input), std::move( - boost::apply_visitor(deltaVisitor, mergeModule))), inputModule); + boost::apply_visitor(GradientVisitor(input, + boost::apply_visitor(deltaVisitor, mergeModule)), inputModule); - boost::apply_visitor(GradientVisitor(std::move( + boost::apply_visitor(GradientVisitor( feedbackOutputParameter[feedbackOutputParameter.size() - 2 - - gradientStep]), std::move(boost::apply_visitor(deltaVisitor, - mergeModule))), feedbackModule); + gradientStep], boost::apply_visitor(deltaVisitor, + mergeModule)), feedbackModule); } else { @@ -256,8 +240,8 @@ boost::apply_visitor(GradientZeroVisitor(), inputModule); boost::apply_visitor(GradientZeroVisitor(), feedbackModule); - boost::apply_visitor(GradientVisitor(std::move(input), std::move( - boost::apply_visitor(deltaVisitor, startModule))), initialModule); + boost::apply_visitor(GradientVisitor(input, + boost::apply_visitor(deltaVisitor, startModule)), initialModule); } gradientStep++; @@ -295,8 +279,8 @@ if (Archive::is_loading::value) { initialModule = new Sequential<>(); - mergeModule = new AddMerge<>(false, false); - recurrentModule = new Sequential<>(false); + mergeModule = new AddMerge<>(false, false, false); + recurrentModule = new Sequential<>(false, false); boost::apply_visitor(AddVisitor(inputModule), initialModule); diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/reinforce_normal.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/reinforce_normal.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/reinforce_normal.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/reinforce_normal.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -49,7 +49,7 @@ * @param output Resulting output activation. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -61,7 +61,7 @@ * @param g The calculated gradient. */ template - void Backward(const DataType&& input, DataType&& /* gy */, DataType&& g); + void Backward(const DataType& input, const DataType& /* gy */, DataType& g); //! Get the output parameter. OutputDataType& OutputParameter() const { return outputParameter; } @@ -87,7 +87,7 @@ * Serialize the layer */ template - void serialize(Archive& /* ar */, const unsigned int /* version */); + void serialize(Archive& ar, const unsigned int /* version */); private: //! Standard deviation used during the forward and backward pass. diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -29,7 +29,7 @@ template template void ReinforceNormal::Forward( - const arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { if (!deterministic) { @@ -49,7 +49,7 @@ template template void ReinforceNormal::Backward( - const DataType&& input, DataType&& /* gy */, DataType&& g) + const DataType& input, const DataType& /* gy */, DataType& g) { g = (input - moduleInputParameter.back()) / std::pow(stdev, 2.0); @@ -63,9 +63,9 @@ template template void ReinforceNormal::serialize( - Archive& /* ar */, const unsigned int /* version */) + Archive& ar, const unsigned int /* version */) { - // Nothing to do here. + ar & BOOST_SERIALIZATION_NVP(stdev); } } // namespace ann diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/reparametrization.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/reparametrization.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/reparametrization.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/reparametrization.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -39,7 +39,8 @@ * Xavier Glorot, Matthew Botvinick, Shakir Mohamed and * Alexander Lerchner | Google DeepMind}, * journal = {2017 International Conference on Learning Representations(ICLR)}, - * year = {2017} + * year = {2017}, + * url = {https://deepmind.com/research/publications/beta-VAE-Learning-Basic-Visual-Concepts-with-a-Constrained-Variational-Framework} * } * @endcode * @@ -79,7 +80,7 @@ * @param output Resulting output activation. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -91,9 +92,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& input, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& input, + const arma::Mat& gy, + arma::Mat& g); //! Get the output parameter. OutputDataType const& OutputParameter() const { return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/reparametrization_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/reparametrization_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/reparametrization_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/reparametrization_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -50,7 +50,7 @@ template template void Reparametrization::Forward( - const arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { if (input.n_rows != 2 * latentSize) { @@ -74,7 +74,7 @@ template template void Reparametrization::Backward( - const arma::Mat&& /* input */, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g) { SoftplusFunction::Deriv(preStdDev, g); diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/select.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/select.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/select.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/select.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -48,7 +48,7 @@ * @param output Resulting output activation. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -60,9 +60,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); //! Get the output parameter. OutputDataType& OutputParameter() const { return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/select_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/select_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/select_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/select_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -31,7 +31,7 @@ template template void Select::Forward( - const arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { if (elements == 0) { @@ -46,9 +46,9 @@ template template void Select::Backward( - const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g) + const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g) { if (elements == 0) { diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/sequential.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/sequential.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/sequential.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/sequential.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -78,6 +78,15 @@ */ Sequential(const bool model = true); + /** + * Create the Sequential object using the specified parameters. + * + * @param model Expose all the network modules. + * @param ownsLayers If true, then this module will delete its layers when + * deallocated. + */ + Sequential(const bool model, const bool ownsLayers); + //! Destroy the Sequential object. ~Sequential(); @@ -89,7 +98,7 @@ * @param output Resulting output activation. */ template - void Forward(arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, using 3rd-order tensors as @@ -101,9 +110,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); /* * Calculate the gradient using the output delta and the input activation. @@ -113,9 +122,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& /* gradient */); + void Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& /* gradient */); /* * Add a new module to the model. @@ -132,11 +141,6 @@ */ void Add(LayerTypes layer) { network.push_back(layer); } - /* - * Destroy all the modules added to the Sequential object. - */ - void DeleteModules(); - //! Return the model modules. std::vector >& Model() { @@ -227,6 +231,9 @@ //! The input height. size_t height; + + //! Whether we are responsible for deleting the layers held in this module. + bool ownsLayers; }; // class Sequential /* @@ -243,6 +250,25 @@ } // namespace ann } // namespace mlpack +//! Set the serialization version of the Sequential class. +namespace boost { +namespace serialization { + +template < + typename InputDataType, + typename OutputDataType, + bool Residual, + typename... CustomLayers +> +struct version> +{ + BOOST_STATIC_CONSTANT(int, value = 1); +}; + +} // namespace serialization +} // namespace boost + // Include implementation. #include "sequential_impl.hpp" diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/sequential_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/sequential_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/sequential_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/sequential_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -27,9 +27,18 @@ template -Sequential< - InputDataType, OutputDataType, Residual, CustomLayers...>::Sequential( - const bool model) : model(model), reset(false), width(0), height(0) +Sequential:: +Sequential(const bool model) : + model(model), reset(false), width(0), height(0), ownsLayers(!model) +{ + // Nothing to do here. +} + +template +Sequential:: +Sequential(const bool model, const bool ownsLayers) : + model(model), reset(false), width(0), height(0), ownsLayers(ownsLayers) { // Nothing to do here. } @@ -39,7 +48,7 @@ Sequential< InputDataType, OutputDataType, Residual, CustomLayers...>::~Sequential() { - if (!model) + if (!model && ownsLayers) { for (LayerTypes& layer : network) boost::apply_visitor(deleteVisitor, layer); @@ -49,12 +58,11 @@ template template -void Sequential< - InputDataType, OutputDataType, Residual, CustomLayers...>::Forward( - arma::Mat&& input, arma::Mat&& output) +void Sequential:: +Forward(const arma::Mat& input, arma::Mat& output) { - boost::apply_visitor(ForwardVisitor(std::move(input), std::move( - boost::apply_visitor(outputParameterVisitor, network.front()))), + boost::apply_visitor(ForwardVisitor(input, + boost::apply_visitor(outputParameterVisitor, network.front())), network.front()); if (!reset) @@ -81,9 +89,9 @@ boost::apply_visitor(SetInputHeightVisitor(height), network[i]); } - boost::apply_visitor(ForwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network[i - 1])), std::move( - boost::apply_visitor(outputParameterVisitor, network[i]))), + boost::apply_visitor(ForwardVisitor(boost::apply_visitor( + outputParameterVisitor, network[i - 1]), + boost::apply_visitor(outputParameterVisitor, network[i])), network[i]); if (!reset) @@ -126,22 +134,22 @@ template void Sequential< InputDataType, OutputDataType, Residual, CustomLayers...>::Backward( - const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g) -{ - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network.back())), std::move(gy), - std::move(boost::apply_visitor(deltaVisitor, network.back()))), + const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g) +{ + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, network.back()), gy, + boost::apply_visitor(deltaVisitor, network.back())), network.back()); for (size_t i = 2; i < network.size() + 1; ++i) { - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network[network.size() - i])), std::move( - boost::apply_visitor(deltaVisitor, network[network.size() - i + 1])), - std::move(boost::apply_visitor(deltaVisitor, - network[network.size() - i]))), network[network.size() - i]); + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, network[network.size() - i]), + boost::apply_visitor(deltaVisitor, network[network.size() - i + 1]), + boost::apply_visitor(deltaVisitor, network[network.size() - i])), + network[network.size() - i]); } g = boost::apply_visitor(deltaVisitor, network.front()); @@ -155,40 +163,25 @@ template template -void Sequential< - InputDataType, OutputDataType, Residual, CustomLayers...>::Gradient( - arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& /* gradient */) +void Sequential:: +Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& /* gradient */) { - boost::apply_visitor(GradientVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network[network.size() - 2])), std::move(error)), + boost::apply_visitor(GradientVisitor(boost::apply_visitor( + outputParameterVisitor, network[network.size() - 2]), error), network.back()); for (size_t i = 2; i < network.size(); ++i) { - boost::apply_visitor(GradientVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, network[network.size() - i - 1])), std::move( - boost::apply_visitor(deltaVisitor, network[network.size() - i + 1]))), + boost::apply_visitor(GradientVisitor(boost::apply_visitor( + outputParameterVisitor, network[network.size() - i - 1]), + boost::apply_visitor(deltaVisitor, network[network.size() - i + 1])), network[network.size() - i]); } - boost::apply_visitor(GradientVisitor(std::move(input), std::move( - boost::apply_visitor(deltaVisitor, network[1]))), network.front()); -} - -template -void Sequential< - InputDataType, OutputDataType, Residual, CustomLayers...>::DeleteModules() -{ - if (model == true) - { - for (LayerTypes& layer : network) - { - boost::apply_visitor(deleteVisitor, layer); - } - } + boost::apply_visitor(GradientVisitor(input, + boost::apply_visitor(deltaVisitor, network[1])), network.front()); } template void Sequential< InputDataType, OutputDataType, Residual, CustomLayers...>::serialize( - Archive& ar, const unsigned int /* version */) + Archive& ar, const unsigned int version) { // If loading, delete the old layers. if (Archive::is_loading::value) @@ -209,6 +202,11 @@ ar & BOOST_SERIALIZATION_NVP(model); ar & BOOST_SERIALIZATION_NVP(network); + + if (version >= 1) + ar & BOOST_SERIALIZATION_NVP(ownsLayers); + else if (Archive::is_loading::value) + ownsLayers = !model; } } // namespace ann diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/softshrink.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/softshrink.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/softshrink.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/softshrink.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,131 @@ +/** + * @file softshrink.hpp + * @author Lakshya Ojha + * + * The soft shrink function has threshold proportional to the noise level given + * by the user. + * The use of a Soft Shrink activation function provides adaptive denoising at + * various noise levels using a single CNN(Convolution Neural) without a + * requirement to train a unique CNN for each noise level. + * + * 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_SOFTSHRINK_HPP +#define MLPACK_METHODS_ANN_LAYER_SOFTSHRINK_HPP + +#include + +namespace mlpack { +namespace ann /** Artifical Neural Network. */ { + +/** + * Soft Shrink operator is defined as, + * @f{eqnarray*}{ + * f(x) &=& \left\{ + * \begin{array}{lr} + * x - lambda & : x > lambda \\ + * x + lambda & : x < -lambda \\ + * 0 & : otherwise + * \end{array} \\ + * \right. + * f'(x) &=& \left\{ + * \begin{array}{lr} + * 1 & : x > lambda \\ + * 1 & : x < -lambda \\ + * 0 & : otherwise + * \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 SoftShrink +{ + public: + /** + * Create Soft Shrink object using specified hyperparameter lambda. + * + * @param lambda The noise level of an image depends on settings of an + * imaging device. The settings can be used to select appropriate + * parameters for denoising methods. It is proportional to the noise + * level entered by the user. + * And it is calculated by multiplying the + * noise level sigma of the input(noisy image) and a + * coefficient 'a' which is one of the training parameters. + * Default value of lambda is 0.5. + */ + SoftShrink(const double lambda = 0.5); + + /** + * 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 Soft Shrink 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 f(x). + * @param gy The backpropagated error. + * @param g The calculated gradient + */ + template + void Backward(const DataType& input, + 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 hyperparameter lambda. + double const& Lambda() const { return lambda; } + //! Modify the hyperparameter lambda. + double& Lambda() { return lambda; } + + /** + * Serialize the layer. + */ + template + void serialize(Archive& ar, const unsigned int /* version */); + + private: + //! Locally-stored delta object. + OutputDataType delta; + + //! Locally-stored output parameter object. + OutputDataType outputParameter; + + //! Locally-stored hyperparamater lambda. + double lambda; +}; // class SoftShrink + +} // namespace ann +} // namespace mlpack + +// Include implementation. +#include "softshrink_impl.hpp" + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/softshrink_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/softshrink_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/softshrink_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/softshrink_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,61 @@ +/** + * @file softshrink.hpp + * @author Lakshya Ojha + * + * Implementation of Soft Shrink activation 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_LAYER_SOFTSHRINK_IMPL_HPP +#define MLPACK_METHODS_ANN_LAYER_SOFTSHRINK_IMPL_HPP + +// In case it hasn't yet been included +#include "softshrink.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +// This constructor is called for Soft Shrink activation function. +// lambda is a hyperparameter. +template +SoftShrink::SoftShrink(const double lambda) : + lambda(lambda) +{ + // Nothing to do here. +} + +template +template +void SoftShrink::Forward( + const InputType& input, OutputType& output) +{ + output = (input > lambda) % (input - lambda) + ( + input < -lambda) % (input + lambda); +} + +template +template +void SoftShrink::Backward( + const DataType& input, DataType& gy, DataType& g) +{ + DataType derivative; + derivative = (arma::ones(arma::size(input)) - (input == 0)); + g = gy % derivative; +} + +template +template +void SoftShrink::serialize( + Archive& ar, + const unsigned int /* version */) +{ + ar & BOOST_SERIALIZATION_NVP(lambda); +} + +} // namespace ann +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/subview.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/subview.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/subview.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/subview.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -66,7 +66,7 @@ * @param output Resulting output activation. */ template - void Forward(InputType&& input, OutputType&& output) + void Forward(const InputType& input, OutputType& output) { size_t batchSize = input.n_cols / inSize; @@ -112,9 +112,9 @@ * @param g The calculated gradient. */ template - void Backward(arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g) + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g) { g = gy; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/transposed_convolution.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/transposed_convolution.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/transposed_convolution.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/transposed_convolution.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -63,29 +63,73 @@ * * @param inSize The number of input maps. * @param outSize The number of output maps. - * @param kW Width of the filter/kernel. - * @param kH Height of the filter/kernel. - * @param dW Stride of filter application in the x direction. - * @param dH Stride of filter application in the y direction. + * @param kernelWidth Width of the filter/kernel. + * @param kernelHeight Height of the filter/kernel. + * @param strideWidth Stride of filter application in the x direction. + * @param strideHeight Stride of filter application in the y direction. * @param padW Padding width of the input. * @param padH Padding height of the input. * @param inputWidth The width of the input data. * @param inputHeight The height of the input data. * @param outputWidth The width of the output data. * @param outputHeight The height of the output data. + * @param paddingType The type of padding (Valid or Same). Defaults to None. */ TransposedConvolution(const size_t inSize, const size_t outSize, - const size_t kW, - const size_t kH, - const size_t dW = 1, - const size_t dH = 1, + const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth = 1, + const size_t strideHeight = 1, const size_t padW = 0, const size_t padH = 0, const size_t inputWidth = 0, const size_t inputHeight = 0, const size_t outputWidth = 0, - const size_t outputHeight = 0); + const size_t outputHeight = 0, + const std::string& paddingType = "None"); + + /** + * Create the Transposed Convolution object using the specified number of + * input maps, output maps, filter size, stride and padding parameter. + * + * Note: The equivalent stride of a transposed convolution operation is always + * equal to 1. In this implementation, stride of filter represents the stride + * of the associated convolution operation. + * Note: Padding of input represents padding of associated convolution + * operation. + * + * @param inSize The number of input maps. + * @param outSize The number of output maps. + * @param kernelWidth Width of the filter/kernel. + * @param kernelHeight Height of the filter/kernel. + * @param strideWidth Stride of filter application in the x direction. + * @param strideHeight Stride of filter application in the y direction. + * @param padW A two-value tuple indicating padding widths of the input. + * First value is padding at left side. Second value is padding on + * right side. + * @param padH A two-value tuple indicating padding heights of the input. + * First value is padding at top. Second value is padding on + * bottom. + * @param inputWidth The width of the input data. + * @param inputHeight The height of the input data. + * @param outputWidth The width of the output data. + * @param outputHeight The height of the output data. + * @param paddingType The type of padding (Valid or Same). Defaults to None. + */ + TransposedConvolution(const size_t inSize, + const size_t outSize, + const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth, + const size_t strideHeight, + const std::tuple& padW, + const std::tuple& padH, + const size_t inputWidth = 0, + const size_t inputHeight = 0, + const size_t outputWidth = 0, + const size_t outputHeight = 0, + const std::string& paddingType = "None"); /* * Set the weight and bias term. @@ -100,7 +144,7 @@ * @param output Resulting output activation. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -112,9 +156,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); /* * Calculate the gradient using the output delta and the input activation. @@ -124,9 +168,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(const arma::Mat&& /* input */, - arma::Mat&& error, - arma::Mat&& gradient); + void Gradient(const arma::Mat& /* input */, + const arma::Mat& error, + arma::Mat& gradient); //! Get the parameters. OutputDataType const& Parameters() const { return weights; } @@ -173,11 +217,57 @@ //! Modify the output height. size_t& OutputHeight() { return outputHeight; } + //! Get the input size. + size_t InputSize() const { return inSize; } + + //! Get the output size. + size_t OutputSize() const { return outSize; } + + //! Get the kernel width. + size_t KernelWidth() const { return kernelWidth; } + //! Modify the kernel width. + size_t& KernelWidth() { return kernelWidth; } + + //! Get the kernel height. + size_t KernelHeight() const { return kernelHeight; } + //! Modify the kernel height. + size_t& KernelHeight() { return kernelHeight; } + + //! Get the stride width. + size_t StrideWidth() const { return strideWidth; } + //! Modify the stride width. + size_t& StrideWidth() { return strideWidth; } + + //! Get the stride height. + size_t StrideHeight() const { return strideHeight; } + //! Modify the stride height. + size_t& StrideHeight() { return strideHeight; } + + //! Get the top padding height. + size_t PadHTop() const { return padHTop; } + //! Modify the top padding height. + size_t& PadHTop() { return padHTop; } + + //! Get the bottom padding height. + size_t PadHBottom() const { return padHBottom; } + //! Modify the bottom padding height. + size_t& PadHBottom() { return padHBottom; } + + //! Get the left padding width. + size_t PadWLeft() const { return padWLeft; } + //! Modify the left padding width. + size_t& PadWLeft() { return padWLeft; } + + //! Get the right padding width. + size_t PadWRight() const { return padWRight; } + //! Modify the right padding width. + size_t& PadWRight() { return padWRight; } + //! Modify the bias weights of the layer. arma::mat& Bias() { return bias; } /** - * Serialize the layer + * Serialize the layer. */ template void serialize(Archive& ar, const unsigned int /* version */); @@ -200,6 +290,11 @@ } /* + * Function to assign padding such that output size is same as input size. + */ + void InitializeSamePadding(); + + /* * Rotates a dense matrix counterclockwise by 180 degrees. * * @param input The input data to be rotated. @@ -212,116 +307,62 @@ output = arma::fliplr(arma::flipud(input)); } - /* - * Pad the given input data. - * - * @param input The input to be padded. - * @param wPad Padding width of the input. - * @param hPad Padding height of the input. - * @param wExtra The number of extra zeros to the right. - * @param hExtra The number of extra zeros to the bottom. - * @param output The padded output data. - */ - template - void Pad(const arma::Mat& input, - const size_t wPad, - const size_t hPad, - const size_t wExtra, - const size_t hExtra, - arma::Mat& output) - { - if (output.n_rows != input.n_rows + wPad * 2 + wExtra || - output.n_cols != input.n_cols + hPad * 2 + hExtra) - { - output = arma::zeros(input.n_rows + wPad * 2 + wExtra, - input.n_cols + hPad * 2 + hExtra); - } - - output.submat(wPad, hPad, wPad + input.n_rows - 1, - hPad + input.n_cols - 1) = input; - } - - /* - * Pad the given input data. - * - * @param input The input to be padded. - * @param wPad Padding width of the input. - * @param hPad Padding height of the input. - * @param wExtra The number of extra zeros to the right. - * @param hExtra The number of extra zeros to the bottom. - * @param output The padded output data. - */ - template - void Pad(const arma::Cube& input, - const size_t wPad, - const size_t hPad, - const size_t wExtra, - const size_t hExtra, - arma::Cube& output) - { - output = arma::zeros(input.n_rows + wPad * 2 + wExtra, - input.n_cols + hPad * 2 + hExtra, input.n_slices); - - for (size_t i = 0; i < input.n_slices; ++i) - { - Pad(input.slice(i), wPad, hPad, wExtra, hExtra, output.slice(i)); - } - } /* * Insert zeros between the units of the given input data. - * Note: This function should be used before the Pad() function. + * Note: This function should be used before using padding layer. * * @param input The input to be padded. - * @param dW Stride of filter application in the x direction. - * @param dH Stride of filter application in the y direction. + * @param strideWidth Stride of filter application in the x direction. + * @param strideHeight Stride of filter application in the y direction. * @param output The padded output data. */ template void InsertZeros(const arma::Mat& input, - const size_t dW, - const size_t dH, + const size_t strideWidth, + const size_t strideHeight, arma::Mat& output) { - if (output.n_rows != input.n_rows * dW - dW + 1 || - output.n_cols != input.n_cols * dH - dH + 1) + if (output.n_rows != input.n_rows * strideWidth - strideWidth + 1 || + output.n_cols != input.n_cols * strideHeight - strideHeight + 1) { - output = arma::zeros(input.n_rows * dW - dW + 1, - input.n_cols * dH - dH + 1); + output = arma::zeros(input.n_rows * strideWidth - strideWidth + 1, + input.n_cols * strideHeight - strideHeight + 1); } - for (size_t i = 0; i < output.n_rows; i += dH) + for (size_t i = 0; i < output.n_rows; i += strideHeight) { - for (size_t j = 0; j < output.n_cols; j += dW) + for (size_t j = 0; j < output.n_cols; j += strideWidth) { // TODO: Use [] instead of () for speedup after this is completely // debugged and approved. - output(i, j) = input(i / dH, j / dW); + output(i, j) = input(i / strideHeight, j / strideWidth); } } } /* * Insert zeros between the units of the given input data. - * Note: This function should be used before the Pad() function. + * Note: This function should be used before using padding layer. * * @param input The input to be padded. - * @param dW Stride of filter application in the x direction. - * @param dH Stride of filter application in the y direction. + * @param strideWidth Stride of filter application in the x direction. + * @param strideHeight Stride of filter application in the y direction. * @param output The padded output data. */ template void InsertZeros(const arma::Cube& input, - const size_t dW, - const size_t dH, + const size_t strideWidth, + const size_t strideHeight, arma::Cube& output) { - output = arma::zeros(input.n_rows * dW - dW + 1, - input.n_cols * dH - dH + 1, input.n_slices); + output = arma::zeros(input.n_rows * strideWidth - strideWidth + 1, + input.n_cols * strideHeight - strideHeight + 1, input.n_slices); for (size_t i = 0; i < input.n_slices; ++i) { - InsertZeros(input.slice(i), dW, dH, output.slice(i)); + InsertZeros(input.slice(i), strideWidth, strideHeight, + output.slice(i)); } } @@ -335,27 +376,33 @@ size_t batchSize; //! Locally-stored filter/kernel width. - size_t kW; + size_t kernelWidth; //! Locally-stored filter/kernel height. - size_t kH; + size_t kernelHeight; //! Locally-stored stride of the filter in x-direction. - size_t dW; + size_t strideWidth; //! Locally-stored stride of the filter in y-direction. - size_t dH; + size_t strideHeight; - //! Locally-stored padding width. - size_t padW; + //! Locally-stored left-side padding width. + size_t padWLeft; - //! Locally-stored padding height. - size_t padH; + //! Locally-stored right-side padding width. + size_t padWRight; + + //! Locally-stored bottom padding height. + size_t padHBottom; + + //! Locally-stored top padding height. + size_t padHTop; //! Locally-stored number of zeros added to the right of input. size_t aW; - //! Locally-stored number of zeros added to the top of input. + //! Locally-stored number of zeros added to the bottom of input. size_t aH; //! Locally-stored weight object. @@ -382,9 +429,6 @@ //! Locally-stored transformed output parameter. arma::cube outputTemp; - //! Locally-stored transformed input parameter. - arma::cube inputTemp; - //! Locally-stored transformed padded input parameter. arma::cube inputPaddedTemp; @@ -397,8 +441,11 @@ //! Locally-stored transformed gradient parameter. arma::cube gradientTemp; - //! Locally-stored padding layer. - Padding<>* padding; + //! Locally-stored padding layer for forward propagation. + ann::Padding<> paddingForward; + + //! Locally-stored padding layer for back propagation. + ann::Padding<> paddingBackward; //! Locally-stored delta object. OutputDataType delta; @@ -416,6 +463,28 @@ } // namespace ann } // namespace mlpack +//! Set the serialization version of the Transposed Convolution class. +namespace boost { +namespace serialization { + +template< + typename ForwardConvolutionRule, + typename BackwardConvolutionRule, + typename GradientConvolutionRule, + typename InputDataType, + typename OutputDataType +> +struct version< + mlpack::ann::TransposedConvolution > +{ + BOOST_STATIC_CONSTANT(int, value = 1); +}; + +} // namespace serialization +} // namespace boost + // Include implementation. #include "transposed_convolution_impl.hpp" diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/transposed_convolution_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/transposed_convolution_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/transposed_convolution_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/transposed_convolution_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -53,43 +53,122 @@ >::TransposedConvolution( const size_t inSize, const size_t outSize, - const size_t kW, - const size_t kH, - const size_t dW, - const size_t dH, + const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth, + const size_t strideHeight, const size_t padW, const size_t padH, const size_t inputWidth, const size_t inputHeight, const size_t outputWidth, - const size_t outputHeight) : + const size_t outputHeight, + const std::string& paddingType) : + TransposedConvolution( + inSize, + outSize, + kernelWidth, + kernelHeight, + strideWidth, + strideHeight, + std::tuple(padW, padW), + std::tuple(padH, padH), + inputWidth, + inputHeight, + outputWidth, + outputHeight, + paddingType) +{ + // Nothing to do here. +} + +template< + typename ForwardConvolutionRule, + typename BackwardConvolutionRule, + typename GradientConvolutionRule, + typename InputDataType, + typename OutputDataType +> +TransposedConvolution< + ForwardConvolutionRule, + BackwardConvolutionRule, + GradientConvolutionRule, + InputDataType, + OutputDataType +>::TransposedConvolution( + const size_t inSize, + const size_t outSize, + const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth, + const size_t strideHeight, + const std::tuple& padW, + const std::tuple& padH, + const size_t inputWidth, + const size_t inputHeight, + const size_t outputWidth, + const size_t outputHeight, + const std::string& paddingType) : inSize(inSize), outSize(outSize), - kW(kW), - kH(kH), - dW(dW), - dH(dH), - padW(kW - padW - 1), - padH(kH - padH - 1), + kernelWidth(kernelWidth), + kernelHeight(kernelHeight), + strideWidth(strideWidth), + strideHeight(strideHeight), + padWLeft(std::get<0>(padW)), + padWRight(std::get<1>(padW)), + padHBottom(std::get<1>(padH)), + padHTop(std::get<0>(padH)), inputWidth(inputWidth), inputHeight(inputHeight), outputWidth(outputWidth), outputHeight(outputHeight) { - weights.set_size((outSize * inSize * kW * kH) + outSize, 1); - // TODO: Use the Padding layer. - // padding = new Padding<>(this->padW, this->padW, this->padH, this->padH); + weights.set_size((outSize * inSize * kernelWidth * kernelHeight) + outSize, + 1); + // Transform paddingType to lowercase. + std::string paddingTypeLow = paddingType; + std::transform(paddingType.begin(), paddingType.end(), paddingTypeLow.begin(), + [](unsigned char c){ return std::tolower(c); }); + + if (paddingTypeLow == "valid") + { + // Set Padding to 0. + padWLeft = 0; + padWRight = 0; + padHTop = 0; + padHBottom = 0; + } + else if (paddingTypeLow == "same") + { + InitializeSamePadding(); + } + + const size_t totalPadWidth = padWLeft + padWRight; + const size_t totalPadHeight = padHTop + padHBottom; - aW = (outputWidth + kW - 2 * this->padW - 2) % dW; - aH = (outputHeight + kH - 2 * this->padH - 2) % dH; + aW = (outputWidth + totalPadWidth - kernelWidth) % strideWidth; + aH = (outputHeight + totalPadHeight - kernelHeight) % strideHeight; + + const size_t padWidthLeftForward = kernelWidth - padWLeft - 1; + const size_t padHeightTopForward = kernelHeight - padHTop - 1; + const size_t padWidthRightForward = kernelWidth - padWRight - 1; + const size_t padHeightBottomtForward = kernelHeight - padHBottom - 1; + + paddingForward = ann::Padding<>(padWidthLeftForward, + padWidthRightForward + aW, padHeightTopForward, + padHeightBottomtForward + aH); + paddingBackward = ann::Padding<>(padWLeft, padWRight, padHTop, padHBottom); // Check if the output height and width are possible given the other // parameters of the layer. - if (outputWidth != dW * (inputWidth - 1) + aW + 2 * this->padW + 2 - kW || - outputHeight != dH * (inputHeight - 1) + aH + 2 * this->padH + 2 - kH) + if (outputWidth != strideWidth * (inputWidth - 1) + + aW + kernelWidth - totalPadWidth || + outputHeight != strideHeight * (inputHeight - 1) + + aH + kernelHeight - totalPadHeight) { Log::Fatal << "The output width / output height is not possible given " - << "the other parameters of the layer." << std::endl; + << "the other parameters of the layer." << std::endl; } } @@ -108,7 +187,7 @@ OutputDataType >::Reset() { - weight = arma::cube(weights.memptr(), kW, kH, + weight = arma::cube(weights.memptr(), kernelWidth, kernelHeight, outSize * inSize, false, false); bias = arma::mat(weights.memptr() + weight.n_elem, outSize, 1, false, false); @@ -128,18 +207,30 @@ GradientConvolutionRule, InputDataType, OutputDataType ->::Forward(const arma::Mat&& input, arma::Mat&& output) +>::Forward(const arma::Mat& input, arma::Mat& output) { batchSize = input.n_cols; - inputTemp = arma::cube(const_cast&&>(input).memptr(), + arma::cube inputTemp(const_cast&>(input).memptr(), inputWidth, inputHeight, inSize * batchSize, false, false); - if (dW > 1 || dH > 1) + if (strideWidth > 1 || strideHeight > 1) { - InsertZeros(inputTemp, dW, dH, inputExpandedTemp); + InsertZeros(inputTemp, strideWidth, strideHeight, inputExpandedTemp); + + if (paddingForward.PadWLeft() != 0 || paddingForward.PadWRight() != 0 || + paddingForward.PadHTop() != 0 || paddingForward.PadHBottom() != 0) + { + inputPaddedTemp.set_size(inputExpandedTemp.n_rows + + paddingForward.PadWLeft() + paddingForward.PadWRight(), + inputExpandedTemp.n_cols + paddingForward.PadHTop() + + paddingForward.PadHBottom(), inputExpandedTemp.n_slices); - if (padW != 0 || padH != 0 || aW != 0 || aH != 0) - Pad(inputExpandedTemp, padW, padH, aW, aH, inputPaddedTemp); + for (size_t i = 0; i < inputExpandedTemp.n_slices; ++i) + { + paddingForward.Forward(inputExpandedTemp.slice(i), + inputPaddedTemp.slice(i)); + } + } else { inputPaddedTemp = arma::Cube(inputExpandedTemp.memptr(), @@ -147,9 +238,20 @@ inputExpandedTemp.n_slices, false, false);; } } - else if (padW != 0 || padH != 0 || aW != 0 || aH != 0) + else if (paddingForward.PadWLeft() != 0 || + paddingForward.PadWRight() != 0 || + paddingForward.PadHTop() != 0 || + paddingForward.PadHBottom() != 0) { - Pad(inputTemp, padW, padH, aW, aH, inputPaddedTemp); + inputPaddedTemp.set_size(inputTemp.n_rows + paddingForward.PadWLeft() + + paddingForward.PadWRight(), inputTemp.n_cols + + paddingForward.PadHTop() + paddingForward.PadHBottom(), + inputTemp.n_slices); + + for (size_t i = 0; i < inputTemp.n_slices; ++i) + { + paddingForward.Forward(inputTemp.slice(i), inputPaddedTemp.slice(i)); + } } output.set_size(outputWidth * outputHeight * outSize, batchSize); @@ -171,7 +273,12 @@ arma::Mat convOutput, rotatedFilter; Rotate180(weight.slice(outMapIdx), rotatedFilter); - if (dW > 1 || dH > 1 || padW != 0 || padH != 0 || aW != 0 || aH != 0) + if (strideWidth > 1 || + strideHeight > 1 || + paddingForward.PadWLeft() != 0 || + paddingForward.PadWRight() != 0 || + paddingForward.PadHTop() != 0 || + paddingForward.PadHBottom() != 0) { ForwardConvolutionRule::Convolution(inputPaddedTemp.slice(inMap + batchCount * inSize), rotatedFilter, convOutput, 1, 1); @@ -204,18 +311,28 @@ InputDataType, OutputDataType >::Backward( - const arma::Mat&& /* input */, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g) { - arma::Cube mappedError(gy.memptr(), outputWidth, outputHeight, - outSize * batchSize, false, false); - + arma::Cube mappedError(((arma::Mat&) gy).memptr(), outputWidth, + outputHeight, outSize * batchSize, false, false); arma::Cube mappedErrorPadded; - if ((int)(kW - padW - 1) > 0 || (int)(kH - padH - 1) > 0) - Pad(mappedError, kW - padW - 1, kH - padH - 1, 0, 0, mappedErrorPadded); + if (paddingBackward.PadWLeft() != 0 || paddingBackward.PadWRight() != 0 || + paddingBackward.PadHTop() != 0 || paddingBackward.PadHBottom() != 0) + { + mappedErrorPadded.set_size(mappedError.n_rows + + paddingBackward.PadWLeft() + paddingBackward.PadWRight(), + mappedError.n_cols + paddingBackward.PadHTop() + + paddingBackward.PadHBottom(), mappedError.n_slices); - g.set_size(inputTemp.n_rows * inputTemp.n_cols * inSize, batchSize); - gTemp = arma::Cube(g.memptr(), inputTemp.n_rows, - inputTemp.n_cols, inputTemp.n_slices, false, false); + for (size_t i = 0; i < mappedError.n_slices; ++i) + { + paddingBackward.Forward(mappedError.slice(i), + mappedErrorPadded.slice(i)); + } + } + g.set_size(inputWidth * inputHeight * inSize, batchSize); + gTemp = arma::Cube(g.memptr(), inputWidth, inputHeight, inSize * + batchSize, false, false); gTemp.zeros(); @@ -232,15 +349,16 @@ { arma::Mat output; - if ((int)(kW - padW - 1) > 0 || (int)(kH - padH - 1) > 0) + if (paddingBackward.PadWLeft() != 0 || paddingBackward.PadWRight() != 0 || + paddingBackward.PadHTop() != 0 || paddingBackward.PadHBottom() != 0) { BackwardConvolutionRule::Convolution(mappedErrorPadded.slice(outMap), - weight.slice(outMapIdx), output, dW, dH); + weight.slice(outMapIdx), output, strideWidth, strideHeight); } else { BackwardConvolutionRule::Convolution(mappedError.slice(outMap), - weight.slice(outMapIdx), output, dW, dH); + weight.slice(outMapIdx), output, strideWidth, strideHeight); } gTemp.slice(inMap + batchCount * inSize) += output; @@ -263,12 +381,14 @@ InputDataType, OutputDataType >::Gradient( - const arma::Mat&& /* input */, - arma::Mat&& error, - arma::Mat&& gradient) + const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient) { - arma::Cube mappedError(error.memptr(), outputWidth, + arma::Cube mappedError(((arma::Mat&) error).memptr(), outputWidth, outputHeight, outSize * batchSize, false, false); + arma::cube inputTemp(const_cast&>(input).memptr(), + inputWidth, inputHeight, inSize * batchSize, false, false); gradient.set_size(weights.n_elem, 1); gradientTemp = arma::Cube(gradient.memptr(), weight.n_rows, @@ -290,7 +410,12 @@ for (size_t inMap = 0; inMap < inSize; inMap++, outMapIdx++) { - if (dW > 1 || dH > 1 || padW != 0 || padH != 0 || aW != 0 || aH != 0) + if (strideWidth > 1 || + strideHeight > 1 || + paddingForward.PadWLeft() != 0 || + paddingForward.PadWRight() != 0 || + paddingForward.PadHTop() != 0 || + paddingForward.PadHBottom() != 0) { inputSlice = inputPaddedTemp.slice(inMap + batchCount * inSize); } @@ -325,28 +450,84 @@ InputDataType, OutputDataType >::serialize( - Archive& ar, const unsigned int /* version */) + Archive& ar, const unsigned int version) { ar & BOOST_SERIALIZATION_NVP(inSize); ar & BOOST_SERIALIZATION_NVP(outSize); ar & BOOST_SERIALIZATION_NVP(batchSize); - ar & BOOST_SERIALIZATION_NVP(kW); - ar & BOOST_SERIALIZATION_NVP(kH); - ar & BOOST_SERIALIZATION_NVP(dW); - ar & BOOST_SERIALIZATION_NVP(dH); - ar & BOOST_SERIALIZATION_NVP(padW); - ar & BOOST_SERIALIZATION_NVP(padH); + ar & BOOST_SERIALIZATION_NVP(kernelWidth); + ar & BOOST_SERIALIZATION_NVP(kernelHeight); + ar & BOOST_SERIALIZATION_NVP(strideWidth); + ar & BOOST_SERIALIZATION_NVP(strideHeight); + if (version == 0) + { + // These are now stored in paddingForward and paddingBackward. + size_t padWidth, padHeight; + ar & BOOST_SERIALIZATION_NVP(padWidth); + ar & BOOST_SERIALIZATION_NVP(padHeight); + } + ar &BOOST_SERIALIZATION_NVP(padWLeft); + ar &BOOST_SERIALIZATION_NVP(padWRight); + ar &BOOST_SERIALIZATION_NVP(padHBottom); + ar &BOOST_SERIALIZATION_NVP(padHTop); ar & BOOST_SERIALIZATION_NVP(inputWidth); ar & BOOST_SERIALIZATION_NVP(inputHeight); ar & BOOST_SERIALIZATION_NVP(outputWidth); ar & BOOST_SERIALIZATION_NVP(outputHeight); + if (version > 0) + { + ar & BOOST_SERIALIZATION_NVP(paddingForward); + ar & BOOST_SERIALIZATION_NVP(paddingBackward); + } + if (Archive::is_loading::value) { - weights.set_size((outSize * inSize * kW * kH) + outSize, 1); + weights.set_size((outSize * inSize * kernelWidth * kernelHeight) + outSize, + 1); + size_t totalPadWidth = padWLeft + padWRight; + size_t totalPadHeight = padHTop + padHBottom; + aW = (outputWidth + kernelWidth - totalPadWidth - 2) % strideWidth; + aH = (outputHeight + kernelHeight - totalPadHeight - 2) % strideHeight; + } +} +template< + typename ForwardConvolutionRule, + typename BackwardConvolutionRule, + typename GradientConvolutionRule, + typename InputDataType, + typename OutputDataType +> +void TransposedConvolution< + ForwardConvolutionRule, + BackwardConvolutionRule, + GradientConvolutionRule, + InputDataType, + OutputDataType +>::InitializeSamePadding(){ + /** + * Using O=s*(I-1) + K -2P + A + * where + * s=stride + * I=Input Shape + * K=Kernel Size + * P=Padding + */ + const size_t totalHorizontalPadding = (strideWidth - 1) * inputWidth + + kernelWidth - strideWidth; + const size_t totalVerticalPadding = (strideHeight - 1) * inputHeight + + kernelHeight - strideHeight; + + padWLeft = totalVerticalPadding / 2; + padWRight = totalVerticalPadding - totalVerticalPadding / 2; + padHTop = totalHorizontalPadding / 2; + padHBottom = totalHorizontalPadding - totalHorizontalPadding / 2; - aW = (outputWidth + kW - 2 * padW - 2) % dW; - aH = (outputHeight + kH - 2 * padH - 2) % dH; + // If Padding is negative throw a fatal error. + if (totalHorizontalPadding < 0 || totalVerticalPadding < 0) + { + Log::Fatal << "The output width / output height is not possible given " + << "same padding for the layer." << std::endl; } } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/virtual_batch_norm.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/virtual_batch_norm.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/virtual_batch_norm.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/virtual_batch_norm.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -76,7 +76,7 @@ * @param output Resulting output activations. */ template - void Forward(const arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Backward pass through the layer. @@ -86,9 +86,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& /* input */, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); /** * Calculate the gradient using the output delta and the input activations. @@ -98,9 +98,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(const arma::Mat&& /* input */, - arma::Mat&& error, - arma::Mat&& gradient); + void Gradient(const arma::Mat& /* input */, + const arma::Mat& error, + arma::Mat& gradient); //! Get the parameters. OutputDataType const& Parameters() const { return weights; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/virtual_batch_norm_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/virtual_batch_norm_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/virtual_batch_norm_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/virtual_batch_norm_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -65,7 +65,7 @@ template template void VirtualBatchNorm::Forward( - const arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { inputParameter = input; arma::mat inputMean = arma::mean(input, 1); @@ -90,7 +90,7 @@ template template void VirtualBatchNorm::Backward( - const arma::Mat&& /* input */, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g) { const arma::mat stdInv = 1.0 / arma::sqrt(variance + eps); @@ -115,9 +115,9 @@ template template void VirtualBatchNorm::Gradient( - const arma::Mat&& /* input */, - arma::Mat&& error, - arma::Mat&& gradient) + const arma::Mat& /* input */, + const arma::Mat& error, + arma::Mat& gradient) { gradient.set_size(size + size, 1); diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/vr_class_reward.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/vr_class_reward.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/vr_class_reward.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/vr_class_reward.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -55,7 +55,7 @@ * between 1 and the number of classes. */ template - double Forward(const InputType&& input, const TargetType&& target); + double Forward(const InputType& input, const TargetType& target); /** * Ordinary feed backward pass of a neural network. The negative log @@ -69,9 +69,9 @@ * @param output The calculated error. */ template - void Backward(const InputType&& input, - const TargetType&& target, - OutputType&& output); + void Backward(const InputType& input, + const TargetType& target, + OutputType& output); //! Get the output parameter. OutputDataType& OutputParameter() const {return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/vr_class_reward_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/vr_class_reward_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/vr_class_reward_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/vr_class_reward_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -34,7 +34,7 @@ template template double VRClassReward::Forward( - const InputType&& input, const TargetType&& target) + const InputType& input, const TargetType& target) { double output = 0; for (size_t i = 0; i < input.n_cols - 1; ++i) @@ -66,9 +66,9 @@ template template void VRClassReward::Backward( - const InputType&& input, - const TargetType&& target, - OutputType&& output) + const InputType& input, + const TargetType& target, + OutputType& output) { output = arma::zeros(input.n_rows, input.n_cols); for (size_t i = 0; i < (input.n_cols - 1); ++i) diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/weight_norm.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/weight_norm.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/weight_norm.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/weight_norm.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -42,7 +42,8 @@ * Training of Deep Neural Networks}, * author = {Tim Salimans, Diederik P. Kingma}, * booktitle = {Neural Information Processing Systems 2016}, - * year = {2016} + * year = {2016}, + * url = {https://arxiv.org/abs/1602.07868}, * } * @endcode * @@ -85,7 +86,7 @@ * @param output Resulting output activations. */ template - void Forward(arma::Mat&& input, arma::Mat&& output); + void Forward(const arma::Mat& input, arma::Mat& output); /** * Backward pass through the layer. This function calls the Backward() @@ -96,9 +97,9 @@ * @param g The calculated gradient. */ template - void Backward(const arma::Mat&& input, - arma::Mat&& gy, - arma::Mat&& g); + void Backward(const arma::Mat& input, + const arma::Mat& gy, + arma::Mat& g); /** * Calculate the gradient using the output delta, input activations and the @@ -109,9 +110,9 @@ * @param gradient The calculated gradient. */ template - void Gradient(arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient); + void Gradient(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient); //! Get the delta. OutputDataType const& Delta() const { return delta; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/layer/weight_norm_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/layer/weight_norm_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/layer/weight_norm_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/layer/weight_norm_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -50,13 +50,12 @@ { // Set the weights of the inside layer to layerWeights. // This is done to set the non-bias terms correctly. - boost::apply_visitor(WeightSetVisitor(std::move(layerWeights), 0), - wrappedLayer); + boost::apply_visitor(WeightSetVisitor(layerWeights, 0), wrappedLayer); boost::apply_visitor(resetVisitor, wrappedLayer); - biasWeightSize = boost::apply_visitor(BiasSetVisitor(std::move(weights), - 0), wrappedLayer); + biasWeightSize = boost::apply_visitor(BiasSetVisitor(weights, 0), + wrappedLayer); vectorParameter = arma::mat(weights.memptr() + biasWeightSize, layerWeightSize - biasWeightSize, 1, false, false); @@ -69,15 +68,15 @@ typename... CustomLayers> template void WeightNorm::Forward( - arma::Mat&& input, arma::Mat&& output) + const arma::Mat& input, arma::Mat& output) { // Initialize the non-bias weights of wrapped layer. const double normVectorParameter = arma::norm(vectorParameter, 2); layerWeights.rows(0, layerWeightSize - biasWeightSize - 1) = scalarParameter(0) * vectorParameter / normVectorParameter; - boost::apply_visitor(ForwardVisitor(std::move(input), std::move( - boost::apply_visitor(outputParameterVisitor, wrappedLayer))), + boost::apply_visitor(ForwardVisitor(input, + boost::apply_visitor(outputParameterVisitor, wrappedLayer)), wrappedLayer); output = boost::apply_visitor(outputParameterVisitor, wrappedLayer); @@ -87,11 +86,11 @@ typename... CustomLayers> template void WeightNorm::Backward( - const arma::Mat&& /* input */, arma::Mat&& gy, arma::Mat&& g) + const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g) { - boost::apply_visitor(BackwardVisitor(std::move(boost::apply_visitor( - outputParameterVisitor, wrappedLayer)), std::move(gy), std::move( - boost::apply_visitor(deltaVisitor, wrappedLayer))), wrappedLayer); + boost::apply_visitor(BackwardVisitor(boost::apply_visitor( + outputParameterVisitor, wrappedLayer), gy, + boost::apply_visitor(deltaVisitor, wrappedLayer)), wrappedLayer); g = boost::apply_visitor(deltaVisitor, wrappedLayer); } @@ -100,15 +99,14 @@ typename... CustomLayers> template void WeightNorm::Gradient( - arma::Mat&& input, - arma::Mat&& error, - arma::Mat&& gradient) + const arma::Mat& input, + const arma::Mat& error, + arma::Mat& gradient) { ResetGradients(layerGradients); // Calculate the gradients of the wrapped layer. - boost::apply_visitor(GradientVisitor(std::move(input), - std::move(error)), wrappedLayer); + boost::apply_visitor(GradientVisitor(input, error), wrappedLayer); // Store the norm of vector parameter temporarily. const double normVectorParameter = arma::norm(vectorParameter, 2); @@ -137,8 +135,7 @@ void WeightNorm::ResetGradients( arma::mat& gradient) { - boost::apply_visitor(GradientSetVisitor(std::move(gradient), 0), - wrappedLayer); + boost::apply_visitor(GradientSetVisitor(gradient, 0), wrappedLayer); } template* /*layer*/) const + { + return "lstm"; + } + + /** + * Return the name of the given layer of type CReLU as a string. + * + * @param Given layer of type CReLU. + * @return The string representation of the layer. + */ + std::string LayerString(CReLU<>* /*layer*/) const + { + return "crelu"; + } + + /** + * Return the name of the given layer of type Highway as a string. + * + * @param Given layer of type Highway. + * @return The string representation of the layer. + */ + std::string LayerString(Highway<>* /*layer*/) const + { + return "highway"; + } + + /** + * Return the name of the given layer of type GRU as a string. + * + * @param Given layer of type GRU. + * @return The string representation of the layer. + */ + std::string LayerString(GRU<>* /*layer*/) const + { + return "gru"; + } + + /** + * Return the name of the given layer of type Glimpse as a string. + * + * @param Given layer of type Glimpse. + * @return The string representation of the layer. + */ + std::string LayerString(Glimpse<>* /*layer*/) const + { + return "glimpse"; + } + + /** + * Return the name of the given layer of type FastLSTM as a string. + * + * @param Given layer of type FastLSTM. + * @return The string representation of the layer. + */ + std::string LayerString(FastLSTM<>* /*layer*/) const + { + return "fastlstm"; + } + + /** + * Return the name of the given layer of type WeightNorm as a string. + * + * @param Given layer of type WeightNorm. + * @return The string representation of the layer. + */ + std::string LayerString(WeightNorm<>* /*layer*/) const + { + return "weightnorm"; + } + + /** * Return the name of the layer of specified type as a string. * * @param Given layer of any type. diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -3,20 +3,34 @@ set(SOURCES cross_entropy_error.hpp cross_entropy_error_impl.hpp + cosine_embedding_loss.hpp + cosine_embedding_loss_impl.hpp dice_loss.hpp dice_loss_impl.hpp earth_mover_distance.hpp earth_mover_distance_impl.hpp + huber_loss.hpp + huber_loss_impl.hpp kl_divergence.hpp kl_divergence_impl.hpp + margin_ranking_loss.hpp + margin_ranking_loss_impl.hpp + mean_bias_error.hpp + mean_bias_error_impl.hpp mean_squared_error.hpp mean_squared_error_impl.hpp + mean_squared_logarithmic_error.hpp + mean_squared_logarithmic_error_impl.hpp negative_log_likelihood.hpp negative_log_likelihood_impl.hpp + log_cosh_loss.hpp + log_cosh_loss_impl.hpp reconstruction_loss.hpp reconstruction_loss_impl.hpp sigmoid_cross_entropy_error.hpp sigmoid_cross_entropy_error_impl.hpp + hinge_embedding_loss.hpp + hinge_embedding_loss_impl.hpp ) # Add directory name to sources. diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/cosine_embedding_loss.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/cosine_embedding_loss.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/cosine_embedding_loss.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/cosine_embedding_loss.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,141 @@ +/** + * @file cosine_embedding_loss.hpp + * @author Kartik Dutt + * + * Definition of the Cosine Embedding 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_COSINE_EMBEDDING_HPP +#define MLPACK_METHODS_ANN_LOSS_FUNCTION_COSINE_EMBEDDING_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * Cosine Embedding Loss function is used for measuring whether two inputs are + * similar or dissimilar, using the cosine distance, and is typically used + * for learning nonlinear embeddings or semi-supervised learning. + * + * @f{eqnarray*}{ + * f(x) = 1 - cos(x1, x2) , for y = 1 + * f(x) = max(0, cos(x1, x2) - margin) , for y = -1 + * @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 CosineEmbeddingLoss +{ + public: + /** + * Create the CosineEmbeddingLoss object. + * + * @param margin Increases cosine distance in case of dissimilarity. + * Refer definition of cosine-embedding-loss above. + * @param similarity Determines whether to use similarity or dissimilarity for + * comparision. + * @param takeMean Boolean variable to specify whether to take mean or not. + * Specifies reduction method i.e. sum or mean corresponding + * to 0 and 1 respectively. Default value = 0. + */ + CosineEmbeddingLoss(const double margin = 0.0, + const bool similarity = true, + const bool takeMean = false); + + /** + * Ordinary feed forward pass of a neural network. + * + * @param input Input data used for evaluating the specified function. + * @param target The target vector. + */ + 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 input parameter. + InputDataType& InputParameter() const { return inputParameter; } + //! Modify the input parameter. + InputDataType& InputParameter() { return inputParameter; } + + //! Get the output parameter. + OutputDataType& OutputParameter() const { return outputParameter; } + //! Modify the output parameter. + OutputDataType& OutputParameter() { return outputParameter; } + + //! Get the delta. + OutputDataType& Delta() const { return delta; } + //! Modify the delta. + OutputDataType& Delta() { return delta; } + + //! Get the value of takeMean. + bool TakeMean() const { return takeMean; } + //! Modify the value of takeMean. + bool& TakeMean() { return takeMean; } + + //! Get the value of margin. + double Margin() const { return margin; } + //! Modify the value of takeMean. + double& Margin() { return margin; } + + //! Get the value of similarity hyperparameter. + bool Similarity() const { return similarity; } + //! Modify the value of takeMean. + bool& Similarity() { return similarity; } + + /** + * Serialize the layer. + */ + template + void serialize(Archive& ar, const unsigned int /* version */); + + private: + //! Locally-stored delta object. + OutputDataType delta; + + //! Locally-stored input parameter object. + InputDataType inputParameter; + + //! Locally-stored output parameter object. + OutputDataType outputParameter; + + //! Locally-stored value of similarity hyper-parameter. + bool similarity; + + //! Locally-stored value of margin hyper-parameter. + double margin; + + //! Locally-stored value of takeMean hyper-parameter. + bool takeMean; +}; // class CosineEmbeddingLoss + +} // namespace ann +} // namespace mlpack + +// Include implementation. +#include "cosine_embedding_loss_impl.hpp" + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/cosine_embedding_loss_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/cosine_embedding_loss_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/cosine_embedding_loss_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/cosine_embedding_loss_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,120 @@ +/** + * @file cosine_embedding_loss_impl.hpp + * @author Kartik Dutt + * + * Implementation of the Cosine Embedding 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_COSINE_EMBEDDING_IMPL_HPP +#define MLPACK_METHODS_ANN_LOSS_FUNCTION_COSINE_EMBEDDING_IMPL_HPP + +// In case it hasn't yet been included. +#include "cosine_embedding_loss.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +CosineEmbeddingLoss::CosineEmbeddingLoss( + const double margin, const bool similarity, const bool takeMean): + margin(margin), similarity(similarity), takeMean(takeMean) +{ + // Nothing to do here. +} + +template +template +typename InputType::elem_type +CosineEmbeddingLoss::Forward( + const InputType& input, + const TargetType& target) +{ + typedef typename InputType::elem_type ElemType; + + const size_t cols = input.n_cols; + const size_t batchSize = input.n_elem / cols; + if (arma::size(input) != arma::size(target)) + Log::Fatal << "Input Tensors must have same dimensions." << std::endl; + + arma::colvec inputTemp1 = arma::vectorise(input); + arma::colvec inputTemp2 = arma::vectorise(target); + ElemType loss = 0.0; + + for (size_t i = 0; i < inputTemp1.n_elem; i += cols) + { + const ElemType cosDist = kernel::CosineDistance::Evaluate( + inputTemp1(arma::span(i, i + cols - 1)), inputTemp2(arma::span(i, + i + cols - 1))); + if (similarity) + loss += 1 - cosDist; + else + { + const ElemType currentLoss = cosDist - margin; + loss += currentLoss > 0 ? currentLoss : 0; + } + } + + if (takeMean) + loss = (ElemType) loss / batchSize; + + return loss; +} + +template +template +void CosineEmbeddingLoss::Backward( + const InputType& input, + const TargetType& target, + OutputType& output) +{ + typedef typename InputType::elem_type ElemType; + + const size_t cols = input.n_cols; + const size_t batchSize = input.n_elem / cols; + if (arma::size(input) != arma::size(target)) + Log::Fatal << "Input Tensors must have same dimensions." << std::endl; + + arma::colvec inputTemp1 = arma::vectorise(input); + arma::colvec inputTemp2 = arma::vectorise(target); + output.set_size(arma::size(inputTemp1)); + + arma::colvec outputTemp(output.memptr(), inputTemp1.n_elem, + false, false); + for (size_t i = 0; i < inputTemp1.n_elem; i += cols) + { + const ElemType cosDist = kernel::CosineDistance::Evaluate(inputTemp1( + arma::span(i, i + cols -1)), inputTemp2(arma::span(i, i + cols -1))); + + if (cosDist < margin && !similarity) + outputTemp(arma::span(i, i + cols - 1)).zeros(); + else + { + const int multiplier = similarity ? 1 : -1; + outputTemp(arma::span(i, i + cols -1)) = -1 * multiplier * + (arma::normalise(inputTemp2(arma::span(i, i + cols - 1))) - + cosDist * arma::normalise(inputTemp1(arma::span(i, i + cols - + 1)))) / std::sqrt(arma::accu(arma::pow(inputTemp1(arma::span(i, i + + cols - 1)), 2))); + } + } +} + +template +template +void CosineEmbeddingLoss::serialize( + Archive& ar , + const unsigned int /* version */) +{ + ar & BOOST_SERIALIZATION_NVP(margin); + ar & BOOST_SERIALIZATION_NVP(similarity); + ar & BOOST_SERIALIZATION_NVP(takeMean); +} + +} // namespace ann +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/cross_entropy_error.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/cross_entropy_error.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/cross_entropy_error.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/cross_entropy_error.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -49,7 +49,8 @@ * @param target The target vector. */ template - double Forward(const InputType&& input, const TargetType&& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. @@ -59,9 +60,9 @@ * @param output The calculated error. */ template - void Backward(const InputType&& input, - const TargetType&& target, - OutputType&& output); + void Backward(const InputType& input, + const TargetType& target, + OutputType& output); //! Get the output parameter. OutputDataType& OutputParameter() const { return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/cross_entropy_error_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/cross_entropy_error_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/cross_entropy_error_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/cross_entropy_error_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -27,8 +27,10 @@ template template -double CrossEntropyError::Forward( - const InputType&& input, const TargetType&& target) +typename InputType::elem_type +CrossEntropyError::Forward( + const InputType& input, + const TargetType& target) { return -arma::accu(target % arma::log(input + eps) + (1. - target) % arma::log(1. - input + eps)); @@ -37,9 +39,9 @@ template template void CrossEntropyError::Backward( - const InputType&& input, - const TargetType&& target, - OutputType&& output) + const InputType& input, + const TargetType& target, + OutputType& output) { output = (1. - target) / (1. - input + eps) - target / (input + eps); } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/dice_loss.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/dice_loss.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/dice_loss.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/dice_loss.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -62,7 +62,8 @@ * @param target The target vector. */ template - double Forward(const InputType&& input, const TargetType&& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. @@ -72,9 +73,9 @@ * @param output The calculated error. */ template - void Backward(const InputType&& input, - const TargetType&& target, - OutputType&& output); + void Backward(const InputType& input, + const TargetType& target, + OutputType& output); //! Get the output parameter. OutputDataType& OutputParameter() const { return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/dice_loss_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/dice_loss_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/dice_loss_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/dice_loss_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -27,8 +27,9 @@ template template -double DiceLoss::Forward( - const InputType&& input, const TargetType&& target) +typename InputType::elem_type DiceLoss::Forward( + const InputType& input, + const TargetType& target) { return 1 - ((2 * arma::accu(target % input) + smooth) / (arma::accu(target % target) + arma::accu( @@ -38,9 +39,9 @@ template template void DiceLoss::Backward( - const InputType&& input, - const TargetType&& target, - OutputType&& output) + const InputType& input, + const TargetType& target, + OutputType& output) { output = -2 * (target * (arma::accu(input % input) + arma::accu(target % target) + smooth) - input * diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/earth_mover_distance.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/earth_mover_distance.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/earth_mover_distance.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/earth_mover_distance.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -45,7 +45,8 @@ * @param target The target vector. */ template - double Forward(const InputType&& input, const TargetType&& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. @@ -55,9 +56,9 @@ * @param output The calculated error. */ template - void Backward(const InputType&& input, - const TargetType&& target, - OutputType&& output); + void Backward(const InputType& input, + const TargetType& target, + OutputType& output); //! Get the output parameter. OutputDataType& OutputParameter() const { return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/earth_mover_distance_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/earth_mover_distance_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/earth_mover_distance_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/earth_mover_distance_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -26,8 +26,10 @@ template template -double EarthMoverDistance::Forward( - const InputType&& input, const TargetType&& target) +typename InputType::elem_type +EarthMoverDistance::Forward( + const InputType& input, + const TargetType& target) { return -arma::accu(target % input); } @@ -35,9 +37,9 @@ template template void EarthMoverDistance::Backward( - const InputType&& /* input */, - const TargetType&& target, - OutputType&& output) + const InputType& /* input */, + const TargetType& target, + OutputType& output) { output = -target; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/hinge_embedding_loss.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/hinge_embedding_loss.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/hinge_embedding_loss.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/hinge_embedding_loss.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,88 @@ +/** + * @file hinge_embedding_loss.hpp + * @author Lakshya Ojha + * + * Definition of the Hinge Embedding Loss Function. + * The Hinge Embedding loss function is often used to improve performance + * in semi-supervised learning or to learn nonlinear embeddings. + * + * 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_HINGE_EMBEDDING_LOSS_HPP +#define MLPACK_METHODS_ANN_LOSS_FUNCTION_HINGE_EMBEDDING_LOSS_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * The Hinge Embedding loss function is often used to compute the loss + * between y_true and y_pred. + * + * @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 HingeEmbeddingLoss +{ + public: + /** + * Create the Hinge Embedding object. + */ + HingeEmbeddingLoss(); + + /** + * Computes the Hinge Embedding loss function. + * + * @param input Input data used for evaluating the specified function. + * @param target Target data to compare with. + */ + 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; } + + /** + * Serialize the loss function. + */ + template + void serialize(Archive& ar, const unsigned int /* version */); + + private: + //! Locally-stored output parameter object. + OutputDataType outputParameter; +}; // class HingeEmbeddingLoss + +} // namespace ann +} // namespace mlpack + +// include implementation +#include "hinge_embedding_loss_impl.hpp" + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/hinge_embedding_loss_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/hinge_embedding_loss_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/hinge_embedding_loss_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/hinge_embedding_loss_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,62 @@ +/** + * @file hinge_embedding_loss_impl.hpp + * @author Lakshya Ojha + * + * Implementation of the Hinge Embedding 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_HINGE_EMBEDDING_LOSS_IMPL_HPP +#define MLPACK_METHODS_ANN_LOSS_FUNCTION_HINGE_EMBEDDING_LOSS_IMPL_HPP + +// In case it hasn't yet been included. +#include "hinge_embedding_loss.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +HingeEmbeddingLoss::HingeEmbeddingLoss() +{ + // Nothing to do here. +} + +template +template +typename InputType::elem_type +HingeEmbeddingLoss::Forward( + const InputType& input, + const TargetType& target) +{ + TargetType temp = target - (target == 0); + return (arma::accu(arma::max(1-input % temp, 0.))) / target.n_elem; +} + +template +template +void HingeEmbeddingLoss::Backward( + const InputType& input, + const TargetType& target, + OutputType& output) +{ + TargetType temp = target - (target == 0); + output = (input < 1 / temp) % -temp; +} + +template +template +void HingeEmbeddingLoss::serialize( + Archive& /* ar */, + const unsigned int /* version */) +{ + // Nothing to do here. +} + +} // namespace ann +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/huber_loss.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/huber_loss.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/huber_loss.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/huber_loss.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,108 @@ +/** + * @file huber_loss.hpp + * @author Mrityunjay Tripathi + * + * Definition of the Huber 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_HUBER_LOSS_HPP +#define MLPACK_METHODS_ANN_LOSS_FUNCTION_HUBER_LOSS_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * The Huber loss is a loss function used in robust regression, + * that is less sensitive to outliers in data than the squared error loss. + * This function is quadratic for small values of \f$ y - f(x) \f$, + * and linear for large values, with equal values and slopes of the different + * sections at the two points where \f$ |y - f(x)| = delta \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 HuberLoss +{ + public: + /** + * Create the HuberLoss object. + * + * @param delta The threshold value upto which squared error is followed and + * after which absolute error is considered. + * @param mean If true then mean loss is computed otherwise sum. + */ + HuberLoss(const double delta = 1.0, const bool mean = true); + + /** + * Computes the Huber Loss function. + * + * @param input Input data used for evaluating the specified function. + * @param target The target vector. + */ + 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 value of delta. + double Delta() const { return delta; } + //! Set the value of delta. + double& Delta() { return delta; } + + //! Get the value of reduction type. + bool Mean() const { return mean; } + //! Set the value of reduction type. + bool& Mean() { return mean; } + + /** + * Serialize the layer. + */ + template + void serialize(Archive& ar, const unsigned int /* version */); + + private: + //! Locally-stored output parameter object. + OutputDataType outputParameter; + + //! Hyperparameter `delta` defines the point upto which MSE is considered. + double delta; + + //! Reduction type. If true, performs mean of loss else sum. + bool mean; +}; // class HuberLoss + +} // namespace ann +} // namespace mlpack + +// Include implementation. +#include "huber_loss_impl.hpp" + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/huber_loss_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/huber_loss_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/huber_loss_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/huber_loss_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,81 @@ +/** + * @file huber_loss_impl.hpp + * @author Mrityunjay Tripathi + * + * Implementation of the Huber 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_HUBER_LOSS_IMPL_HPP +#define MLPACK_METHODS_ANN_LOSS_FUNCTION_HUBER_LOSS_IMPL_HPP + +// In case it hasn't yet been included. +#include "huber_loss.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +HuberLoss::HuberLoss( + const double delta, + const bool mean): + delta(delta), + mean(mean) +{ + // Nothing to do here. +} + +template +template +typename InputType::elem_type +HuberLoss::Forward(const InputType& input, + const TargetType& target) +{ + typedef typename InputType::elem_type ElemType; + ElemType loss = 0; + for (size_t i = 0; i < input.n_elem; ++i) + { + const ElemType absError = std::abs(target[i] - input[i]); + loss += absError > delta + ? delta * (absError - 0.5 * delta) : 0.5 * std::pow(absError, 2); + } + return mean ? loss / input.n_elem : loss; +} + +template +template +void HuberLoss::Backward( + const InputType& input, + const TargetType& target, + OutputType& output) +{ + typedef typename InputType::elem_type ElemType; + + output.set_size(size(input)); + for (size_t i = 0; i < output.n_elem; ++i) + { + const ElemType absError = std::abs(target[i] - input[i]); + output[i] = absError > delta + ? - delta * (target[i] - input[i]) / absError : input[i] - target[i]; + if (mean) + output[i] /= output.n_elem; + } +} + +template +template +void HuberLoss::serialize( + Archive& ar, + const unsigned int /* version */) +{ + ar & BOOST_SERIALIZATION_NVP(delta); + ar & BOOST_SERIALIZATION_NVP(mean); +} + +} // namespace ann +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/kl_divergence.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/kl_divergence.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/kl_divergence.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/kl_divergence.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -60,7 +60,8 @@ * @param target Target data to compare with. */ template - double Forward(const InputType&& input, const TargetType&& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. @@ -70,9 +71,9 @@ * @param output The calculated error. */ template - void Backward(const InputType&& input, - const TargetType&& target, - OutputType&& output); + void Backward(const InputType& input, + const TargetType& target, + OutputType& output); //! Get the output parameter. OutputDataType& OutputParameter() const { return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/kl_divergence_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/kl_divergence_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/kl_divergence_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/kl_divergence_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -28,8 +28,9 @@ template template -double KLDivergence::Forward( - const InputType&& input, const TargetType&& target) +typename InputType::elem_type +KLDivergence::Forward(const InputType& input, + const TargetType& target) { if (takeMean) { @@ -45,9 +46,9 @@ template template void KLDivergence::Backward( - const InputType&& input, - const TargetType&& target, - OutputType&& output) + const InputType& input, + const TargetType& target, + OutputType& output) { if (takeMean) { @@ -62,10 +63,10 @@ template template void KLDivergence::serialize( - Archive& /* ar */, + Archive& ar, const unsigned int /* version */) { - // Nothing to do here. + ar & BOOST_SERIALIZATION_NVP(takeMean); } } // namespace ann diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/log_cosh_loss.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/log_cosh_loss.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/log_cosh_loss.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/log_cosh_loss.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,103 @@ +/** + * @file log_cosh_loss.hpp + * @author Kartik Dutt + * + * Definition of the Log-Hyperbolic-Cosine 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_LOG_COSH_LOSS_HPP +#define MLPACK_METHODS_ANN_LOSS_FUNCTION_LOG_COSH_LOSS_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * The Log-Hyperbolic-Cosine loss function is often used to improve + * variational auto encoder. This function is the log of hyperbolic + * cosine of difference between true values and predicted values. + * + * @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 LogCoshLoss +{ + public: + /** + * Create the Log-Hyperbolic-Cosine object with the specified + * parameters. + * + * @param a A double type value for smoothening loss function. + * It must be positive a real number, Sharpness of loss + * function is directly proportional to a. It can also + * act as a scaling factor hence making the loss + * function more sensitive to small losses around the + * origin. Default value = 1.0. + */ + LogCoshLoss(const double a = 1.0); + + /** + * Computes the Log-Hyperbolic-Cosine loss function. + * + * @param input Input data used for evaluating the specified function. + * @param target Target data to compare with. + */ + 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 value of hyperparameter a. + double A() const { return a; } + //! Modify the value of hyperparameter a. + double& A() { return a; } + + /** + * Serialize the loss function. + */ + template + void serialize(Archive& ar, const unsigned int /* version */); + + private: + //! Locally-stored output parameter object. + OutputDataType outputParameter; + + //! Hyperparameter a for smoothening function curve. + double a; +}; // class LogCoshLoss + +} // namespace ann +} // namespace mlpack + +// include implementation +#include "log_cosh_loss_impl.hpp" + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/log_cosh_loss_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/log_cosh_loss_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/log_cosh_loss_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/log_cosh_loss_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,60 @@ +/** + * @file log_cosh_loss_impl.hpp + * @author Kartik Dutt + * + * Implementation of the Log-Hyperbolic-Cosine 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_LOG_COSH_LOSS_IMPL_HPP +#define MLPACK_METHODS_ANN_LOSS_FUNCTION_LOG_COSH_LOSS_IMPL_HPP + +// In case it hasn't yet been included. +#include "log_cosh_loss.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +LogCoshLoss::LogCoshLoss(const double a) : + a(a) +{ + Log::Assert(a > 0, "Hyper-Parameter \'a\' must be positive"); +} + +template +template +typename InputType::elem_type +LogCoshLoss::Forward(const InputType& input, + const TargetType& target) +{ + return arma::accu(arma::log(arma::cosh(a * (target - input)))) / a; +} + +template +template +void LogCoshLoss::Backward( + const InputType& input, + const TargetType& target, + OutputType& output) +{ + output = arma::tanh(a * (target - input)); +} + +template +template +void LogCoshLoss::serialize( + Archive& ar, + const unsigned int /* version */) +{ + ar & BOOST_SERIALIZATION_NVP(a); +} + +} // namespace ann +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/margin_ranking_loss.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/margin_ranking_loss.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/margin_ranking_loss.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/margin_ranking_loss.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,102 @@ +/** + * @file margin_ranking_loss.hpp + * @author Andrei Mihalea + * + * Definition of the Margin Ranking 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_ANN_LOSS_FUNCTION_MARGIN_RANKING_LOSS_HPP +#define MLPACK_ANN_LOSS_FUNCTION_MARGIN_RANKING_LOSS_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * Margin ranking loss measures the loss given inputs and a label vector with + * values of 1 or -1. If the label is 1 then the first input should be ranked + * higher than the second input at a distance larger than a margin, and vice- + * versa if the label is -1. + * + * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, + * arma::sp_mat or arma::cube). + * @tparam OutputDataType Type of the output data (arma::colvec, arma::mat, + * arma::sp_mat or arma::cube). + */ +template < + typename InputDataType = arma::mat, + typename OutputDataType = arma::mat +> +class MarginRankingLoss +{ + public: + /** + * Create the MarginRankingLoss object with Hyperparameter margin. + * Hyperparameter margin defines a minimum distance between correctly ranked + * samples. + */ + MarginRankingLoss(const double margin = 1.0); + + /** + * Computes the Margin Ranking Loss function. + * + * @param input Concatenation of the two inputs for evaluating the specified + * function. + * @param target The label vector which contains values of -1 or 1. + */ + template + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); + + /** + * Ordinary feed backward pass of a neural network. + * + * @param input The propagated concatenated input activation. + * @param target The label vector which contains -1 or 1 values. + * @param output The calculated error. + */ + template < + typename InputType, + typename TargetType, + typename OutputType + > + 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 margin parameter. + double Margin() const { return margin; } + //! Modify the margin parameter. + double& Margin() { return margin; } + + /** + * Serialize the layer. + */ + template + void serialize(Archive& ar, const unsigned int /* version */); + + private: + //! Locally-stored output parameter object. + OutputDataType outputParameter; + + //! The margin value used in calculating Margin Ranking Loss. + double margin; +}; // class MarginRankingLoss + +} // namespace ann +} // namespace mlpack + +// include implementation. +#include "margin_ranking_loss_impl.hpp" + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/margin_ranking_loss_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/margin_ranking_loss_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/margin_ranking_loss_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/margin_ranking_loss_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,74 @@ +/** + * @file margin_ranking_loss_impl.hpp + * @author Andrei Mihalea + * + * Implementation of the Margin Ranking 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_MARGIN_IMPL_LOSS_HPP +#define MLPACK_METHODS_ANN_LOSS_FUNCTION_MARGIN_IMPL_LOSS_HPP + +// In case it hasn't been included. +#include "margin_ranking_loss.hpp" + +namespace mlpack { +namespace ann /** Artifical Neural Network. */ { + +template +MarginRankingLoss::MarginRankingLoss( + const double margin) : margin(margin) +{ + // Nothing to do here. +} + +template +template +typename InputType::elem_type +MarginRankingLoss::Forward( + const InputType& input, + const TargetType& target) +{ + const int inputRows = input.n_rows; + const InputType& input1 = input.rows(0, inputRows / 2 - 1); + const InputType& input2 = input.rows(inputRows / 2, inputRows - 1); + return arma::accu(arma::max(arma::zeros(size(target)), + -target % (input1 - input2) + margin)) / target.n_cols; +} + +template +template < + typename InputType, + typename TargetType, + typename OutputType +> +void MarginRankingLoss::Backward( + const InputType& input, + const TargetType& target, + OutputType& output) +{ + const int inputRows = input.n_rows; + const InputType& input1 = input.rows(0, inputRows / 2 - 1); + const InputType& input2 = input.rows(inputRows / 2, inputRows - 1); + output = -target % (input1 - input2) + margin; + output.elem(arma::find(output >= 0)).ones(); + output.elem(arma::find(output < 0)).zeros(); + output = (input2 - input1) % output / target.n_cols; +} + +template +template +void MarginRankingLoss::serialize( + Archive& ar, + const unsigned int /* version */) +{ + ar & BOOST_SERIALIZATION_NVP(margin); +} + +} // namespace ann +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/mean_bias_error.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/mean_bias_error.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/mean_bias_error.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/mean_bias_error.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,85 @@ +/** + * @file mean_bias_error.hpp + * @author Saksham Rastogi + * + * Definition of the mean bias error performance 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_MEAN_BIAS_ERROR_HPP +#define MLPACK_METHODS_ANN_LOSS_FUNCTION_MEAN_BIAS_ERROR_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * The mean bias error performance function measures the network's + * performance according to the mean of errors. + * + * @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 MeanBiasError +{ + public: + /** + * Create the MeanBiasError object. + */ + MeanBiasError(); + + /** + * Computes the mean bias error function. + * + * @param input Input data used for evaluating the specified function. + * @param target The target vector. + */ + 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; } + + /** + * Serialize the layer. + */ + template + void serialize(Archive& ar, const unsigned int /* version */); + + private: + //! Locally-stored output parameter object. + OutputDataType outputParameter; +}; // class MeanBiasError + +} // namespace ann +} // namespace mlpack + +// Include implementation. +#include "mean_bias_error_impl.hpp" + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/mean_bias_error_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/mean_bias_error_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/mean_bias_error_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/mean_bias_error_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,60 @@ +/** + * @file mean_bias_error_impl.hpp + * @author Saksham Rastogi + * + * Implementation of the mean bias error performance 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_MEAN_BIAS_ERROR_IMPL_HPP +#define MLPACK_METHODS_ANN_LOSS_FUNCTION_MEAN_BIAS_ERROR_IMPL_HPP + + +// In case it hasn't yet been included. +#include "mean_bias_error.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +MeanBiasError::MeanBiasError() +{ + // Nothing to do here. +} + +template +template +typename InputType::elem_type +MeanBiasError::Forward(const InputType& input, + const TargetType& target) +{ + return arma::accu(target - input) / target.n_cols; +} + +template +template +void MeanBiasError::Backward( + const InputType& input, + const TargetType& /* target */, + OutputType& output) +{ + output.set_size(arma::size(input)); + output.fill(-1.0); +} + +template +template +void MeanBiasError::serialize( + Archive& /* ar */, + const unsigned int /* version */) +{ + // Nothing to do here. +} + +} // namespace ann +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/mean_squared_error.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/mean_squared_error.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/mean_squared_error.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/mean_squared_error.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -46,7 +46,9 @@ * @param target The target vector. */ template - double Forward(const InputType&& input, const TargetType&& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); + /** * Ordinary feed backward pass of a neural network. * @@ -55,9 +57,9 @@ * @param output The calculated error. */ template - void Backward(const InputType&& input, - const TargetType&& target, - OutputType&& output); + void Backward(const InputType& input, + const TargetType& target, + OutputType& output); //! Get the output parameter. OutputDataType& OutputParameter() const { return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/mean_squared_error_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/mean_squared_error_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/mean_squared_error_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/mean_squared_error_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -26,8 +26,10 @@ template template -double MeanSquaredError::Forward( - const InputType&& input, const TargetType&& target) +typename InputType::elem_type +MeanSquaredError::Forward( + const InputType& input, + const TargetType& target) { return arma::accu(arma::square(input - target)) / target.n_cols; } @@ -35,9 +37,9 @@ template template void MeanSquaredError::Backward( - const InputType&& input, - const TargetType&& target, - OutputType&& output) + const InputType& input, + const TargetType& target, + OutputType& output) { output = 2 * (input - target) / target.n_cols; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/mean_squared_logarithmic_error.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/mean_squared_logarithmic_error.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/mean_squared_logarithmic_error.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/mean_squared_logarithmic_error.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,85 @@ +/** + * @file mean_squared_logarithmic_error.hpp + * @author Saksham Rastogi + * + * Definition of the mean squared logarithmic error 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_MEAN_SQUARED_LOGARITHMIC_ERROR_HPP +#define MLPACK_METHODS_ANN_LOSS_FUNCTION_MEAN_SQUARED_LOGARITHMIC_ERROR_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * The mean squared logarithmic error performance function measures the network's + * performance according to the mean of squared logarithmic errors. + * + * @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 MeanSquaredLogarithmicError +{ + public: + /** + * Create the MeanSquaredLogarithmicError object. + */ + MeanSquaredLogarithmicError(); + + /** + * Computes the mean squared logarithmic error function. + * + * @param input Input data used for evaluating the specified function. + * @param target The target vector. + */ + 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; } + + /** + * Serialize the layer + */ + template + void serialize(Archive& ar, const unsigned int /* version */); + + private: + //! Locally-stored output parameter object. + OutputDataType outputParameter; +}; // class MeanSquaredLogarithmicError + +} // namespace ann +} // namespace mlpack + +// Include implementation. +#include "mean_squared_logarithmic_error_impl.hpp" + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/mean_squared_logarithmic_error_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/mean_squared_logarithmic_error_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/mean_squared_logarithmic_error_impl.hpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/mean_squared_logarithmic_error_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,62 @@ +/** + * @file mean_squared_logarithmic_error_impl.hpp + * @author Saksham Rastogi + * + * Implementation of the mean squared logarithmic error 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_MEAN_SQUARED_LOGARITHMIC_ERROR_IMPL_HPP +#define MLPACK_METHODS_ANN_LOSS_FUNCTION_MEAN_SQUARED_LOGARITHMIC_ERROR_IMPL_HPP + +// In case it hasn't yet been included. +#include "mean_squared_logarithmic_error.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +MeanSquaredLogarithmicError +::MeanSquaredLogarithmicError() +{ + // Nothing to do here. +} + +template +template +typename InputType::elem_type +MeanSquaredLogarithmicError::Forward( + const InputType& input, + const TargetType& target) +{ + return arma::accu(arma::square(arma::log(1. + target) - + arma::log(1. + input))) / target.n_cols; +} + +template +template +void MeanSquaredLogarithmicError::Backward( + const InputType& input, + const TargetType& target, + OutputType& output) +{ + output = 2 * (arma::log(1. + input) - arma::log(1. + target)) / + ((1. + input) * target.n_cols); +} + +template +template +void MeanSquaredLogarithmicError::serialize( + Archive& /* ar */, + const unsigned int /* version */) +{ + // Nothing to do here. +} + +} // namespace ann +} // namespace mlpack + +#endif diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/negative_log_likelihood.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/negative_log_likelihood.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/negative_log_likelihood.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/negative_log_likelihood.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -48,7 +48,8 @@ * between 1 and the number of classes. */ template - double Forward(const InputType&& input, TargetType&& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. The negative log @@ -62,9 +63,9 @@ * @param output The calculated error. */ template - void Backward(const InputType&& input, - const TargetType&& target, - OutputType&& output); + void Backward(const InputType& input, + const TargetType& target, + OutputType& output); //! Get the input parameter. InputDataType& InputParameter() const { return inputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/negative_log_likelihood_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/negative_log_likelihood_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/negative_log_likelihood_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/negative_log_likelihood_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -26,10 +26,13 @@ template template -double NegativeLogLikelihood::Forward( - const InputType&& input, TargetType&& target) +typename InputType::elem_type +NegativeLogLikelihood::Forward( + const InputType& input, + const TargetType& target) { - double output = 0; + typedef typename InputType::elem_type ElemType; + ElemType output = 0; for (size_t i = 0; i < input.n_cols; ++i) { size_t currentTarget = target(i) - 1; @@ -45,9 +48,9 @@ template template void NegativeLogLikelihood::Backward( - const InputType&& input, - const TargetType&& target, - OutputType&& output) + const InputType& input, + const TargetType& target, + OutputType& output) { output = arma::zeros(input.n_rows, input.n_cols); for (size_t i = 0; i < input.n_cols; ++i) diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/reconstruction_loss.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/reconstruction_loss.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/reconstruction_loss.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/reconstruction_loss.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -49,7 +49,8 @@ * @param target The target matrix. */ template - double Forward(const InputType&& input, const TargetType&& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. @@ -59,9 +60,9 @@ * @param output The calculated error. */ template - void Backward(const InputType&& input, - const TargetType&& target, - OutputType&& output); + void Backward(const InputType& input, + const TargetType& target, + OutputType& output); //! Get the output parameter. OutputDataType& OutputParameter() const { return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/reconstruction_loss_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/reconstruction_loss_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/reconstruction_loss_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/reconstruction_loss_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -30,21 +30,22 @@ template template -double ReconstructionLoss::Forward( - const InputType&& input, const TargetType&& target) +typename InputType::elem_type +ReconstructionLoss::Forward( + const InputType& input, const TargetType& target) { - dist = DistType(std::move(input)); - return -dist.LogProbability(std::move(target)); + dist = DistType(input); + return -dist.LogProbability(target); } template template void ReconstructionLoss::Backward( - const InputType&& /* input */, - const TargetType&& target, - OutputType&& output) + const InputType& /* input */, + const TargetType& target, + OutputType& output) { - dist.LogProbBackward(std::move(target), std::move(output)); + dist.LogProbBackward(target, output); output *= -1; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/sigmoid_cross_entropy_error.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/sigmoid_cross_entropy_error.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/sigmoid_cross_entropy_error.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/sigmoid_cross_entropy_error.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -64,8 +64,8 @@ * @param target The target vector. */ template - inline double Forward(const InputType&& input, - const TargetType&& target); + inline typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. * @@ -74,9 +74,9 @@ * @param output The calculated error. */ template - inline void Backward(const InputType&& input, - const TargetType&& target, - OutputType&& output); + inline void Backward(const InputType& input, + const TargetType& target, + OutputType& output); //! Get the output parameter. OutputDataType& OutputParameter() const { return outputParameter; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/sigmoid_cross_entropy_error_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/sigmoid_cross_entropy_error_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/loss_functions/sigmoid_cross_entropy_error_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/loss_functions/sigmoid_cross_entropy_error_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -29,10 +29,13 @@ template template -inline double SigmoidCrossEntropyError::Forward( - const InputType&& input, const TargetType&& target) +inline typename InputType::elem_type +SigmoidCrossEntropyError::Forward( + const InputType& input, + const TargetType& target) { - double maximum = 0; + typedef typename InputType::elem_type ElemType; + ElemType maximum = 0; for (size_t i = 0; i < input.n_elem; ++i) { maximum += std::max(input[i], 0.0) + @@ -45,9 +48,9 @@ template template inline void SigmoidCrossEntropyError::Backward( - const InputType&& input, - const TargetType&& target, - OutputType&& output) + const InputType& input, + const TargetType& target, + OutputType& output) { output = 1.0 / (1.0 + arma::exp(-input)) - target; } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/rbm/rbm.hpp mlpack-3.3.0/src/mlpack/methods/ann/rbm/rbm.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/rbm/rbm.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/rbm/rbm.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -86,11 +86,16 @@ * optimization. If this is not what you want, then you should access the * parameters vector directly with Parameters() and modify it as desired. * + * @tparam OptimizerType Type of optimizer to use to train the model. + * @tparam CallbackTypes Types of Callback functions. * @param optimizer Optimizer type. + * @param callbacks Callback Functions for ensmallen optimizer + * `OptimizerType`. + * See https://www.ensmallen.org/docs.html#callback-documentation. * @return The final objective of the trained model (NaN or Inf on error). */ - template - double Train(OptimizerType& optimizer); + template + double Train(OptimizerType& optimizer, CallbackType&&... callbacks); /** * Evaluate the RBM network with the given parameters. diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/rbm/rbm_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/rbm/rbm_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/rbm/rbm_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/rbm/rbm_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -91,16 +91,16 @@ typename DataType, typename PolicyType > -template +template double RBM::Train( - OptimizerType& optimizer) + OptimizerType& optimizer, CallbackType&&... callbacks) { if (!reset) { Reset(); } - return optimizer.Optimize(*this, parameter); + return optimizer.Optimize(*this, parameter, callbacks...); } template< diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/rnn.hpp mlpack-3.3.0/src/mlpack/methods/ann/rnn.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/rnn.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/rnn.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -73,6 +74,35 @@ ~RNN(); /** + * Check if the optimizer has MaxIterations() parameter, if it does + * then check if it's value is less than the number of datapoints + * in the dataset. + * + * @tparam OptimizerType Type of optimizer to use to train the model. + * @param optimizer optimizer used in the training process. + * @param samples Number of datapoints in the dataset. + */ + template + typename std::enable_if< + HasMaxIterations + ::value, void>::type + WarnMessageMaxIterations(OptimizerType& optimizer, size_t samples) const; + + /** + * Check if the optimizer has MaxIterations() parameter, if it + * doesn't then simply return from the function. + * + * @tparam OptimizerType Type of optimizer to use to train the model. + * @param optimizer optimizer used in the training process. + * @param samples Number of datapoints in the dataset. + */ + template + typename std::enable_if< + !HasMaxIterations + ::value, void>::type + WarnMessageMaxIterations(OptimizerType& optimizer, size_t samples) const; + + /** * Train the recurrent neural network on the given input data using the given * optimizer. * @@ -295,7 +325,8 @@ * * @param input Data sequence to compute probabilities for. */ - void Forward(arma::mat&& input); + template + void Forward(const InputType& input); /** * Reset the state of RNN cells in the network for new input sequence. @@ -313,7 +344,7 @@ * layer defined optimizer. */ template - void Gradient(InputType&& input); + void Gradient(const InputType& input); /** * Reset the module status by setting the current deterministic parameter diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/rnn_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/rnn_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/rnn_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/rnn_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -63,6 +63,40 @@ template +template +typename std::enable_if< + HasMaxIterations + ::value, void>::type +RNN:: +WarnMessageMaxIterations(OptimizerType& optimizer, size_t samples) const +{ + if (optimizer.MaxIterations() < samples && + optimizer.MaxIterations() != 0) + { + Log::Warn << "The optimizer's maximum number of iterations " + << "is less than the size of the dataset; the " + << "optimizer will not pass over the entire " + << "dataset. To fix this, modify the maximum " + << "number of iterations to be at least equal " + << "to the number of points of your dataset " + << "(" << samples << ")." << std::endl; + } +} + +template +template +typename std::enable_if< + !HasMaxIterations + ::value, void>::type +RNN:: +WarnMessageMaxIterations(OptimizerType& optimizer, size_t samples) const +{ + return; +} + +template template double RNN::Train( arma::cube predictors, @@ -83,6 +117,8 @@ ResetParameters(); } + WarnMessageMaxIterations(optimizer, this->predictors.n_cols); + // Train the model. Timer::Start("rnn_optimization"); const double out = optimizer.Optimize(*this, parameter, callbacks...); @@ -127,6 +163,8 @@ OptimizerType optimizer; + WarnMessageMaxIterations(optimizer, this->predictors.n_cols); + // Train the model. Timer::Start("rnn_optimization"); const double out = optimizer.Optimize(*this, parameter, callbacks...); @@ -158,8 +196,8 @@ const size_t effectiveBatchSize = std::min(batchSize, size_t(predictors.n_cols)); - Forward(std::move(arma::mat(predictors.slice(0).colptr(0), - predictors.n_rows, effectiveBatchSize, false, true))); + Forward(arma::mat(predictors.slice(0).colptr(0), predictors.n_rows, + effectiveBatchSize, false, true)); arma::mat resultsTemp = boost::apply_visitor(outputParameterVisitor, network.back()); @@ -175,8 +213,8 @@ size_t(predictors.n_cols - begin)); for (size_t seqNum = !begin; seqNum < rho; ++seqNum) { - Forward(std::move(arma::mat(predictors.slice(seqNum).colptr(begin), - predictors.n_rows, effectiveBatchSize, false, true))); + Forward(arma::mat(predictors.slice(seqNum).colptr(begin), + predictors.n_rows, effectiveBatchSize, false, true)); results.slice(seqNum).submat(0, begin, results.n_rows - 1, begin + effectiveBatchSize - 1) = boost::apply_visitor(outputParameterVisitor, @@ -224,16 +262,16 @@ // Wrap a matrix around our data to avoid a copy. arma::mat stepData(predictors.slice(seqNum).colptr(begin), predictors.n_rows, batchSize, false, true); - Forward(std::move(stepData)); + Forward(stepData); if (!single) { responseSeq = seqNum; } - performance += outputLayer.Forward(std::move(boost::apply_visitor( - outputParameterVisitor, network.back())), - std::move(arma::mat(responses.slice(responseSeq).colptr(begin), - responses.n_rows, batchSize, false, true))); + performance += outputLayer.Forward(boost::apply_visitor( + outputParameterVisitor, network.back()), + arma::mat(responses.slice(responseSeq).colptr(begin), + responses.n_rows, batchSize, false, true)); } if (outputSize == 0) @@ -299,13 +337,14 @@ double performance = 0; size_t responseSeq = 0; + const size_t effectiveRho = std::min(rho, size_t(responses.size())); - for (size_t seqNum = 0; seqNum < rho; ++seqNum) + for (size_t seqNum = 0; seqNum < effectiveRho; ++seqNum) { // Wrap a matrix around our data to avoid a copy. arma::mat stepData(predictors.slice(seqNum).colptr(begin), predictors.n_rows, batchSize, false, true); - Forward(std::move(stepData)); + Forward(stepData); if (!single) { responseSeq = seqNum; @@ -313,14 +352,14 @@ for (size_t l = 0; l < network.size(); ++l) { - boost::apply_visitor(SaveOutputParameterVisitor( - std::move(moduleOutputParameter)), network[l]); + boost::apply_visitor(SaveOutputParameterVisitor(moduleOutputParameter), + network[l]); } - performance += outputLayer.Forward(std::move(boost::apply_visitor( - outputParameterVisitor, network.back())), - std::move(arma::mat(responses.slice(responseSeq).colptr(begin), - responses.n_rows, batchSize, false, true))); + performance += outputLayer.Forward(boost::apply_visitor( + outputParameterVisitor, network.back()), + arma::mat(responses.slice(responseSeq).colptr(begin), + responses.n_rows, batchSize, false, true)); } if (outputSize == 0) @@ -338,14 +377,13 @@ ResetGradients(currentGradient); - for (size_t seqNum = 0; seqNum < rho; ++seqNum) + for (size_t seqNum = 0; seqNum < effectiveRho; ++seqNum) { currentGradient.zeros(); - for (size_t l = 0; l < network.size(); ++l) { - boost::apply_visitor(LoadOutputParameterVisitor( - std::move(moduleOutputParameter)), network[network.size() - 1 - l]); + boost::apply_visitor(LoadOutputParameterVisitor(moduleOutputParameter), + network[network.size() - 1 - l]); } if (single && seqNum > 0) @@ -354,23 +392,23 @@ } else if (single && seqNum == 0) { - outputLayer.Backward(std::move(boost::apply_visitor( - outputParameterVisitor, network.back())), - std::move(arma::mat(responses.slice(0).colptr(begin), - responses.n_rows, batchSize, false, true)), std::move(error)); + outputLayer.Backward(boost::apply_visitor( + outputParameterVisitor, network.back()), + arma::mat(responses.slice(0).colptr(begin), + responses.n_rows, batchSize, false, true), error); } else { - outputLayer.Backward(std::move(boost::apply_visitor( - outputParameterVisitor, network.back())), - std::move(arma::mat(responses.slice(rho - seqNum - 1).colptr(begin), - responses.n_rows, batchSize, false, true)), std::move(error)); + outputLayer.Backward(boost::apply_visitor( + outputParameterVisitor, network.back()), + arma::mat(responses.slice(effectiveRho - seqNum - 1).colptr(begin), + responses.n_rows, batchSize, false, true), error); } Backward(); - Gradient(std::move( - arma::mat(predictors.slice(rho - seqNum - 1).colptr(begin), - predictors.n_rows, batchSize, false, true))); + Gradient( + arma::mat(predictors.slice(effectiveRho - seqNum - 1).colptr(begin), + predictors.n_rows, batchSize, false, true)); gradient += currentGradient; } @@ -443,25 +481,25 @@ size_t offset = 0; for (LayerTypes& layer : network) { - offset += boost::apply_visitor(GradientSetVisitor(std::move(gradient), - offset), layer); + offset += boost::apply_visitor(GradientSetVisitor(gradient, offset), layer); } } template +template void RNN::Forward(arma::mat&& input) + CustomLayers...>::Forward(const InputType& input) { - boost::apply_visitor(ForwardVisitor(std::move(input), std::move( - boost::apply_visitor(outputParameterVisitor, network.front()))), + boost::apply_visitor(ForwardVisitor(input, + boost::apply_visitor(outputParameterVisitor, network.front())), network.front()); for (size_t i = 1; i < network.size(); ++i) { boost::apply_visitor(ForwardVisitor( - std::move(boost::apply_visitor(outputParameterVisitor, network[i - 1])), - std::move(boost::apply_visitor(outputParameterVisitor, network[i]))), + boost::apply_visitor(outputParameterVisitor, network[i - 1]), + boost::apply_visitor(outputParameterVisitor, network[i])), network[i]); } } @@ -471,17 +509,17 @@ void RNN::Backward() { boost::apply_visitor(BackwardVisitor( - std::move(boost::apply_visitor(outputParameterVisitor, network.back())), - std::move(error), std::move(boost::apply_visitor(deltaVisitor, - network.back()))), network.back()); + boost::apply_visitor(outputParameterVisitor, network.back()), + error, boost::apply_visitor(deltaVisitor, + network.back())), network.back()); for (size_t i = 2; i < network.size(); ++i) { boost::apply_visitor(BackwardVisitor( - std::move(boost::apply_visitor(outputParameterVisitor, - network[network.size() - i])), std::move(boost::apply_visitor( - deltaVisitor, network[network.size() - i + 1])), std::move( - boost::apply_visitor(deltaVisitor, network[network.size() - i]))), + boost::apply_visitor(outputParameterVisitor, + network[network.size() - i]), boost::apply_visitor( + deltaVisitor, network[network.size() - i + 1]), + boost::apply_visitor(deltaVisitor, network[network.size() - i])), network[network.size() - i]); } } @@ -490,16 +528,16 @@ typename... CustomLayers> template void RNN::Gradient(InputType&& input) + CustomLayers...>::Gradient(const InputType& input) { - boost::apply_visitor(GradientVisitor(std::move(input), std::move( - boost::apply_visitor(deltaVisitor, network[1]))), network.front()); + boost::apply_visitor(GradientVisitor(input, + boost::apply_visitor(deltaVisitor, network[1])), network.front()); for (size_t i = 1; i < network.size() - 1; ++i) { boost::apply_visitor(GradientVisitor( - std::move(boost::apply_visitor(outputParameterVisitor, network[i - 1])), - std::move(boost::apply_visitor(deltaVisitor, network[i + 1]))), + boost::apply_visitor(outputParameterVisitor, network[i - 1]), + boost::apply_visitor(deltaVisitor, network[i + 1])), network[i]); } } @@ -543,8 +581,8 @@ size_t offset = 0; for (LayerTypes& layer : network) { - offset += boost::apply_visitor(WeightSetVisitor(std::move(parameter), - offset), layer); + offset += boost::apply_visitor(WeightSetVisitor(parameter, offset), + layer); boost::apply_visitor(resetVisitor, layer); } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/backward_visitor.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/backward_visitor.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/backward_visitor.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/backward_visitor.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -30,11 +30,15 @@ public: //! Execute the Backward() function given the input, error and delta //! parameter. - BackwardVisitor(arma::mat&& input, arma::mat&& error, arma::mat&& delta); + BackwardVisitor(const arma::mat& input, + const arma::mat& error, + arma::mat& delta); //! Execute the Backward() function for the layer with the specified index. - BackwardVisitor(arma::mat&& input, arma::mat&& error, arma::mat&& delta, - const size_t index); + BackwardVisitor(const arma::mat& input, + const arma::mat& error, + arma::mat& delta, + const size_t index); //! Execute the Backward() function. template @@ -44,13 +48,13 @@ private: //! The input parameter set. - arma::mat&& input; + const arma::mat& input; //! The error parameter. - arma::mat&& error; + const arma::mat& error; //! The delta parameter. - arma::mat&& delta; + arma::mat& delta; //! The index of the layer to run. size_t index; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/backward_visitor_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/backward_visitor_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/backward_visitor_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/backward_visitor_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -19,25 +19,25 @@ namespace ann { //! BackwardVisitor visitor class. -inline BackwardVisitor::BackwardVisitor(arma::mat&& input, - arma::mat&& error, - arma::mat&& delta) : - input(std::move(input)), - error(std::move(error)), - delta(std::move(delta)), +inline BackwardVisitor::BackwardVisitor(const arma::mat& input, + const arma::mat& error, + arma::mat& delta) : + input(input), + error(error), + delta(delta), index(0), hasIndex(false) { /* Nothing to do here. */ } -inline BackwardVisitor::BackwardVisitor(arma::mat&& input, - arma::mat&& error, - arma::mat&& delta, +inline BackwardVisitor::BackwardVisitor(const arma::mat& input, + const arma::mat& error, + arma::mat& delta, const size_t index) : - input(std::move(input)), - error(std::move(error)), - delta(std::move(delta)), + input(input), + error(error), + delta(delta), index(index), hasIndex(true) { @@ -60,7 +60,7 @@ !HasRunCheck::value, void>::type BackwardVisitor::LayerBackward(T* layer, arma::mat& /* input */) const { - layer->Backward(std::move(input), std::move(error), std::move(delta)); + layer->Backward(input, error, delta); } template @@ -70,13 +70,11 @@ { if (!hasIndex) { - layer->Backward(std::move(input), std::move(error), - std::move(delta)); + layer->Backward(input, error, delta); } else { - layer->Backward(std::move(input), std::move(error), - std::move(delta), index); + layer->Backward(input, error, delta, index); } } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/bias_set_visitor.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/bias_set_visitor.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/bias_set_visitor.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/bias_set_visitor.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -27,7 +27,7 @@ { public: //! Update the bias parameters given the parameters' set and offset. - BiasSetVisitor(arma::mat&& weight, const size_t offset = 0); + BiasSetVisitor(arma::mat& weight, const size_t offset = 0); //! Update the parameters' set. template @@ -37,7 +37,7 @@ private: //! The parameters' set. - arma::mat&& weight; + arma::mat& weight; //! The parameters' offset. const size_t offset; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/bias_set_visitor_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/bias_set_visitor_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/bias_set_visitor_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/bias_set_visitor_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -19,8 +19,8 @@ namespace ann { //! BiasSetVisitor visitor class. -inline BiasSetVisitor::BiasSetVisitor(arma::mat&& weight, const size_t offset) : - weight(std::move(weight)), +inline BiasSetVisitor::BiasSetVisitor(arma::mat& weight, const size_t offset) : + weight(weight), offset(offset) { /* Nothing to do here. */ @@ -57,7 +57,7 @@ for (size_t i = 0; i < layer->Model().size(); ++i) { modelOffset += boost::apply_visitor(BiasSetVisitor( - std::move(weight), modelOffset + offset), layer->Model()[i]); + weight, modelOffset + offset), layer->Model()[i]); } return modelOffset; @@ -89,7 +89,7 @@ for (size_t i = 0; i < layer->Model().size(); ++i) { modelOffset += boost::apply_visitor(BiasSetVisitor( - std::move(weight), modelOffset + offset), layer->Model()[i]); + weight, modelOffset + offset), layer->Model()[i]); } return modelOffset; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/delete_visitor.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/delete_visitor.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/delete_visitor.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/delete_visitor.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -27,9 +27,17 @@ class DeleteVisitor : public boost::static_visitor { public: - //! Execute the destructor. + //! Execute the destructor if the layer does not hold layers internally. template - void operator()(LayerType* layer) const; + typename std::enable_if< + !HasModelCheck::value, void>::type + operator()(LayerType* layer) const; + + //! Execute the destructor if the layer does hold layers internally. + template + typename std::enable_if< + HasModelCheck::value, void>::type + operator()(LayerType* layer) const; void operator()(MoreTypes layer) const; }; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/delete_visitor_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/delete_visitor_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/delete_visitor_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/delete_visitor_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -20,12 +20,28 @@ //! DeleteVisitor visitor class. template -inline void DeleteVisitor::operator()(LayerType* layer) const +inline typename std::enable_if< + !HasModelCheck::value, void>::type +DeleteVisitor::operator()(LayerType* layer) const { if (layer) delete layer; } +template +inline typename std::enable_if< + HasModelCheck::value, void>::type +DeleteVisitor::operator()(LayerType* layer) const +{ + if (layer) + { + for (size_t i = 0; i < layer->Model().size(); ++i) + boost::apply_visitor(DeleteVisitor(), layer->Model()[i]); + + delete layer; + } +} + inline void DeleteVisitor::operator()(MoreTypes layer) const { layer.apply_visitor(*this); diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/forward_visitor.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/forward_visitor.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/forward_visitor.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/forward_visitor.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -29,7 +29,7 @@ { public: //! Execute the Forward() function given the input and output parameter. - ForwardVisitor(arma::mat&& input, arma::mat&& output); + ForwardVisitor(const arma::mat& input, arma::mat& output); //! Execute the Forward() function. template @@ -39,10 +39,10 @@ private: //! The input parameter set. - arma::mat&& input; + const arma::mat& input; //! The output parameter set. - arma::mat&& output; + arma::mat& output; }; } // namespace ann diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/forward_visitor_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/forward_visitor_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/forward_visitor_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/forward_visitor_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -19,9 +19,9 @@ namespace ann { //! ForwardVisitor visitor class. -inline ForwardVisitor::ForwardVisitor(arma::mat&& input, arma::mat&& output) : - input(std::move(input)), - output(std::move(output)) +inline ForwardVisitor::ForwardVisitor(const arma::mat& input, arma::mat& output) : + input(input), + output(output) { /* Nothing to do here. */ } @@ -29,7 +29,7 @@ template inline void ForwardVisitor::operator()(LayerType* layer) const { - layer->Forward(std::move(input), std::move(output)); + layer->Forward(input, output); } inline void ForwardVisitor::operator()(MoreTypes layer) const diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/gradient_set_visitor.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/gradient_set_visitor.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/gradient_set_visitor.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/gradient_set_visitor.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -27,7 +27,7 @@ { public: //! Update the gradient parameter given the gradient set. - GradientSetVisitor(arma::mat&& gradient, size_t offset = 0); + GradientSetVisitor(arma::mat& gradient, size_t offset = 0); //! Update the gradient parameter. template @@ -37,7 +37,7 @@ private: //! The gradient set. - arma::mat&& gradient; + arma::mat& gradient; //! The gradient offset. size_t offset; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/gradient_set_visitor_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/gradient_set_visitor_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/gradient_set_visitor_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/gradient_set_visitor_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -19,9 +19,9 @@ namespace ann { //! GradientSetVisitor visitor class. -inline GradientSetVisitor::GradientSetVisitor(arma::mat&& gradient, +inline GradientSetVisitor::GradientSetVisitor(arma::mat& gradient, size_t offset) : - gradient(std::move(gradient)), + gradient(gradient), offset(offset) { /* Nothing to do here. */ @@ -60,7 +60,7 @@ for (size_t i = 0; i < layer->Model().size(); ++i) { modelOffset += boost::apply_visitor(GradientSetVisitor( - std::move(gradient), modelOffset + offset), layer->Model()[i]); + gradient, modelOffset + offset), layer->Model()[i]); } return modelOffset; @@ -79,7 +79,7 @@ for (size_t i = 0; i < layer->Model().size(); ++i) { modelOffset += boost::apply_visitor(GradientSetVisitor( - std::move(gradient), modelOffset + offset), layer->Model()[i]); + gradient, modelOffset + offset), layer->Model()[i]); } return modelOffset; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/gradient_update_visitor.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/gradient_update_visitor.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/gradient_update_visitor.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/gradient_update_visitor.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -27,7 +27,7 @@ { public: //! Update the gradient parameter given the gradient set. - GradientUpdateVisitor(arma::mat&& gradient, size_t offset = 0); + GradientUpdateVisitor(arma::mat& gradient, size_t offset = 0); //! Update the gradient parameter. template @@ -37,7 +37,7 @@ private: //! The gradient set. - arma::mat&& gradient; + arma::mat& gradient; //! The gradient offset. size_t offset; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/gradient_update_visitor_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/gradient_update_visitor_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/gradient_update_visitor_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/gradient_update_visitor_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -19,9 +19,9 @@ namespace ann { //! GradientUpdateVisitor visitor class. -inline GradientUpdateVisitor::GradientUpdateVisitor(arma::mat&& gradient, +inline GradientUpdateVisitor::GradientUpdateVisitor(arma::mat& gradient, size_t offset) : - gradient(std::move(gradient)), + gradient(gradient), offset(offset) { /* Nothing to do here. */ @@ -63,7 +63,7 @@ for (size_t i = 0; i < layer->Model().size(); ++i) { modelOffset += boost::apply_visitor(GradientUpdateVisitor( - std::move(gradient), modelOffset + offset), layer->Model()[i]); + gradient, modelOffset + offset), layer->Model()[i]); } return modelOffset; @@ -85,7 +85,7 @@ for (size_t i = 0; i < layer->Model().size(); ++i) { modelOffset += boost::apply_visitor(GradientUpdateVisitor( - std::move(gradient), modelOffset + offset), layer->Model()[i]); + gradient, modelOffset + offset), layer->Model()[i]); } return modelOffset; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/gradient_visitor.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/gradient_visitor.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/gradient_visitor.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/gradient_visitor.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -30,10 +30,12 @@ public: //! Executes the Gradient() method of the given module using the input and //! delta parameter. - GradientVisitor(arma::mat&& input, arma::mat&& delta); + GradientVisitor(const arma::mat& input, const arma::mat& delta); //! Executes the Gradient() method for the layer with the specified index. - GradientVisitor(arma::mat&& input, arma::mat&& delta, const size_t index); + GradientVisitor(const arma::mat& input, + const arma::mat& delta, + const size_t index); //! Executes the Gradient() method. template @@ -43,10 +45,10 @@ private: //! The input set. - arma::mat&& input; + const arma::mat& input; //! The delta parameter. - arma::mat&& delta; + const arma::mat& delta; //! Index of the layer to run. size_t index; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/gradient_visitor_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/gradient_visitor_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/gradient_visitor_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/gradient_visitor_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -19,19 +19,21 @@ namespace ann { //! GradientVisitor visitor class. -inline GradientVisitor::GradientVisitor(arma::mat&& input, arma::mat&& delta) : - input(std::move(input)), - delta(std::move(delta)), +inline GradientVisitor::GradientVisitor(const arma::mat& input, + const arma::mat& delta) : + input(input), + delta(delta), index(0), hasIndex(false) { /* Nothing to do here. */ } -inline GradientVisitor::GradientVisitor(arma::mat&& input, arma::mat&& delta, +inline GradientVisitor::GradientVisitor(const arma::mat& input, + const arma::mat& delta, const size_t index) : - input(std::move(input)), - delta(std::move(delta)), + input(input), + delta(delta), index(index), hasIndex(true) { @@ -55,8 +57,7 @@ !HasRunCheck::value, void>::type GradientVisitor::LayerGradients(T* layer, arma::mat& /* input */) const { - layer->Gradient(std::move(input), std::move(delta), - std::move(layer->Gradient())); + layer->Gradient(input, delta, layer->Gradient()); } template @@ -67,13 +68,11 @@ { if (!hasIndex) { - layer->Gradient(std::move(input), std::move(delta), - std::move(layer->Gradient())); + layer->Gradient(input, delta, layer->Gradient()); } else { - layer->Gradient(std::move(input), std::move(delta), - std::move(layer->Gradient()), index); + layer->Gradient(input, delta, layer->Gradient(), index); } } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/load_output_parameter_visitor.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/load_output_parameter_visitor.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/load_output_parameter_visitor.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/load_output_parameter_visitor.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -29,7 +29,7 @@ { public: //! Restore the output parameter given a parameter set. - LoadOutputParameterVisitor(std::vector&& parameter); + LoadOutputParameterVisitor(std::vector& parameter); //! Restore the output parameter. template @@ -39,7 +39,7 @@ private: //! The parameter set. - std::vector&& parameter; + std::vector& parameter; //! Restore the output parameter for a module which doesn't implement the //! Model() function. diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/load_output_parameter_visitor_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/load_output_parameter_visitor_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/load_output_parameter_visitor_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/load_output_parameter_visitor_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -20,7 +20,7 @@ //! LoadOutputParameterVisitor visitor class. inline LoadOutputParameterVisitor::LoadOutputParameterVisitor( - std::vector&& parameter) : parameter(std::move(parameter)) + std::vector& parameter) : parameter(parameter) { /* Nothing to do here. */ } @@ -52,7 +52,7 @@ { for (size_t i = 0; i < layer->Model().size(); ++i) { - boost::apply_visitor(LoadOutputParameterVisitor(std::move(parameter)), + boost::apply_visitor(LoadOutputParameterVisitor(parameter), layer->Model()[layer->Model().size() - i - 1]); } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/parameters_set_visitor.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/parameters_set_visitor.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/parameters_set_visitor.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/parameters_set_visitor.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -28,7 +28,7 @@ { public: //! Update the parameters set given the parameters matrix. - ParametersSetVisitor(arma::mat&& parameters); + ParametersSetVisitor(arma::mat& parameters); //! Update the parameters set. template @@ -38,7 +38,7 @@ private: //! The parameters set. - arma::mat&& parameters; + arma::mat& parameters; //! Do not update the parameters set if the module doesn't implement the //! Parameters() function. diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/parameters_set_visitor_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/parameters_set_visitor_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/parameters_set_visitor_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/parameters_set_visitor_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -19,8 +19,8 @@ namespace ann { //! ParametersSetVisitor visitor class. -inline ParametersSetVisitor::ParametersSetVisitor(arma::mat&& parameters) : - parameters(std::move(parameters)) +inline ParametersSetVisitor::ParametersSetVisitor(arma::mat& parameters) : + parameters(parameters) { /* Nothing to do here. */ } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/parameters_visitor.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/parameters_visitor.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/parameters_visitor.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/parameters_visitor.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -29,7 +29,7 @@ { public: //! Store the parameters set into the given parameters matrix. - ParametersVisitor(arma::mat&& parameters); + ParametersVisitor(arma::mat& parameters); //! Set the parameters set. template @@ -39,7 +39,7 @@ private: //! The parameters set. - arma::mat&& parameters; + arma::mat& parameters; //! Do not set the parameters set if the module doesn't implement the //! Parameters() function. diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/parameters_visitor_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/parameters_visitor_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/parameters_visitor_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/parameters_visitor_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -19,8 +19,8 @@ namespace ann { //! ParametersVisitor visitor class. -inline ParametersVisitor::ParametersVisitor(arma::mat&& parameters) : - parameters(std::move(parameters)) +inline ParametersVisitor::ParametersVisitor(arma::mat& parameters) : + parameters(parameters) { /* Nothing to do here. */ } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/save_output_parameter_visitor.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/save_output_parameter_visitor.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/save_output_parameter_visitor.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/save_output_parameter_visitor.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -28,7 +28,7 @@ { public: //! Save the output parameter into the given parameter set. - SaveOutputParameterVisitor(std::vector&& parameter); + SaveOutputParameterVisitor(std::vector& parameter); //! Save the output parameter. template @@ -38,7 +38,7 @@ private: //! The parameter set. - std::vector&& parameter; + std::vector& parameter; //! Save the output parameter for a module which doesn't implement the //! Model() function. diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/save_output_parameter_visitor_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/save_output_parameter_visitor_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/save_output_parameter_visitor_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/save_output_parameter_visitor_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -20,7 +20,7 @@ //! SaveOutputParameterVisitor visitor class. inline SaveOutputParameterVisitor::SaveOutputParameterVisitor( - std::vector&& parameter) : parameter(std::move(parameter)) + std::vector& parameter) : parameter(parameter) { /* Nothing to do here. */ } @@ -53,7 +53,7 @@ for (size_t i = 0; i < layer->Model().size(); ++i) { - boost::apply_visitor(SaveOutputParameterVisitor(std::move(parameter)), + boost::apply_visitor(SaveOutputParameterVisitor(parameter), layer->Model()[i]); } } diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/weight_set_visitor.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/weight_set_visitor.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/weight_set_visitor.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/weight_set_visitor.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -27,7 +27,7 @@ { public: //! Update the parameters given the parameters set and offset. - WeightSetVisitor(arma::mat&& weight, const size_t offset = 0); + WeightSetVisitor(arma::mat& weight, const size_t offset = 0); //! Update the parameters set. template @@ -37,7 +37,7 @@ private: //! The parameters set. - arma::mat&& weight; + arma::mat& weight; //! The parameters offset. const size_t offset; diff -Nru mlpack-3.2.2/src/mlpack/methods/ann/visitor/weight_set_visitor_impl.hpp mlpack-3.3.0/src/mlpack/methods/ann/visitor/weight_set_visitor_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/ann/visitor/weight_set_visitor_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/ann/visitor/weight_set_visitor_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -19,9 +19,9 @@ namespace ann { //! WeightSetVisitor visitor class. -inline WeightSetVisitor::WeightSetVisitor(arma::mat&& weight, +inline WeightSetVisitor::WeightSetVisitor(arma::mat& weight, const size_t offset) : - weight(std::move(weight)), + weight(weight), offset(offset) { /* Nothing to do here. */ @@ -30,7 +30,7 @@ template inline size_t WeightSetVisitor::operator()(LayerType* layer) const { - return LayerSize(layer, std::move(layer->OutputParameter())); + return LayerSize(layer, layer->OutputParameter()); } inline size_t WeightSetVisitor::operator()(MoreTypes layer) const @@ -57,7 +57,7 @@ for (size_t i = 0; i < layer->Model().size(); ++i) { modelOffset += boost::apply_visitor(WeightSetVisitor( - std::move(weight), modelOffset + offset), layer->Model()[i]); + weight, modelOffset + offset), layer->Model()[i]); } return modelOffset; @@ -88,7 +88,7 @@ for (size_t i = 0; i < layer->Model().size(); ++i) { modelOffset += boost::apply_visitor(WeightSetVisitor( - std::move(weight), modelOffset + offset), layer->Model()[i]); + weight, modelOffset + offset), layer->Model()[i]); } return modelOffset; diff -Nru mlpack-3.2.2/src/mlpack/methods/approx_kfn/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/approx_kfn/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/approx_kfn/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/approx_kfn/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -21,4 +21,5 @@ # This program computes approximate furthest neighbors. add_cli_executable(approx_kfn) add_python_binding(approx_kfn) -add_markdown_docs(approx_kfn "cli;python" "geometry") +add_julia_binding(approx_kfn) +add_markdown_docs(approx_kfn "cli;python;julia" "geometry") diff -Nru mlpack-3.2.2/src/mlpack/methods/cf/cf_main.cpp mlpack-3.3.0/src/mlpack/methods/cf/cf_main.cpp --- mlpack-3.2.2/src/mlpack/methods/cf/cf_main.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/cf/cf_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -100,6 +100,15 @@ " - 'average' -- Average Interpolation Algorithm\n" " - 'regression' -- Regression Interpolation Algorithm\n" " - 'similarity' -- Similarity Interpolation Algorithm\n" + "\n\n" + "The following ranking normalization algorithms can be specified via" + + " the " + PRINT_PARAM_STRING("normalization") + " parameter:" + "\n" + " - 'none' -- No Normalization\n" + " - 'item_mean' -- Item Mean Normalization\n" + " - 'overall_mean' -- Overall Mean Normalization\n" + " - 'user_mean' -- User Mean Normalization\n" + " - 'z_score' -- Z-Score Normalization\n" "\n" "A trained model may be saved to with the " + PRINT_PARAM_STRING("output_model") + " output parameter." @@ -136,6 +145,8 @@ PARAM_MATRIX_IN("training", "Input dataset to perform CF on.", "t"); PARAM_STRING_IN("algorithm", "Algorithm used for matrix factorization.", "a", "NMF"); +PARAM_STRING_IN("normalization", "Normalization performed on the ratings.", "z", + "none"); PARAM_INT_IN("neighborhood", "Size of the neighborhood of similar users to " "consider for each query user.", "n", 5); PARAM_INT_IN("rank", "Rank of decomposed matrices (if 0, a heuristic is used to" @@ -212,14 +223,14 @@ const size_t numRecs, arma::Mat& recommendations) { - // Verifying the Interpolation algorithms + // Verify the Interpolation algorithms. RequireParamInSet("interpolation", { "average", "regression", "similarity" }, true, "unknown interpolation algorithm"); - // Taking Interpolation Alternatives + // Taking Interpolation Alternatives const string interpolationAlgorithm = CLI::GetParam("interpolation"); - // Determining the Interpolation Algorithm + // Determining the Interpolation Algorithm if (interpolationAlgorithm == "average") { ComputeRecommendations @@ -371,11 +382,29 @@ const double minResidue) { const size_t neighborhood = (size_t) CLI::GetParam("neighborhood"); + + // Make sure the normalization strategy is valid. + RequireParamInSet("normalization", { "overall_mean", "item_mean", + "user_mean", "z_score", "none" }, true, "unknown normalization type"); + CFModel* c = new CFModel(); + + const string normalizationType = CLI::GetParam("normalization"); + c->template Train(dataset, neighborhood, rank, - maxIterations, minResidue, CLI::HasParam("iteration_only_termination")); + maxIterations, minResidue, CLI::HasParam("iteration_only_termination"), + normalizationType); - PerformAction(c); + try + { + PerformAction(c); + } + catch (std::exception& e) + { + // Clean the memory before throwing completely. + delete c; + throw; + } } void AssembleFactorizerType(const std::string& algorithm, diff -Nru mlpack-3.2.2/src/mlpack/methods/cf/cf_model.hpp mlpack-3.3.0/src/mlpack/methods/cf/cf_model.hpp --- mlpack-3.2.2/src/mlpack/methods/cf/cf_model.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/cf/cf_model.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -1,6 +1,7 @@ /** * @file cf_model.hpp * @author Wenhao Huang + * @author Khizir Siddiqui * * A serializable CF model, used by the main program. * @@ -24,6 +25,12 @@ #include #include +#include +#include +#include +#include +#include + namespace mlpack { namespace cf { @@ -35,8 +42,9 @@ { public: //! Delete CFType object. - template - void operator()(CFType* c) const; + template + void operator()(CFType* c) const; }; /** @@ -46,8 +54,9 @@ { public: //! Return stored pointer as void* type. - template - void* operator()(CFType* c) const; + template + void* operator()(CFType* c) const; }; /** @@ -66,8 +75,9 @@ public: //! Predict ratings for each user-item combination. - template - void operator()(CFType* c) const; + template + void operator()(CFType* c) const; //! Visitor constructor. PredictVisitor(const arma::Mat& combinations, @@ -100,8 +110,9 @@ const bool usersGiven); //! Generates the given number of recommendations. - template - void operator()(CFType* c) const; + template + void operator()(CFType* c) const; }; /** @@ -112,17 +123,54 @@ private: /** * cf holds an instance of the CFType class for the current - * decompositionPolicy. It is initialized every time Train() is executed. - * We access to the contained value through the visitor classes defined above. + * decompositionPolicy and normalizationType. It is initialized every time + * Train() is executed. We access to the contained value through the visitor + * classes defined above. */ - boost::variant*, - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - CFType*> cf; + boost::variant*, + CFType*, + CFType*, + CFType*, + CFType*, + CFType*, + CFType*, + CFType*, + + CFType*, + CFType*, + CFType*, + CFType*, + CFType*, + CFType*, + CFType*, + CFType*, + + CFType*, + CFType*, + CFType*, + CFType*, + CFType*, + CFType*, + CFType*, + CFType*, + + CFType*, + CFType*, + CFType*, + CFType*, + CFType*, + CFType*, + CFType*, + CFType*, + + CFType*, + CFType*, + CFType*, + CFType*, + CFType*, + CFType*, + CFType*, + CFType*> cf; public: //! Create an empty CF model. @@ -132,8 +180,9 @@ ~CFModel(); //! Get the pointer to CFType<> object. - template - const CFType* CFPtr() const; + template + const CFType* CFPtr() const; //! Train the model. template +#include +#include +#include +#include +#include + using namespace mlpack::cf; -template -void DeleteVisitor::operator()(CFType* c) const +template +void DeleteVisitor:: +operator()(CFType* c) const { if (c) delete c; } -template -void* GetValueVisitor::operator()(CFType* c) const +template +void* GetValueVisitor:: +operator()(CFType* c) const { if (!c) throw std::runtime_error("no cf model initialized"); @@ -45,9 +55,10 @@ template -template +template void PredictVisitor - ::operator()(CFType* c) const + ::operator()(CFType* c) const { if (!c) { @@ -75,9 +86,10 @@ template -template +template void RecommendationVisitor - ::operator()(CFType* c) const + ::operator()(CFType* c) const { if (!c) { @@ -105,15 +117,50 @@ const size_t rank, const size_t maxIterations, const double minResidue, - const bool mit) + const bool mit, + const std::string& normalization) { // Delete the current CFType object, if there is one. boost::apply_visitor(DeleteVisitor(), cf); // Instantiate a new CFType object. DecompositionPolicy decomposition; - cf = new CFType(data, decomposition, - numUsersForSimilarity, rank, maxIterations, minResidue, mit); + if (normalization == "overall_mean") + { + cf = new CFType(data, + decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, + mit); + } + else if (normalization == "item_mean") + { + cf = new CFType(data, + decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, + mit); + } + else if (normalization == "user_mean") + { + cf = new CFType(data, + decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, + mit); + } + else if (normalization == "z_score") + { + cf = new CFType(data, + decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, + mit); + } + else if (normalization == "none") + { + cf = new CFType(data, + decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, + mit); + } + else + { + throw std::runtime_error("Unsupported normalization algorithm." + " It should be one of none, overall_mean, " + "item_mean, user_mean or z_score"); + } } //! Make predictions. @@ -151,11 +198,12 @@ boost::apply_visitor(recommendation, cf); } -template -const CFType* CFModel::CFPtr() const +template +const CFType* CFModel::CFPtr() const { void* pointer = boost::apply_visitor(GetValueVisitor(), cf); - return (CFType*) pointer; + return (CFType*) pointer; } template diff -Nru mlpack-3.2.2/src/mlpack/methods/cf/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/cf/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/cf/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/cf/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -25,4 +25,5 @@ add_cli_executable(cf) add_python_binding(cf) -add_markdown_docs(cf "cli;python" "misc. / other") +add_julia_binding(cf) +add_markdown_docs(cf "cli;python;julia" "misc. / other") diff -Nru mlpack-3.2.2/src/mlpack/methods/dbscan/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/dbscan/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/dbscan/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/dbscan/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -18,4 +18,5 @@ add_cli_executable(dbscan) add_python_binding(dbscan) -add_markdown_docs(dbscan "cli;python" "clustering") +add_julia_binding(dbscan) +add_markdown_docs(dbscan "cli;python;julia" "clustering") diff -Nru mlpack-3.2.2/src/mlpack/methods/decision_stump/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/decision_stump/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/decision_stump/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/decision_stump/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -16,4 +16,5 @@ add_cli_executable(decision_stump) add_python_binding(decision_stump) -add_markdown_docs(decision_stump "cli;python" "classification") +add_julia_binding(decision_stump) +add_markdown_docs(decision_stump "cli;python;julia" "classification") diff -Nru mlpack-3.2.2/src/mlpack/methods/decision_stump/decision_stump.hpp mlpack-3.3.0/src/mlpack/methods/decision_stump/decision_stump.hpp --- mlpack-3.2.2/src/mlpack/methods/decision_stump/decision_stump.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/decision_stump/decision_stump.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -28,6 +28,10 @@ * last bin has range up to \infty (split[i + 1] does not exist in that case). * Points that are below the first bin will take the label of the first bin. * + * @note + * This class has been deprecated and should be removed in mlpack 4.0.0. Use + * `ID3DecisionStump`, found in src/mlpack/methods/decision_tree/, instead. + * * @tparam MatType Type of matrix that is being used (sparse or dense). */ template @@ -43,10 +47,10 @@ * @param numClasses Number of distinct classes in labels. * @param bucketSize Minimum size of bucket when splitting. */ - DecisionStump(const MatType& data, - const arma::Row& labels, - const size_t numClasses, - const size_t bucketSize = 10); + mlpack_deprecated DecisionStump(const MatType& data, + const arma::Row& labels, + const size_t numClasses, + const size_t bucketSize = 10); /** * Alternate constructor which copies the parameters bucketSize and classes @@ -59,11 +63,11 @@ * @param labels The labels of data. * @param weights Weight vector to use while training. For boosting purposes. */ - DecisionStump(const DecisionStump<>& other, - const MatType& data, - const arma::Row& labels, - const size_t numClasses, - const arma::rowvec& weights); + mlpack_deprecated DecisionStump(const DecisionStump<>& other, + const MatType& data, + const arma::Row& labels, + const size_t numClasses, + const arma::rowvec& weights); /** * Create a decision stump without training. This stump will not be useful @@ -83,10 +87,10 @@ * @param bucketSize Minimum size of bucket when splitting. * @return The final entropy after splitting. */ - double Train(const MatType& data, - const arma::Row& labels, - const size_t numClasses, - const size_t bucketSize); + mlpack_deprecated double Train(const MatType& data, + const arma::Row& labels, + const size_t numClasses, + const size_t bucketSize); /** * Train the decision stump on the given data, with the given weights. This @@ -100,11 +104,11 @@ * @param bucketSize Minimum size of bucket when splitting. * @return The final entropy after splitting. */ - double Train(const MatType& data, - const arma::Row& labels, - const arma::rowvec& weights, - const size_t numClasses, - const size_t bucketSize); + mlpack_deprecated double Train(const MatType& data, + const arma::Row& labels, + const arma::rowvec& weights, + const size_t numClasses, + const size_t bucketSize); /** * Classification function. After training, classify test, and put the @@ -114,7 +118,8 @@ * @param predictedLabels Vector to store the predicted classes after * classifying test data. */ - void Classify(const MatType& test, arma::Row& predictedLabels); + mlpack_deprecated void Classify(const MatType& test, + arma::Row& predictedLabels); //! Access the splitting dimension. size_t SplitDimension() const { return splitDimension; } diff -Nru mlpack-3.2.2/src/mlpack/methods/decision_stump/decision_stump_main.cpp mlpack-3.3.0/src/mlpack/methods/decision_stump/decision_stump_main.cpp --- mlpack-3.2.2/src/mlpack/methods/decision_stump/decision_stump_main.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/decision_stump/decision_stump_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -125,6 +125,11 @@ ReportIgnoredParam({{ "test", false }}, "predictions"); + Log::Warn << "DecisionStump is deprecated and will be removed in mlpack " + << "4.0.0. Please use DecisionTree instead with the maximum tree " + << "depth option set to 1 (that will produce a stump)." + << std::endl; + // We must either load a model, or train a new stump. DSModel* model; if (CLI::HasParam("training")) Binary files /tmp/tmp6ZKWyg/Pe8n_yOU9a/mlpack-3.2.2/src/mlpack/methods/decision_tree/.all_categorical_split_impl.hpp.swp and /tmp/tmp6ZKWyg/dq_62_D0lp/mlpack-3.3.0/src/mlpack/methods/decision_tree/.all_categorical_split_impl.hpp.swp differ Binary files /tmp/tmp6ZKWyg/Pe8n_yOU9a/mlpack-3.2.2/src/mlpack/methods/decision_tree/.best_binary_numeric_split_impl.hpp.swp and /tmp/tmp6ZKWyg/dq_62_D0lp/mlpack-3.3.0/src/mlpack/methods/decision_tree/.best_binary_numeric_split_impl.hpp.swp differ diff -Nru mlpack-3.2.2/src/mlpack/methods/decision_tree/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/decision_tree/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/decision_tree/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/decision_tree/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -25,4 +25,5 @@ add_cli_executable(decision_tree) add_python_binding(decision_tree) -add_markdown_docs(decision_tree "cli;python" "classification") +add_julia_binding(decision_tree) +add_markdown_docs(decision_tree "cli;python;julia" "classification") diff -Nru mlpack-3.2.2/src/mlpack/methods/decision_tree/decision_tree.hpp mlpack-3.3.0/src/mlpack/methods/decision_tree/decision_tree.hpp --- mlpack-3.2.2/src/mlpack/methods/decision_tree/decision_tree.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/decision_tree/decision_tree.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -15,6 +15,7 @@ #include #include "gini_gain.hpp" +#include "information_gain.hpp" #include "best_binary_numeric_split.hpp" #include "all_categorical_split.hpp" #include "all_dimension_select.hpp" @@ -124,20 +125,49 @@ * @param dimensionSelector Instantiated dimension selection policy. */ template - DecisionTree(MatType data, - const data::DatasetInfo& datasetInfo, - LabelsType labels, - const size_t numClasses, - WeightsType weights, - const size_t minimumLeafSize = 10, - const double minimumGainSplit = 1e-7, - const size_t maximumDepth = 0, - DimensionSelectionType dimensionSelector = - DimensionSelectionType(), - const std::enable_if_t::type>::value>* - = 0); - + DecisionTree( + MatType data, + const data::DatasetInfo& datasetInfo, + LabelsType labels, + const size_t numClasses, + WeightsType weights, + const size_t minimumLeafSize = 10, + const double minimumGainSplit = 1e-7, + const size_t maximumDepth = 0, + DimensionSelectionType dimensionSelector = DimensionSelectionType(), + const std::enable_if_t::type>::value>* = 0); + + /** + * Take ownership of another decision tree and train on the given data and + * labels with weights, where the data can be both numeric and categorical. + * Setting minimumLeafSize and minimumGainSplit too small may cause the + * tree to overfit, but setting them too large may cause it to underfit. + * + * Use std::move if data, labels or weights are no longer needed to avoid + * copies. + * + * @param other Tree to take ownership of. + * @param data Dataset to train on. + * @param datasetInfo Type information for each dimension of the dataset. + * @param labels Labels for each training point. + * @param numClasses Number of classes in the dataset. + * @param weights The weight list of given label. + * @param minimumLeafSize Minimum number of points in each leaf node. + * @param minimumGainSplit Minimum gain for the node to split. + */ + template + DecisionTree( + const DecisionTree& other, + MatType data, + const data::DatasetInfo& datasetInfo, + LabelsType labels, + const size_t numClasses, + WeightsType weights, + const size_t minimumLeafSize = 10, + const double minimumGainSplit = 1e-7, + const std::enable_if_t::type>::value>* = 0); /** * Construct the decision tree on the given data and labels with weights, * assuming that the data is all of the numeric type. Setting minimumLeafSize @@ -157,19 +187,49 @@ * @param dimensionSelector Instantiated dimension selection policy. */ template - DecisionTree(MatType data, - LabelsType labels, - const size_t numClasses, - WeightsType weights, - const size_t minimumLeafSize = 10, - const double minimumGainSplit = 1e-7, - const size_t maximumDepth = 0, - DimensionSelectionType dimensionSelector = - DimensionSelectionType(), - const std::enable_if_t::type>::value>* - = 0); - + DecisionTree( + MatType data, + LabelsType labels, + const size_t numClasses, + WeightsType weights, + const size_t minimumLeafSize = 10, + const double minimumGainSplit = 1e-7, + const size_t maximumDepth = 0, + DimensionSelectionType dimensionSelector = DimensionSelectionType(), + const std::enable_if_t::type>::value>* = 0); + + /** + * Take ownership of another decision tree and train on the given data and labels + * with weights, assuming that the data is all of the numeric type. Setting + * minimumLeafSize and minimumGainSplit too small may cause the tree to + * overfit, but setting them too large may cause it to underfit. + * + * Use std::move if data, labels or weights are no longer needed to avoid + * copies. + * @param other Tree to take ownership of. + * @param data Dataset to train on. + * @param labels Labels for each training point. + * @param numClasses Number of classes in the dataset. + * @param weights The Weight list of given labels. + * @param minimumLeafSize Minimum number of points in each leaf node. + * @param minimumGainSplit Minimum gain for the node to split. + * @param maximumDepth Maximum depth for the tree. + * @param dimensionSelector Instantiated dimension selection policy. + */ + template + DecisionTree( + const DecisionTree& other, + MatType data, + LabelsType labels, + const size_t numClasses, + WeightsType weights, + const size_t minimumLeafSize = 10, + const double minimumGainSplit = 1e-7, + const size_t maximumDepth = 0, + DimensionSelectionType dimensionSelector = DimensionSelectionType(), + const std::enable_if_t::type>::value>* = 0); /** * Construct a decision tree without training it. It will be a leaf node with @@ -529,6 +589,16 @@ ElemType, false>; +/** + * Convenience typedef for ID3 decision stumps (single level decision trees made + * with the ID3 algorithm). + */ +typedef DecisionTree ID3DecisionStump; } // namespace tree } // namespace mlpack diff -Nru mlpack-3.2.2/src/mlpack/methods/decision_tree/decision_tree_impl.hpp mlpack-3.3.0/src/mlpack/methods/decision_tree/decision_tree_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/decision_tree/decision_tree_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/decision_tree/decision_tree_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -12,6 +12,8 @@ #ifndef MLPACK_METHODS_DECISION_TREE_DECISION_TREE_IMPL_HPP #define MLPACK_METHODS_DECISION_TREE_DECISION_TREE_IMPL_HPP +#include "decision_tree.hpp" + namespace mlpack { namespace tree { @@ -116,10 +118,8 @@ const double minimumGainSplit, const size_t maximumDepth, DimensionSelectionType dimensionSelector, - const std::enable_if_t< - arma::is_arma_type< - typename std::remove_reference< - WeightsType>::type>::value>*) + const std::enable_if_t::type>::value>*) { using TrueMatType = typename std::decay::type; using TrueLabelsType = typename std::decay::type; @@ -141,6 +141,47 @@ //! Construct and train with weights. template class NumericSplitType, + template class CategoricalSplitType, + typename DimensionSelectionType, + typename ElemType, + bool NoRecursion> +template +DecisionTree::DecisionTree( + const DecisionTree& other, + MatType data, + const data::DatasetInfo& datasetInfo, + LabelsType labels, + const size_t numClasses, + WeightsType weights, + const size_t minimumLeafSize, + const double minimumGainSplit, + const std::enable_if_t::type>::value>*): + NumericAuxiliarySplitInfo(other), + CategoricalAuxiliarySplitInfo(other) +{ + using TrueMatType = typename std::decay::type; + using TrueLabelsType = typename std::decay::type; + using TrueWeightsType = typename std::decay::type; + + // Copy or move data. + TrueMatType tmpData(std::move(data)); + TrueLabelsType tmpLabels(std::move(labels)); + TrueWeightsType tmpWeights(std::move(weights)); + + // Pass off work to the weighted Train() method. + Train(tmpData, 0, tmpData.n_cols, datasetInfo, tmpLabels, numClasses, + tmpWeights, minimumLeafSize, minimumGainSplit); +} + +//! Construct and train with weights. +template class NumericSplitType, template class CategoricalSplitType, typename DimensionSelectionType, @@ -183,6 +224,52 @@ minimumLeafSize, minimumGainSplit, maximumDepth, dimensionSelector); } +//! Construct and train with weights. +template class NumericSplitType, + template class CategoricalSplitType, + typename DimensionSelectionType, + typename ElemType, + bool NoRecursion> +template +DecisionTree::DecisionTree( + const DecisionTree& other, + MatType data, + LabelsType labels, + const size_t numClasses, + WeightsType weights, + const size_t minimumLeafSize, + const double minimumGainSplit, + const size_t maximumDepth, + DimensionSelectionType dimensionSelector, + const std::enable_if_t::type>::value>*): + NumericAuxiliarySplitInfo(other), + CategoricalAuxiliarySplitInfo(other) // other info does need to copy +{ + using TrueMatType = typename std::decay::type; + using TrueLabelsType = typename std::decay::type; + using TrueWeightsType = typename std::decay::type; + + // Copy or move data. + TrueMatType tmpData(std::move(data)); + TrueLabelsType tmpLabels(std::move(labels)); + TrueWeightsType tmpWeights(std::move(weights)); + + // Set the correct dimensionality for the dimension selector. + dimensionSelector.Dimensions() = tmpData.n_rows; + + // Pass off work to the weighted Train() method. + Train(tmpData, 0, tmpData.n_cols, tmpLabels, numClasses, tmpWeights, + minimumLeafSize, minimumGainSplit, maximumDepth, dimensionSelector); +} + //! Construct, don't train. template class NumericSplitType, @@ -568,7 +655,7 @@ dimensionSelector); } -//! Train on the given data. +//! Train on the given data, assuming all dimensions are numeric. template class NumericSplitType, template class CategoricalSplitType, Binary files /tmp/tmp6ZKWyg/Pe8n_yOU9a/mlpack-3.2.2/src/mlpack/methods/decision_tree/.decision_tree_impl.hpp.swp and /tmp/tmp6ZKWyg/dq_62_D0lp/mlpack-3.3.0/src/mlpack/methods/decision_tree/.decision_tree_impl.hpp.swp differ diff -Nru mlpack-3.2.2/src/mlpack/methods/det/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/det/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/det/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/det/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -21,4 +21,5 @@ add_cli_executable(det) add_python_binding(det) -add_markdown_docs(det "cli;python" "misc. / other") +add_julia_binding(det) +add_markdown_docs(det "cli;python;julia" "misc. / other") diff -Nru mlpack-3.2.2/src/mlpack/methods/emst/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/emst/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/emst/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/emst/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -23,4 +23,5 @@ add_cli_executable(emst) add_python_binding(emst) -add_markdown_docs(emst "cli;python" "geometry") +add_julia_binding(emst) +add_markdown_docs(emst "cli;python;julia" "geometry") diff -Nru mlpack-3.2.2/src/mlpack/methods/fastmks/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/fastmks/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/fastmks/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/fastmks/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -22,4 +22,5 @@ add_cli_executable(fastmks) add_python_binding(fastmks) -add_markdown_docs(fastmks "cli;python" "geometry") +add_julia_binding(fastmks) +add_markdown_docs(fastmks "cli;python;julia" "geometry") diff -Nru mlpack-3.2.2/src/mlpack/methods/fastmks/fastmks_main.cpp mlpack-3.3.0/src/mlpack/methods/fastmks/fastmks_main.cpp --- mlpack-3.2.2/src/mlpack/methods/fastmks/fastmks_main.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/fastmks/fastmks_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -128,6 +128,12 @@ "number of maximum kernels must be greater than 0"); } + if (CLI::HasParam("base")) + { + RequireParamValue("base", [](double x) { return x > 1.0; }, true, + "base must be greater than or equal to 1!"); + } + // Naive mode overrides single mode. ReportIgnoredParam({{ "naive", true }}, "single"); @@ -223,12 +229,32 @@ Log::Info << "Loaded query data (" << queryData.n_rows << " x " << queryData.n_cols << ")." << endl; - model->Search(queryData, (size_t) CLI::GetParam("k"), indices, - kernels, base); + try + { + model->Search(queryData, (size_t) CLI::GetParam("k"), indices, + kernels, base); + } + catch (std::invalid_argument& e) + { + // Delete the memory, if needed. + if (CLI::HasParam("reference")) + delete model; + throw; + } } else { - model->Search((size_t) CLI::GetParam("k"), indices, kernels); + try + { + model->Search((size_t) CLI::GetParam("k"), indices, kernels); + } + catch (std::invalid_argument& e) + { + // Delete the memory, if needed. + if (CLI::HasParam("reference")) + delete model; + throw e; + } } // Save output. diff -Nru mlpack-3.2.2/src/mlpack/methods/gmm/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/gmm/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/gmm/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/gmm/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -26,12 +26,15 @@ add_cli_executable(gmm_train) add_python_binding(gmm_train) -add_markdown_docs(gmm_train "cli;python" "clustering") +add_julia_binding(gmm_train) +add_markdown_docs(gmm_train "cli;python;julia" "clustering") add_cli_executable(gmm_generate) add_python_binding(gmm_generate) -add_markdown_docs(gmm_generate "cli;python" "clustering") +add_julia_binding(gmm_generate) +add_markdown_docs(gmm_generate "cli;python;julia" "clustering") add_cli_executable(gmm_probability) add_python_binding(gmm_probability) -add_markdown_docs(gmm_probability "cli;python" "clustering") +add_julia_binding(gmm_probability) +add_markdown_docs(gmm_probability "cli;python;julia" "clustering") diff -Nru mlpack-3.2.2/src/mlpack/methods/gmm/eigenvalue_ratio_constraint.hpp mlpack-3.3.0/src/mlpack/methods/gmm/eigenvalue_ratio_constraint.hpp --- mlpack-3.2.2/src/mlpack/methods/gmm/eigenvalue_ratio_constraint.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/gmm/eigenvalue_ratio_constraint.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -64,7 +64,12 @@ // Eigendecompose the matrix. arma::vec eigenvalues; arma::mat eigenvectors; - arma::eig_sym(eigenvalues, eigenvectors, covariance); + covariance = arma::symmatu(covariance); + if (!arma::eig_sym(eigenvalues, eigenvectors, covariance)) + { + Log::Fatal << "applying to constraint could not be accomplished." + << std::endl; + } // Change the eigenvalues to what we are forcing them to be. There // shouldn't be any negative eigenvalues anyway, so it doesn't matter if we diff -Nru mlpack-3.2.2/src/mlpack/methods/gmm/em_fit_impl.hpp mlpack-3.3.0/src/mlpack/methods/gmm/em_fit_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/gmm/em_fit_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/gmm/em_fit_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -16,6 +16,7 @@ // In case it hasn't been included yet. #include "em_fit.hpp" #include "diagonal_constraint.hpp" +#include namespace mlpack { namespace gmm { @@ -76,7 +77,7 @@ << l << std::endl; double lOld = -DBL_MAX; - arma::mat condProb(observations.n_cols, dists.size()); + arma::mat condLogProb(observations.n_cols, dists.size()); // Iterate to update the model until no more improvement is found. size_t iteration = 1; @@ -89,33 +90,38 @@ // Gaussian given the observations and the present theta value. for (size_t i = 0; i < dists.size(); i++) { - // Store conditional probabilities into condProb vector for each - // Gaussian. First we make an alias of the condProb vector. - arma::vec condProbAlias = condProb.unsafe_col(i); - dists[i].Probability(observations, condProbAlias); - condProbAlias *= weights[i]; + // Store conditional log probabilities into condLogProb vector for each + // Gaussian. First we make an alias of the condLogProb vector. + arma::vec condLogProbAlias = condLogProb.unsafe_col(i); + dists[i].LogProbability(observations, condLogProbAlias); + condLogProbAlias += log(weights[i]); } // Normalize row-wise. - for (size_t i = 0; i < condProb.n_rows; i++) + for (size_t i = 0; i < condLogProb.n_rows; i++) { // Avoid dividing by zero; if the probability for everything is 0, we // don't want to make it NaN. - const double probSum = accu(condProb.row(i)); - if (probSum != 0.0) - condProb.row(i) /= probSum; + const double probSum = mlpack::math::AccuLog(condLogProb.row(i)); + if (probSum != -std::numeric_limits::infinity()) + condLogProb.row(i) -= probSum; } // Store the sum of the probability of each state over all the observations. - arma::vec probRowSums = trans(arma::sum(condProb, 0 /* columnwise */)); + arma::vec probRowSums(dists.size()); + for (size_t i = 0; i < dists.size(); ++i) + { + probRowSums(i) = mlpack::math::AccuLog(condLogProb.col(i)); + } // Calculate the new value of the means using the updated conditional // probabilities. for (size_t i = 0; i < dists.size(); i++) { // Don't update if there's no probability of the Gaussian having points. - if (probRowSums[i] != 0) - dists[i].Mean() = (observations * condProb.col(i)) / probRowSums[i]; + if (probRowSums[i] != -std::numeric_limits::infinity()) + dists[i].Mean() = observations * arma::exp(condLogProb.col(i) - + probRowSums[i]); else continue; @@ -130,7 +136,7 @@ { arma::vec covariance = arma::sum((tmp % tmp) % (arma::ones(observations.n_rows) * - trans(condProb.col(i))), 1) / probRowSums[i]; + trans(arma::exp(condLogProb.col(i) - probRowSums[i]))), 1); // Apply covariance constraint. constraint.ApplyConstraint(covariance); @@ -138,8 +144,9 @@ } else { - arma::mat tmpB = tmp.each_row() % trans(condProb.col(i)); - arma::mat covariance = (tmp * trans(tmpB)) / probRowSums[i]; + arma::mat tmpB = tmp.each_row() % trans(arma::exp(condLogProb.col(i) - + probRowSums[i])); + arma::mat covariance = tmp * trans(tmpB); // Apply covariance constraint. constraint.ApplyConstraint(covariance); @@ -149,7 +156,7 @@ // Calculate the new values for omega using the updated conditional // probabilities. - weights = probRowSums / observations.n_cols; + weights = arma::exp(probRowSums - log(observations.n_cols)); // Update values of l; calculate new log-likelihood. lOld = l; @@ -178,7 +185,7 @@ << l << std::endl; double lOld = -DBL_MAX; - arma::mat condProb(observations.n_cols, dists.size()); + arma::mat condLogProb(observations.n_cols, dists.size()); // Iterate to update the model until no more improvement is found. size_t iteration = 1; @@ -188,21 +195,21 @@ // Gaussian given the observations and the present theta value. for (size_t i = 0; i < dists.size(); i++) { - // Store conditional probabilities into condProb vector for each - // Gaussian. First we make an alias of the condProb vector. - arma::vec condProbAlias = condProb.unsafe_col(i); - dists[i].Probability(observations, condProbAlias); - condProbAlias *= weights[i]; + // Store conditional log probabilities into condLogProb vector for each + // Gaussian. First we make an alias of the condLogProb vector. + arma::vec condLogProbAlias = condLogProb.unsafe_col(i); + dists[i].LogProbability(observations, condLogProbAlias); + condLogProbAlias += log(weights[i]); } // Normalize row-wise. - for (size_t i = 0; i < condProb.n_rows; i++) + for (size_t i = 0; i < condLogProb.n_rows; i++) { // Avoid dividing by zero; if the probability for everything is 0, we // don't want to make it NaN. - const double probSum = accu(condProb.row(i)); - if (probSum != 0.0) - condProb.row(i) /= probSum; + const double probSum = mlpack::math::AccuLog(condLogProb.row(i)); + if (probSum != -std::numeric_limits::infinity()) + condLogProb.row(i) -= probSum; } // This will store the sum of probabilities of each state over all the @@ -211,19 +218,21 @@ // Calculate the new value of the means using the updated conditional // probabilities. + arma::vec logProbabilities = arma::log(probabilities); for (size_t i = 0; i < dists.size(); i++) { // Calculate the sum of probabilities of points, which is the // conditional probability of each point being from Gaussian i // multiplied by the probability of the point being from this mixture // model. - probRowSums[i] = accu(condProb.col(i) % probabilities); + arma::vec tmpProb = condLogProb.col(i) + logProbabilities; + probRowSums[i] = mlpack::math::AccuLog(tmpProb); // Don't update if there's no probability of the Gaussian having points. - if (probRowSums[i] != 0) + if (probRowSums[i] != -std::numeric_limits::infinity()) { - dists[i].Mean() = (observations * (condProb.col(i) % probabilities)) / - probRowSums[i]; + dists[i].Mean() = observations * + arma::exp(condLogProb.col(i) + logProbabilities - probRowSums[i]); } else continue; @@ -239,7 +248,8 @@ { arma::vec cov = arma::sum((tmp % tmp) % (arma::ones(observations.n_rows) * - trans(condProb.col(i) % probabilities)), 1) / probRowSums[i]; + trans(arma::exp(condLogProb.col(i) + + logProbabilities - probRowSums[i]))), 1); // Apply covariance constraint. constraint.ApplyConstraint(cov); @@ -247,9 +257,9 @@ } else { - arma::mat tmpB = tmp.each_row() % trans(condProb.col(i) % - probabilities); - arma::mat cov = (tmp * trans(tmpB)) / probRowSums[i]; + arma::mat tmpB = tmp.each_row() % trans(arma::exp(condLogProb.col(i) + + logProbabilities - probRowSums[i])); + arma::mat cov = (tmp * trans(tmpB)); // Apply covariance constraint. constraint.ApplyConstraint(cov); @@ -259,7 +269,7 @@ // Calculate the new values for omega using the updated conditional // probabilities. - weights = probRowSums / accu(probabilities); + weights = arma::exp(probRowSums - mlpack::math::AccuLog(logProbabilities)); // Update values of l; calculate new log-likelihood. lOld = l; @@ -373,21 +383,25 @@ { double logLikelihood = 0; - arma::vec phis; - arma::mat likelihoods(dists.size(), observations.n_cols); + arma::vec logPhis; + arma::mat logLikelihoods(dists.size(), observations.n_cols); + // It has to be LogProbability() otherwise Probability() would overflow easily for (size_t i = 0; i < dists.size(); ++i) { - dists[i].Probability(observations, phis); - likelihoods.row(i) = weights(i) * trans(phis); + dists[i].LogProbability(observations, logPhis); + logLikelihoods.row(i) = log(weights(i)) + trans(logPhis); } // Now sum over every point. for (size_t j = 0; j < observations.n_cols; ++j) { - if (accu(likelihoods.col(j)) == 0) + if (mlpack::math::AccuLog(logLikelihoods.col(j)) == + -std::numeric_limits::infinity()) + { Log::Info << "Likelihood of point " << j << " is 0! It is probably an " << "outlier." << std::endl; - logLikelihood += log(accu(likelihoods.col(j))); + } + logLikelihood += mlpack::math::AccuLog(logLikelihoods.col(j)); } return logLikelihood; diff -Nru mlpack-3.2.2/src/mlpack/methods/gmm/gmm.cpp mlpack-3.3.0/src/mlpack/methods/gmm/gmm.cpp --- mlpack-3.2.2/src/mlpack/methods/gmm/gmm.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/gmm/gmm.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -117,7 +117,12 @@ } } - return trans(chol(dists[gaussian].Covariance())) * + arma::mat cholDecomp; + if (!arma::chol(cholDecomp, dists[gaussian].Covariance())) + { + Log::Fatal << "Cholesky decomposition failed." << std::endl; + } + return trans(cholDecomp) * arma::randn(dimensionality) + dists[gaussian].Mean(); } @@ -136,10 +141,12 @@ for (size_t i = 0; i < observations.n_cols; ++i) { // Find maximum probability component. - double probability = 0; + double probability = -std::numeric_limits::infinity(); for (size_t j = 0; j < gaussians; ++j) { - double newProb = Probability(observations.unsafe_col(i), j); + // We have to use LogProbability() otherwise Probability() would overflow + // easily. + double newProb = LogProbability(observations.unsafe_col(i), j); if (newProb >= probability) { probability = newProb; @@ -158,18 +165,19 @@ const arma::vec& weightsL) const { double loglikelihood = 0; - arma::vec phis; - arma::mat likelihoods(gaussians, data.n_cols); + arma::vec logPhis; + arma::mat logLikelihoods(gaussians, data.n_cols); + // It has to be LogProbability() otherwise Probability() would overflow easily for (size_t i = 0; i < gaussians; i++) { - distsL[i].Probability(data, phis); - likelihoods.row(i) = weightsL(i) * trans(phis); + distsL[i].LogProbability(data, logPhis); + logLikelihoods.row(i) = log(weightsL(i)) + trans(logPhis); } // Now sum over every point. for (size_t j = 0; j < data.n_cols; j++) - loglikelihood += log(accu(likelihoods.col(j))); + loglikelihood += mlpack::math::AccuLog(logLikelihoods.col(j)); return loglikelihood; } diff -Nru mlpack-3.2.2/src/mlpack/methods/gmm/gmm_train_main.cpp mlpack-3.3.0/src/mlpack/methods/gmm/gmm_train_main.cpp --- mlpack-3.2.2/src/mlpack/methods/gmm/gmm_train_main.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/gmm/gmm_train_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -188,10 +188,6 @@ << " model (given with " << PRINT_PARAM_STRING("input_model") << " has dimensionality " << gmm->Dimensionality() << "!" << endl; } - else - { - gmm = new GMM(size_t(gaussians), dataPoints.n_rows); - } // Gather parameters for EMFit object. const size_t maxIterations = (size_t) CLI::GetParam("max_iterations"); @@ -212,6 +208,11 @@ return x > 0.0 && x <= 1.0; }, true, "percentage to sample must be " "be greater than 0.0 and less than or equal to 1.0"); + // Initialize the GMM if needed. (We didn't do this earlier, because + // RequireParamValue() would leak the memory if the check failed.) + if (!CLI::HasParam("input_model")) + gmm = new GMM(size_t(gaussians), dataPoints.n_rows); + const int samplings = CLI::GetParam("samplings"); const double percentage = CLI::GetParam("percentage"); @@ -274,6 +275,10 @@ } else { + // Initialize the GMM if needed. + if (!CLI::HasParam("input_model")) + gmm = new GMM(size_t(gaussians), dataPoints.n_rows); + // Depending on the value of forcePositive and diagonalCovariance, we have // to use different types. if (diagonalCovariance) diff -Nru mlpack-3.2.2/src/mlpack/methods/gmm/positive_definite_constraint.hpp mlpack-3.3.0/src/mlpack/methods/gmm/positive_definite_constraint.hpp --- mlpack-3.2.2/src/mlpack/methods/gmm/positive_definite_constraint.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/gmm/positive_definite_constraint.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -41,7 +41,12 @@ // eigenvalues are at least 1e-50). arma::vec eigval; arma::mat eigvec; - arma::eig_sym(eigval, eigvec, covariance); + covariance = arma::symmatu(covariance); + if (!arma::eig_sym(eigval, eigvec, covariance)) + { + Log::Fatal << "applying to constraint could not be accomplished." + << std::endl; + } // If the matrix is not positive definite or if the condition number is // large, we must project it back onto the cone of positive definite diff -Nru mlpack-3.2.2/src/mlpack/methods/hmm/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/hmm/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/hmm/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/hmm/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -21,16 +21,20 @@ add_cli_executable(hmm_train) add_python_binding(hmm_train) -add_markdown_docs(hmm_train "cli;python" "misc. / other") +add_julia_binding(hmm_train) +add_markdown_docs(hmm_train "cli;python;julia" "misc. / other") add_cli_executable(hmm_loglik) add_python_binding(hmm_loglik) -add_markdown_docs(hmm_loglik "cli;python" "misc. / other") +add_julia_binding(hmm_loglik) +add_markdown_docs(hmm_loglik "cli;python;julia" "misc. / other") add_cli_executable(hmm_viterbi) add_python_binding(hmm_viterbi) -add_markdown_docs(hmm_viterbi "cli;python" "misc. / other") +add_julia_binding(hmm_viterbi) +add_markdown_docs(hmm_viterbi "cli;python;julia" "misc. / other") add_cli_executable(hmm_generate) add_python_binding(hmm_generate) -add_markdown_docs(hmm_generate "cli;python" "misc. / other") +add_julia_binding(hmm_generate) +add_markdown_docs(hmm_generate "cli;python;julia" "misc. / other") diff -Nru mlpack-3.2.2/src/mlpack/methods/hmm/hmm.hpp mlpack-3.3.0/src/mlpack/methods/hmm/hmm.hpp --- mlpack-3.2.2/src/mlpack/methods/hmm/hmm.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/hmm/hmm.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -201,14 +201,14 @@ * of the most probable sequence is returned. * * @param dataSeq Sequence of observations. - * @param stateProb Matrix in which the log probabilities of each state at each - * time interval will be stored. - * @param forwardProb Matrix in which the forward log probabilities of each state - * at each time interval will be stored. + * @param stateProb Matrix in which the log probabilities of each state at + * each time interval will be stored. + * @param forwardProb Matrix in which the forward log probabilities of each + * state at each time interval will be stored. * @param backwardProb Matrix in which the backward log probabilities of each * state at each time interval will be stored. - * @param scales Vector in which the log of scaling factors at each time interval - * will be stored. + * @param scales Vector in which the log of scaling factors at each time + * interval will be stored. * @return Log-likelihood of most likely state sequence. */ double LogEstimate(const arma::mat& dataSeq, @@ -323,14 +323,22 @@ arma::mat& smoothSeq) const; //! Return the vector of initial state probabilities. - const arma::vec& Initial() const { return initial; } + const arma::vec& Initial() const { return initialProxy; } //! Modify the vector of initial state probabilities. - arma::vec& Initial() { return initial; } + arma::vec& Initial() + { + recalculateInitial = true; + return initialProxy; + } //! Return the transition matrix. - const arma::mat& Transition() const { return transition; } + const arma::mat& Transition() const { return transitionProxy; } //! Return a modifiable transition matrix reference. - arma::mat& Transition() { return transition; } + arma::mat& Transition() + { + recalculateTransition = true; + return transitionProxy; + } //! Return the emission distributions. const std::vector& Emission() const { return emission; } @@ -348,10 +356,19 @@ double& Tolerance() { return tolerance; } /** - * Serialize the object. + * Load the object. */ template - void serialize(Archive& ar, const unsigned int version); + void load(Archive& ar, const unsigned int version); + + /** + * Save the object. + */ + template + void save(Archive& ar, const unsigned int version) const; + + BOOST_SERIALIZATION_SPLIT_MEMBER(); + protected: // Helper functions. @@ -387,18 +404,49 @@ //! Set of emission probability distributions; one for each state. std::vector emission; - //! Transition probability matrix. - arma::mat transition; + /** + * A proxy variable in linear space for logTransition. + * Should be removed in mlpack 4.0. + */ + arma::mat transitionProxy; + + //! Transition probability matrix. No need to be mutable in mlpack 4.0. + mutable arma::mat logTransition; private: - //! Initial state probability vector. - arma::vec initial; + /** + * Make sure the variables in log space are in sync + * with the linear counter parts. + * Should be removed in mlpack 4.0. + */ + void ConvertToLogSpace() const; + + /** + * A proxy vriable in linear space for logInitial. + * Should be removed in mlpack 4.0. + */ + arma::vec initialProxy; + + //! Initial state probability vector. No need to be mutable in mlpack 4.0. + mutable arma::vec logInitial; //! Dimensionality of observations. size_t dimensionality; //! Tolerance of Baum-Welch algorithm. double tolerance; + + /** + * Whether or not we need to update the logInitial from initialProxy. + * Should be removed in mlpack 4.0. + */ + mutable bool recalculateInitial; + + /** + * Whether or not we need to update the logTransition from transitionProxy. + * Should be removed in mlpack 4.0. + */ + mutable bool recalculateTransition; }; } // namespace hmm diff -Nru mlpack-3.2.2/src/mlpack/methods/hmm/hmm_impl.hpp mlpack-3.3.0/src/mlpack/methods/hmm/hmm_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/hmm/hmm_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/hmm/hmm_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -30,15 +30,20 @@ const Distribution emissions, const double tolerance) : emission(states, /* default distribution */ emissions), - transition(arma::randu(states, states)), - initial(arma::randu(states) / (double) states), + transitionProxy(arma::randu(states, states)), + initialProxy(arma::randu(states) / (double) states), dimensionality(emissions.Dimensionality()), - tolerance(tolerance) + tolerance(tolerance), + recalculateInitial(false), + recalculateTransition(false) { // Normalize the transition probabilities and initial state probabilities. - initial /= arma::accu(initial); - for (size_t i = 0; i < transition.n_cols; ++i) - transition.col(i) /= arma::accu(transition.col(i)); + initialProxy /= arma::accu(initialProxy); + for (size_t i = 0; i < transitionProxy.n_cols; ++i) + transitionProxy.col(i) /= arma::accu(transitionProxy.col(i)); + + logTransition = log(transitionProxy); + logInitial = log(initialProxy); } /** @@ -51,9 +56,13 @@ const std::vector& emission, const double tolerance) : emission(emission), - transition(transition), - initial(initial), - tolerance(tolerance) + transitionProxy(transition), + logTransition(log(transition)), + initialProxy(initial), + logInitial(log(initial)), + tolerance(tolerance), + recalculateInitial(false), + recalculateTransition(false) { // Set the dimensionality, if we can. if (emission.size() > 0) @@ -106,7 +115,7 @@ // These are used later for training of each distribution. We initialize it // all now so we don't have to do any allocation later on. - std::vector emissionProb(transition.n_cols, + std::vector emissionProb(logTransition.n_cols, arma::vec(totalLength)); arma::mat emissionList(dimensionality, totalLength); @@ -116,9 +125,9 @@ for (size_t iter = 0; iter < iterations; iter++) { // Clear new transition matrix and emission probabilities. - arma::vec newLogInitial(transition.n_rows); + arma::vec newLogInitial(logTransition.n_rows); newLogInitial.fill(-std::numeric_limits::infinity()); - arma::mat newLogTransition(transition.n_rows, transition.n_cols); + arma::mat newLogTransition(logTransition.n_rows, logTransition.n_cols); newLogTransition.fill(-std::numeric_limits::infinity()); // Reset log likelihood. @@ -140,7 +149,7 @@ backwardLog, logScales); // Add to estimate of initial probability for state j. - for (size_t j = 0; j < transition.n_cols; ++j) + for (size_t j = 0; j < logTransition.n_cols; ++j) newLogInitial[j] = math::LogAdd(newLogInitial[j], stateLogProb(j, 0)); // Now re-estimate the parameters. This is the M-step. @@ -151,13 +160,13 @@ // We store the new estimates in a different matrix. for (size_t t = 0; t < dataSeq[seq].n_cols; ++t) { - for (size_t j = 0; j < transition.n_cols; ++j) + for (size_t j = 0; j < logTransition.n_cols; ++j) { if (t < dataSeq[seq].n_cols - 1) { // Estimate of T_ij (probability of transition from state j to state // i). We postpone multiplication of the old T_ij until later. - for (size_t i = 0; i < transition.n_rows; i++) + for (size_t i = 0; i < logTransition.n_rows; i++) { newLogTransition(i, j) = math::LogAdd(newLogTransition(i, j), forwardLog(j, t) + backwardLog(i, t + 1) + @@ -184,28 +193,30 @@ // Normalize the new initial probabilities. if (dataSeq.size() > 1) - initial = exp(newLogInitial) / dataSeq.size(); + logInitial = newLogInitial - log(dataSeq.size()); else - initial = exp(newLogInitial); + logInitial = newLogInitial; // Assign the new transition matrix. We use %= (element-wise // multiplication) because every element of the new transition matrix must // still be multiplied by the old elements (this is the multiplication we // earlier postponed). - transition %= exp(newLogTransition); + logTransition += newLogTransition; // Now we normalize the transition matrix. - for (size_t i = 0; i < transition.n_cols; i++) + for (size_t i = 0; i < logTransition.n_cols; i++) { - const double sum = accu(transition.col(i)); - if (sum > 0.0) - transition.col(i) /= sum; + const double sum = math::AccuLog(logTransition.col(i)); + if (std::isfinite(sum)) + logTransition.col(i) -= sum; else - transition.col(i).fill(1.0 / (double) transition.n_rows); + logTransition.col(i).fill(-log((double) logTransition.n_rows)); } + initialProxy = exp(logInitial); + transitionProxy = exp(logTransition); // Now estimate emission probabilities. - for (size_t state = 0; state < transition.n_cols; state++) + for (size_t state = 0; state < logTransition.n_cols; state++) emission[state].Train(emissionList, emissionProb[state]); Log::Debug << "Iteration " << iter << ": log-likelihood " << loglik @@ -230,8 +241,9 @@ << ")." << std::endl; } - initial.zeros(); - transition.zeros(); + arma::mat initial = arma::zeros(logInitial.n_elem); + arma::mat transition = arma::zeros(logTransition.n_rows, + logTransition.n_cols); // Estimate the transition and emission matrices directly from the // observations. The emission list holds the time indices for observations @@ -284,6 +296,11 @@ transition.col(col) /= sum; } + initialProxy = initial; + transitionProxy = transition; + logTransition = log(transition); + logInitial = log(initial); + // Estimate emission matrix. for (size_t state = 0; state < transition.n_cols; state++) { @@ -406,6 +423,8 @@ // distribution of emissions for our starting state. dataSequence.col(0) = emission[startState].Random(); + ConvertToLogSpace(); + // Now choose the states and emissions for the rest of the sequence. for (size_t t = 1; t < length; t++) { @@ -415,9 +434,9 @@ // Now find where our random value sits in the probability distribution of // state changes. double probSum = 0; - for (size_t st = 0; st < transition.n_rows; st++) + for (size_t st = 0; st < logTransition.n_rows; st++) { - probSum += transition(st, stateSequence[t - 1]); + probSum += exp(logTransition(st, stateSequence[t - 1])); if (randValue <= probSum) { stateSequence[t] = st; @@ -444,20 +463,18 @@ // don't use log-likelihoods to save that little bit of time, but we'll // calculate the log-likelihood at the end of it all. stateSeq.set_size(dataSeq.n_cols); - arma::mat logStateProb(transition.n_rows, dataSeq.n_cols); - arma::mat stateSeqBack(transition.n_rows, dataSeq.n_cols); + arma::mat logStateProb(logTransition.n_rows, dataSeq.n_cols); + arma::mat stateSeqBack(logTransition.n_rows, dataSeq.n_cols); - // Store the logs of the transposed transition matrix. This is because we - // will be using the rows of the transition matrix. - arma::mat logTrans(log(trans(transition))); + ConvertToLogSpace(); // The calculation of the first state is slightly different; the probability // of the first state being state j is the maximum probability that the state // came to be j from another state. logStateProb.col(0).zeros(); - for (size_t state = 0; state < transition.n_rows; state++) + for (size_t state = 0; state < logTransition.n_rows; state++) { - logStateProb(state, 0) = log(initial[state]) + + logStateProb(state, 0) = logInitial[state] + emission[state].LogProbability(dataSeq.unsafe_col(0)); stateSeqBack(state, 0) = state; } @@ -469,9 +486,9 @@ // Assemble the state probability for this element. // Given that we are in state j, we use state with the highest probability // of being the previous state. - for (size_t j = 0; j < transition.n_rows; j++) + for (size_t j = 0; j < logTransition.n_rows; j++) { - arma::vec prob = logStateProb.col(t - 1) + logTrans.col(j); + arma::vec prob = logStateProb.col(t - 1) + logTransition.row(j).t(); logStateProb(j, t) = prob.max(index) + emission[j].LogProbability(dataSeq.unsafe_col(t)); stateSeqBack(j, t) = index; @@ -518,11 +535,11 @@ arma::vec logScales; Forward(dataSeq, logScales, forwardLogProb); - arma::mat forwardProb = exp(forwardLogProb); - // Propagate state ahead. if (ahead != 0) - forwardProb = pow(transition, ahead) * forwardProb; + forwardLogProb += ahead * logTransition; + + arma::mat forwardProb = exp(forwardLogProb); // Compute expected emissions. // Will not work for distributions without a Mean() function. @@ -563,21 +580,21 @@ { // Our goal is to calculate the forward probabilities: // P(X_k | o_{1:k}) for all possible states X_k, for each time point k. - forwardLogProb.resize(transition.n_rows, dataSeq.n_cols); + forwardLogProb.resize(logTransition.n_rows, dataSeq.n_cols); forwardLogProb.fill(-std::numeric_limits::infinity()); logScales.resize(dataSeq.n_cols); logScales.fill(-std::numeric_limits::infinity()); - arma::mat logTrans = trans(log(transition)); + ConvertToLogSpace(); // The first entry in the forward algorithm uses the initial state // probabilities. Note that MATLAB assumes that the starting state (at // t = -1) is state 0; this is not our assumption here. To force that // behavior, you could append a single starting state to every single data // sequence and that should produce results in line with MATLAB. - for (size_t state = 0; state < transition.n_rows; state++) + for (size_t state = 0; state < logTransition.n_rows; state++) { - forwardLogProb(state, 0) = log(initial(state)) + + forwardLogProb(state, 0) = logInitial(state) + emission[state].LogProbability(dataSeq.unsafe_col(0)); } @@ -589,12 +606,12 @@ // Now compute the probabilities for each successive observation. for (size_t t = 1; t < dataSeq.n_cols; t++) { - for (size_t j = 0; j < transition.n_rows; j++) + for (size_t j = 0; j < logTransition.n_rows; j++) { // The forward probability of state j at time t is the sum over all states // of the probability of the previous state transitioning to the current // state and emitting the given observation. - arma::vec tmp = forwardLogProb.col(t - 1) + logTrans.col(j); + arma::vec tmp = forwardLogProb.col(t - 1) + logTransition.row(j).t(); forwardLogProb(j, t) = math::AccuLog(tmp) + emission[j].LogProbability(dataSeq.unsafe_col(t)); } @@ -613,9 +630,8 @@ { // Our goal is to calculate the backward probabilities: // P(X_k | o_{k + 1:T}) for all possible states X_k, for each time point k. - backwardLogProb.resize(transition.n_rows, dataSeq.n_cols); + backwardLogProb.resize(logTransition.n_rows, dataSeq.n_cols); backwardLogProb.fill(-std::numeric_limits::infinity()); - arma::mat logTrans = log(transition); // The last element probability is 1. backwardLogProb.col(dataSeq.n_cols - 1).fill(0); @@ -623,16 +639,16 @@ // Now step backwards through all other observations. for (size_t t = dataSeq.n_cols - 2; t + 1 > 0; t--) { - for (size_t j = 0; j < transition.n_rows; j++) + for (size_t j = 0; j < logTransition.n_rows; j++) { // The backward probability of state j at time t is the sum over all state // of the probability of the next state having been a transition from the // current state multiplied by the probability of each of those states // emitting the given observation. - for (size_t state = 0; state < transition.n_rows; state++) + for (size_t state = 0; state < logTransition.n_rows; state++) { backwardLogProb(j, t) = math::LogAdd(backwardLogProb(j, t), - logTrans(state, j) + backwardLogProb(state, t + 1) + logTransition(state, j) + backwardLogProb(state, t + 1) + emission[state].LogProbability(dataSeq.unsafe_col(t + 1))); } @@ -643,11 +659,32 @@ } } +/** + * Make sure the variables in log space are in sync with the linear counter parts + */ +template +void HMM::ConvertToLogSpace() const +{ + if (recalculateInitial) + { + logInitial = log(initialProxy); + recalculateInitial = false; + } + + if (recalculateTransition) + { + logTransition = log(transitionProxy); + recalculateTransition = false; + } +} + //! Serialize the HMM. template template -void HMM::serialize(Archive& ar, const unsigned int /* version */) +void HMM::load(Archive& ar, const unsigned int /* version */) { + arma::mat transition; + arma::vec initial; ar & BOOST_SERIALIZATION_NVP(dimensionality); ar & BOOST_SERIALIZATION_NVP(tolerance); ar & BOOST_SERIALIZATION_NVP(transition); @@ -655,11 +692,29 @@ // Now serialize each emission. If we are loading, we must resize the vector // of emissions correctly. - if (Archive::is_loading::value) - emission.resize(transition.n_rows); - + emission.resize(transition.n_rows); // Load the emissions; generate the correct name for each one. - ar & BOOST_SERIALIZATION_NVP(emission); + ar & BOOST_SERIALIZATION_NVP(emission); + + logTransition = log(transition); + logInitial = log(initial); + initialProxy = std::move(initial); + transitionProxy = std::move(transition); +} + +//! Serialize the HMM. +template +template +void HMM::save(Archive& ar, + const unsigned int /* version */) const +{ + arma::mat transition = exp(logTransition); + arma::vec initial = exp(logInitial); + ar & BOOST_SERIALIZATION_NVP(dimensionality); + ar & BOOST_SERIALIZATION_NVP(tolerance); + ar & BOOST_SERIALIZATION_NVP(transition); + ar & BOOST_SERIALIZATION_NVP(initial); + ar & BOOST_SERIALIZATION_NVP(emission); } } // namespace hmm diff -Nru mlpack-3.2.2/src/mlpack/methods/hmm/hmm_train_main.cpp mlpack-3.3.0/src/mlpack/methods/hmm/hmm_train_main.cpp --- mlpack-3.2.2/src/mlpack/methods/hmm/hmm_train_main.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/hmm/hmm_train_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -515,16 +515,26 @@ if (CLI::HasParam("input_model")) { hmm = CLI::GetParam("input_model"); + + hmm->PerformAction>(&trainSeq); } else { // We need to initialize the model. hmm = new HMMModel(typeId); - hmm->PerformAction>(&trainSeq); - } - // Train the model. - hmm->PerformAction>(&trainSeq); + // Catch any exceptions so that we can clean the model if needed. + try + { + hmm->PerformAction>(&trainSeq); + hmm->PerformAction>(&trainSeq); + } + catch (std::exception& e) + { + delete hmm; + throw; + } + } // If necessary, save the output. CLI::GetParam("output_model") = hmm; diff -Nru mlpack-3.2.2/src/mlpack/methods/hoeffding_trees/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/hoeffding_trees/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/hoeffding_trees/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/hoeffding_trees/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -30,4 +30,5 @@ add_cli_executable(hoeffding_tree) add_python_binding(hoeffding_tree) -add_markdown_docs(hoeffding_tree "cli;python" "classification") +add_julia_binding(hoeffding_tree) +add_markdown_docs(hoeffding_tree "cli;python;julia" "classification") diff -Nru mlpack-3.2.2/src/mlpack/methods/hoeffding_trees/hoeffding_tree.hpp mlpack-3.3.0/src/mlpack/methods/hoeffding_trees/hoeffding_tree.hpp --- mlpack-3.2.2/src/mlpack/methods/hoeffding_trees/hoeffding_tree.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/hoeffding_trees/hoeffding_tree.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -121,6 +121,8 @@ * @param dimensionMappings Mappings from dimension indices to positions in * numeric and categorical split vectors. If left NULL, a new one will * be created. + * @param copyDatasetInfo If true, then a copy of the datasetInfo will be + * made. */ HoeffdingTree(const data::DatasetInfo& datasetInfo, const size_t numClasses, @@ -133,7 +135,8 @@ const NumericSplitType& numericSplitIn = NumericSplitType(0), std::unordered_map>* - dimensionMappings = NULL); + dimensionMappings = NULL, + const bool copyDatasetInfo = true); /** * Construct a Hoeffding tree with no data and no information. Be sure to diff -Nru mlpack-3.2.2/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp mlpack-3.3.0/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -96,7 +96,8 @@ categoricalSplitIn, const NumericSplitType& numericSplitIn, std::unordered_map>* - dimensionMappingsIn) : + dimensionMappingsIn, + const bool copyDatasetInfo) : dimensionMappings((dimensionMappingsIn != NULL) ? dimensionMappingsIn : new std::unordered_map>()), ownsMappings(dimensionMappingsIn == NULL), @@ -105,8 +106,9 @@ maxSamples((maxSamples == 0) ? size_t(-1) : maxSamples), checkInterval(checkInterval), minSamples(minSamples), - datasetInfo(new data::DatasetInfo(datasetInfo)), - ownsInfo(true), + datasetInfo(copyDatasetInfo ? new data::DatasetInfo(datasetInfo) : + &datasetInfo), + ownsInfo(copyDatasetInfo), successProbability(successProbability), splitDimension(size_t(-1)), majorityClass(0), @@ -208,7 +210,18 @@ { // Copy each of the children. for (size_t i = 0; i < other.children.size(); ++i) + { children.push_back(new HoeffdingTree(*other.children[i])); + + // Delete copied datasetInfo and dimension mappings. + delete children[i]->datasetInfo; + children[i]->datasetInfo = this->datasetInfo; + children[i]->ownsInfo = false; + + delete children[i]->dimensionMappings; + children[i]->dimensionMappings = this->dimensionMappings; + children[i]->ownsMappings = false; + } } template(0, numClasses), - numericSplits[0], dimensionMappings)); + numericSplits[0], dimensionMappings, false)); } else if (numericSplits.size() == 0) { @@ -752,14 +765,14 @@ children.push_back(new HoeffdingTree(*datasetInfo, numClasses, successProbability, maxSamples, checkInterval, minSamples, categoricalSplits[0], NumericSplitType(numClasses), - dimensionMappings)); + dimensionMappings, false)); } else { // Pass both splits that we already have. children.push_back(new HoeffdingTree(*datasetInfo, numClasses, successProbability, maxSamples, checkInterval, minSamples, - categoricalSplits[0], numericSplits[0], dimensionMappings)); + categoricalSplits[0], numericSplits[0], dimensionMappings, false)); } children[i]->MajorityClass() = childMajorities[i]; @@ -874,7 +887,8 @@ { // The child doesn't actually own its own DatasetInfo. We do. The same // applies for the dimension mappings. - children[i]->ownsInfo = false; + if (children[i]->datasetInfo == datasetInfo) + children[i]->ownsInfo = false; children[i]->ownsMappings = false; } diff -Nru mlpack-3.2.2/src/mlpack/methods/hoeffding_trees/hoeffding_tree_model.cpp mlpack-3.3.0/src/mlpack/methods/hoeffding_trees/hoeffding_tree_model.cpp --- mlpack-3.2.2/src/mlpack/methods/hoeffding_trees/hoeffding_tree_model.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/hoeffding_trees/hoeffding_tree_model.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -135,6 +135,12 @@ const size_t bins, const size_t observationsBeforeBinning) { + // Clean memory, if needed. + delete giniHoeffdingTree; + delete giniBinaryTree; + delete infoHoeffdingTree; + delete infoBinaryTree; + // Depending on the type, create the tree. switch (type) { diff -Nru mlpack-3.2.2/src/mlpack/methods/hoeffding_trees/hoeffding_tree_model.hpp mlpack-3.3.0/src/mlpack/methods/hoeffding_trees/hoeffding_tree_model.hpp --- mlpack-3.2.2/src/mlpack/methods/hoeffding_trees/hoeffding_tree_model.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/hoeffding_trees/hoeffding_tree_model.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -187,33 +187,13 @@ // Fake dataset info may be needed to create fake trees. data::DatasetInfo info; if (type == GINI_HOEFFDING) - { - // Create fake tree to load into if needed. - if (Archive::is_loading::value) - giniHoeffdingTree = new GiniHoeffdingTreeType(info, 1, 1); ar & BOOST_SERIALIZATION_NVP(giniHoeffdingTree); - } else if (type == GINI_BINARY) - { - // Create fake tree to load into if needed. - if (Archive::is_loading::value) - giniBinaryTree = new GiniBinaryTreeType(info, 1, 1); ar & BOOST_SERIALIZATION_NVP(giniBinaryTree); - } else if (type == INFO_HOEFFDING) - { - // Create fake tree to load into if needed. - if (Archive::is_loading::value) - infoHoeffdingTree = new InfoHoeffdingTreeType(info, 1, 1); ar & BOOST_SERIALIZATION_NVP(infoHoeffdingTree); - } else if (type == INFO_BINARY) - { - // Create fake tree to load into if needed. - if (Archive::is_loading::value) - infoBinaryTree = new InfoBinaryTreeType(info, 1, 1); ar & BOOST_SERIALIZATION_NVP(infoBinaryTree); - } } private: diff -Nru mlpack-3.2.2/src/mlpack/methods/kde/kde_impl.hpp mlpack-3.3.0/src/mlpack/methods/kde/kde_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/kde/kde_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/kde/kde_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -336,7 +336,16 @@ std::vector oldFromNewQueries; Tree* queryTree = BuildTree(std::move(querySet), oldFromNewQueries); Timer::Stop("building_query_tree"); - this->Evaluate(queryTree, oldFromNewQueries, estimations); + try + { + this->Evaluate(queryTree, oldFromNewQueries, estimations); + } + catch (std::exception& e) + { + // Make sure we delete the query tree. + delete queryTree; + throw; + } delete queryTree; } else if (mode == SINGLE_TREE_MODE) diff -Nru mlpack-3.2.2/src/mlpack/methods/kde/kde_main.cpp mlpack-3.3.0/src/mlpack/methods/kde/kde_main.cpp --- mlpack-3.2.2/src/mlpack/methods/kde/kde_main.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/kde/kde_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -314,6 +314,5 @@ CLI::GetParam("predictions") = std::move(estimations); // Save model. - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = kde; + CLI::GetParam("output_model") = kde; } diff -Nru mlpack-3.2.2/src/mlpack/methods/kernel_pca/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/kernel_pca/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/kernel_pca/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/kernel_pca/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -18,4 +18,5 @@ add_cli_executable(kernel_pca) add_python_binding(kernel_pca) -add_markdown_docs(kernel_pca "cli;python" "transformations") +add_julia_binding(kernel_pca) +add_markdown_docs(kernel_pca "cli;python;julia" "transformations") diff -Nru mlpack-3.2.2/src/mlpack/methods/kernel_pca/kernel_rules/naive_method.hpp mlpack-3.3.0/src/mlpack/methods/kernel_pca/kernel_rules/naive_method.hpp --- mlpack-3.2.2/src/mlpack/methods/kernel_pca/kernel_rules/naive_method.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/kernel_pca/kernel_rules/naive_method.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -73,7 +73,11 @@ kernelMatrix += arma::sum(rowMean) / kernelMatrix.n_cols; // Eigendecompose the centered kernel matrix. - arma::eig_sym(eigval, eigvec, kernelMatrix); + kernelMatrix = arma::symmatu(kernelMatrix); + if (!arma::eig_sym(eigval, eigvec, kernelMatrix)) + { + Log::Fatal << "Failed to construct the kernel matrix." << std::endl; + } // Swap the eigenvalues since they are ordered backwards (we need largest to // smallest). diff -Nru mlpack-3.2.2/src/mlpack/methods/kernel_pca/kernel_rules/nystroem_method.hpp mlpack-3.3.0/src/mlpack/methods/kernel_pca/kernel_rules/nystroem_method.hpp --- mlpack-3.2.2/src/mlpack/methods/kernel_pca/kernel_rules/nystroem_method.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/kernel_pca/kernel_rules/nystroem_method.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -64,7 +64,11 @@ G += arma::sum(colMean) / G.n_rows; // Eigendecompose the centered kernel matrix. - arma::eig_sym(eigval, eigvec, transformedData); + transformedData = arma::symmatu(transformedData); + if (!arma::eig_sym(eigval, eigvec, transformedData)) + { + Log::Fatal << "Failed to construct the kernel matrix." << std::endl; + } // Swap the eigenvalues since they are ordered backwards (we need largest // to smallest). diff -Nru mlpack-3.2.2/src/mlpack/methods/kmeans/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/kmeans/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/kmeans/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/kmeans/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -40,4 +40,5 @@ add_cli_executable(kmeans) add_python_binding(kmeans) -add_markdown_docs(kmeans "cli;python" "clustering") +add_julia_binding(kmeans) +add_markdown_docs(kmeans "cli;python;julia" "clustering") diff -Nru mlpack-3.2.2/src/mlpack/methods/lars/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/lars/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/lars/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/lars/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -16,4 +16,5 @@ add_cli_executable(lars) add_python_binding(lars) -add_markdown_docs(lars "cli;python" "regression") +add_julia_binding(lars) +add_markdown_docs(lars "cli;python;julia" "regression") diff -Nru mlpack-3.2.2/src/mlpack/methods/lars/lars.cpp mlpack-3.3.0/src/mlpack/methods/lars/lars.cpp --- mlpack-3.2.2/src/mlpack/methods/lars/lars.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/lars/lars.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -361,7 +361,7 @@ beta = betaPath.back(); Timer::Stop("lars_regression"); - return maxCorr; + return ComputeError(matX, y, !transposeData); } double LARS::Train(const arma::mat& data, @@ -538,3 +538,18 @@ matUtriCholFactor.shed_row(n); } } + +double LARS::ComputeError(const arma::mat& matX, + const arma::rowvec& y, + const bool rowMajor) +{ + if (rowMajor) + { + return arma::accu(arma::pow(y - trans(matX * betaPath.back()), 2.0)); + } + + else + { + return arma::accu(arma::pow(y - betaPath.back().t() * matX, 2.0)); + } +} diff -Nru mlpack-3.2.2/src/mlpack/methods/lars/lars.hpp mlpack-3.3.0/src/mlpack/methods/lars/lars.hpp --- mlpack-3.2.2/src/mlpack/methods/lars/lars.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/lars/lars.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -183,7 +183,7 @@ * @param responses A vector of targets. * @param beta Vector to store the solution (the coefficients) in. * @param transposeData Set to false if the data is row-major. - * @return The final absolute maximum correlation. + * @return minimum cost error(||y-beta*X||2 is used to calculate error). */ double Train(const arma::mat& data, const arma::rowvec& responses, @@ -202,7 +202,7 @@ * @param responses A vector of targets. * @param transposeData Should be true if the input data is column-major and * false otherwise. - * @return The final absolute maximum correlation. + * @return minimum cost error(||y-beta*X||2 is used to calculate error). */ double Train(const arma::mat& data, const arma::rowvec& responses, @@ -244,6 +244,22 @@ template void serialize(Archive& ar, const unsigned int /* version */); + /** + * Compute cost error of the given data matrix using the + * currently-trained LARS model. Only ||y-beta*X||2 is used to calculate + * cost error. + * + * @param data Column-major input data (or row-major input data if rowMajor = + * true). + * @param responses A vector of targets. + * @param rowMajor Should be true if the data points matrix is row-major and + * false otherwise. + * @return The minimum cost error. + */ + double ComputeError(const arma::mat& matX, + const arma::rowvec& y, + const bool rowMajor = false); + private: //! Gram matrix. arma::mat matGramInternal; diff -Nru mlpack-3.2.2/src/mlpack/methods/linear_regression/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/linear_regression/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/linear_regression/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/linear_regression/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -17,4 +17,5 @@ add_cli_executable(linear_regression) add_python_binding(linear_regression) -add_markdown_docs(linear_regression "cli;python" "regression") +add_julia_binding(linear_regression) +add_markdown_docs(linear_regression "cli;python;julia" "regression") diff -Nru mlpack-3.2.2/src/mlpack/methods/linear_svm/linear_svm_main.cpp mlpack-3.3.0/src/mlpack/methods/linear_svm/linear_svm_main.cpp --- mlpack-3.2.2/src/mlpack/methods/linear_svm/linear_svm_main.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/linear_svm/linear_svm_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -312,6 +312,13 @@ model->svm.NumClasses() = numClasses; model->svm.FitIntercept() = intercept; + if (numClasses <= 1) + { + if (!CLI::HasParam("input_model")) + delete model; + throw std::invalid_argument("Given input data has only 1 class!"); + } + if (optimizerType == "lbfgs") { ens::L_BFGS lbfgsOpt; @@ -369,6 +376,9 @@ // Checking the dimensionality of the test data. if (testSet.n_rows != trainingDimensionality) { + // Clean memory if needed. + if (!CLI::HasParam("input_model")) + delete model; Log::Fatal << "Test data dimensionality (" << testSet.n_rows << ") must " << "be the same as the dimensionality of the training data (" << trainingDimensionality << ")!" << endl; @@ -398,6 +408,8 @@ if (testSet.n_cols != testLabels.n_elem) { + if (!CLI::HasParam("input_model")) + delete model; Log::Fatal << "Test data given with " << PRINT_PARAM_STRING("test") << " has " << testSet.n_cols << " points, but labels in " << PRINT_PARAM_STRING("test_labels") << " have " diff -Nru mlpack-3.2.2/src/mlpack/methods/lmnn/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/lmnn/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/lmnn/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/lmnn/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -20,4 +20,5 @@ add_cli_executable(lmnn) add_python_binding(lmnn) -add_markdown_docs(lmnn "cli;python" "transformations") +add_julia_binding(lmnn) +add_markdown_docs(lmnn "cli;python;julia" "transformations") diff -Nru mlpack-3.2.2/src/mlpack/methods/local_coordinate_coding/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/local_coordinate_coding/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/local_coordinate_coding/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/local_coordinate_coding/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -20,4 +20,5 @@ add_cli_executable(local_coordinate_coding) add_python_binding(local_coordinate_coding) -add_markdown_docs(local_coordinate_coding "cli;python" "transformations") +add_julia_binding(local_coordinate_coding) +add_markdown_docs(local_coordinate_coding "cli;python;julia" "transformations") diff -Nru mlpack-3.2.2/src/mlpack/methods/local_coordinate_coding/local_coordinate_coding_main.cpp mlpack-3.3.0/src/mlpack/methods/local_coordinate_coding/local_coordinate_coding_main.cpp --- mlpack-3.2.2/src/mlpack/methods/local_coordinate_coding/local_coordinate_coding_main.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/local_coordinate_coding/local_coordinate_coding_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -134,8 +134,6 @@ LocalCoordinateCoding* lcc; if (CLI::HasParam("input_model")) lcc = CLI::GetParam("input_model"); - else - lcc = new LocalCoordinateCoding(0, 0.0); if (CLI::HasParam("training")) { @@ -160,6 +158,8 @@ RequireParamValue("tolerance", [](double x) { return x > 0; }, 1, "Tolerance should be a positive real number"); + lcc = new LocalCoordinateCoding(0, 0.0); + lcc->Lambda() = CLI::GetParam("lambda"); lcc->Atoms() = (size_t) CLI::GetParam("atoms"); lcc->MaxIterations() = (size_t) CLI::GetParam("max_iterations"); @@ -181,14 +181,21 @@ // Validate the size of the initial dictionary. if (lcc->Dictionary().n_cols != lcc->Atoms()) { - Log::Fatal << "The initial dictionary has " << lcc->Dictionary().n_cols + const size_t dictionarySize = lcc->Dictionary().n_cols; + const size_t atoms = lcc->Atoms(); + if (!CLI::HasParam("input_model")) + delete lcc; + Log::Fatal << "The initial dictionary has " << dictionarySize << " atoms, but the number of atoms was specified to be " - << lcc->Atoms() << "!" << endl; + << atoms << "!" << endl; } if (lcc->Dictionary().n_rows != matX.n_rows) { - Log::Fatal << "The initial dictionary has " << lcc->Dictionary().n_rows + const size_t dictionaryDimension = lcc->Dictionary().n_rows; + if (!CLI::HasParam("input_model")) + delete lcc; + Log::Fatal << "The initial dictionary has " << dictionaryDimension << " dimensions, but the data has " << matX.n_rows << " dimensions!" << endl; } @@ -209,10 +216,15 @@ mat matY = std::move(CLI::GetParam("test")); if (matY.n_rows != lcc->Dictionary().n_rows) + { + const size_t dictionaryDimension = lcc->Dictionary().n_rows; + if (!CLI::HasParam("input_model")) + delete lcc; Log::Fatal << "Model was trained with a dimensionality of " - << lcc->Dictionary().n_rows << ", but data in test file " + << dictionaryDimension << ", but data in test file " << CLI::GetPrintableParam("test") << " has a dimensionality of " << matY.n_rows << "!" << endl; + } // Normalize each point if the user asked for it. if (CLI::HasParam("normalize")) diff -Nru mlpack-3.2.2/src/mlpack/methods/logistic_regression/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/logistic_regression/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/logistic_regression/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/logistic_regression/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -19,4 +19,5 @@ add_cli_executable(logistic_regression) add_python_binding(logistic_regression) -add_markdown_docs(logistic_regression "cli;python" "classification") +add_julia_binding(logistic_regression) +add_markdown_docs(logistic_regression "cli;python;julia" "classification") diff -Nru mlpack-3.2.2/src/mlpack/methods/logistic_regression/logistic_regression_function_impl.hpp mlpack-3.3.0/src/mlpack/methods/logistic_regression/logistic_regression_function_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/logistic_regression/logistic_regression_function_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/logistic_regression/logistic_regression_function_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -15,6 +15,8 @@ // In case it hasn't been included yet. #include "logistic_regression_function.hpp" +#include + namespace mlpack { namespace regression { diff -Nru mlpack-3.2.2/src/mlpack/methods/logistic_regression/logistic_regression_impl.hpp mlpack-3.3.0/src/mlpack/methods/logistic_regression/logistic_regression_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/logistic_regression/logistic_regression_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/logistic_regression/logistic_regression_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -25,7 +25,6 @@ const MatType& predictors, const arma::Row& responses, const double lambda) : - parameters(arma::rowvec(predictors.n_rows + 1, arma::fill::zeros)), lambda(lambda) { Train(predictors, responses); @@ -60,7 +59,6 @@ const arma::Row& responses, OptimizerType& optimizer, const double lambda) : - parameters(arma::rowvec(predictors.n_rows + 1, arma::fill::zeros)), lambda(lambda) { Train(predictors, responses, optimizer); @@ -85,9 +83,11 @@ OptimizerType& optimizer, CallbackTypes&&... callbacks) { - LogisticRegressionFunction errorFunction(predictors, - responses, - lambda); + LogisticRegressionFunction errorFunction(predictors, responses, + lambda); + + // Set size of parameters vector according to the input data received. + parameters = arma::rowvec(predictors.n_rows + 1, arma::fill::zeros); errorFunction.InitialPoint() = parameters; Timer::Start("logistic_regression_optimization"); diff -Nru mlpack-3.2.2/src/mlpack/methods/lsh/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/lsh/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/lsh/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/lsh/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -19,4 +19,5 @@ # sets with p-stable LSH. add_cli_executable(lsh) add_python_binding(lsh) -add_markdown_docs(lsh "cli;python" "geometry") +add_julia_binding(lsh) +add_markdown_docs(lsh "cli;python;julia" "geometry") diff -Nru mlpack-3.2.2/src/mlpack/methods/lsh/lsh_main.cpp mlpack-3.3.0/src/mlpack/methods/lsh/lsh_main.cpp --- mlpack-3.2.2/src/mlpack/methods/lsh/lsh_main.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/lsh/lsh_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -220,8 +220,11 @@ if (trueNeighbors.n_rows != neighbors.n_rows || trueNeighbors.n_cols != neighbors.n_cols) { - Log::Fatal << "The true neighbors file must have the same number of " - << "values as the set of neighbors being queried!" << endl; + // Delete the model if needed. + if (CLI::HasParam("reference")) + delete allkann; + Log::Fatal << "The true neighbors file must have the same number of " + << "values as the set of neighbors being queried!" << endl; } Log::Info << "Using true neighbor indices from '" diff -Nru mlpack-3.2.2/src/mlpack/methods/mean_shift/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/mean_shift/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/mean_shift/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/mean_shift/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -16,4 +16,5 @@ add_cli_executable(mean_shift) add_python_binding(mean_shift) -add_markdown_docs(mean_shift "cli;python" "clustering") +add_julia_binding(mean_shift) +add_markdown_docs(mean_shift "cli;python;julia" "clustering") diff -Nru mlpack-3.2.2/src/mlpack/methods/naive_bayes/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/naive_bayes/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/naive_bayes/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/naive_bayes/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -16,4 +16,5 @@ add_cli_executable(nbc) add_python_binding(nbc) -add_markdown_docs(nbc "cli;python" "classification") +add_julia_binding(nbc) +add_markdown_docs(nbc "cli;python;julia" "classification") diff -Nru mlpack-3.2.2/src/mlpack/methods/nca/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/nca/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/nca/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/nca/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -18,4 +18,5 @@ add_cli_executable(nca) add_python_binding(nca) -add_markdown_docs(nca "cli;python" "transformations") +add_julia_binding(nca) +add_markdown_docs(nca "cli;python;julia" "transformations") diff -Nru mlpack-3.2.2/src/mlpack/methods/nca/nca_softmax_error_function_impl.hpp mlpack-3.3.0/src/mlpack/methods/nca/nca_softmax_error_function_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/nca/nca_softmax_error_function_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/nca/nca_softmax_error_function_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -15,6 +15,8 @@ // In case it hasn't been included already. #include "nca_softmax_error_function.hpp" +#include + namespace mlpack { namespace nca { diff -Nru mlpack-3.2.2/src/mlpack/methods/neighbor_search/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/neighbor_search/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/neighbor_search/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/neighbor_search/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -29,8 +29,10 @@ # Add mlpack_knn and mlpack_kfn executables. add_cli_executable(knn) add_python_binding(knn) -add_markdown_docs(knn "cli;python" "geometry") +add_julia_binding(knn) +add_markdown_docs(knn "cli;python;julia" "geometry") add_cli_executable(kfn) add_python_binding(kfn) -add_markdown_docs(kfn "cli;python" "geometry") +add_julia_binding(kfn) +add_markdown_docs(kfn "cli;python;julia" "geometry") diff -Nru mlpack-3.2.2/src/mlpack/methods/neighbor_search/kfn_main.cpp mlpack-3.3.0/src/mlpack/methods/neighbor_search/kfn_main.cpp --- mlpack-3.2.2/src/mlpack/methods/neighbor_search/kfn_main.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/neighbor_search/kfn_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -188,8 +188,6 @@ if (CLI::HasParam("reference")) { - kfn = new KFNModel(); - // Get all the parameters. RequireParamInSet("tree_type", { "kd", "cover", "r", "r-star", "ball", "x", "hilbert-r", "r-plus", "r-plus-plus", "vp", "rp", "max-rp", @@ -197,6 +195,8 @@ const string treeType = CLI::GetParam("tree_type"); const bool randomBasis = CLI::HasParam("random_basis"); + kfn = new KFNModel(); + KFNModel::TreeTypes tree = KFNModel::KD_TREE; if (treeType == "kd") tree = KFNModel::KD_TREE; @@ -274,8 +274,12 @@ << queryData.n_rows << "x" << queryData.n_cols << ")." << endl; if (queryData.n_rows != kfn->Dataset().n_rows) { + // Clean memory if needed. + const size_t dimensions = kfn->Dataset().n_rows; + if (CLI::HasParam("reference")) + delete kfn; Log::Fatal << "Query has invalid dimensions (" << queryData.n_rows << - "); should be " << kfn->Dataset().n_rows << "!" << endl; + "); should be " << dimensions << "!" << endl; } } @@ -284,18 +288,26 @@ // we only test the upper bound. if (k > kfn->Dataset().n_cols) { + // Clean memory if needed. + const size_t referencePoints = kfn->Dataset().n_cols; + if (CLI::HasParam("reference")) + delete kfn; Log::Fatal << "Invalid k: " << k << "; must be greater than 0 and less " << "than or equal to the number of reference points (" - << kfn->Dataset().n_cols << ")." << endl; + << referencePoints << ")." << endl; } // Sanity check on k value: must not be equal to the number of reference // points when query data has not been provided. if (!CLI::HasParam("query") && k == kfn->Dataset().n_cols) { + // Clean memory if needed. + const size_t referencePoints = kfn->Dataset().n_cols; + if (CLI::HasParam("reference")) + delete kfn; Log::Fatal << "Invalid k: " << k << "; must be less than the number of " - << "reference points (" << kfn->Dataset().n_cols << ") " - << "if query data has not been provided." << endl; + << "reference points (" << referencePoints << ") if query data has " + << "not been provided." << endl; } // Now run the search. @@ -321,8 +333,13 @@ if (trueDistances.n_rows != distances.n_rows || trueDistances.n_cols != distances.n_cols) + { + // Clean memory if needed. + if (CLI::HasParam("reference")) + delete kfn; Log::Fatal << "The true distances file must have the same number of " << "values than the set of distances being queried!" << endl; + } Log::Info << "Effective error: " << KFN::EffectiveError(distances, trueDistances) << endl; @@ -341,8 +358,13 @@ if (trueNeighbors.n_rows != neighbors.n_rows || trueNeighbors.n_cols != neighbors.n_cols) + { + // Clean memory if needed. + if (CLI::HasParam("reference")) + delete kfn; Log::Fatal << "The true neighbors file must have the same number of " << "values than the set of neighbors being queried!" << endl; + } Log::Info << "Recall: " << KFN::Recall(neighbors, trueNeighbors) << endl; } diff -Nru mlpack-3.2.2/src/mlpack/methods/neighbor_search/knn_main.cpp mlpack-3.3.0/src/mlpack/methods/neighbor_search/knn_main.cpp --- mlpack-3.2.2/src/mlpack/methods/neighbor_search/knn_main.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/neighbor_search/knn_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -53,7 +53,8 @@ "in " + PRINT_DATASET("distances") + " and the neighbors in " + PRINT_DATASET("neighbors") + ": " "\n\n" + - PRINT_CALL("knn", "k", 5, "reference", "input", "neighbors", "neighbors") + + PRINT_CALL("knn", "k", 5, "reference", "input", "neighbors", "neighbors", + "distances", "distances") + "\n\n" "The output is organized such that row i and column j in the neighbors " "output matrix corresponds to the index of the point in the reference set " @@ -199,8 +200,6 @@ if (CLI::HasParam("reference")) { - knn = new KNNModel(); - // Get all the parameters. const string treeType = CLI::GetParam("tree_type"); const bool randomBasis = CLI::HasParam("random_basis"); @@ -209,6 +208,9 @@ RequireParamInSet("tree_type", { "kd", "cover", "r", "r-star", "ball", "x", "hilbert-r", "r-plus", "r-plus-plus", "spill", "vp", "rp", "max-rp", "ub", "oct" }, true, "unknown tree type"); + + knn = new KNNModel(); + if (treeType == "kd") tree = KNNModel::KD_TREE; else if (treeType == "cover") @@ -291,8 +293,12 @@ << queryData.n_rows << "x" << queryData.n_cols << ")." << endl; if (queryData.n_rows != knn->Dataset().n_rows) { + // Clean memory if needed before crashing. + const size_t dimensions = knn->Dataset().n_rows; + if (CLI::HasParam("reference")) + delete knn; Log::Fatal << "Query has invalid dimensions(" << queryData.n_rows << - "); should be " << knn->Dataset().n_rows << "!" << endl; + "); should be " << dimensions << "!" << endl; } } @@ -301,18 +307,26 @@ // we only test the upper bound. if (k > knn->Dataset().n_cols) { + // Clean memory if needed before crashing. + const size_t referencePoints = knn->Dataset().n_cols; + if (CLI::HasParam("reference")) + delete knn; Log::Fatal << "Invalid k: " << k << "; must be greater than 0 and less " << "than or equal to the number of reference points (" - << knn->Dataset().n_cols << ")." << endl; + << referencePoints << ")." << endl; } // Sanity check on k value: must not be equal to the number of reference // points when query data has not been provided. if (!CLI::HasParam("query") && k == knn->Dataset().n_cols) { + // Clean memory if needed before crashing. + const size_t referencePoints = knn->Dataset().n_cols; + if (CLI::HasParam("reference")) + delete knn; Log::Fatal << "Invalid k: " << k << "; must be less than the number of " - << "reference points (" << knn->Dataset().n_cols << ") " - << "if query data has not been provided." << endl; + << "reference points (" << referencePoints << ") if query data has " + << "not been provided." << endl; } // Now run the search. @@ -338,8 +352,12 @@ if (trueDistances.n_rows != distances.n_rows || trueDistances.n_cols != distances.n_cols) + { + if (CLI::HasParam("reference")) + delete knn; Log::Fatal << "The true distances file must have the same number of " << "values than the set of distances being queried!" << endl; + } Log::Info << "Effective error: " << KNN::EffectiveError(distances, trueDistances) << endl; @@ -358,8 +376,12 @@ if (trueNeighbors.n_rows != neighbors.n_rows || trueNeighbors.n_cols != neighbors.n_cols) + { + if (CLI::HasParam("reference")) + delete knn; Log::Fatal << "The true neighbors file must have the same number of " << "values than the set of neighbors being queried!" << endl; + } Log::Info << "Recall: " << KNN::Recall(neighbors, trueNeighbors) << endl; } diff -Nru mlpack-3.2.2/src/mlpack/methods/nmf/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/nmf/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/nmf/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/nmf/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -1,3 +1,4 @@ add_cli_executable(nmf) add_python_binding(nmf) -add_markdown_docs(nmf "cli;python" "misc. / other") +add_julia_binding(nmf) +add_markdown_docs(nmf "cli;python;julia" "misc. / other") diff -Nru mlpack-3.2.2/src/mlpack/methods/nmf/nmf_main.cpp mlpack-3.3.0/src/mlpack/methods/nmf/nmf_main.cpp --- mlpack-3.2.2/src/mlpack/methods/nmf/nmf_main.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/nmf/nmf_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -14,9 +14,9 @@ #include #include - #include #include +#include #include #include #include @@ -130,6 +130,68 @@ } } +template +void ApplyFactorization(const arma::mat& V, + const size_t r, + arma::mat& W, + arma::mat& H) +{ + const size_t maxIterations = CLI::GetParam("max_iterations"); + const double minResidue = CLI::GetParam("min_residue"); + + SimpleResidueTermination srt(minResidue, maxIterations); + + // Load input dataset. We know if the data is transposed based on the + // BINDING_MATRIX_TRANSPOSED macro, which will be 'true' or 'false'. + arma::mat initialW, initialH; + LoadInitialWH(BINDING_MATRIX_TRANSPOSED, initialW, initialH); + if (CLI::HasParam("initial_w") && CLI::HasParam("initial_h")) + { + // Initialize W and H with given matrices + GivenInitialization ginit = GivenInitialization(initialW, initialH); + AMF amf(srt, ginit); + amf.Apply(V, r, W, H); + } + else if (CLI::HasParam("initial_w")) + { + // Merge GivenInitialization and RandomInitialization rules + // to initialize W with the given matrix, and H with random noise + GivenInitialization ginit = GivenInitialization(initialW); + RandomInitialization rinit = RandomInitialization(); + MergeInitialization minit = + MergeInitialization + (ginit, rinit); + AMF, + UpdateRuleType> amf(srt, minit); + amf.Apply(V, r, W, H); + } + else if (CLI::HasParam("initial_h")) + { + // Merge GivenInitialization and RandomInitialization rules + // to initialize H with the given matrix, and W with random noise + GivenInitialization ginit = GivenInitialization(initialH, false); + RandomInitialization rinit = RandomInitialization(); + MergeInitialization minit = + MergeInitialization + (rinit, ginit); + AMF, + UpdateRuleType> amf(srt, minit); + amf.Apply(V, r, W, H); + } + else + { + // Use random initialization + AMF amf(srt); + amf.Apply(V, r, W, H); + } +} + static void mlpackMain() { // Initialize random seed. @@ -140,8 +202,6 @@ // Gather parameters. const size_t r = CLI::GetParam("rank"); - const size_t maxIterations = CLI::GetParam("max_iterations"); - const double minResidue = CLI::GetParam("min_residue"); const string updateRules = CLI::GetParam("update_rules"); // Validate parameters. @@ -153,10 +213,7 @@ true, "max_iterations must be non-negative"); RequireAtLeastOnePassed({ "h", "w" }, false, "no output will be saved"); - RequireNoneOrAllPassed({"initial_w", "initial_h"}, true); - // Load input dataset. We know if the data is transposed based on the - // BINDING_MATRIX_TRANSPOSED macro, which will be 'true' or 'false'. arma::mat V = std::move(CLI::GetParam("input")); arma::mat W; @@ -167,76 +224,19 @@ { Log::Info << "Performing NMF with multiplicative distance-based update " << "rules." << std::endl; - - SimpleResidueTermination srt(minResidue, maxIterations); - if (CLI::HasParam("initial_w")) - { - // Initialization with given W, H matrices. - arma::mat initialW, initialH; - LoadInitialWH(BINDING_MATRIX_TRANSPOSED, initialW, initialH); - GivenInitialization ginit = GivenInitialization(initialW, initialH); - - AMF amf(srt, ginit); - amf.Apply(V, r, W, H); - } - else - { - AMF<> amf(srt); - amf.Apply(V, r, W, H); - } + ApplyFactorization(V, r, W, H); } else if (updateRules == "multdiv") { Log::Info << "Performing NMF with multiplicative divergence-based update " << "rules." << std::endl; - - SimpleResidueTermination srt(minResidue, maxIterations); - if (CLI::HasParam("initial_w")) - { - // Initialization with given W, H matrices. - arma::mat initialW, initialH; - LoadInitialWH(BINDING_MATRIX_TRANSPOSED, initialW, initialH); - GivenInitialization ginit = GivenInitialization(initialW, initialH); - - AMF amf(srt, ginit); - amf.Apply(V, r, W, H); - } - else - { - AMF amf(srt); - amf.Apply(V, r, W, H); - } + ApplyFactorization(V, r, W, H); } else if (updateRules == "als") { Log::Info << "Performing NMF with alternating least squared update rules." << std::endl; - - SimpleResidueTermination srt(minResidue, maxIterations); - if (CLI::HasParam("initial_w")) - { - // Initialization with given W, H matrices. - arma::mat initialW, initialH; - LoadInitialWH(BINDING_MATRIX_TRANSPOSED, initialW, initialH); - GivenInitialization ginit = GivenInitialization(initialW, initialH); - - AMF amf(srt, ginit); - amf.Apply(V, r, W, H); - } - else - { - AMF amf(srt); - amf.Apply(V, r, W, H); - } + ApplyFactorization(V, r, W, H); } // Save results. Remember from our discussion in the comments earlier that we diff -Nru mlpack-3.2.2/src/mlpack/methods/pca/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/pca/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/pca/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/pca/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -3,8 +3,6 @@ set(SOURCES pca.hpp pca_impl.hpp -# pca_nomain.hpp -# pca_nomain.cpp ) add_subdirectory(decomposition_policies) @@ -20,4 +18,5 @@ add_cli_executable(pca) add_python_binding(pca) -add_markdown_docs(pca "cli;python" "transformations") +add_julia_binding(pca) +add_markdown_docs(pca "cli;python;julia" "transformations") diff -Nru mlpack-3.2.2/src/mlpack/methods/pca/pca_impl.hpp mlpack-3.3.0/src/mlpack/methods/pca/pca_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/pca/pca_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/pca/pca_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -20,8 +20,6 @@ #include #include "pca.hpp" -using namespace std; - namespace mlpack { namespace pca { @@ -95,11 +93,11 @@ // Parameter validation. if (newDimension == 0) Log::Fatal << "PCA::Apply(): newDimension (" << newDimension << ") cannot " - << "be zero!" << endl; + << "be zero!" << std::endl; if (newDimension > data.n_rows) Log::Fatal << "PCA::Apply(): newDimension (" << newDimension << ") cannot " << "be greater than the existing dimensionality of the data (" - << data.n_rows << ")!" << endl; + << data.n_rows << ")!" << std::endl; arma::mat eigvec; arma::vec eigVal; @@ -146,10 +144,10 @@ // Parameter validation. if (varRetained < 0) Log::Fatal << "PCA::Apply(): varRetained (" << varRetained << ") must be " - << "greater than or equal to 0." << endl; + << "greater than or equal to 0." << std::endl; if (varRetained > 1) Log::Fatal << "PCA::Apply(): varRetained (" << varRetained << ") should be " - << "less than or equal to 1." << endl; + << "less than or equal to 1." << std::endl; arma::mat eigvec; arma::vec eigVal; diff -Nru mlpack-3.2.2/src/mlpack/methods/perceptron/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/perceptron/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/perceptron/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/perceptron/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -19,4 +19,5 @@ add_cli_executable(perceptron) add_python_binding(perceptron) -add_markdown_docs(perceptron "cli;python" "classification") +add_julia_binding(perceptron) +add_markdown_docs(perceptron "cli;python;julia" "classification") diff -Nru mlpack-3.2.2/src/mlpack/methods/preprocess/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/preprocess/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/preprocess/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/preprocess/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -15,23 +15,37 @@ set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) #add_cli_executable(preprocess_stats) + add_cli_executable(preprocess_split) add_python_binding(preprocess_split) -add_markdown_docs(preprocess_split "cli;python" "preprocessing") +add_julia_binding(preprocess_split) +add_markdown_docs(preprocess_split "cli;python;julia" "preprocessing") add_cli_executable(preprocess_binarize) add_python_binding(preprocess_binarize) -add_markdown_docs(preprocess_binarize "cli;python" "preprocessing") +add_julia_binding(preprocess_binarize) +add_markdown_docs(preprocess_binarize "cli;python;julia" "preprocessing") add_cli_executable(preprocess_describe) add_python_binding(preprocess_describe) -add_markdown_docs(preprocess_describe "cli;python" "preprocessing") +add_julia_binding(preprocess_describe) +add_markdown_docs(preprocess_describe "cli;python;julia" "preprocessing") #add_cli_executable(preprocess_scan) + add_cli_executable(preprocess_imputer) #add_python_binding(preprocess_imputer) +#add_julia_binding(preprocess_imputer) add_markdown_docs(preprocess_imputer "cli" "preprocessing") add_cli_executable(preprocess_scale) add_python_binding(preprocess_scale) -add_markdown_docs(preprocess_scale "cli;python" "preprocessing") +add_julia_binding(preprocess_scale) +add_markdown_docs(preprocess_scale "cli;python;julia" "preprocessing") + +if (STB_AVAILABLE) + add_cli_executable(image_converter) + add_python_binding(image_converter) + add_julia_binding(image_converter) + add_markdown_docs(image_converter "cli;python;julia" "preprocessing") +endif () \ No newline at end of file diff -Nru mlpack-3.2.2/src/mlpack/methods/preprocess/image_converter_main.cpp mlpack-3.3.0/src/mlpack/methods/preprocess/image_converter_main.cpp --- mlpack-3.2.2/src/mlpack/methods/preprocess/image_converter_main.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/preprocess/image_converter_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,114 @@ +/** + * @file image_converter_main.cpp + * @author Jeffin Sam + * + * A CLI executable to load and save a image dataset. + * + * 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 + +using namespace mlpack; +using namespace mlpack::util; +using namespace arma; +using namespace std; +using namespace mlpack::data; + +PROGRAM_INFO("Image Converter", + // Short description. + "A utility to load an image or set of images into a single dataset that" + " can then be used by other mlpack methods and utilities. This can also" + " unpack an image dataset into individual files, for instance after mlpack" + " methods have been used.", + // Long description. + "This utility takes an image or an array of images and loads them to a" + " matrix. You can optionally specify the height " + + PRINT_PARAM_STRING("height") + " width " + PRINT_PARAM_STRING("width") + + " and channel " + PRINT_PARAM_STRING("channels") + " of the images that" + " needs to be loaded; otherwise, these parameters will be automatically" + " detected from the image." + "\n" + "There are other options too, that can be specified such as " + + PRINT_PARAM_STRING("quality") + + ".\n\n" + + "You can also provide a dataset and save them as images using " + + PRINT_PARAM_STRING("dataset") + " and " + PRINT_PARAM_STRING("save") + + " as an parameter. An example to load an image : " + + "\n\n" + + PRINT_CALL("image_converter", "input", "X", "height", 256, "width", 256, + "channels", 3, "output", "Y") + + "\n\n" + + " An example to save an image is :" + + "\n\n" + + PRINT_CALL("image_converter", "input", "X", "height", 256, "width", 256, + "channels", 3, "dataset", "Y", "save", true), + SEE_ALSO("@preprocess_binarize", "#preprocess_binarize"), + SEE_ALSO("@preprocess_describe", "#preprocess_describe"), + SEE_ALSO("@preprocess_imputer", "#preprocess_imputer")); + +// DEFINE PARAM +PARAM_VECTOR_IN_REQ(string, "input", "Image filenames which have to " + "be loaded/saved.", "i"); + +PARAM_INT_IN("width", "Width of the image.", "w", 0); +PARAM_INT_IN("channels", "Number of channels in the image.", "c", 0); + +PARAM_MATRIX_OUT("output", "Matrix to save images data to, Only" + "needed if you are specifying 'save' option.", "o"); + +PARAM_INT_IN("quality", "Compression of the image if saved as jpg (0-100).", + "q", 90); + +PARAM_INT_IN("height", "Height of the images.", "H", 0); +PARAM_FLAG("save", "Save a dataset as images.", "s"); +PARAM_MATRIX_IN("dataset", "Input matrix to save as images.", "I"); + +static void mlpackMain() +{ + Timer::Start("Loading/Saving Image"); + // Parse command line options. + const vector fileNames = CLI::GetParam >("input"); + arma::mat out; + + if (!CLI::HasParam("save")) + { + ReportIgnoredParam("width", "Width of image is determined from file."); + ReportIgnoredParam("height", "Height of image is determined from file."); + ReportIgnoredParam("channels", "Number of channels determined from file."); + data::ImageInfo info; + Load(fileNames, out, info, true); + if (CLI::HasParam("output")) + CLI::GetParam("output") = std::move(out); + } + else + { + RequireNoneOrAllPassed({ "save", "width", "height", "channels", "dataset" } + , true, "Image size information is needed when 'save' is specified!"); + // Positive value for width. + RequireParamValue("width", [](int x) { return x >= 0;}, true, + "width must be positive"); + // Positive value for height. + RequireParamValue("height", [](int x) { return x >= 0;}, true, + "height must be positive"); + // Positive value for channel. + RequireParamValue("channels", [](int x) { return x >= 0;}, true, + "channels must be positive"); + // Positive value for quality. + RequireParamValue("quality", [](int x) { return x >= 0;}, true, + "quality must be positive"); + + const size_t height = CLI::GetParam("height"); + const size_t width = CLI::GetParam("width"); + const size_t channels = CLI::GetParam("channels"); + const size_t quality = CLI::GetParam("quality"); + data::ImageInfo info(width, height, channels, quality); + Save(fileNames, CLI::GetParam("dataset"), info, true); + } +} + diff -Nru mlpack-3.2.2/src/mlpack/methods/preprocess/preprocess_scale_main.cpp mlpack-3.3.0/src/mlpack/methods/preprocess/preprocess_scale_main.cpp --- mlpack-3.2.2/src/mlpack/methods/preprocess/preprocess_scale_main.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/preprocess/preprocess_scale_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -10,9 +10,10 @@ * http://www.opensource.org/licenses/BSD-3-Clause for more information. */ #include +#include #include #include -#include +#include #include #include #include @@ -131,6 +132,7 @@ { m = new ScalingModel(CLI::GetParam("min_value"), CLI::GetParam("max_value"), CLI::GetParam("epsilon")); + if (scalerMethod == "standard_scaler") { m->ScalerType() = ScalingModel::ScalerTypes::STANDARD_SCALER; @@ -155,8 +157,20 @@ { m->ScalerType() = ScalingModel::ScalerTypes::PCA_WHITENING; } - m->Fit(input); + + // Fit() can throw an exception on invalid inputs, so we have to catch that + // and clean the memory in that situation. + try + { + m->Fit(input); + } + catch (std::exception& e) + { + delete m; + throw; + } } + if (!CLI::HasParam("inverse_scaling")) { m->Transform(input, output); @@ -165,8 +179,8 @@ { if (!CLI::HasParam("input_model")) { - delete(m); - throw std::runtime_error("Please provide a saved model"); + delete m; + throw std::runtime_error("Please provide a saved model."); } m->InverseTransform(input, output); } @@ -175,6 +189,6 @@ if (CLI::HasParam("output")) CLI::GetParam("output") = std::move(output); Timer::Stop("feature_scaling"); - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = m; + + CLI::GetParam("output_model") = m; } diff -Nru mlpack-3.2.2/src/mlpack/methods/preprocess/preprocess_split_main.cpp mlpack-3.3.0/src/mlpack/methods/preprocess/preprocess_split_main.cpp --- mlpack-3.2.2/src/mlpack/methods/preprocess/preprocess_split_main.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/preprocess/preprocess_split_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -10,9 +10,9 @@ * http://www.opensource.org/licenses/BSD-3-Clause for more information. */ #include +#include #include #include -#include #include PROGRAM_INFO("Split Data", diff -Nru mlpack-3.2.2/src/mlpack/methods/radical/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/radical/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/radical/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/radical/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -15,4 +15,5 @@ add_cli_executable(radical) add_python_binding(radical) -add_markdown_docs(radical "cli;python" "transformations") +add_julia_binding(radical) +add_markdown_docs(radical "cli;python;julia" "transformations") diff -Nru mlpack-3.2.2/src/mlpack/methods/random_forest/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/random_forest/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/random_forest/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/random_forest/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -17,4 +17,5 @@ add_cli_executable(random_forest) add_python_binding(random_forest) -add_markdown_docs(random_forest "cli;python" "classification") +add_julia_binding(random_forest) +add_markdown_docs(random_forest "cli;python;julia" "classification") diff -Nru mlpack-3.2.2/src/mlpack/methods/range_search/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/range_search/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/range_search/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/range_search/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -21,4 +21,5 @@ add_cli_executable(range_search) #add_python_binding(range_search) +#add_julia_binding(range_search) add_markdown_docs(range_search "cli" "geometry") diff -Nru mlpack-3.2.2/src/mlpack/methods/range_search/range_search_main.cpp mlpack-3.3.0/src/mlpack/methods/range_search/range_search_main.cpp --- mlpack-3.2.2/src/mlpack/methods/range_search/range_search_main.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/range_search/range_search_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -155,8 +155,6 @@ const bool singleMode = CLI::HasParam("single_mode"); if (CLI::HasParam("reference")) { - rs = new RSModel(); - // Get all the parameters. const string treeType = CLI::GetParam("tree_type"); RequireParamInSet("tree_type", { "kd", "cover", "r", "r-star", @@ -164,6 +162,8 @@ "ub", "oct" }, true, "unknown tree type"); const bool randomBasis = CLI::HasParam("random_basis"); + rs = new RSModel(); + RSModel::TreeTypes tree = RSModel::KD_TREE; if (treeType == "kd") tree = RSModel::KD_TREE; diff -Nru mlpack-3.2.2/src/mlpack/methods/rann/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/rann/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/rann/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/rann/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -37,4 +37,5 @@ # reference sets. add_cli_executable(krann) add_python_binding(krann) -add_markdown_docs(krann "cli;python" "geometry") +add_julia_binding(krann) +add_markdown_docs(krann "cli;python;julia" "geometry") diff -Nru mlpack-3.2.2/src/mlpack/methods/reinforcement_learning/environment/acrobot.hpp mlpack-3.3.0/src/mlpack/methods/reinforcement_learning/environment/acrobot.hpp --- mlpack-3.2.2/src/mlpack/methods/reinforcement_learning/environment/acrobot.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/reinforcement_learning/environment/acrobot.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -169,10 +169,10 @@ nextState.Theta2() = Wrap(currentNextState[1], -M_PI, M_PI); //! The value of angular velocity is bounded in min and max value. - nextState.AngularVelocity1() = std::min( - std::max(currentNextState[2], -maxVel1), maxVel1); - nextState.AngularVelocity2() = std::min( - std::max(currentNextState[3], -maxVel2), maxVel2); + nextState.AngularVelocity1() = math::ClampRange(currentNextState[2], + -maxVel1, maxVel1); + nextState.AngularVelocity2() = math::ClampRange(currentNextState[3], + -maxVel2, maxVel2); // Check if the episode has terminated. bool done = IsTerminal(nextState); diff -Nru mlpack-3.2.2/src/mlpack/methods/reinforcement_learning/environment/continuous_mountain_car.hpp mlpack-3.3.0/src/mlpack/methods/reinforcement_learning/environment/continuous_mountain_car.hpp --- mlpack-3.2.2/src/mlpack/methods/reinforcement_learning/environment/continuous_mountain_car.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/reinforcement_learning/environment/continuous_mountain_car.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -18,6 +18,7 @@ #define MLPACK_METHODS_RL_ENVIRONMENT_CONTINUOUS_MOUNTAIN_CAR_HPP #include +#include namespace mlpack { namespace rl { @@ -96,7 +97,7 @@ * @param positionGoal Final target position. * @param velocityMin Minimum legal velocity. * @param velocityMax Maximum legal velocity. - * @param power Power generated by car. + * @param duration Time Duration for which force is applied on the car. * @param doneReward Reward recieved by the agent on success. * @param maxSteps The number of steps after which the episode * terminates. If the value is 0, there is no limit. @@ -106,7 +107,7 @@ const double positionGoal = 0.45, const double velocityMin = -0.07, const double velocityMax = 0.07, - const double power = 0.0015, + const double duration = 0.0015, const double doneReward = 100, const size_t maxSteps = 0) : positionMin(positionMin), @@ -114,7 +115,7 @@ positionGoal(positionGoal), velocityMin(velocityMin), velocityMax(velocityMax), - power(power), + duration(duration), doneReward(doneReward), maxSteps(maxSteps), stepsPerformed(0) @@ -136,16 +137,16 @@ stepsPerformed++; // Calculate acceleration. - double force = std::min(std::max(action.action[0], -1.0), 1.0); + double force = math::ClampRange(action.action[0], -1.0, 1.0); // Update states. - nextState.Velocity() = state.Velocity() + force * power - 0.0025 * + nextState.Velocity() = state.Velocity() + force * duration - 0.0025 * std::cos(3 * state.Position()); - nextState.Velocity() = std::min( - std::max(nextState.Velocity(), velocityMin), velocityMax); + nextState.Velocity() = math::ClampRange(nextState.Velocity(), + velocityMin, velocityMax); nextState.Position() = state.Position() + nextState.Velocity(); - nextState.Position() = std::min( - std::max(nextState.Position(), positionMin), positionMax); + nextState.Position() = math::ClampRange(nextState.Position(), + positionMin, positionMax); if (nextState.Position() == positionMin && nextState.Velocity() < 0) nextState.Velocity() = 0.0; @@ -236,8 +237,8 @@ //! Locally-stored maximum legal velocity. double velocityMax; - //! Locally-stored power. - double power; + //! Locally-stored duration. + double duration; //! Locally-stored done reward. double doneReward; diff -Nru mlpack-3.2.2/src/mlpack/methods/reinforcement_learning/environment/mountain_car.hpp mlpack-3.3.0/src/mlpack/methods/reinforcement_learning/environment/mountain_car.hpp --- mlpack-3.2.2/src/mlpack/methods/reinforcement_learning/environment/mountain_car.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/reinforcement_learning/environment/mountain_car.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -17,6 +17,7 @@ #define MLPACK_METHODS_RL_ENVIRONMENT_MOUNTAIN_CAR_HPP #include +#include namespace mlpack { namespace rl { @@ -134,13 +135,13 @@ int direction = action - 1; nextState.Velocity() = state.Velocity() + 0.001 * direction - 0.0025 * std::cos(3 * state.Position()); - nextState.Velocity() = std::min( - std::max(nextState.Velocity(), velocityMin), velocityMax); + nextState.Velocity() = math::ClampRange(nextState.Velocity(), + velocityMin, velocityMax); // Update states. nextState.Position() = state.Position() + nextState.Velocity(); - nextState.Position() = std::min( - std::max(nextState.Position(), positionMin), positionMax); + nextState.Position() = math::ClampRange(nextState.Position(), + positionMin, positionMax); if (nextState.Position() == positionMin && nextState.Velocity() < 0) nextState.Velocity() = 0.0; diff -Nru mlpack-3.2.2/src/mlpack/methods/reinforcement_learning/environment/pendulum.hpp mlpack-3.3.0/src/mlpack/methods/reinforcement_learning/environment/pendulum.hpp --- mlpack-3.2.2/src/mlpack/methods/reinforcement_learning/environment/pendulum.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/reinforcement_learning/environment/pendulum.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -17,6 +17,7 @@ #define MLPACK_METHODS_RL_ENVIRONMENT_PENDULUM_HPP #include +#include namespace mlpack { namespace rl { @@ -140,8 +141,7 @@ const double length = 1.0; // Get action and clip the values between max and min limits. - double torque = std::min( - std::max(action.action[0], -maxTorque), maxTorque); + double torque = math::ClampRange(action.action[0], -maxTorque, maxTorque); // Calculate costs of taking this action in the current state. double costs = std::pow(AngleNormalize(theta), 2) + 0.1 * @@ -151,8 +151,8 @@ double newAngularVelocity = angularVelocity + (-3.0 * gravity / (2 * length) * std::sin(theta + M_PI) + 3.0 / std::pow(mass * length, 2) * torque) * dt; - nextState.AngularVelocity() = std::min(std::max(newAngularVelocity, - -maxAngularVelocity), maxAngularVelocity); + nextState.AngularVelocity() = math::ClampRange(newAngularVelocity, + -maxAngularVelocity, maxAngularVelocity); nextState.Theta() = theta + newAngularVelocity * dt; // Check if the episode has terminated diff -Nru mlpack-3.2.2/src/mlpack/methods/reinforcement_learning/environment/reward_clipping.hpp mlpack-3.3.0/src/mlpack/methods/reinforcement_learning/environment/reward_clipping.hpp --- mlpack-3.2.2/src/mlpack/methods/reinforcement_learning/environment/reward_clipping.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/reinforcement_learning/environment/reward_clipping.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -13,6 +13,7 @@ #define MLPACK_METHODS_RL_ENVIRONMENT_REWARD_CLIPPING_HPP #include +#include namespace mlpack { namespace rl { @@ -91,7 +92,7 @@ // Get original unclipped reward from base environment. double unclippedReward = environment.Sample(state, action, nextState); // Clip rewards according to the min and max limit and return. - return std::min(std::max(unclippedReward, minReward), maxReward); + return math::ClampRange(unclippedReward, minReward, maxReward); } /** diff -Nru mlpack-3.2.2/src/mlpack/methods/reinforcement_learning/q_learning_impl.hpp mlpack-3.3.0/src/mlpack/methods/reinforcement_learning/q_learning_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/reinforcement_learning/q_learning_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/reinforcement_learning/q_learning_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -179,6 +179,7 @@ // Compute the update target. arma::mat target; learningNetwork.Forward(sampledStates, target); + /** * If the agent is at a terminal state, then we don't need to add the * discounted reward. At terminal state, the agent wont perform any @@ -199,7 +200,7 @@ // Learn from experience. arma::mat gradients; - learningNetwork.Backward(target, gradients); + learningNetwork.Backward(sampledStates, target, gradients); replayMethod.Update(target, sampledActions, nextActionValues, gradients); diff -Nru mlpack-3.2.2/src/mlpack/methods/reinforcement_learning/worker/n_step_q_learning_worker.hpp mlpack-3.3.0/src/mlpack/methods/reinforcement_learning/worker/n_step_q_learning_worker.hpp --- mlpack-3.2.2/src/mlpack/methods/reinforcement_learning/worker/n_step_q_learning_worker.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/reinforcement_learning/worker/n_step_q_learning_worker.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -301,12 +301,13 @@ target = config.Discount() * target + std::get<2>(transition); // Compute the training target for current state. - network.Forward(std::get<0>(transition).Encode(), actionValue); + arma::mat input = std::get<0>(transition).Encode(); + network.Forward(input, actionValue); actionValue[std::get<1>(transition)] = target; // Compute gradient. arma::mat gradients; - network.Backward(actionValue, gradients); + network.Backward(input, actionValue, gradients); // Accumulate gradients. totalGradients += gradients; diff -Nru mlpack-3.2.2/src/mlpack/methods/reinforcement_learning/worker/one_step_q_learning_worker.hpp mlpack-3.3.0/src/mlpack/methods/reinforcement_learning/worker/one_step_q_learning_worker.hpp --- mlpack-3.2.2/src/mlpack/methods/reinforcement_learning/worker/one_step_q_learning_worker.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/reinforcement_learning/worker/one_step_q_learning_worker.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -301,12 +301,13 @@ config.Discount() * targetActionValue; // Compute the training target for current state. - network.Forward(std::get<0>(transition).Encode(), actionValue); + arma::mat input = std::get<0>(transition).Encode(); + network.Forward(input, actionValue); actionValue[std::get<1>(transition)] = targetActionValue; // Compute gradient. arma::mat gradients; - network.Backward(actionValue, gradients); + network.Backward(input, actionValue, gradients); // Accumulate gradients. totalGradients += gradients; diff -Nru mlpack-3.2.2/src/mlpack/methods/reinforcement_learning/worker/one_step_sarsa_worker.hpp mlpack-3.3.0/src/mlpack/methods/reinforcement_learning/worker/one_step_sarsa_worker.hpp --- mlpack-3.2.2/src/mlpack/methods/reinforcement_learning/worker/one_step_sarsa_worker.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/reinforcement_learning/worker/one_step_sarsa_worker.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -314,12 +314,13 @@ config.Discount() * targetActionValue; // Compute the training target for current state. - network.Forward(std::get<0>(transition).Encode(), actionValue); + arma::mat input = std::get<0>(transition).Encode(); + network.Forward(input, actionValue); actionValue[std::get<1>(transition)] = targetActionValue; // Compute gradient. arma::mat gradients; - network.Backward(actionValue, gradients); + network.Backward(input, actionValue, gradients); // Accumulate gradients. totalGradients += gradients; diff -Nru mlpack-3.2.2/src/mlpack/methods/softmax_regression/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/softmax_regression/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/softmax_regression/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/softmax_regression/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -19,4 +19,5 @@ add_cli_executable(softmax_regression) add_python_binding(softmax_regression) -add_markdown_docs(softmax_regression "cli;python" "classification") +add_julia_binding(softmax_regression) +add_markdown_docs(softmax_regression "cli;python;julia" "classification") diff -Nru mlpack-3.2.2/src/mlpack/methods/softmax_regression/softmax_regression_function.hpp mlpack-3.3.0/src/mlpack/methods/softmax_regression/softmax_regression_function.hpp --- mlpack-3.2.2/src/mlpack/methods/softmax_regression/softmax_regression_function.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/softmax_regression/softmax_regression_function.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -175,6 +175,11 @@ { return initialPoint.n_cols; } + /** + * Return the number of separable functions + (the number of predictor points). + */ + size_t NumFunctions() const { return data.n_cols; } //! Sets the regularization parameter. double& Lambda() { return lambda; } diff -Nru mlpack-3.2.2/src/mlpack/methods/softmax_regression/softmax_regression.hpp mlpack-3.3.0/src/mlpack/methods/softmax_regression/softmax_regression.hpp --- mlpack-3.2.2/src/mlpack/methods/softmax_regression/softmax_regression.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/softmax_regression/softmax_regression.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -71,7 +71,6 @@ SoftmaxRegression(const size_t inputSize = 0, const size_t numClasses = 0, const bool fitIntercept = false); - /** * Construct the SoftmaxRegression class with the provided data and labels. * This will train the model. Optionally, the parameter 'lambda' can be @@ -94,23 +93,45 @@ const double lambda = 0.0001, const bool fitIntercept = false, OptimizerType optimizer = OptimizerType()); - + /** + * Construct the SoftmaxRegression class with the provided data and labels. + * This will train the model. Optionally, the parameter 'lambda' can be + * passed, which controls the amount of L2-regularization in the objective + * function. By default, the model takes a small value. + * + * @tparam OptimizerType Desired optimizer type. + * @tparam CallbackTypes Types of Callback Functions. + * @param data Input training features. Each column associate with one sample + * @param labels Labels associated with the feature data. + * @param inputSize Size of the input feature vector. + * @param numClasses Number of classes for classification. + * @param lambda L2-regularization constant. + * @param fitIntercept add intercept term or not. + * @param optimizer Desired optimizer. + * @param callbacks Callback function for ensmallen optimizer `OptimizerType`. + * See https://www.ensmallen.org/docs.html#callback-documentation. + */ + template + SoftmaxRegression(const arma::mat& data, + const arma::Row& labels, + const size_t numClasses, + const double lambda, + const bool fitIntercept, + OptimizerType optimizer, + CallbackTypes&&... callbacks); /** * Classify the given points, returning the predicted labels for each point. * The function calculates the probabilities for every class, given a data * point. It then chooses the class which has the highest probability among * all. - * * @param dataset Set of points to classify. * @param labels Predicted labels for each point. */ void Classify(const arma::mat& dataset, arma::Row& labels) const; - /** * Classify the given point. The predicted class label is returned. * The function calculates the probabilites for every class, given the point. * It then chooses the class which has the highest probability among all. - * * @param point Point to be classified. * @return Predicted class label of the point. */ @@ -151,7 +172,6 @@ */ double ComputeAccuracy(const arma::mat& testData, const arma::Row& labels) const; - /** * Train the softmax regression with the given training data. * @@ -167,6 +187,25 @@ const arma::Row& labels, const size_t numClasses, OptimizerType optimizer = OptimizerType()); + /** + * Train the softmax regression with the given training data. + * + * @tparam OptimizerType Desired optimizer type. + * @tparam CallbackTypes Types of Callback Functions. + * @param data Input data with each column as one example. + * @param labels Labels associated with the feature data. + * @param numClasses Number of classes for classification. + * @param optimizer Desired optimizer. + * @param callbacks Callback function for ensmallen optimizer `OptimizerType`. + * See https://www.ensmallen.org/docs.html#callback-documentation. + * @return Objective value of the final point. + */ + template + double Train(const arma::mat& data, + const arma::Row& labels, + const size_t numClasses, + OptimizerType optimizer, + CallbackTypes&&... callbacks); //! Sets the number of classes. size_t& NumClasses() { return numClasses; } @@ -188,7 +227,7 @@ //! Gets the features size of the training data size_t FeatureSize() const - { return fitIntercept ? parameters.n_cols - 1 : + { return fitIntercept ? parameters.n_cols - 1: parameters.n_cols; } /** diff -Nru mlpack-3.2.2/src/mlpack/methods/softmax_regression/softmax_regression_impl.hpp mlpack-3.3.0/src/mlpack/methods/softmax_regression/softmax_regression_impl.hpp --- mlpack-3.2.2/src/mlpack/methods/softmax_regression/softmax_regression_impl.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/softmax_regression/softmax_regression_impl.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -33,6 +33,22 @@ Train(data, labels, numClasses, optimizer); } +template +SoftmaxRegression::SoftmaxRegression( + const arma::mat& data, + const arma::Row& labels, + const size_t numClasses, + const double lambda, + const bool fitIntercept, + OptimizerType optimizer, + CallbackTypes&&... callbacks) : + numClasses(numClasses), + lambda(lambda), + fitIntercept(fitIntercept) +{ + Train(data, labels, numClasses, optimizer, callbacks...); +} + template size_t SoftmaxRegression::Classify(const VecType& point) const { @@ -47,9 +63,9 @@ const size_t numClasses, OptimizerType optimizer) { - SoftmaxRegressionFunction regressor(data, labels, numClasses, - lambda, fitIntercept); - if (parameters.is_empty()) + SoftmaxRegressionFunction regressor(data, labels, numClasses, lambda, + fitIntercept); + if (parameters.n_elem != regressor.GetInitialPoint().n_elem) parameters = regressor.GetInitialPoint(); // Train the model. @@ -58,6 +74,29 @@ Timer::Stop("softmax_regression_optimization"); Log::Info << "SoftmaxRegression::SoftmaxRegression(): final objective of " + << "trained model is " << out << "." << std::endl; + + return out; +} + +template +double SoftmaxRegression::Train(const arma::mat& data, + const arma::Row& labels, + const size_t numClasses, + OptimizerType optimizer, + CallbackTypes&&... callbacks) +{ + SoftmaxRegressionFunction regressor(data, labels, numClasses, lambda, + fitIntercept); + if (parameters.n_elem != regressor.GetInitialPoint().n_elem) + parameters = regressor.GetInitialPoint(); + + // Train the model. + Timer::Start("softmax_regression_optimization"); + const double out = optimizer.Optimize(regressor, parameters, callbacks...); + Timer::Stop("softmax_regression_optimization"); + + Log::Info << "SoftmaxRegression::SoftmaxRegression(): final objective of " << "trained model is " << out << "." << std::endl; return out; diff -Nru mlpack-3.2.2/src/mlpack/methods/softmax_regression/softmax_regression_main.cpp mlpack-3.3.0/src/mlpack/methods/softmax_regression/softmax_regression_main.cpp --- mlpack-3.2.2/src/mlpack/methods/softmax_regression/softmax_regression_main.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/softmax_regression/softmax_regression_main.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -273,6 +273,5 @@ sm = new Model(trainData, trainLabels, numClasses, CLI::GetParam("lambda"), intercept, std::move(optimizer)); } - return sm; } diff -Nru mlpack-3.2.2/src/mlpack/methods/sparse_coding/CMakeLists.txt mlpack-3.3.0/src/mlpack/methods/sparse_coding/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/methods/sparse_coding/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/methods/sparse_coding/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -20,4 +20,5 @@ add_cli_executable(sparse_coding) add_python_binding(sparse_coding) -add_markdown_docs(sparse_coding "cli;python" "transformations") +add_julia_binding(sparse_coding) +add_markdown_docs(sparse_coding "cli;python;julia" "transformations") diff -Nru mlpack-3.2.2/src/mlpack/tests/activation_functions_test.cpp mlpack-3.3.0/src/mlpack/tests/activation_functions_test.cpp --- mlpack-3.2.2/src/mlpack/tests/activation_functions_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/activation_functions_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -21,6 +21,9 @@ #include #include #include +#include +#include +#include #include #include "test_tools.hpp" @@ -130,7 +133,7 @@ // Test the activation function using the entire vector as input. arma::colvec activations; - htf.Forward(std::move(input), std::move(activations)); + htf.Forward(input, activations); for (size_t i = 0; i < activations.n_elem; i++) { BOOST_REQUIRE_CLOSE(activations.at(i), target.at(i), 1e-3); @@ -154,7 +157,7 @@ // This error vector will be set to 1 to get the derivatives. arma::colvec error = arma::ones(input.n_elem); - htf.Backward(std::move(input), std::move(error), std::move(derivatives)); + htf.Backward(input, error, derivatives); for (size_t i = 0; i < derivatives.n_elem; i++) { @@ -176,7 +179,7 @@ // Test the activation function using the entire vector as input. arma::colvec activations; - lrf.Forward(std::move(input), std::move(activations)); + lrf.Forward(input, activations); for (size_t i = 0; i < activations.n_elem; i++) { BOOST_REQUIRE_CLOSE(activations.at(i), target.at(i), 1e-3); @@ -201,7 +204,7 @@ // This error vector will be set to 1 to get the derivatives. arma::colvec error = arma::ones(input.n_elem); - lrf.Backward(std::move(input), std::move(error), std::move(derivatives)); + lrf.Backward(input, error, derivatives); for (size_t i = 0; i < derivatives.n_elem; i++) { BOOST_REQUIRE_CLOSE(derivatives.at(i), target.at(i), 1e-3); @@ -216,14 +219,14 @@ * @param target Target data used to evaluate the ELU activation. */ void CheckELUActivationCorrect(const arma::colvec input, - const arma::colvec target) + const arma::colvec target) { // Initialize ELU object with alpha = 1.0. ELU<> lrf(1.0); // Test the activation function using the entire vector as input. arma::colvec activations; - lrf.Forward(std::move(input), std::move(activations)); + lrf.Forward(input, activations); for (size_t i = 0; i < activations.n_elem; i++) { BOOST_REQUIRE_CLOSE(activations.at(i), target.at(i), 1e-3); @@ -238,7 +241,7 @@ * @param target Target data used to evaluate the ELU activation. */ void CheckELUDerivativeCorrect(const arma::colvec input, - const arma::colvec target) + const arma::colvec target) { // Initialize ELU object with alpha = 1.0. ELU<> lrf(1.0); @@ -248,9 +251,8 @@ // This error vector will be set to 1 to get the derivatives. arma::colvec error = arma::ones(input.n_elem); - lrf.Forward(std::move(input), std::move(activations)); - lrf.Backward(std::move(activations), std::move(error), - std::move(derivatives)); + lrf.Forward(input, activations); + lrf.Backward(activations, error, derivatives); for (size_t i = 0; i < derivatives.n_elem; i++) { BOOST_REQUIRE_CLOSE(derivatives.at(i), target.at(i), 1e-3); @@ -259,20 +261,20 @@ /* * Implementation of the PReLU activation function test. The function - * is implemented as PReLU layer in the file perametric_relu.hpp + * is implemented as PReLU layer in the file parametric_relu.hpp. * * @param input Input data used for evaluating the PReLU activation * function. * @param target Target data used to evaluate the PReLU activation. */ void CheckPReLUActivationCorrect(const arma::colvec input, - const arma::colvec target) + const arma::colvec target) { PReLU<> prelu; // Test the activation function using the entire vector as input. arma::colvec activations; - prelu.Forward(std::move(input), std::move(activations)); + prelu.Forward(input, activations); for (size_t i = 0; i < activations.n_elem; i++) { BOOST_REQUIRE_CLOSE(activations.at(i), target.at(i), 1e-3); @@ -282,14 +284,14 @@ /* * Implementation of the PReLU activation function derivative test. * The function is implemented as PReLU layer in the file - * perametric_relu.hpp + * parametric_relu.hpp * * @param input Input data used for evaluating the PReLU activation * function. * @param target Target data used to evaluate the PReLU activation. */ void CheckPReLUDerivativeCorrect(const arma::colvec input, - const arma::colvec target) + const arma::colvec target) { PReLU<> prelu; @@ -298,7 +300,7 @@ // This error vector will be set to 1 to get the derivatives. arma::colvec error = arma::ones(input.n_elem); - prelu.Backward(std::move(input), std::move(error), std::move(derivatives)); + prelu.Backward(input, error, derivatives); for (size_t i = 0; i < derivatives.n_elem; i++) { BOOST_REQUIRE_CLOSE(derivatives.at(i), target.at(i), 1e-3); @@ -308,14 +310,14 @@ /* * Implementation of the PReLU activation function gradient test. * The function is implemented as PReLU layer in the file - * perametric_relu.hpp + * parametric_relu.hpp * * @param input Input data used for evaluating the PReLU activation * function. * @param target Target data used to evaluate the PReLU gradient. */ void CheckPReLUGradientCorrect(const arma::colvec input, - const arma::colvec target) + const arma::colvec target) { PReLU<> prelu; @@ -324,13 +326,105 @@ // This error vector will be set to 1 to get the gradient. arma::colvec error = arma::ones(input.n_elem); - prelu.Gradient(std::move(input), std::move(error), std::move(gradient)); + prelu.Gradient(input, error, gradient); BOOST_REQUIRE_EQUAL(gradient.n_rows, 1); BOOST_REQUIRE_EQUAL(gradient.n_cols, 1); BOOST_REQUIRE_CLOSE(gradient(0), target(0), 1e-3); } /* + * Implementation of the Hard Shrink activation function test. The function is + * implemented as Hard Shrink layer in the file hardshrink.hpp + * + * @param input Input data used for evaluating the Hard Shrink activation function. + * @param target Target data used to evaluate the Hard Shrink activation. + */ +void CheckHardShrinkActivationCorrect(const arma::colvec input, + const arma::colvec target) +{ + HardShrink<> hardshrink; + + // Test the activation function using the entire vector as input. + arma::colvec activations; + hardshrink.Forward(input, activations); + for (size_t i = 0; i < activations.n_elem; i++) + { + BOOST_REQUIRE_CLOSE(activations.at(i), target.at(i), 1e-3); + } +} + +/* + * Implementation of the HardShrink activation function derivative test. + * The derivative function is implemented as HardShrink layer in the file + * hardshrink.hpp + * + * @param input Input data used for evaluating the HardShrink activation function. + * @param target Target data used to evaluate the HardShrink activation. + */ +void CheckHardShrinkDerivativeCorrect(const arma::colvec input, + const arma::colvec target) +{ + HardShrink<> hardshrink; + + // Test the calculation of the derivatives using the entire vector as input. + arma::colvec derivatives; + + // This error vector will be set to 1 to get the derivatives. + arma::colvec error = arma::ones(input.n_elem); + hardshrink.Backward(input, error, derivatives); + for (size_t i = 0; i < derivatives.n_elem; i++) + { + BOOST_REQUIRE_CLOSE(derivatives.at(i), target.at(i), 1e-3); + } +} + +/* + * Implementation of the Soft Shrink activation function test. The function is + * implemented as Soft Shrink layer in the file softshrink.hpp. + * + * @param input Input data used for evaluating the Soft Shrink activation function. + * @param target Target data used to evaluate the Soft Shrink activation. + */ +void CheckSoftShrinkActivationCorrect(const arma::colvec input, + const arma::colvec target) +{ + SoftShrink<> softshrink; + + // Test the activation function using the entire vector as input. + arma::colvec activations; + softshrink.Forward(input, activations); + for (size_t i = 0; i < activations.n_elem; i++) + { + BOOST_REQUIRE_CLOSE(activations.at(i), target.at(i), 1e-3); + } +} + +/* + * Implementation of the Soft Shrink activation function derivative test. + * The derivative function is implemented as Soft Shrink layer in the file + * softshrink.hpp + * + * @param input Input data used for evaluating the Soft Shrink activation function. + * @param target Target data used to evaluate the Soft Shrink activation. + */ +void CheckSoftShrinkDerivativeCorrect(const arma::colvec input, + const arma::colvec target) +{ + SoftShrink<> softshrink; + + // Test the calculation of the derivatives using the entire vector as input. + arma::colvec derivatives; + + // This error vector will be set to 1 to get the derivatives. + arma::colvec error = arma::ones(input.n_elem); + softshrink.Backward(input, error, derivatives); + for (size_t i = 0; i < derivatives.n_elem; i++) + { + BOOST_REQUIRE_CLOSE(derivatives.at(i), target.at(i), 1e-3); + } +} + +/* * Simple SELU activation test to check whether the mean and variance remain * invariant after passing normalized inputs through the function. */ @@ -342,7 +436,7 @@ SELU selu; - selu.Forward(std::move(input), output); + selu.Forward(input, output); BOOST_REQUIRE_LE(arma::as_scalar(arma::abs(arma::mean(input) - arma::mean(output))), 0.1); @@ -364,7 +458,7 @@ SELU selu; - selu.Forward(std::move(input), output); + selu.Forward(input, output); BOOST_REQUIRE_GE(arma::as_scalar(arma::abs(arma::mean(input) - arma::mean(output))), 0.1); @@ -388,24 +482,70 @@ SELU selu; - selu.Forward(std::move(input), activations); - selu.Backward(std::move(activations), std::move(error), - std::move(derivatives)); + selu.Forward(input, activations); + selu.Backward(activations, error, derivatives); BOOST_REQUIRE_LE(arma::as_scalar(arma::abs(arma::mean(derivatives) - selu.Lambda())), 10e-4); input.fill(-1); - selu.Forward(std::move(input), activations); - selu.Backward(std::move(activations), std::move(error), - std::move(derivatives)); + selu.Forward(input, activations); + selu.Backward(activations, error, derivatives); BOOST_REQUIRE_LE(arma::as_scalar(arma::abs(arma::mean(derivatives) - selu.Lambda() * selu.Alpha() - arma::mean(activations))), 10e-4); } /** + * Implementation of the CELU activation function test. The function is + * implemented as CELU layer in the file celu.hpp. + * + * @param input Input data used for evaluating the CELU activation function. + * @param target Target data used to evaluate the CELU activation. + */ +void CheckCELUActivationCorrect(const arma::colvec input, + const arma::colvec target) +{ + // Initialize CELU object with alpha = 1.0. + CELU<> lrf(1.0); + + // Test the activation function using the entire vector as input. + arma::colvec activations; + lrf.Forward(input, activations); + for (size_t i = 0; i < activations.n_elem; i++) + { + BOOST_REQUIRE_CLOSE(activations.at(i), target.at(i), 1e-3); + } +} + +/** + * Implementation of the CELU activation function derivative test. The function + * is implemented as CELU layer in the file celu.hpp. + * + * @param input Input data used for evaluating the CELU activation function. + * @param target Target data used to evaluate the CELU activation. + */ +void CheckCELUDerivativeCorrect(const arma::colvec input, + const arma::colvec target) +{ + // Initialize CELU object with alpha = 1.0. + CELU<> lrf(1.0); + + // Test the calculation of the derivatives using the entire vector as input. + arma::colvec derivatives, activations; + + // This error vector will be set to 1 to get the derivatives. + arma::colvec error = arma::ones(input.n_elem); + lrf.Forward(input, activations); + lrf.Backward(activations, error, derivatives); + for (size_t i = 0; i < derivatives.n_elem; i++) + { + BOOST_REQUIRE_CLOSE(derivatives.at(i), target.at(i), 1e-3); + } +} + +/** * Basic test of the tanh function. */ BOOST_AUTO_TEST_CASE(TanhFunctionTest) @@ -579,12 +719,11 @@ CReLU<> crelu; // Test the activation function using the entire vector as input. arma::colvec activations; - crelu.Forward(std::move(activationData), std::move(activations)); + crelu.Forward(activationData, activations); arma::colvec derivatives; // This error vector will be set to 1 to get the derivatives. arma::colvec error = arma::ones(desiredActivations.n_elem); - crelu.Backward(std::move(desiredActivations), std::move(error), - std::move(derivatives)); + crelu.Backward(desiredActivations, error, derivatives); for (size_t i = 0; i < activations.n_elem; i++) { BOOST_REQUIRE_CLOSE(activations.at(i), desiredActivations.at(i), 1e-3); @@ -634,4 +773,123 @@ desiredDerivatives); } +/** + * Basic test of the Mish function. + */ +BOOST_AUTO_TEST_CASE(MishFunctionTest) +{ + // Calculated using tfa.activations.mish(). + // where tfa is tensorflow_addons. + const arma::colvec desiredActivations("-0.25250152 3.1901977 \ + 4.498914 -3.05183208e-42 0.86509836 \ + -0.30340138 1.943959 0"); + + const arma::colvec desiredDerivatives("0.4382387 1.0159768849 \ + 1.0019108 0.6 \ + 1.0192586 0.40639898 \ + 1.0725079 0.6"); + + CheckActivationCorrect(activationData, + desiredActivations); + CheckDerivativeCorrect(desiredActivations, + desiredDerivatives); +} + +/** + * Basic test of the LiSHT function. + */ +BOOST_AUTO_TEST_CASE(LiSHTFunctionTest) +{ + // Calculated using tfa.activations.LiSHT(). + // where tfa is tensorflow_addons. + const arma::colvec desiredActivations("1.928055 3.189384 \ + 4.4988894 100.2 0.7615942 \ + 0.7615942 1.9280552 0"); + + const arma::colvec desiredDerivatives("1.1150033 1.0181904 \ + 1.001978 1.0 \ + 1.0896928 1.0896928 \ + 1.1150033 0.0"); + + CheckActivationCorrect(activationData, + desiredActivations); + CheckDerivativeCorrect(desiredActivations, + desiredDerivatives); +} + +/** + * Basic test of the GELU function. + */ +BOOST_AUTO_TEST_CASE(GELUFunctionTest) +{ + // Calculated using torch.nn.gelu(). + const arma::colvec desiredActivations("-0.04540230591222 \ + 3.1981304348379158 \ + 4.5000 -0.0000 \ + 0.84119199060827676 \ + -0.15880800939172329 \ + 1.954597694087775 \ + 0.0000"); + + const arma::colvec desiredDerivatives("0.46379920685377229 \ + 1.0065302165778773 \ + 1.0000293221871797 \ + 0.5 \ + 1.0351344625840642 \ + 0.37435387859861063 \ + 1.0909840032535403 \ + 0.5"); + + CheckActivationCorrect(activationData, + desiredActivations); + CheckDerivativeCorrect(desiredActivations, + desiredDerivatives); +} + +/** + * Basic test of the Hard Shrink function. + */ +BOOST_AUTO_TEST_CASE(HardShrinkFunctionTest) +{ + const arma::colvec desiredActivations("-2 3.2 4.5 -100.2 1 -1 2 0"); + + const arma::colvec desiredDerivatives("1 1 1 1 1 1 1 0"); + + CheckHardShrinkActivationCorrect(activationData, + desiredActivations); + CheckHardShrinkDerivativeCorrect(desiredActivations, + desiredDerivatives); +} + +/** + * Basic test of the Soft Shrink function. + */ +BOOST_AUTO_TEST_CASE(SoftShrinkFunctionTest) +{ + const arma::colvec desiredActivations("-1.5 2.7 4 -99.7 0.5 -0.5 1.5 0"); + + const arma::colvec desiredDerivatives("1 1 1 1 1 1 1 0"); + + CheckSoftShrinkActivationCorrect(activationData, + desiredActivations); + CheckSoftShrinkDerivativeCorrect(desiredActivations, + desiredDerivatives); +} + +/** + * Basic test of the CELU activation function. + */ +BOOST_AUTO_TEST_CASE(CELUFunctionTest) +{ + const arma::colvec desiredActivations("-0.86466472 3.2 4.5 \ + -1 1 -0.63212056 2 0"); + + const arma::colvec desiredDerivatives("0.42119275 1 1 \ + 0.36787944 1 \ + 0.5314636 1 1"); + + CheckCELUActivationCorrect(activationData, desiredActivations); + CheckCELUDerivativeCorrect(desiredActivations, desiredDerivatives); +} + BOOST_AUTO_TEST_SUITE_END(); diff -Nru mlpack-3.2.2/src/mlpack/tests/adaboost_test.cpp mlpack-3.3.0/src/mlpack/tests/adaboost_test.cpp --- mlpack-3.2.2/src/mlpack/tests/adaboost_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/adaboost_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -19,7 +19,7 @@ using namespace arma; using namespace mlpack; using namespace mlpack::adaboost; -using namespace mlpack::decision_stump; +using namespace mlpack::tree; using namespace mlpack::perceptron; BOOST_AUTO_TEST_SUITE(AdaBoostTest); @@ -58,10 +58,7 @@ arma::Row predictedLabels; a.Classify(inputData, predictedLabels); - size_t countError = 0; - for (size_t i = 0; i < labels.n_cols; i++) - if (labels(i) != predictedLabels(i)) - countError++; + size_t countError = arma::accu(labels != predictedLabels); double hammingLoss = (double) countError / labels.n_cols; // Check that ztProduct is finite. @@ -96,10 +93,7 @@ Perceptron<> p(inputData, labels.row(0), numClasses, perceptronIter); p.Classify(inputData, perceptronPrediction); - size_t countWeakLearnerError = 0; - for (size_t i = 0; i < labels.n_cols; i++) - if (labels(i) != perceptronPrediction(i)) - countWeakLearnerError++; + size_t countWeakLearnerError = arma::accu(labels != perceptronPrediction); double weakLearnerErrorRate = (double) countWeakLearnerError / labels.n_cols; // Define parameters for AdaBoost. @@ -110,10 +104,7 @@ arma::Row predictedLabels; a.Classify(inputData, predictedLabels); - size_t countError = 0; - for (size_t i = 0; i < labels.n_cols; i++) - if (labels(i) != predictedLabels(i)) - countError++; + size_t countError = arma::accu(labels != predictedLabels);; double error = (double) countError / labels.n_cols; BOOST_REQUIRE_LE(error, weakLearnerErrorRate); @@ -151,10 +142,7 @@ arma::Row predictedLabels; a.Classify(inputData, predictedLabels); - size_t countError = 0; - for (size_t i = 0; i < labels.n_cols; i++) - if (labels(i) != predictedLabels(i)) - countError++; + size_t countError = arma::accu(labels != predictedLabels); double hammingLoss = (double) countError / labels.n_cols; // Check that ztProduct is finite. @@ -187,10 +175,7 @@ Perceptron<> p(inputData, labels.row(0), numClasses, perceptronIter); p.Classify(inputData, perceptronPrediction); - size_t countWeakLearnerError = 0; - for (size_t i = 0; i < labels.n_cols; i++) - if (labels(i) != perceptronPrediction(i)) - countWeakLearnerError++; + size_t countWeakLearnerError = arma::accu(labels != perceptronPrediction); double weakLearnerErrorRate = (double) countWeakLearnerError / labels.n_cols; // Define parameters for AdaBoost. @@ -201,10 +186,7 @@ arma::Row predictedLabels; a.Classify(inputData, predictedLabels); - size_t countError = 0; - for (size_t i = 0; i < labels.n_cols; i++) - if (labels(i) != predictedLabels(i)) - countError++; + size_t countError = arma::accu(labels != predictedLabels); double error = (double) countError / labels.n_cols; BOOST_REQUIRE_LE(error, weakLearnerErrorRate); @@ -242,10 +224,7 @@ arma::Row predictedLabels; a.Classify(inputData, predictedLabels); - size_t countError = 0; - for (size_t i = 0; i < labels.n_cols; i++) - if (labels(i) != predictedLabels(i)) - countError++; + size_t countError = arma::accu(labels == predictedLabels); double hammingLoss = (double) countError / labels.n_cols; // Check that ztProduct is finite. @@ -278,10 +257,7 @@ Perceptron<> p(inputData, labels.row(0), numClasses, perceptronIter); p.Classify(inputData, perceptronPrediction); - size_t countWeakLearnerError = 0; - for (size_t i = 0; i < labels.n_cols; i++) - if (labels(i) != perceptronPrediction(i)) - countWeakLearnerError++; + size_t countWeakLearnerError = arma::accu(labels != perceptronPrediction); double weakLearnerErrorRate = (double) countWeakLearnerError / labels.n_cols; // Define parameters for AdaBoost. @@ -292,10 +268,7 @@ arma::Row predictedLabels; a.Classify(inputData, predictedLabels); - size_t countError = 0; - for (size_t i = 0; i < labels.n_cols; i++) - if (labels(i) != predictedLabels(i)) - countError++; + size_t countError = arma::accu(labels != predictedLabels); double error = (double) countError / labels.n_cols; BOOST_REQUIRE_LE(error, weakLearnerErrorRate); @@ -319,22 +292,20 @@ // Define your own weak learner, decision stumps in this case. const size_t numClasses = 3; const size_t inpBucketSize = 6; - DecisionStump<> ds(inputData, labels.row(0), numClasses, inpBucketSize); + arma::Row labelsvec = labels.row(0); + ID3DecisionStump ds(inputData, labelsvec, numClasses, inpBucketSize); // Define parameters for AdaBoost. size_t iterations = 50; double tolerance = 1e-10; - AdaBoost> a(tolerance); - double ztProduct = a.Train(inputData, labels.row(0), numClasses, ds, + AdaBoost a(tolerance); + double ztProduct = a.Train(inputData, labelsvec, numClasses, ds, iterations, tolerance); arma::Row predictedLabels; a.Classify(inputData, predictedLabels); - size_t countError = 0; - for (size_t i = 0; i < labels.n_cols; i++) - if (labels(i) != predictedLabels(i)) - countError++; + size_t countError = arma::accu(labels != predictedLabels); double hammingLoss = (double) countError / labels.n_cols; // Check that ztProduct is finite. @@ -363,32 +334,27 @@ // Define your own weak learner, decision stumps in this case. const size_t numClasses = 3; const size_t inpBucketSize = 6; + arma::Row labelsvec = labels.row(0); arma::Row dsPrediction(labels.n_cols); - DecisionStump<> ds(inputData, labels.row(0), numClasses, inpBucketSize); + ID3DecisionStump ds(inputData, labelsvec, numClasses, inpBucketSize); ds.Classify(inputData, dsPrediction); - size_t countWeakLearnerError = 0; - for (size_t i = 0; i < labels.n_cols; i++) - if (labels(i) != dsPrediction(i)) - countWeakLearnerError++; + size_t countWeakLearnerError = arma::accu(labels != dsPrediction); double weakLearnerErrorRate = (double) countWeakLearnerError / labels.n_cols; // Define parameters for AdaBoost. size_t iterations = 50; double tolerance = 1e-10; - AdaBoost> a(inputData, labels.row(0), numClasses, ds, + AdaBoost a(inputData, labelsvec, numClasses, ds, iterations, tolerance); arma::Row predictedLabels; a.Classify(inputData, predictedLabels); - size_t countError = 0; - for (size_t i = 0; i < labels.n_cols; i++) - if (labels(i) != predictedLabels(i)) - countError++; + size_t countError = arma::accu(labels != predictedLabels); double error = (double) countError / labels.n_cols; BOOST_REQUIRE_LE(error, weakLearnerErrorRate); @@ -413,24 +379,22 @@ // Define your own weak learner, decision stumps in this case. const size_t numClasses = 3; const size_t inpBucketSize = 6; + arma::Row labelsvec = labels.row(0); - DecisionStump<> ds(inputData, labels.row(0), numClasses, inpBucketSize); + ID3DecisionStump ds(inputData, labelsvec, numClasses, inpBucketSize); // Define parameters for AdaBoost. size_t iterations = 50; double tolerance = 1e-10; - AdaBoost> a(tolerance); - double ztProduct = a.Train(inputData, labels.row(0), numClasses, ds, + AdaBoost a(tolerance); + double ztProduct = a.Train(inputData, labelsvec, numClasses, ds, iterations, tolerance); arma::Row predictedLabels; a.Classify(inputData, predictedLabels); - size_t countError = 0; - for (size_t i = 0; i < labels.n_cols; i++) - if (labels(i) != predictedLabels(i)) - countError++; + size_t countError = arma::accu(labels != predictedLabels); double hammingLoss = (double) countError / labels.n_cols; // Check that ztProduct is finite. @@ -458,30 +422,24 @@ const size_t numClasses = 3; const size_t inpBucketSize = 6; arma::Row dsPrediction(labels.n_cols); + arma::Row labelsvec = labels.row(0); - DecisionStump<> ds(inputData, labels.row(0), numClasses, inpBucketSize); + ID3DecisionStump ds(inputData, labelsvec, numClasses, inpBucketSize); ds.Classify(inputData, dsPrediction); - size_t countWeakLearnerError = 0; - for (size_t i = 0; i < labels.n_cols; i++) - if (labels(i) != dsPrediction(i)) - countWeakLearnerError++; - + size_t countWeakLearnerError = arma::accu(labels != dsPrediction); double weakLearnerErrorRate = (double) countWeakLearnerError / labels.n_cols; // Define parameters for AdaBoost. size_t iterations = 50; double tolerance = 1e-10; - AdaBoost> a(inputData, labels.row(0), numClasses, ds, + AdaBoost a(inputData, labelsvec, numClasses, ds, iterations, tolerance); arma::Row predictedLabels; a.Classify(inputData, predictedLabels); - size_t countError = 0; - for (size_t i = 0; i < labels.n_cols; i++) - if (labels(i) != predictedLabels(i)) - countError++; + size_t countError = arma::accu(labels != predictedLabels); double error = (double) countError / labels.n_cols; BOOST_REQUIRE_LE(error, weakLearnerErrorRate); @@ -505,24 +463,22 @@ // Define your own weak learner, decision stumps in this case. const size_t numClasses = 2; const size_t inpBucketSize = 6; + arma::Row labelsvec = labels.row(0); - DecisionStump<> ds(inputData, labels.row(0), numClasses, inpBucketSize); + ID3DecisionStump ds(inputData, labelsvec, numClasses, inpBucketSize); // Define parameters for Adaboost. size_t iterations = 50; double tolerance = 1e-10; - AdaBoost> a(tolerance); - double ztProduct = a.Train(inputData, labels.row(0), numClasses, ds, + AdaBoost a(tolerance); + double ztProduct = a.Train(inputData, labelsvec, numClasses, ds, iterations, tolerance); arma::Row predictedLabels; a.Classify(inputData, predictedLabels); - size_t countError = 0; - for (size_t i = 0; i < labels.n_cols; i++) - if (labels(i) != predictedLabels(i)) - countError++; + size_t countError = arma::accu(labels != predictedLabels); double hammingLoss = (double) countError / labels.n_cols; // Check that ztProduct is finite. @@ -549,32 +505,27 @@ // Define your own weak learner, decision stumps in this case. const size_t numClasses = 2; const size_t inpBucketSize = 3; + arma::Row labelsvec = labels.row(0); arma::Row dsPrediction(labels.n_cols); - DecisionStump<> ds(inputData, labels.row(0), numClasses, inpBucketSize); + ID3DecisionStump ds(inputData, labelsvec, numClasses, inpBucketSize); ds.Classify(inputData, dsPrediction); - size_t countWeakLearnerError = 0; - for (size_t i = 0; i < labels.n_cols; i++) - if (labels(i) != dsPrediction(i)) - countWeakLearnerError++; + size_t countWeakLearnerError = arma::accu(labels != dsPrediction); double weakLearnerErrorRate = (double) countWeakLearnerError / labels.n_cols; // Define parameters for AdaBoost. size_t iterations = 500; double tolerance = 1e-23; - AdaBoost > a(inputData, labels.row(0), numClasses, ds, + AdaBoost a(inputData, labelsvec, numClasses, ds, iterations, tolerance); arma::Row predictedLabels; a.Classify(inputData, predictedLabels); - size_t countError = 0; - for (size_t i = 0; i < labels.n_cols; i++) - if (labels(i) != predictedLabels(i)) - countError++; + size_t countError = arma::accu(labels != predictedLabels); double error = (double) countError / labels.n_cols; BOOST_REQUIRE_LE(error, weakLearnerErrorRate); @@ -620,14 +571,31 @@ double tolerance = 1e-10; AdaBoost<> a(inputData, labels.row(0), numClasses, p, iterations, tolerance); - arma::Row predictedLabels(testData.n_cols); - a.Classify(testData, predictedLabels); + arma::Row predictedLabels1(testData.n_cols), + predictedLabels2(testData.n_cols); + arma::mat probabilities; + + a.Classify(testData, predictedLabels1); + a.Classify(testData, predictedLabels2, probabilities); + + BOOST_REQUIRE_EQUAL(probabilities.n_cols, testData.n_cols); + BOOST_REQUIRE_EQUAL(probabilities.n_rows, numClasses); + + for (size_t i = 0; i < predictedLabels1.n_cols; ++i) + BOOST_REQUIRE_EQUAL(predictedLabels1[i], predictedLabels2[i]); + + arma::colvec pRow; + arma::uword maxIndex = 0; - size_t localError = 0; - for (size_t i = 0; i < trueTestLabels.n_cols; i++) - if (trueTestLabels(i) != predictedLabels(i)) - localError++; + for (size_t i = 0; i < predictedLabels1.n_cols; i++) + { + pRow = probabilities.unsafe_col(i); + pRow.max(maxIndex); + BOOST_REQUIRE_EQUAL(predictedLabels1(i), maxIndex); + BOOST_REQUIRE_CLOSE(arma::accu(probabilities.col(i)), 1, 1e-5); + } + size_t localError = arma::accu(trueTestLabels != predictedLabels1); double lError = (double) localError / trueTestLabels.n_cols; BOOST_REQUIRE_LE(lError, 0.30); } @@ -650,6 +618,7 @@ // Define your own weak learner; in this test decision stumps are used. const size_t numClasses = 2; const size_t inpBucketSize = 3; + arma::Row labelsvec = labels.row(0); arma::mat testData; @@ -663,22 +632,38 @@ arma::Row dsPrediction(labels.n_cols); - DecisionStump<> ds(inputData, labels.row(0), numClasses, inpBucketSize); + ID3DecisionStump ds(inputData, labelsvec, numClasses, inpBucketSize); // Define parameters for AdaBoost. size_t iterations = 50; double tolerance = 1e-10; - AdaBoost > a(inputData, labels.row(0), numClasses, ds, + AdaBoost a(inputData, labelsvec, numClasses, ds, iterations, tolerance); - arma::Row predictedLabels(testData.n_cols); - a.Classify(testData, predictedLabels); + arma::Row predictedLabels1(testData.n_cols), + predictedLabels2(testData.n_cols); + arma::mat probabilities; + + a.Classify(testData, predictedLabels1); + a.Classify(testData, predictedLabels2, probabilities); + + BOOST_REQUIRE_EQUAL(probabilities.n_cols, testData.n_cols); + + for (size_t i = 0; i < predictedLabels1.n_cols; ++i) + BOOST_REQUIRE_EQUAL(predictedLabels1[i], predictedLabels2[i]); - size_t localError = 0; - for (size_t i = 0; i < trueTestLabels.n_cols; i++) - if (trueTestLabels(i) != predictedLabels(i)) - localError++; + arma::colvec pRow; + arma::uword maxIndex = 0; + for (size_t i = 0; i < predictedLabels1.n_cols; i++) + { + pRow = probabilities.unsafe_col(i); + pRow.max(maxIndex); + BOOST_REQUIRE_EQUAL(predictedLabels1(i), maxIndex); + BOOST_REQUIRE_CLOSE(arma::accu(probabilities.col(i)), 1, 1e-5); + } + + size_t localError = arma::accu(trueTestLabels != predictedLabels1); double lError = (double) localError / trueTestLabels.n_cols; BOOST_REQUIRE_LE(lError, 0.30); } @@ -716,17 +701,36 @@ BOOST_FAIL("Cannot load test dataset iris_test.csv!"); arma::Row predictedLabels(testData.n_cols); - a.Classify(testData, predictedLabels); arma::Mat trueTestLabels; if (!data::Load("iris_test_labels.csv", trueTestLabels)) BOOST_FAIL("Cannot load test dataset iris_test_labels.csv!"); - size_t localError = 0; - for (size_t i = 0; i < trueTestLabels.n_cols; i++) - if (trueTestLabels(i) != predictedLabels(i)) - localError++; + arma::Row predictedLabels1(testData.n_cols), + predictedLabels2(testData.n_cols); + arma::mat probabilities; + + a.Classify(testData, predictedLabels1); + a.Classify(testData, predictedLabels2, probabilities); + + BOOST_REQUIRE_EQUAL(probabilities.n_cols, testData.n_cols); + + for (size_t i = 0; i < predictedLabels1.n_cols; ++i) + BOOST_REQUIRE_EQUAL(predictedLabels1[i], predictedLabels2[i]); + + arma::colvec pRow; + arma::uword maxIndex = 0; + + for (size_t i = 0; i < predictedLabels1.n_cols; i++) + { + pRow = probabilities.unsafe_col(i); + pRow.max(maxIndex); + BOOST_REQUIRE_EQUAL(predictedLabels1(i), maxIndex); + BOOST_REQUIRE_CLOSE(arma::accu(probabilities.col(i)), 1, 1e-5); + } + + size_t localError = arma::accu(trueTestLabels != predictedLabels1); double lError = (double) localError / labels.n_cols; BOOST_REQUIRE_LE(lError, 0.30); } @@ -781,11 +785,7 @@ arma::Row predictedLabels(testData.n_cols); a.Classify(testData, predictedLabels); - int localError = 0; - for (size_t i = 0; i < trueTestLabels.n_cols; i++) - if (trueTestLabels(i) != predictedLabels(i)) - localError++; - + int localError = arma::accu(trueTestLabels != predictedLabels); double lError = (double) localError / trueTestLabels.n_cols; BOOST_REQUIRE_LE(lError, 0.30); @@ -844,7 +844,7 @@ } } -BOOST_AUTO_TEST_CASE(DecisionStumpSerializationTest) +BOOST_AUTO_TEST_CASE(ID3DecisionStumpSerializationTest) { // Build an AdaBoost object. mat data = randu(10, 500); @@ -854,8 +854,8 @@ for (size_t i = 250; i < 500; ++i) labels[i] = 1; - DecisionStump<> p(data, labels, 2, 800); - AdaBoost> ab(data, labels, 2, p, 50, 1e-10); + ID3DecisionStump p(data, labels, 2, 800); + AdaBoost ab(data, labels, 2, p, 50, 1e-10); // Now create another dataset to train with. mat otherData = randu(5, 200); @@ -867,10 +867,10 @@ for (size_t i = 150; i < 200; ++i) otherLabels[i] = 2; - DecisionStump<> p2(otherData, otherLabels, 3, 500); - AdaBoost> abText(otherData, otherLabels, 3, p2, 50, 1e-10); + ID3DecisionStump p2(otherData, otherLabels, 3, 500); + AdaBoost abText(otherData, otherLabels, 3, p2, 50, 1e-10); - AdaBoost> abXml, abBinary; + AdaBoost abXml, abBinary; SerializeObjectAll(ab, abXml, abText, abBinary); @@ -891,16 +891,6 @@ abText.WeakLearner(i).SplitDimension()); BOOST_REQUIRE_EQUAL(ab.WeakLearner(i).SplitDimension(), abBinary.WeakLearner(i).SplitDimension()); - - CheckMatrices(ab.WeakLearner(i).Split(), - abXml.WeakLearner(i).Split(), - abText.WeakLearner(i).Split(), - abBinary.WeakLearner(i).Split()); - - CheckMatrices(ab.WeakLearner(i).BinLabels(), - abXml.WeakLearner(i).BinLabels(), - abText.WeakLearner(i).BinLabels(), - abBinary.WeakLearner(i).BinLabels()); } } diff -Nru mlpack-3.2.2/src/mlpack/tests/ann_dist_test.cpp mlpack-3.3.0/src/mlpack/tests/ann_dist_test.cpp --- mlpack-3.2.2/src/mlpack/tests/ann_dist_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/ann_dist_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -30,7 +30,7 @@ BOOST_AUTO_TEST_CASE(SimpleBernoulliDistributionTest) { arma::mat param = arma::mat("1 1 0"); - BernoulliDistribution<> module(std::move(param), false); + BernoulliDistribution<> module(param, false); arma::mat sample = module.Sample(); // As the probabilities are [1, 1, 0], the bernoulli samples should be @@ -53,7 +53,7 @@ arma::mat target; target.randn(targetElements, 1); - BernoulliDistribution<> module(std::move(param), false); + BernoulliDistribution<> module(param, false); const double perturbation = 1e-6; double outputA, outputB, original; @@ -66,16 +66,16 @@ { original = module.Probability()(j); module.Probability()(j) = original - perturbation; - outputA = module.LogProbability(std::move(target)); + outputA = module.LogProbability(target); module.Probability()(j) = original + perturbation; - outputB = module.LogProbability(std::move(target)); + outputB = module.LogProbability(target); module.Probability()(j) = original; outputB -= outputA; outputB /= 2 * perturbation; jacobianA(j) = outputB; } - module.LogProbBackward(std::move(target), std::move(jacobianB)); + module.LogProbBackward(target, jacobianB); BOOST_REQUIRE_LE(arma::max(arma::max(arma::abs(jacobianA - jacobianB))), 1e-5); } @@ -96,7 +96,7 @@ arma::mat target; target.randn(targetElements, 1); - BernoulliDistribution<> module(std::move(param)); + BernoulliDistribution<> module(param); const double perturbation = 1e-6; double outputA, outputB, original; @@ -110,10 +110,10 @@ original = module.Logits()(j); module.Logits()(j) = original - perturbation; LogisticFunction::Fn(module.Logits(), module.Probability()); - outputA = module.LogProbability(std::move(target)); + outputA = module.LogProbability(target); module.Logits()(j) = original + perturbation; LogisticFunction::Fn(module.Logits(), module.Probability()); - outputB = module.LogProbability(std::move(target)); + outputB = module.LogProbability(target); module.Logits()(j) = original; LogisticFunction::Fn(module.Logits(), module.Probability()); outputB -= outputA; @@ -121,7 +121,7 @@ jacobianA(j) = outputB; } - module.LogProbBackward(std::move(target), std::move(jacobianB)); + module.LogProbBackward(target, jacobianB); BOOST_REQUIRE_LE(arma::max(arma::max(arma::abs(jacobianA - jacobianB))), 3e-5); } diff -Nru mlpack-3.2.2/src/mlpack/tests/ann_layer_test.cpp mlpack-3.3.0/src/mlpack/tests/ann_layer_test.cpp --- mlpack-3.2.2/src/mlpack/tests/ann_layer_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/ann_layer_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -41,21 +41,21 @@ // Test the Forward function. input = arma::zeros(10, 1); - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); BOOST_REQUIRE_EQUAL(arma::accu(module.Parameters()), arma::accu(output)); // Test the Backward function. - module.Backward(std::move(input), std::move(output), std::move(delta)); + module.Backward(input, output, delta); BOOST_REQUIRE_EQUAL(arma::accu(output), arma::accu(delta)); // Test the forward function. input = arma::ones(10, 1); - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); BOOST_REQUIRE_CLOSE(10 + arma::accu(module.Parameters()), arma::accu(output), 1e-3); // Test the backward function. - module.Backward(std::move(input), std::move(output), std::move(delta)); + module.Backward(input, output, delta); BOOST_REQUIRE_CLOSE(arma::accu(output), arma::accu(delta), 1e-3); } @@ -131,20 +131,20 @@ // Test the Forward function. input = arma::zeros(10, 1); - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); BOOST_REQUIRE_EQUAL(arma::accu(output), 30.0); // Test the Backward function. - module.Backward(std::move(input), std::move(output), std::move(delta)); + module.Backward(input, output, delta); BOOST_REQUIRE_EQUAL(arma::accu(delta), 0); // Test the forward function. input = arma::ones(10, 1); - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); BOOST_REQUIRE_EQUAL(arma::accu(output), 30.0); // Test the backward function. - module.Backward(std::move(input), std::move(output), std::move(delta)); + module.Backward(input, output, delta); BOOST_REQUIRE_EQUAL(arma::accu(delta), 0); } @@ -183,19 +183,19 @@ // Test the Forward function. arma::mat output; - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); BOOST_REQUIRE_LE( arma::as_scalar(arma::abs(arma::mean(output) - (1 - p))), 0.05); // Test the Backward function. arma::mat delta; - module.Backward(std::move(input), std::move(input), std::move(delta)); + module.Backward(input, input, delta); BOOST_REQUIRE_LE( arma::as_scalar(arma::abs(arma::mean(delta) - (1 - p))), 0.05); // Test the Forward function. module.Deterministic() = true; - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); BOOST_REQUIRE_EQUAL(arma::accu(input), arma::accu(output)); } @@ -219,7 +219,7 @@ module.Deterministic() = false; arma::mat output; - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); // Return a column vector containing the indices of elements of X that // are non-zero, we just need the number of non-zero values. @@ -244,7 +244,7 @@ module.Deterministic() = false; arma::mat output; - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); BOOST_REQUIRE_EQUAL(arma::accu(output), arma::accu(input)); } @@ -267,7 +267,7 @@ // Test the Forward function when training phase. arma::mat output; - module.Forward(std::move(input), std::move(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); @@ -278,13 +278,13 @@ // Test the Backward function when training phase. arma::mat delta; - module.Backward(std::move(input), std::move(input), std::move(delta)); + module.Backward(input, input, delta); BOOST_REQUIRE_LE( arma::as_scalar(arma::abs(arma::mean(delta) - 0)), 0.05); // Test the Forward function when testing phase. module.Deterministic() = true; - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); BOOST_REQUIRE_EQUAL(arma::accu(input), arma::accu(output)); } @@ -308,7 +308,7 @@ module.Deterministic() = false; arma::mat output; - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); // Return a column vector containing the indices of elements of X // that are not alphaDash, we just need the number of @@ -336,7 +336,7 @@ module.Deterministic() = false; arma::mat output; - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); BOOST_REQUIRE_EQUAL(arma::accu(output), arma::accu(input)); } @@ -353,13 +353,13 @@ // Test the Forward function. input = arma::zeros(10, 1); - module.Forward(std::move(input), std::move(output)); + 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); // Test the Backward function. - module.Backward(std::move(input), std::move(input), std::move(delta)); + module.Backward(input, input, delta); BOOST_REQUIRE_EQUAL(arma::accu(delta), 0); } @@ -439,11 +439,11 @@ // Test the Forward function. input = arma::zeros(10, 1); - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); BOOST_REQUIRE_EQUAL(0, arma::accu(output)); // Test the Backward function. - module.Backward(std::move(input), std::move(input), std::move(delta)); + module.Backward(input, input, delta); BOOST_REQUIRE_EQUAL(arma::accu(delta), 0); } @@ -457,13 +457,13 @@ // Test the Forward function. input = arma::randu(10, 1); - module.Forward(std::move(input), std::move(output)); + 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); // Test the Backward function. - module.Backward(std::move(input), std::move(output), std::move(delta)); + module.Backward(input, output, delta); CheckMatrices(delta, input); } @@ -688,20 +688,20 @@ // Test the Forward function. Select<> moduleA(3); - moduleA.Forward(std::move(input), std::move(outputA)); + moduleA.Forward(input, outputA); BOOST_REQUIRE_EQUAL(30, arma::accu(outputA)); // Test the Forward function. Select<> moduleB(3, 5); - moduleB.Forward(std::move(input), std::move(outputB)); + moduleB.Forward(input, outputB); BOOST_REQUIRE_EQUAL(15, arma::accu(outputB)); // Test the Backward function. - moduleA.Backward(std::move(input), std::move(outputA), std::move(delta)); + moduleA.Backward(input, outputA, delta); BOOST_REQUIRE_EQUAL(30, arma::accu(delta)); // Test the Backward function. - moduleB.Backward(std::move(input), std::move(outputA), std::move(delta)); + moduleB.Backward(input, outputA, delta); BOOST_REQUIRE_EQUAL(15, arma::accu(delta)); } @@ -715,14 +715,14 @@ // Test the Forward function. Join<> module; - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); BOOST_REQUIRE_EQUAL(50, arma::accu(output)); bool b = output.n_rows == 1 || output.n_cols == 1; BOOST_REQUIRE_EQUAL(b, true); // Test the Backward function. - module.Backward(std::move(input), std::move(output), std::move(delta)); + module.Backward(input, output, delta); BOOST_REQUIRE_EQUAL(50, arma::accu(delta)); b = delta.n_rows == input.n_rows && input.n_cols; @@ -744,18 +744,17 @@ for (size_t m = 0; m < numMergeModules; ++m) { IdentityLayer<> identityLayer; - identityLayer.Forward(std::move(input), - std::move(identityLayer.OutputParameter())); + identityLayer.Forward(input, identityLayer.OutputParameter()); module.Add >(identityLayer); } // Test the Forward function. - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); BOOST_REQUIRE_EQUAL(10 * numMergeModules, arma::accu(output)); // Test the Backward function. - module.Backward(std::move(input), std::move(output), std::move(delta)); + module.Backward(input, output, delta); BOOST_REQUIRE_EQUAL(arma::accu(output), arma::accu(delta)); } } @@ -961,9 +960,9 @@ input.n_rows, input.n_cols, false, true); // Apply Forward() on LSTM layer. - lstm.Forward(std::move(stepData), // Input. - std::move(outLstm), // Output. - std::move(cellLstm), // Cell state. + lstm.Forward(stepData, // Input. + outLstm, // Output. + cellLstm, // Cell state. false); // Don't write into the cell state. // Compute the value of cell state and output. @@ -1043,9 +1042,9 @@ } // Apply Forward() on the LSTM layer. - lstm.Forward(std::move(stepData), // Input. - std::move(outLstm), // Output. - std::move(cellLstm), // Cell state. + lstm.Forward(stepData, // Input. + outLstm, // Output. + cellLstm, // Cell state. true); // Write into cell state. // Compute the value of cell state and output. @@ -1081,18 +1080,18 @@ arma::mat stepData(input.slice(0).memptr(), input.n_rows, input.n_cols, false, true); - lstm.Forward(std::move(stepData), // Input. - std::move(outLstm), // Output. - std::move(cellLstm), // Cell state. - true); // Write into cell state. + lstm.Forward(stepData, // Input. + outLstm, // Output. + cellLstm, // Cell state. + true); // Write into cell state. for (size_t seqNum = 1; seqNum < rho; ++seqNum) { arma::mat empty; // Should throw error. - BOOST_REQUIRE_THROW(lstm.Forward(std::move(stepData), // Input. - std::move(outLstm), // Output. - std::move(empty), // Cell state. + BOOST_REQUIRE_THROW(lstm.Forward(stepData, // Input. + outLstm, // Output. + empty, // Cell state. true), // Write into cell state. std::runtime_error); } @@ -1149,7 +1148,9 @@ */ BOOST_AUTO_TEST_CASE(ForwardGRULayerTest) { - GRU<> gru(3, 3, 5); + // This will make it easier to clean memory later. + GRU<>* gruAlloc = new GRU<>(3, 3, 5); + GRU<>& gru = *gruAlloc; // Initialize the weights to all ones. NetworkInitialization @@ -1160,7 +1161,7 @@ arma::mat input = arma::ones(3, 1); arma::mat output; - gru.Forward(std::move(input), std::move(output)); + gru.Forward(input, output); // Compute the z_t gate output. arma::mat expectedOutput = arma::ones(3, 1); @@ -1175,7 +1176,7 @@ expectedOutput = output; - gru.Forward(std::move(input), std::move(output)); + gru.Forward(input, output); double s = arma::as_scalar(arma::sum(expectedOutput)); @@ -1195,6 +1196,9 @@ expectedOutput = z_t % expectedOutput + (arma::ones(3, 1) - z_t) % o_t; BOOST_REQUIRE_LE(arma::as_scalar(arma::trans(output) * expectedOutput), 1e-2); + + LayerTypes<> layer(gruAlloc); + boost::apply_visitor(DeleteVisitor(), layer); } /** @@ -1218,7 +1222,7 @@ // Test the Forward function. input = arma::zeros(10, 1); - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); BOOST_REQUIRE_CLOSE(arma::accu( moduleA.Parameters().submat(100, 0, moduleA.Parameters().n_elem - 1, 0)) + arma::accu(moduleB.Parameters().submat(100, 0, @@ -1227,7 +1231,7 @@ // Test the Backward function. error = arma::zeros(20, 1); - module.Backward(std::move(input), std::move(error), std::move(delta)); + module.Backward(input, error, delta); BOOST_REQUIRE_EQUAL(arma::accu(delta), 0); } @@ -1260,8 +1264,8 @@ moduleB.Parameters().randu(); // Compute output of each layer. - moduleA.Forward(std::move(input), std::move(outputA)); - moduleB.Forward(std::move(input), std::move(outputB)); + moduleA.Forward(input, outputA); + moduleB.Forward(input, outputB); arma::cube A(outputA.memptr(), outputWidth, outputHeight, outputChannel); arma::cube B(outputB.memptr(), outputWidth, outputHeight, outputChannel); @@ -1305,7 +1309,7 @@ Concat<> module(inputSize, axis); module.Add(moduleA); module.Add(moduleB); - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); arma::cube concatOut(output.memptr(), x * outputWidth, y * outputHeight, z * outputChannel); @@ -1374,12 +1378,12 @@ module.Concat() = arma::ones(5, 1) * 0.5; // Test the Forward function. - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); BOOST_REQUIRE_EQUAL(arma::accu(output), 7.5); // Test the Backward function. - module.Backward(std::move(input), std::move(output), std::move(delta)); + module.Backward(input, output, delta); BOOST_REQUIRE_EQUAL(arma::accu(delta), 5); } @@ -1447,7 +1451,7 @@ input(0) = 1; input(1) = 3; - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); // The Lookup module uses index - 1 for the cols. const double outputSum = arma::accu(module.Parameters().col(0)) + @@ -1456,7 +1460,7 @@ BOOST_REQUIRE_CLOSE(outputSum, arma::accu(output), 1e-3); // Test the Backward function. - module.Backward(std::move(input), std::move(input), std::move(delta)); + module.Backward(input, input, delta); BOOST_REQUIRE_EQUAL(arma::accu(input), arma::accu(input)); // Test the Gradient function. @@ -1464,7 +1468,7 @@ error = error.t(); error.col(1) *= 0.5; - module.Gradient(std::move(input), std::move(error), std::move(gradient)); + module.Gradient(input, error, gradient); // The Lookup module uses index - 1 for the cols. const double gradientSum = arma::accu(gradient.col(0)) + @@ -1484,7 +1488,7 @@ // Test the Forward function. input = arma::mat("0.5; 0.5"); - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); BOOST_REQUIRE_SMALL(arma::accu(arma::abs( arma::mat("-0.6931; -0.6931") - output)), 1e-3); @@ -1492,7 +1496,7 @@ 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(std::move(input), std::move(error), std::move(delta)); + module.Backward(input, error, delta); BOOST_REQUIRE_SMALL(arma::accu(arma::abs( arma::mat("1.6487; 0.6487") - delta)), 1e-3); } @@ -1521,13 +1525,12 @@ 2.0000 2.4000 2.8000 3.0000 3.0000 \ 2.0000 2.4000 2.8000 3.0000 3.0000"); expectedOutput.reshape(25, 1); - layer.Forward(std::move(input), std::move(output)); + layer.Forward(input, output); CheckMatrices(output - expectedOutput, arma::zeros(output.n_rows), 1e-12); expectedOutput = arma::mat("1.0000 1.9000 1.9000 2.8000"); expectedOutput.reshape(4, 1); - layer.Backward(std::move(output), std::move(output), - std::move(unzoomedOutput)); + layer.Backward(output, output, unzoomedOutput); CheckMatrices(unzoomedOutput - expectedOutput, arma::zeros(input.n_rows), 1e-12); } @@ -1549,7 +1552,7 @@ // Non-Deteministic Forward Pass Test. model.Deterministic() = false; - model.Forward(std::move(input), std::move(output)); + model.Forward(input, output); arma::mat result; result << 1.1658 << 0.1100 << -1.2758 << arma::endr << 1.2579 << -0.0699 << -1.1880 << arma::endr @@ -1576,7 +1579,7 @@ result.clear(); model.Deterministic() = true; - model.Forward(std::move(input), std::move(output)); + model.Forward(input, output); result << 1.1658 << 0.1100 << -1.2757 << arma::endr << 1.2579 << -0.0699 << -1.1880 << arma::endr @@ -1733,12 +1736,12 @@ module1.Parameters()(0) = 1.0; module1.Parameters()(8) = 2.0; module1.Reset(); - module1.Forward(std::move(input), std::move(output)); + module1.Forward(input, output); // Value calculated using tensorflow.nn.conv2d_transpose() BOOST_REQUIRE_EQUAL(arma::accu(output), 360.0); // Test the backward function. - module1.Backward(std::move(input), std::move(output), std::move(delta)); + module1.Backward(input, output, delta); // Value calculated using tensorflow.nn.conv2d() BOOST_REQUIRE_EQUAL(arma::accu(delta), 720.0); @@ -1753,12 +1756,12 @@ module2.Parameters()(12) = 1.0; module2.Parameters()(15) = 2.0; module2.Reset(); - module2.Forward(std::move(input), std::move(output)); + module2.Forward(input, output); // Value calculated using torch.nn.functional.conv_transpose2d() BOOST_REQUIRE_EQUAL(arma::accu(output), 1512.0); // Test the backward function. - module2.Backward(std::move(input), std::move(output), std::move(delta)); + module2.Backward(input, output, delta); // Value calculated using torch.nn.functional.conv2d() BOOST_REQUIRE_EQUAL(arma::accu(delta), 6504.0); @@ -1771,12 +1774,12 @@ module3.Parameters()(3) = 3.0; module3.Parameters()(8) = 1.0; module3.Reset(); - module3.Forward(std::move(input), std::move(output)); + module3.Forward(input, output); // Value calculated using torch.nn.functional.conv_transpose2d() BOOST_REQUIRE_EQUAL(arma::accu(output), 2370.0); // Test the backward function. - module3.Backward(std::move(input), std::move(output), std::move(delta)); + module3.Backward(input, output, delta); // Value calculated using torch.nn.functional.conv2d() BOOST_REQUIRE_EQUAL(arma::accu(delta), 19154.0); @@ -1789,12 +1792,12 @@ module4.Parameters()(6) = 6.0; module4.Parameters()(8) = 8.0; module4.Reset(); - module4.Forward(std::move(input), std::move(output)); + module4.Forward(input, output); // Value calculated using torch.nn.functional.conv_transpose2d() BOOST_REQUIRE_EQUAL(arma::accu(output), 6000.0); // Test the backward function. - module4.Backward(std::move(input), std::move(output), std::move(delta)); + module4.Backward(input, output, delta); // Value calculated using torch.nn.functional.conv2d() BOOST_REQUIRE_EQUAL(arma::accu(delta), 86208.0); @@ -1807,12 +1810,12 @@ module5.Parameters()(6) = 4.0; module5.Parameters()(8) = 2.0; module5.Reset(); - module5.Forward(std::move(input), std::move(output)); + module5.Forward(input, output); // Value calculated using torch.nn.functional.conv_transpose2d() BOOST_REQUIRE_EQUAL(arma::accu(output), 120.0); // Test the backward function. - module5.Backward(std::move(input), std::move(output), std::move(delta)); + module5.Backward(input, output, delta); // Value calculated using torch.nn.functional.conv2d() BOOST_REQUIRE_EQUAL(arma::accu(delta), 960.0); @@ -1825,12 +1828,12 @@ module6.Parameters()(6) = 2.0; module6.Parameters()(8) = 4.0; module6.Reset(); - module6.Forward(std::move(input), std::move(output)); + module6.Forward(input, output); // Value calculated using torch.nn.functional.conv_transpose2d() BOOST_REQUIRE_EQUAL(arma::accu(output), 410.0); // Test the backward function. - module6.Backward(std::move(input), std::move(output), std::move(delta)); + module6.Backward(input, output, delta); // Value calculated using torch.nn.functional.conv2d() BOOST_REQUIRE_EQUAL(arma::accu(delta), 4444.0); @@ -1843,11 +1846,11 @@ module7.Parameters()(4) = 2.0; module7.Parameters()(8) = 4.0; module7.Reset(); - module7.Forward(std::move(input), std::move(output)); + module7.Forward(input, output); // Value calculated using torch.nn.functional.conv_transpose2d() BOOST_REQUIRE_EQUAL(arma::accu(output), 606.0); - module7.Backward(std::move(input), std::move(output), std::move(delta)); + module7.Backward(input, output, delta); // Value calculated using torch.nn.functional.conv2d() BOOST_REQUIRE_EQUAL(arma::accu(delta), 7732.0); } @@ -1919,18 +1922,17 @@ for (size_t m = 0; m < numMergeModules; ++m) { IdentityLayer<> identityLayer; - identityLayer.Forward(std::move(input), - std::move(identityLayer.OutputParameter())); + identityLayer.Forward(input, identityLayer.OutputParameter()); module.Add >(identityLayer); } // Test the Forward function. - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); BOOST_REQUIRE_EQUAL(10, arma::accu(output)); // Test the Backward function. - module.Backward(std::move(input), std::move(output), std::move(delta)); + module.Backward(input, output, delta); BOOST_REQUIRE_EQUAL(arma::accu(output), arma::accu(delta)); } } @@ -1949,12 +1951,12 @@ module1.Parameters()(0) = 1.0; module1.Parameters()(8) = 2.0; module1.Reset(); - module1.Forward(std::move(input), std::move(output)); + module1.Forward(input, output); // Value calculated using tensorflow.nn.atrous_conv2d() BOOST_REQUIRE_EQUAL(arma::accu(output), 792.0); // Test the Backward function. - module1.Backward(std::move(input), std::move(output), std::move(delta)); + module1.Backward(input, output, delta); BOOST_REQUIRE_EQUAL(arma::accu(delta), 2376); AtrousConvolution<> module2(1, 1, 3, 3, 2, 2, 0, 0, 7, 7, 2, 2); @@ -1965,12 +1967,12 @@ module2.Parameters()(3) = 1.0; module2.Parameters()(6) = 1.0; module2.Reset(); - module2.Forward(std::move(input), std::move(output)); + module2.Forward(input, output); // Value calculated using tensorflow.nn.conv2d() BOOST_REQUIRE_EQUAL(arma::accu(output), 264.0); // Test the backward function. - module2.Backward(std::move(input), std::move(output), std::move(delta)); + module2.Backward(input, output, delta); BOOST_REQUIRE_EQUAL(arma::accu(delta), 792.0); } @@ -2019,6 +2021,65 @@ } /** + * Test the functions to access and modify the parameters of the + * AtrousConvolution layer. + */ +BOOST_AUTO_TEST_CASE(AtrousConvolutionLayerParametersTest) +{ + // Parameter order for the constructor: inSize, outSize, kW, kH, dW, dH, padW, + // padH, inputWidth, inputHeight, dilationW, dilationH, paddingType ("none"). + AtrousConvolution<> layer1(1, 2, 3, 4, 5, 6, std::make_tuple(7, 8), + std::make_tuple(9, 10), 11, 12, 13, 14); + AtrousConvolution<> layer2(2, 3, 4, 5, 6, 7, std::make_tuple(8, 9), + 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); + + // Now modify the parameters to match the second layer. + layer1.InputWidth() = 12; + layer1.InputHeight() = 13; + layer1.KernelWidth() = 4; + layer1.KernelHeight() = 5; + layer1.StrideWidth() = 6; + layer1.StrideHeight() = 7; + layer1.Padding().PadHTop() = 10; + layer1.Padding().PadHBottom() = 11; + layer1.Padding().PadWLeft() = 8; + layer1.Padding().PadWRight() = 9; + layer1.DilationWidth() = 14; + 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(), + layer2.Padding().PadHBottom()); + BOOST_REQUIRE_EQUAL(layer1.Padding().PadWLeft(), + layer2.Padding().PadWLeft()); + BOOST_REQUIRE_EQUAL(layer1.Padding().PadWRight(), + layer2.Padding().PadWRight()); + BOOST_REQUIRE_EQUAL(layer1.DilationWidth(), layer2.DilationWidth()); + BOOST_REQUIRE_EQUAL(layer1.DilationHeight(), layer2.DilationHeight()); +} + +/** * Test that the padding options are working correctly in Atrous Convolution * layer. */ @@ -2035,14 +2096,14 @@ input = arma::linspace(0, 48, 49); module1.Parameters() = arma::mat(9 + 1, 1, arma::fill::zeros); module1.Reset(); - module1.Forward(std::move(input), std::move(output)); + 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); // Test the Backward function. - module1.Backward(std::move(input), std::move(output), std::move(delta)); + module1.Backward(input, output, delta); // Check same padding option. AtrousConvolution<> module2(1, 1, 3, 3, 1, 1, @@ -2053,14 +2114,14 @@ input = arma::linspace(0, 48, 49); module2.Parameters() = arma::mat(9 + 1, 1, arma::fill::zeros); module2.Reset(); - module2.Forward(std::move(input), std::move(output)); + 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); // Test the backward function. - module2.Backward(std::move(input), std::move(output), std::move(delta)); + module2.Backward(input, output, delta); } /** @@ -2076,7 +2137,7 @@ LayerNorm<> model(input.n_rows); model.Reset(); - model.Forward(std::move(input), std::move(output)); + model.Forward(input, output); arma::mat result; result << 1.2247 << 1.2978 << arma::endr << 0 << -1.1355 << arma::endr @@ -2159,13 +2220,13 @@ linear->Reset(); input = arma::zeros(10, 1); - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); double parameterSum = arma::accu(linear->Parameters().submat( 100, 0, linear->Parameters().n_elem - 1, 0)); // Test the Backward function. - module.Backward(std::move(input), std::move(input), std::move(delta)); + module.Backward(input, input, delta); // Clean up before we break, delete linear; @@ -2191,13 +2252,13 @@ linear->Reset(); input = arma::zeros(10, 1); - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); double parameterSum = arma::accu(linear->Parameters().submat( 100, 0, linear->Parameters().n_elem - 1, 0)); // Test the Backward function. - module.Backward(std::move(input), std::move(input), std::move(delta)); + module.Backward(input, input, delta); // Clean up before we break, delete linear; @@ -2216,19 +2277,19 @@ // Test the Forward function for a vector. input = arma::ones(20, 1); - moduleRow.Forward(std::move(input), std::move(output)); + moduleRow.Forward(input, output); BOOST_REQUIRE_EQUAL(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(std::move(input), std::move(outputMat)); + moduleMat.Forward(input, outputMat); BOOST_REQUIRE_EQUAL(outputMat.n_rows, 12); BOOST_REQUIRE_EQUAL(outputMat.n_cols, 2); // Test the Backward function. - moduleMat.Backward(std::move(input), std::move(input), std::move(delta)); + moduleMat.Backward(input, input, delta); BOOST_REQUIRE_EQUAL(accu(delta), 160); BOOST_REQUIRE_EQUAL(delta.n_rows, 20); } @@ -2245,21 +2306,21 @@ Subview<> moduleStart(1, 0, 9); arma::mat subStart = arma::linspace(1, 10, 10); - moduleStart.Forward(std::move(input), std::move(outputStart)); + moduleStart.Forward(input, outputStart); CheckMatrices(outputStart, subStart); // Slicing from the mid indices. Subview<> moduleMid(1, 6, 15); arma::mat subMid = arma::linspace(7, 16, 10); - moduleMid.Forward(std::move(input), std::move(outputMid)); + moduleMid.Forward(input, outputMid); CheckMatrices(outputMid, subMid); // Slicing from the end indices. Subview<> moduleEnd(1, 10, 19); arma::mat subEnd = arma::linspace(11, 20, 10); - moduleEnd.Forward(std::move(input), std::move(outputEnd)); + moduleEnd.Forward(input, outputEnd); CheckMatrices(outputEnd, subEnd); } @@ -2275,14 +2336,14 @@ // Test with inSize 1. input = arma::ones(20, 8); - moduleCol.Forward(std::move(input), std::move(outputCol)); + moduleCol.Forward(input, outputCol); CheckMatrices(outputCol, input); // Few rows and columns selected. Subview<> moduleMat(4, 3, 6, 0, 2); // Test with inSize greater than 1. - moduleMat.Forward(std::move(input), std::move(outputMat)); + moduleMat.Forward(input, outputMat); output = arma::ones(12, 2); CheckMatrices(outputMat, output); @@ -2290,7 +2351,7 @@ Subview<> moduleDef(4, 1, 6, 0, 4); // Test with inSize greater than 1 and endCol >= inSize. - moduleDef.Forward(std::move(input), std::move(outputDef)); + moduleDef.Forward(input, outputDef); output = arma::ones(24, 2); CheckMatrices(outputDef, output); } @@ -2308,12 +2369,12 @@ // output should be small enough. input = join_cols(arma::ones(5, 1) * -15, arma::zeros(5, 1)); - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); BOOST_REQUIRE_LE(arma::accu(output), 1e-5); // Test the Backward function. arma::mat gy = arma::zeros(5, 1); - module.Backward(std::move(input), std::move(gy), std::move(delta)); + module.Backward(input, gy, delta); BOOST_REQUIRE(arma::accu(delta) != 0); // klBackward will be added. } @@ -2329,8 +2390,8 @@ arma::zeros(5, 1)); // Test if two forward passes generate same output. - module.Forward(std::move(input), std::move(outputA)); - module.Forward(std::move(input), std::move(outputB)); + module.Forward(input, outputA); + module.Forward(input, outputB); CheckMatrices(outputA, outputB); } @@ -2345,14 +2406,14 @@ input = join_cols(arma::ones(5, 1), arma::zeros(5, 1)); - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); // As KL divergence is not included, with the above inputs, the delta // matrix should be all zeros. gy = arma::zeros(output.n_rows, output.n_cols); - module.Backward(std::move(output), std::move(gy), std::move(delta)); + module.Backward(output, gy, delta); - BOOST_REQUIRE_EQUAL(arma::accu(std::move(delta)), 0); + BOOST_REQUIRE_EQUAL(arma::accu(delta), 0); } /** @@ -2490,14 +2551,14 @@ // Test the Forward function (pass the same input to both). input = arma::randu(10, 1); - sequential->Forward(std::move(input), std::move(outputA)); - residual->Forward(std::move(input), std::move(outputB)); + sequential->Forward(input, outputA); + residual->Forward(input, outputB); CheckMatrices(outputA, outputB - input); // Test the Backward function (pass the same error to both). - sequential->Backward(std::move(input), std::move(input), std::move(deltaA)); - residual->Backward(std::move(input), std::move(input), std::move(deltaB)); + sequential->Backward(input, input, deltaA); + residual->Backward(input, input, deltaB); CheckMatrices(deltaA, deltaB - input); @@ -2534,8 +2595,8 @@ // Test the Forward function (pass the same input to both). input = arma::randu(10, 1); - sequential->Forward(std::move(input), std::move(outputA)); - highway->Forward(std::move(input), std::move(outputB)); + sequential->Forward(input, outputA); + highway->Forward(input, outputB); CheckMatrices(outputB, input * 0.5 + outputA * 0.5); @@ -2577,7 +2638,6 @@ ~GradientFunction() { - highway->DeleteModules(); delete model; } @@ -2629,7 +2689,6 @@ ~GradientFunction() { - sequential->DeleteModules(); delete model; } @@ -2715,10 +2774,10 @@ linear->Bias().zeros(); input = arma::zeros(10, 1); - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); // Test the Backward function. - module.Backward(std::move(input), std::move(input), std::move(delta)); + module.Backward(input, input, delta); BOOST_REQUIRE_EQUAL(0, arma::accu(output)); BOOST_REQUIRE_EQUAL(arma::accu(delta), 0); @@ -2781,6 +2840,56 @@ } /** + * Test that the functions that can modify and access the parameters of the + * Convolution layer work. + */ +BOOST_AUTO_TEST_CASE(ConvolutionLayerParametersTest) +{ + // Parameter order: inSize, outSize, kW, kH, dW, dH, padW, padH, inputWidth, + // inputHeight, paddingType. + Convolution<> layer1(1, 2, 3, 4, 5, 6, std::tuple(7, 8), + std::tuple(9, 10), 11, 12, "none"); + Convolution<> layer2(2, 3, 4, 5, 6, 7, std::tuple(8, 9), + 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); + + // Now modify the parameters to match the second layer. + layer1.InputWidth() = 12; + layer1.InputHeight() = 13; + layer1.KernelWidth() = 4; + layer1.KernelHeight() = 5; + layer1.StrideWidth() = 6; + layer1.StrideHeight() = 7; + layer1.PadWLeft() = 8; + layer1.PadWRight() = 9; + layer1.PadHTop() = 10; + 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()); +} + +/** * Test that the padding options are working correctly in Convolution layer. */ BOOST_AUTO_TEST_CASE(ConvolutionLayerPaddingTest) @@ -2795,14 +2904,14 @@ input = arma::linspace(0, 48, 49); module1.Parameters() = arma::mat(9 + 1, 1, arma::fill::zeros); module1.Reset(); - module1.Forward(std::move(input), std::move(output)); + 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); // Test the Backward function. - module1.Backward(std::move(input), std::move(output), std::move(delta)); + module1.Backward(input, output, delta); // Check same padding option. Convolution<> module2(1, 1, 3, 3, 1, 1, std::tuple(0, 0), @@ -2812,14 +2921,200 @@ input = arma::linspace(0, 48, 49); module2.Parameters() = arma::mat(9 + 1, 1, arma::fill::zeros); module2.Reset(); - module2.Forward(std::move(input), std::move(output)); + 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); // Test the backward function. - module2.Backward(std::move(input), std::move(output), std::move(delta)); + module2.Backward(input, output, delta); +} + +/** + * Test that the padding options in Transposed Convolution layer. + */ +BOOST_AUTO_TEST_CASE(TransposedConvolutionLayerPaddingTest) +{ + arma::mat output, input, delta; + + TransposedConvolution<> module1(1, 1, 3, 3, 1, 1, 0, 0, 4, 4, 6, 6, "VALID"); + // Test the forward function. + // Valid Should give the same result. + input = arma::linspace(0, 15, 16); + module1.Parameters() = arma::mat(9 + 1, 1, arma::fill::zeros); + module1.Reset(); + module1.Forward(input, output); + // Value calculated using tensorflow.nn.conv2d_transpose(). + BOOST_REQUIRE_EQUAL(arma::accu(output), 0.0); + + // Test the Backward Function. + module1.Backward(input, output, delta); + BOOST_REQUIRE_EQUAL(arma::accu(delta), 0.0); + + // Test Valid for non zero padding. + TransposedConvolution<> module2(1, 1, 3, 3, 2, 2, + std::tuple(0, 0), std::tuple(0, 0), + 2, 2, 5, 5, "VALID"); + // Test the forward function. + input = arma::linspace(0, 3, 4); + module2.Parameters() = arma::mat(25 + 1, 1, arma::fill::zeros); + module2.Parameters()(2) = 8.0; + module2.Parameters()(4) = 6.0; + module2.Parameters()(6) = 4.0; + module2.Parameters()(8) = 2.0; + module2.Reset(); + module2.Forward(input, output); + // Value calculated using torch.nn.functional.conv_transpose2d(). + BOOST_REQUIRE_EQUAL(arma::accu(output), 120.0); + + // Test the Backward Function. + module2.Backward(input, output, delta); + BOOST_REQUIRE_EQUAL(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"); + // Test the forward function. + input = arma::linspace(0, 8, 9); + 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); + + // Test the Backward Function. + module3.Backward(input, output, delta); + BOOST_REQUIRE_EQUAL(arma::accu(delta), 0.0); + + // Output shape should equal input. + TransposedConvolution<> module4(1, 1, 3, 3, 1, 1, + std::tuple(2, 2), std::tuple(2, 2), + 5, 5, 5, 5, "SAME"); + // Test the forward function. + input = arma::linspace(0, 24, 25); + 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); + + // Test the Backward Function. + module4.Backward(input, output, delta); + BOOST_REQUIRE_EQUAL(arma::accu(delta), 0.0); + + TransposedConvolution<> module5(1, 1, 3, 3, 2, 2, 0, 0, 2, 2, 2, 2, "SAME"); + // Test the forward function. + input = arma::linspace(0, 3, 4); + 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); + + // Test the Backward Function. + module5.Backward(input, output, delta); + BOOST_REQUIRE_EQUAL(arma::accu(delta), 0.0); + + TransposedConvolution<> module6(1, 1, 4, 4, 1, 1, 1, 1, 5, 5, 5, 5, "SAME"); + // Test the forward function. + input = arma::linspace(0, 24, 25); + 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); + + // Test the Backward Function. + module6.Backward(input, output, delta); + BOOST_REQUIRE_EQUAL(arma::accu(delta), 0.0); } +/** + * Simple test for Max Pooling layer. + */ +BOOST_AUTO_TEST_CASE(MaxPoolingTestCase) +{ + // For rectangular input to pooling layers. + arma::mat input = arma::mat(12, 1); + arma::mat output; + input.zeros(); + input(0) = 1; + input(1) = 2; + input(2) = 3; + input(3) = input(8) = 7; + input(4) = 4; + input(5) = 5; + input(6) = input(7) = 6; + input(10) = 8; + input(11) = 9; + // Output-Size should be 2 x 2. + // Square output. + MaxPooling<> module1(2, 2, 2, 1); + module1.InputHeight() = 3; + 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); + + // For Square input. + input = arma::mat(9, 1); + input.zeros(); + input(0) = 6; + input(1) = 3; + input(2) = 9; + input(3) = 3; + input(6) = 3; + // Output-Size should be 1 x 2. + // Rectangular output. + MaxPooling<> module2(3, 2, 3, 1); + module2.InputHeight() = 3; + 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); + + // For Square input. + input = arma::mat(16, 1); + input.zeros(); + input(0) = 6; + input(1) = 3; + input(2) = 9; + input(4) = 3; + input(8) = 3; + // Output-Size should be 3 x 3. + // Square output. + MaxPooling<> module3(2, 2, 1, 1); + module3.InputHeight() = 4; + 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); + + // For Rectangular input. + input = arma::mat(6, 1); + input.zeros(); + input(0) = 1; + input(1) = 1; + input(3) = 1; + // Output-Size should be 2 x 2. + // Square output. + MaxPooling<> module4(2, 1, 1, 1); + module4.InputHeight() = 2; + 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); +} BOOST_AUTO_TEST_SUITE_END(); diff -Nru mlpack-3.2.2/src/mlpack/tests/ann_test_tools.hpp mlpack-3.3.0/src/mlpack/tests/ann_test_tools.hpp --- mlpack-3.2.2/src/mlpack/tests/ann_test_tools.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/ann_test_tools.hpp 2020-04-07 13:17:16.000000000 +0000 @@ -53,7 +53,7 @@ ResetFunction(module); // Initialize the jacobian matrix. - module.Forward(std::move(input), std::move(output)); + module.Forward(input, output); jacobianA = arma::zeros(input.n_elem, output.n_elem); // Share the input paramter matrix. @@ -64,9 +64,9 @@ { double original = sin(i); sin(i) = original - perturbation; - module.Forward(std::move(input), std::move(outputA)); + module.Forward(input, outputA); sin(i) = original + perturbation; - module.Forward(std::move(input), std::move(outputB)); + module.Forward(input, outputB); sin(i) = original; outputB -= outputA; @@ -90,7 +90,7 @@ derivTemp(i) = 1; arma::mat delta; - module.Backward(std::move(input), std::move(deriv), std::move(delta)); + module.Backward(input, deriv, delta); jacobianB.col(i) = delta; } @@ -106,10 +106,10 @@ arma::mat& target, const double eps = 1e-6) { - module.Forward(std::move(input), std::move(target)); + module.Forward(input, target); arma::mat delta; - module.Backward(std::move(input), std::move(target), std::move(delta)); + module.Backward(input, target, delta); arma::mat centralDifference = arma::zeros(delta.n_rows, delta.n_cols); arma::mat inputTemp = arma::mat(input.memptr(), input.n_rows, input.n_cols, @@ -121,9 +121,9 @@ for (size_t i = 0; i < input.n_elem; ++i) { inputTemp(i) = inputTemp(i) + eps; - double outputA = module.Forward(std::move(input), std::move(target)); + double outputA = module.Forward(input, target); inputTemp(i) = inputTemp(i) - (2 * eps); - double outputB = module.Forward(std::move(input), std::move(target)); + double outputB = module.Forward(input, target); centralDifferenceTemp(i) = (outputA - outputB) / (2 * eps); inputTemp(i) = inputTemp(i) + eps; diff -Nru mlpack-3.2.2/src/mlpack/tests/ann_visitor_test.cpp mlpack-3.3.0/src/mlpack/tests/ann_visitor_test.cpp --- mlpack-3.2.2/src/mlpack/tests/ann_visitor_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/ann_visitor_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -35,24 +35,24 @@ ResetVisitor resetVisitor; - boost::apply_visitor(WeightSetVisitor(std::move(layerWeights), 0), linear); + boost::apply_visitor(WeightSetVisitor(layerWeights, 0), linear); boost::apply_visitor(resetVisitor, linear); arma::mat weight = {"1 2 3 4 5 6 7 8 9 10"}; - size_t biasSize = boost::apply_visitor(BiasSetVisitor(std::move(weight), - 0), linear); + size_t biasSize = boost::apply_visitor(BiasSetVisitor(weight, 0), linear); BOOST_REQUIRE_EQUAL(biasSize, 10); arma::mat input(10, 1), output; input.randu(); - boost::apply_visitor(ForwardVisitor(std::move(input), std::move(output)), - linear); + boost::apply_visitor(ForwardVisitor(input, output), linear); BOOST_REQUIRE_EQUAL(arma::accu(output), 55); + + boost::apply_visitor(DeleteVisitor(), linear); } BOOST_AUTO_TEST_SUITE_END(); diff -Nru mlpack-3.2.2/src/mlpack/tests/callback_test.cpp mlpack-3.3.0/src/mlpack/tests/callback_test.cpp --- mlpack-3.2.2/src/mlpack/tests/callback_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/callback_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -13,12 +13,15 @@ #include #include #include +#include #include #include #include #include #include - +#include +#include +#include #include using namespace mlpack; @@ -27,6 +30,7 @@ using namespace mlpack::lmnn; using namespace mlpack::metric; using namespace mlpack::nca; +using namespace mlpack::distribution; BOOST_AUTO_TEST_SUITE(CallbackTest); @@ -92,12 +96,12 @@ // Create model with user defined rho parameter. RNN, RandomInitialization> model( rho, false, NegativeLogLikelihood<>(), init); - model.Add >(); - model.Add >(1, 10); + model.Add>(); + model.Add>(1, 10); // Use LSTM layer with rho. - model.Add >(10, 3, rho); - model.Add >(); + model.Add>(10, 3, rho); + model.Add>(); std::stringstream stream; model.Train(input, target, ens::PrintLoss(stream)); @@ -118,12 +122,12 @@ // Create model with user defined rho parameter. RNN, RandomInitialization> model( rho, false, NegativeLogLikelihood<>(), init); - model.Add >(); - model.Add >(1, 10); + model.Add>(); + model.Add>(1, 10); // Use LSTM layer with rho. - model.Add >(10, 3, rho); - model.Add >(); + model.Add>(10, 3, rho); + model.Add>(); std::stringstream stream; ens::StandardSGD opt(0.1, 1, 5); @@ -137,17 +141,17 @@ */ BOOST_AUTO_TEST_CASE(LRWithOptimizerCallback) { - arma::mat data("1 2 3;" - "1 2 3"); - arma::Row responses("1 1 0"); - - ens::StandardSGD sgd(0.1, 1, 5); - LogisticRegression<> logisticRegression(data, responses, sgd, 0.001); - std::stringstream stream; - logisticRegression.Train(data, responses, sgd, - ens::PrintLoss(stream)); + arma::mat data("1 2 3;" + "1 2 3"); + arma::Row responses("1 1 0"); + + ens::StandardSGD sgd(0.1, 1, 5); + LogisticRegression<> logisticRegression(data, responses, sgd, 0.001); + std::stringstream stream; + logisticRegression.Train(data, responses, sgd, + ens::PrintLoss(stream)); - BOOST_REQUIRE_GT(stream.str().length(), 0); + BOOST_REQUIRE_GT(stream.str().length(), 0); } /** @@ -156,8 +160,8 @@ BOOST_AUTO_TEST_CASE(LMNNWithOptimizerCallback) { // Useful but simple dataset with six points and two classes. - arma::mat dataset = "-0.1 -0.1 -0.1 0.1 0.1 0.1;" - " 1.0 0.0 -1.0 1.0 0.0 -1.0 "; + arma::mat dataset = "-0.1 -0.1 -0.1 0.1 0.1 0.1;" + " 1.0 0.0 -1.0 1.0 0.0 -1.0 "; arma::Row labels = " 0 0 0 1 1 1 "; LMNN<> lmnn(dataset, labels, 1); @@ -175,8 +179,8 @@ BOOST_AUTO_TEST_CASE(NCAWithOptimizerCallback) { // Useful but simple dataset with six points and two classes. - arma::mat data = "-0.1 -0.1 -0.1 0.1 0.1 0.1;" - " 1.0 0.0 -1.0 1.0 0.0 -1.0 "; + arma::mat data = "-0.1 -0.1 -0.1 0.1 0.1 0.1;" + " 1.0 0.0 -1.0 1.0 0.0 -1.0 "; arma::Row labels = " 0 0 0 1 1 1 "; NCA nca(data, labels); @@ -188,4 +192,69 @@ BOOST_REQUIRE_GT(stream.str().length(), 0); } +/** + * Test softmax_regression implementation with PrintLoss callback. + */ +BOOST_AUTO_TEST_CASE(SRWithOptimizerCallback) +{ + const size_t points = 1000; + const size_t inputSize = 3; + const size_t numClasses = 3; + const double lambda = 0.5; + + // Generate two-Gaussian dataset. + GaussianDistribution g1(arma::vec("1.0 9.0 1.0"), arma::eye(3, 3)); + GaussianDistribution g2(arma::vec("4.0 3.0 4.0"), arma::eye(3, 3)); + + arma::mat data(inputSize, points); + arma::Row labels(points); + + for (size_t i = 0; i < points / 2; i++) + { + data.col(i) = g1.Random(); + labels(i) = 0; + } + for (size_t i = points / 2; i < points; i++) + { + data.col(i) = g2.Random(); + labels(i) = 1; + } + ens::StandardSGD sgd(0.1, 1, 5); + std::stringstream stream; + // Train softmax regression object. + SoftmaxRegression sr(data, labels, numClasses, lambda); + sr.Train(data, labels, numClasses, sgd, ens::ProgressBar(70, stream)); + + BOOST_REQUIRE_GT(stream.str().length(), 0); +} + +/* + * Tests the RBM Implementation with PrintLoss callback. + */ +BOOST_AUTO_TEST_CASE(RBMCallbackTest) +{ + // Normalised dataset. + int hiddenLayerSize = 10; + size_t batchSize = 10; + arma::mat trainData, testData, dataset; + arma::mat trainLabelsTemp, testLabelsTemp; + trainData.load("digits_train.arm"); + + GaussianInitialization gaussian(0, 0.1); + RBM model(trainData, + gaussian, + trainData.n_rows, + hiddenLayerSize, + batchSize); + + size_t numRBMIterations = 10; + ens::StandardSGD msgd(0.03, batchSize, numRBMIterations, 0, true); + std::stringstream stream; + + // Call the train function with printloss callback. + double objVal = model.Train(msgd, ens::ProgressBar(70, stream)); + BOOST_REQUIRE(!std::isnan(objVal)); + BOOST_REQUIRE_GT(stream.str().length(), 0); +} + BOOST_AUTO_TEST_SUITE_END(); diff -Nru mlpack-3.2.2/src/mlpack/tests/CMakeLists.txt mlpack-3.3.0/src/mlpack/tests/CMakeLists.txt --- mlpack-3.2.2/src/mlpack/tests/CMakeLists.txt 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/CMakeLists.txt 2020-04-07 13:17:16.000000000 +0000 @@ -94,6 +94,7 @@ regularized_svd_test.cpp reward_clipping_test.cpp rl_components_test.cpp + scaling_test.cpp serialization.cpp serialization.hpp serialization_test.cpp @@ -104,6 +105,7 @@ sparse_coding_test.cpp spill_tree_test.cpp split_data_test.cpp + string_encoding_test.cpp sumtree_test.cpp svd_batch_test.cpp svd_incremental_test.cpp @@ -114,7 +116,6 @@ timer_test.cpp tree_test.cpp tree_traits_test.cpp - scaling_test.cpp ub_tree_test.cpp union_find_test.cpp vantage_point_tree_test.cpp @@ -136,6 +137,7 @@ main_tests/kfn_test.cpp main_tests/knn_test.cpp main_tests/linear_regression_test.cpp + main_tests/image_converter_test.cpp main_tests/linear_svm_test.cpp main_tests/logistic_regression_test.cpp main_tests/local_coordinate_coding_test.cpp @@ -185,11 +187,11 @@ ) add_custom_command(TARGET mlpack_test POST_BUILD - COMMAND ${CMAKE_COMMAND} -E tar xjpf mnist_first250_training_4s_and_9s.tar.bz2 - COMMAND ${CMAKE_COMMAND} -E tar xjpf digits_train.tar.bz2 - COMMAND ${CMAKE_COMMAND} -E tar xjpf digits_test.tar.bz2 - COMMAND ${CMAKE_COMMAND} -E tar xjpf digits_train_label.tar.bz2 - COMMAND ${CMAKE_COMMAND} -E tar xjpf digits_test_label.tar.bz2 + COMMAND ${CMAKE_COMMAND} -E tar xjf mnist_first250_training_4s_and_9s.tar.bz2 + COMMAND ${CMAKE_COMMAND} -E tar xjf digits_train.tar.bz2 + COMMAND ${CMAKE_COMMAND} -E tar xjf digits_test.tar.bz2 + COMMAND ${CMAKE_COMMAND} -E tar xjf digits_train_label.tar.bz2 + COMMAND ${CMAKE_COMMAND} -E tar xjf digits_test_label.tar.bz2 WORKING_DIRECTORY ${PROJECT_BINARY_DIR} ) diff -Nru mlpack-3.2.2/src/mlpack/tests/convolutional_network_test.cpp mlpack-3.3.0/src/mlpack/tests/convolutional_network_test.cpp --- mlpack-3.2.2/src/mlpack/tests/convolutional_network_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/convolutional_network_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -114,13 +114,7 @@ arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)) + 1; } - size_t correct = 0; - for (size_t i = 0; i < X.n_cols; i++) - { - if (prediction(i) == Y(i)) - correct++; - } - + size_t correct = arma::accu(prediction == Y); double classificationError = 1 - double(correct) / X.n_cols; if (classificationError <= 0.25) { diff -Nru mlpack-3.2.2/src/mlpack/tests/cosine_tree_test.cpp mlpack-3.3.0/src/mlpack/tests/cosine_tree_test.cpp --- mlpack-3.2.2/src/mlpack/tests/cosine_tree_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/cosine_tree_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -222,4 +222,218 @@ } } +/** + * Test the copy constructor & copy assignment using Cosine trees. + */ +BOOST_AUTO_TEST_CASE(CopyConstructorAndOperatorCosineTreeTest) +{ + // Initialize constants required for the test. + const size_t numRows = 10; + const size_t numCols = 15; + + // Vectors to hold depth-first traversal + // of the number of columns in each node. + std::vector v1, v2, v3; + + // Make a random dataset. + arma::mat* data = new arma::mat(numRows, numCols, arma::fill::randu); + + // Make a cosine tree, with the generated dataset. + CosineTree* ctree1 = new CosineTree(*data); + + // Stacks for depth first search of the tree. + std::vector nodeStack1, nodeStack2, nodeStack3; + nodeStack1.push_back(ctree1); + + // While stack is not empty. + while (nodeStack1.size()) + { + // Pop a node from the stack and split it. + CosineTree *currentNode1, *currentLeft1, *currentRight1; + + currentNode1 = nodeStack1.back(); + currentNode1->CosineNodeSplit(); + nodeStack1.pop_back(); + + // Obtain pointers to the children of the node. + currentLeft1 = currentNode1->Left(); + currentRight1 = currentNode1->Right(); + + // If children exist. + if (currentLeft1 && currentRight1) + { + // Push the child nodes on to the stack. + nodeStack1.push_back(currentLeft1); + nodeStack1.push_back(currentRight1); + + v1.push_back(currentNode1->NumColumns()); + } + } + + // Copy constructor and operator. + CosineTree ctree2(*ctree1); + CosineTree ctree3 = *ctree1; + + delete ctree1; + delete data; + + nodeStack2.push_back(&ctree2); + nodeStack3.push_back(&ctree3); + + // While stacks are not empty. + while (nodeStack2.size() && nodeStack3.size()) + { + // Pop a node from the stack and split it. + CosineTree *currentNode2, *currentLeft2, *currentRight2; + CosineTree *currentNode3, *currentLeft3, *currentRight3; + + currentNode2 = nodeStack2.back(); + nodeStack2.pop_back(); + + currentNode3 = nodeStack3.back(); + nodeStack3.pop_back(); + + // Obtain pointers to the children of the node. + currentLeft2 = currentNode2->Left(); + currentRight2 = currentNode2->Right(); + + currentLeft3 = currentNode3->Left(); + currentRight3 = currentNode3->Right(); + + // If children exist. + if (currentLeft2 && currentRight2 && currentLeft3 && currentRight3) + { + // Push the child nodes on to the stack. + nodeStack2.push_back(currentLeft2); + nodeStack2.push_back(currentRight2); + + v2.push_back(currentNode2->NumColumns()); + + nodeStack3.push_back(currentLeft3); + nodeStack3.push_back(currentRight3); + + v3.push_back(currentNode3->NumColumns()); + } + } + + for (size_t i = 0; i < v1.size(); i++) + { + BOOST_REQUIRE_EQUAL(v1.at(i), v2.at(i)); + BOOST_REQUIRE_EQUAL(v1.at(i), v3.at(i)); + } +} + +/** + * Test the move constructor & move assignment using Cosine trees. + */ +BOOST_AUTO_TEST_CASE(MoveConstructorAndOperatorCosineTreeTest) +{ + // Initialize constants required for the test. + const size_t numRows = 10; + const size_t numCols = 15; + + // Vectors to hold depth-first traversal + // of the number of columns in each node. + std::vector v1, v2, v3; + + // Make a random dataset. + arma::mat data = arma::randu(numRows, numCols); + + // Make a cosine tree, with the generated dataset. + CosineTree ctree1(data); + + // Stacks for depth first search of the tree. + std::vector nodeStack1, nodeStack2, nodeStack3; + nodeStack1.push_back(&ctree1); + + // While stack is not empty. + while (nodeStack1.size()) + { + // Pop a node from the stack and split it. + CosineTree *currentNode1, *currentLeft1, *currentRight1; + + currentNode1 = nodeStack1.back(); + currentNode1->CosineNodeSplit(); + nodeStack1.pop_back(); + + // Obtain pointers to the children of the node. + currentLeft1 = currentNode1->Left(); + currentRight1 = currentNode1->Right(); + + // If children exist. + if (currentLeft1 && currentRight1) + { + // Push the child nodes on to the stack. + nodeStack1.push_back(currentLeft1); + nodeStack1.push_back(currentRight1); + + v1.push_back(currentNode1->NumColumns()); + } + } + + // Move constructor. + CosineTree ctree2(std::move(ctree1)); + + nodeStack2.push_back(&ctree2); + + // While stacks are not empty. + while (nodeStack2.size()) + { + // Pop a node from the stack and split it. + CosineTree *currentNode2, *currentLeft2, *currentRight2; + + currentNode2 = nodeStack2.back(); + nodeStack2.pop_back(); + + // Obtain pointers to the children of the node. + currentLeft2 = currentNode2->Left(); + currentRight2 = currentNode2->Right(); + + // If children exist. + if (currentLeft2 && currentRight2) + { + // Push the child nodes on to the stack. + nodeStack2.push_back(currentLeft2); + nodeStack2.push_back(currentRight2); + + v2.push_back(currentNode2->NumColumns()); + } + } + + // Move operator. + CosineTree ctree3 = std::move(ctree2); + + nodeStack3.push_back(&ctree3); + + // While stacks are not empty. + while (nodeStack3.size()) + { + // Pop a node from the stack and split it. + CosineTree *currentNode3, *currentLeft3, *currentRight3; + + currentNode3 = nodeStack3.back(); + nodeStack3.pop_back(); + + // Obtain pointers to the children of the node. + currentLeft3 = currentNode3->Left(); + currentRight3 = currentNode3->Right(); + + // If children exist. + if (currentLeft3 && currentRight3) + { + // Push the child nodes on to the stack. + nodeStack3.push_back(currentLeft3); + nodeStack3.push_back(currentRight3); + + v3.push_back(currentNode3->NumColumns()); + } + } + + for (size_t i = 0; i < v1.size(); i++) + { + BOOST_REQUIRE_EQUAL(v1.at(i), v2.at(i)); + BOOST_REQUIRE_EQUAL(v1.at(i), v3.at(i)); + } +} + BOOST_AUTO_TEST_SUITE_END(); diff -Nru mlpack-3.2.2/src/mlpack/tests/cv_test.cpp mlpack-3.3.0/src/mlpack/tests/cv_test.cpp --- mlpack-3.2.2/src/mlpack/tests/cv_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/cv_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -165,6 +166,28 @@ } /** + * Test the R squared metric (R2 Score). + */ +BOOST_AUTO_TEST_CASE(R2ScoreTest) +{ + // Making two points that define the linear function f(x) = x - 1. + arma::mat trainingData("0 1"); + arma::rowvec trainingResponses("-1 0"); + + LinearRegression lr(trainingData, trainingResponses); + + // Making five responses that are the output of regression function f(x) + // with some responses having a slight deviation of 0.005. + // Mean Responses = (1 + 2 + 3 + 6 + 8)/5 = 4. + arma::mat data("2 3 4 7 9"); + arma::rowvec responses("1 2.005 3 6.005 8.005"); + + double expectedR2 = 0.99999779; + + BOOST_REQUIRE_CLOSE(R2Score::Evaluate(lr, data, responses), expectedR2, 1e-5); +} + +/** * Test the mean squared error with matrix responses. */ BOOST_AUTO_TEST_CASE(MSEMatResponsesTest) diff -Nru mlpack-3.2.2/src/mlpack/tests/feedforward_network_test.cpp mlpack-3.3.0/src/mlpack/tests/feedforward_network_test.cpp --- mlpack-3.2.2/src/mlpack/tests/feedforward_network_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/feedforward_network_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -53,17 +53,8 @@ arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)) + 1; } - size_t error = 0; - for (size_t i = 0; i < testData.n_cols; i++) - { - if (int(arma::as_scalar(prediction.col(i))) == - int(arma::as_scalar(testLabels.col(i)))) - { - error++; - } - } - - double classificationError = 1 - double(error) / testData.n_cols; + size_t correct = arma::accu(prediction == testLabels); + double classificationError = 1 - double(correct) / testData.n_cols; BOOST_REQUIRE_LE(classificationError, classificationErrorThreshold); } @@ -183,7 +174,7 @@ arma::mat currentResuls; model.Forward(currentData, currentResuls); arma::mat gradients; - model.Backward(currentLabels, gradients); + model.Backward(currentData, currentLabels, gradients); #if ENS_VERSION_MAJOR == 1 opt.Update(model.Parameters(), stepSize, gradients); #else @@ -199,16 +190,7 @@ arma::max(currentResuls.col(i)) == currentResuls.col(i), 1)) + 1; } - size_t correct = 0; - for (size_t i = 0; i < currentLabels.n_cols; i++) - { - if (int(arma::as_scalar(prediction.col(i))) == - int(arma::as_scalar(currentLabels.col(i)))) - { - correct++; - } - } - + size_t correct = arma::accu(prediction == currentLabels); error(1 - (double) correct / batchSize); } Log::Debug << "Current training error: " << error.mean() << std::endl; @@ -318,7 +300,7 @@ Highway<>* highway = new Highway<>(10, true); highway->Add >(10, 10); highway->Add >(); - model.Add(highway); + model.Add(highway); // This takes ownership of the memory. model.Add >(10, 2); model.Add >(); TestNetwork<>(model, dataset, labels, dataset, labels, 10, 0.2); @@ -600,10 +582,8 @@ // Get the layer parameter from layer A and layer B and store them in // parameterA and parameterB. arma::mat parameterA, parameterB; - boost::apply_visitor(ParametersVisitor(std::move(parameterA)), - model.Model()[0]); - boost::apply_visitor(ParametersVisitor(std::move(parameterB)), - model.Model()[1]); + boost::apply_visitor(ParametersVisitor(parameterA), model.Model()[0]); + boost::apply_visitor(ParametersVisitor(parameterB), model.Model()[1]); CheckMatrices(parameterA, arma::ones(3 * 3 + 3, 1)); CheckMatrices(parameterB, arma::zeros(3 * 4 + 4, 1)); @@ -612,4 +592,33 @@ CheckMatrices(linearB->Parameters(), arma::zeros(3 * 4 + 4, 1)); } +/** + * Test to see if the FFN code compiles when the Optimizer + * doesn't have the MaxIterations() method. + */ +BOOST_AUTO_TEST_CASE(OptimizerTest) +{ + // Load the dataset. + arma::mat trainData; + data::Load("thyroid_train.csv", trainData, true); + + arma::mat trainLabels = trainData.row(trainData.n_rows - 1); + trainData.shed_row(trainData.n_rows - 1); + + arma::mat testData; + data::Load("thyroid_test.csv", testData, true); + + arma::mat testLabels = testData.row(testData.n_rows - 1); + testData.shed_row(testData.n_rows - 1); + + FFN, RandomInitialization, CustomLayer<> > model; + model.Add >(trainData.n_rows, 8); + model.Add >(); + model.Add >(8, 3); + model.Add >(); + + ens::DE opt(200, 1000, 0.6, 0.8, 1e-5); + model.Train(trainData, trainLabels, opt); +} + BOOST_AUTO_TEST_SUITE_END(); diff -Nru mlpack-3.2.2/src/mlpack/tests/image_load_test.cpp mlpack-3.3.0/src/mlpack/tests/image_load_test.cpp --- mlpack-3.2.2/src/mlpack/tests/image_load_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/image_load_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -12,6 +12,8 @@ #include #include +#include "test_tools.hpp" +#include "serialization.hpp" using namespace mlpack; using namespace mlpack::data; @@ -29,8 +31,10 @@ { arma::Mat matrix; data::ImageInfo info; + Log::Fatal.ignoreInput = true; BOOST_REQUIRE_THROW(data::Load("invalidExtendion.p4ng", matrix, info, - false, true), std::runtime_error); + true), std::runtime_error); + Log::Fatal.ignoreInput = false; } /** @@ -40,9 +44,12 @@ { arma::Mat matrix; data::ImageInfo info; - BOOST_REQUIRE(data::Load("test_image.png", matrix, info, false, - true) == true); - BOOST_REQUIRE_EQUAL(matrix.n_rows, 50 * 50 * 3); // width * height * channels. + BOOST_REQUIRE(data::Load("test_image.png", matrix, info, false) == true); + // width * height * channels. + BOOST_REQUIRE_EQUAL(matrix.n_rows, 50 * 50 * 3); + BOOST_REQUIRE_EQUAL(info.Height(), 50); + BOOST_REQUIRE_EQUAL(info.Width(), 50); + BOOST_REQUIRE_EQUAL(info.Channels(), 3); BOOST_REQUIRE_EQUAL(matrix.n_cols, 1); } @@ -56,15 +63,98 @@ arma::Mat im1; size_t dimension = info.Width() * info.Height() * info.Channels(); im1 = arma::randi>(dimension, 1); - BOOST_REQUIRE(data::Save("APITest.bmp", im1, info, false, true) == true); + BOOST_REQUIRE(data::Save("APITest.bmp", im1, info, false) == true); arma::Mat im2; - BOOST_REQUIRE(data::Load("APITest.bmp", im2, info, false, true) == true); + BOOST_REQUIRE(data::Load("APITest.bmp", im2, info, false) == true); BOOST_REQUIRE_EQUAL(im1.n_cols, im2.n_cols); BOOST_REQUIRE_EQUAL(im1.n_rows, im2.n_rows); - for (size_t i = 10; i < im1.n_elem; ++i) + for (size_t i = 0; i < im1.n_elem; ++i) BOOST_REQUIRE_EQUAL(im1[i], im2[i]); + remove("APITest.bmp"); +} + +/** + * Test if an image with a wrong dimesion throws an expected + * exception while saving. + */ +BOOST_AUTO_TEST_CASE(SaveImageWrongInfo) +{ + data::ImageInfo info(5, 5, 3, 90); + + arma::Mat im1; + size_t dimension = info.Width() * info.Height() * info.Channels(); + im1 = arma::randi>(24 * 25 * 7, 1); + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(data::Save("APITest.bmp", im1, info, false), + std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Test that the image is loaded correctly into the matrix using the API + * for vectors. + */ +BOOST_AUTO_TEST_CASE(LoadVectorImageAPITest) +{ + arma::Mat matrix; + data::ImageInfo info; + std::vector files = {"test_image.png", "test_image.png"}; + BOOST_REQUIRE(data::Load(files, matrix, info, false) == true); + // width * height * channels. + BOOST_REQUIRE_EQUAL(matrix.n_rows, 50 * 50 * 3); + BOOST_REQUIRE_EQUAL(info.Height(), 50); + BOOST_REQUIRE_EQUAL(info.Width(), 50); + BOOST_REQUIRE_EQUAL(info.Channels(), 3); + BOOST_REQUIRE_EQUAL(matrix.n_cols, 2); +} + +/** + * Test if the image is saved correctly using API for arma mat. + */ +BOOST_AUTO_TEST_CASE(SaveImageMatAPITest) +{ + data::ImageInfo info(5, 5, 3); + + arma::Mat im1; + size_t dimension = info.Width() * info.Height() * info.Channels(); + im1 = arma::randi>(dimension, 1); + arma::mat input = arma::conv_to::from(im1); + BOOST_REQUIRE(Save("APITest.bmp", input, info, false) == true); + + arma::mat output; + BOOST_REQUIRE(Load("APITest.bmp", output, info, false) == true); + + BOOST_REQUIRE_EQUAL(input.n_cols, output.n_cols); + BOOST_REQUIRE_EQUAL(input.n_rows, output.n_rows); + for (size_t i = 0; i < input.n_elem; ++i) + BOOST_REQUIRE_CLOSE(input[i], output[i], 1e-5); + remove("APITest.bmp"); +} + +/** + * Serialization test for the ImageInfo class. + */ +BOOST_AUTO_TEST_CASE(ImageInfoSerialization) +{ + data::ImageInfo info(5, 5, 3, 90); + data::ImageInfo xmlInfo, textInfo, binaryInfo; + + SerializeObjectAll(info, xmlInfo, textInfo, binaryInfo); + + BOOST_REQUIRE_EQUAL(info.Width(), xmlInfo.Width()); + BOOST_REQUIRE_EQUAL(info.Height(), xmlInfo.Height()); + BOOST_REQUIRE_EQUAL(info.Channels(), xmlInfo.Channels()); + BOOST_REQUIRE_EQUAL(info.Quality(), xmlInfo.Quality()); + BOOST_REQUIRE_EQUAL(info.Width(), textInfo.Width()); + BOOST_REQUIRE_EQUAL(info.Height(), textInfo.Height()); + BOOST_REQUIRE_EQUAL(info.Channels(), textInfo.Channels()); + BOOST_REQUIRE_EQUAL(info.Quality(), textInfo.Quality()); + BOOST_REQUIRE_EQUAL(info.Width(), binaryInfo.Width()); + BOOST_REQUIRE_EQUAL(info.Height(), binaryInfo.Height()); + BOOST_REQUIRE_EQUAL(info.Channels(), binaryInfo.Channels()); + BOOST_REQUIRE_EQUAL(info.Quality(), binaryInfo.Quality()); } BOOST_AUTO_TEST_SUITE_END(); diff -Nru mlpack-3.2.2/src/mlpack/tests/knn_test.cpp mlpack-3.3.0/src/mlpack/tests/knn_test.cpp --- mlpack-3.2.2/src/mlpack/tests/knn_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/knn_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -1358,6 +1358,34 @@ } /** + * Test the copy constructor and copy operator using the BinarySpaceTree. + */ +BOOST_AUTO_TEST_CASE(CopyConstructorAndOperatorBinarySpaceTreeTest) +{ + arma::mat dataset = arma::randu(5, 500); + typedef NeighborSearch NeighborSearchType; + NeighborSearchType knn(std::move(dataset)); + + // Copy constructor and operator. + NeighborSearchType knn2(knn); + NeighborSearchType knn3 = knn; + + // Get results. + arma::mat distances, distances2, distances3; + arma::Mat neighbors, neighbors2, neighbors3; + + knn.Search(3, neighbors, distances); + knn2.Search(3, neighbors2, distances2); + knn3.Search(3, neighbors3, distances3); + + CheckMatrices(neighbors, neighbors2); + CheckMatrices(neighbors, neighbors3); + CheckMatrices(distances, distances2); + CheckMatrices(distances, distances3); +} + +/** * Test the copy constructor and copy operator using the Spill Tree. */ BOOST_AUTO_TEST_CASE(CopyConstructorAndOperatorSpillTreeTest) @@ -1386,6 +1414,34 @@ } /** + * Test the copy constructor and copy operator using the Octree. + */ +BOOST_AUTO_TEST_CASE(CopyConstructorAndOperatorOctreeTest) +{ + arma::mat dataset = arma::randu(5, 500); + typedef NeighborSearch NeighborSearchType; + NeighborSearchType knn(std::move(dataset)); + + // Copy constructor and operator. + NeighborSearchType knn2(knn); + NeighborSearchType knn3 = knn; + + // Get results. + arma::mat distances, distances2, distances3; + arma::Mat neighbors, neighbors2, neighbors3; + + knn.Search(3, neighbors, distances); + knn2.Search(3, neighbors2, distances2); + knn3.Search(3, neighbors3, distances3); + + CheckMatrices(neighbors, neighbors2); + CheckMatrices(neighbors, neighbors3); + CheckMatrices(distances, distances2); + CheckMatrices(distances, distances3); +} + +/** * Test the move constructor. */ BOOST_AUTO_TEST_CASE(MoveConstructorTest) @@ -1411,7 +1467,7 @@ } /** - * Test the move constructor using R trees. + * Test the move constructor & move assignment using R trees. */ BOOST_AUTO_TEST_CASE(MoveConstructorRTreeTest) { @@ -1421,8 +1477,42 @@ NeighborSearchType* knn = new NeighborSearchType(std::move(dataset)); // Get predictions. - arma::mat distances, distances2; - arma::Mat neighbors, neighbors2; + arma::mat distances, distances2, distances3; + arma::Mat neighbors, neighbors2, neighbors3; + + knn->Search(3, neighbors, distances); + + // Use move constructor. + NeighborSearchType knn2(std::move(*knn)); + + delete knn; + + knn2.Search(3, neighbors2, distances2); + + // Use move assignment. + NeighborSearchType knn3 = std::move(knn2); + knn3.Search(3, neighbors3, distances3); + + CheckMatrices(neighbors, neighbors2); + CheckMatrices(neighbors, neighbors3); + CheckMatrices(distances, distances2); + CheckMatrices(distances, distances3); +} + + +/** + * Test the move constructor & move assignment using Binary Space trees. + */ +BOOST_AUTO_TEST_CASE(MoveConstructorBinarySpaceTreeTest) +{ + arma::mat dataset = arma::randu(5, 500); + typedef NeighborSearch NeighborSearchType; + NeighborSearchType* knn = new NeighborSearchType(std::move(dataset)); + + // Get predictions. + arma::mat distances, distances2, distances3; + arma::Mat neighbors, neighbors2, neighbors3; knn->Search(3, neighbors, distances); @@ -1433,10 +1523,48 @@ knn2.Search(3, neighbors2, distances2); + // Use move assignment. + NeighborSearchType knn3 = std::move(knn2); + knn3.Search(3, neighbors3, distances3); + CheckMatrices(neighbors, neighbors2); + CheckMatrices(neighbors, neighbors3); CheckMatrices(distances, distances2); + CheckMatrices(distances, distances3); } +/** + * Test the move constructor & move assignment using Octree. + */ +BOOST_AUTO_TEST_CASE(MoveConstructorOctreeTest) +{ + arma::mat dataset = arma::randu(5, 500); + typedef NeighborSearch NeighborSearchType; + NeighborSearchType* knn = new NeighborSearchType(std::move(dataset)); + + // Get predictions. + arma::mat distances, distances2, distances3; + arma::Mat neighbors, neighbors2, neighbors3; + + knn->Search(3, neighbors, distances); + + // Use move constructor. + NeighborSearchType knn2(std::move(*knn)); + + delete knn; + + knn2.Search(3, neighbors2, distances2); + + // Use move assignment. + NeighborSearchType knn3 = std::move(knn2); + knn3.Search(3, neighbors3, distances3); + + CheckMatrices(neighbors, neighbors2); + CheckMatrices(neighbors, neighbors3); + CheckMatrices(distances, distances2); + CheckMatrices(distances, distances3); +} /** * Test the move constructor & move assignment using Cover Tree. diff -Nru mlpack-3.2.2/src/mlpack/tests/lars_test.cpp mlpack-3.3.0/src/mlpack/tests/lars_test.cpp --- mlpack-3.2.2/src/mlpack/tests/lars_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/lars_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -353,7 +353,7 @@ } /** - * Test that LARS::Train() returns finite correlation value. + * Test that LARS::Train() returns finite error value. */ BOOST_AUTO_TEST_CASE(LARSTrainReturnCorrelation) { @@ -371,30 +371,54 @@ // Test with Cholesky decomposition and with lasso. LARS lars1(true, lambda1, 0.0); arma::vec betaOpt1; - double maxCorr = lars1.Train(X, y, betaOpt1); + double error = lars1.Train(X, y, betaOpt1); - BOOST_REQUIRE_EQUAL(std::isfinite(maxCorr), true); + BOOST_REQUIRE_EQUAL(std::isfinite(error), true); // Test without Cholesky decomposition and with lasso. LARS lars2(false, lambda1, 0.0); arma::vec betaOpt2; - maxCorr = lars2.Train(X, y, betaOpt2); + error = lars2.Train(X, y, betaOpt2); - BOOST_REQUIRE_EQUAL(std::isfinite(maxCorr), true); + BOOST_REQUIRE_EQUAL(std::isfinite(error), true); // Test with Cholesky decomposition and with elasticnet. LARS lars3(true, lambda1, lambda2); arma::vec betaOpt3; - maxCorr = lars3.Train(X, y, betaOpt3); + error = lars3.Train(X, y, betaOpt3); - BOOST_REQUIRE_EQUAL(std::isfinite(maxCorr), true); + BOOST_REQUIRE_EQUAL(std::isfinite(error), true); // Test without Cholesky decomposition and with elasticnet. LARS lars4(false, lambda1, lambda2); arma::vec betaOpt4; - maxCorr = lars4.Train(X, y, betaOpt4); + error = lars4.Train(X, y, betaOpt4); - BOOST_REQUIRE_EQUAL(std::isfinite(maxCorr), true); + BOOST_REQUIRE_EQUAL(std::isfinite(error), true); +} + +/** + * Test that LARS::ComputeError() returns error value less than 1 + * and greater than 0. + */ +BOOST_AUTO_TEST_CASE(LARSTestComputeError) +{ + arma::mat X; + arma::mat Y; + + data::Load("lars_dependent_x.csv", X); + data::Load("lars_dependent_y.csv", Y); + + arma::rowvec y = Y.row(0); + + LARS lars1(true, 0.1, 0.0); + arma::vec betaOpt1; + double train1 = lars1.Train(X, y, betaOpt1); + double cost = lars1.ComputeError(X, y); + + BOOST_REQUIRE_EQUAL(cost <= 1, true); + BOOST_REQUIRE_EQUAL(cost >= 0, true); + BOOST_REQUIRE_EQUAL(cost == train1, true); } BOOST_AUTO_TEST_SUITE_END(); diff -Nru mlpack-3.2.2/src/mlpack/tests/layer_names_test.cpp mlpack-3.3.0/src/mlpack/tests/layer_names_test.cpp --- mlpack-3.2.2/src/mlpack/tests/layer_names_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/layer_names_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -52,6 +52,14 @@ LayerTypes<> pReLU = new PReLU<>(); LayerTypes<> sigmoidLayer = new SigmoidLayer<>(); LayerTypes<> logSoftMax = new LogSoftMax<>(); + LayerTypes<> lstmLayer = new LSTM<>(100, 10); + LayerTypes<> creluLayer = new CReLU<>(); + LayerTypes<> highwayLayer = new Highway<>(); + LayerTypes<> gruLayer = new GRU<>(); + LayerTypes<> glimpseLayer = new Glimpse<>(); + LayerTypes<> fastlstmLayer = new FastLSTM<>(); + LayerTypes<> weightnormLayer = new WeightNorm<>(new IdentityLayer<>()); + // Bilinear interpolation is not yet supported by the string converter. LayerTypes<> unsupportedLayer = new BilinearInterpolation<>(); @@ -105,6 +113,20 @@ logSoftMax) == "logsoftmax"); BOOST_REQUIRE(boost::apply_visitor(LayerNameVisitor(), unsupportedLayer) == "unsupported"); + BOOST_REQUIRE(boost::apply_visitor(LayerNameVisitor(), + lstmLayer) == "lstm"); + BOOST_REQUIRE(boost::apply_visitor(LayerNameVisitor(), + creluLayer) == "crelu"); + BOOST_REQUIRE(boost::apply_visitor(LayerNameVisitor(), + highwayLayer) == "highway"); + BOOST_REQUIRE(boost::apply_visitor(LayerNameVisitor(), + gruLayer) == "gru"); + BOOST_REQUIRE(boost::apply_visitor(LayerNameVisitor(), + glimpseLayer) == "glimpse"); + BOOST_REQUIRE(boost::apply_visitor(LayerNameVisitor(), + fastlstmLayer) == "fastlstm"); + BOOST_REQUIRE(boost::apply_visitor(LayerNameVisitor(), + weightnormLayer) == "weightnorm"); // Delete all instances. boost::apply_visitor(DeleteVisitor(), atrousConvolution); boost::apply_visitor(DeleteVisitor(), alphaDropout); @@ -131,6 +153,13 @@ boost::apply_visitor(DeleteVisitor(), sigmoidLayer); boost::apply_visitor(DeleteVisitor(), logSoftMax); boost::apply_visitor(DeleteVisitor(), unsupportedLayer); + boost::apply_visitor(DeleteVisitor(), lstmLayer); + boost::apply_visitor(DeleteVisitor(), creluLayer); + boost::apply_visitor(DeleteVisitor(), highwayLayer); + boost::apply_visitor(DeleteVisitor(), gruLayer); + boost::apply_visitor(DeleteVisitor(), glimpseLayer); + boost::apply_visitor(DeleteVisitor(), fastlstmLayer); + boost::apply_visitor(DeleteVisitor(), weightnormLayer); } BOOST_AUTO_TEST_SUITE_END(); diff -Nru mlpack-3.2.2/src/mlpack/tests/lin_alg_test.cpp mlpack-3.3.0/src/mlpack/tests/lin_alg_test.cpp --- mlpack-3.2.2/src/mlpack/tests/lin_alg_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/lin_alg_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -78,37 +78,6 @@ BOOST_REQUIRE_CLOSE(tmp_out(row, col), (double) (col - 2.5) * row, 1e-5); } -BOOST_AUTO_TEST_CASE(TestWhitenUsingEig) -{ - // After whitening using eigendecomposition, the covariance of - // our matrix will be I (or something very close to that). - // We are loading a matrix from an external file... bad choice. - mat tmp, tmp_centered, whitened, whitening_matrix; - - data::Load("trainSet.csv", tmp); - Center(tmp, tmp_centered); - WhitenUsingEig(tmp_centered, whitened, whitening_matrix); - - mat newcov = mlpack::math::ColumnCovariance(whitened); - for (int row = 0; row < 5; row++) - { - for (int col = 0; col < 5; col++) - { - if (row == col) - { - // diagonal will be 0 in the case of any zero-valued eigenvalues - // (rank-deficient covariance case) - if (std::abs(newcov(row, col)) > 1e-10) - BOOST_REQUIRE_CLOSE(newcov(row, col), 1.0, 1e-10); - } - else - { - BOOST_REQUIRE_SMALL(newcov(row, col), 1e-10); - } - } - } -} - BOOST_AUTO_TEST_CASE(TestOrthogonalize) { // Generate a random matrix; then, orthogonalize it and test if it's diff -Nru mlpack-3.2.2/src/mlpack/tests/logistic_regression_test.cpp mlpack-3.3.0/src/mlpack/tests/logistic_regression_test.cpp --- mlpack-3.2.2/src/mlpack/tests/logistic_regression_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/logistic_regression_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -1002,4 +1002,25 @@ BOOST_REQUIRE_EQUAL(std::isfinite(objVal), true); } +/** + * Test that construction *then* training works fine. Thanks @Trento89 for the + * test case (see #2358). + */ +BOOST_AUTO_TEST_CASE(ConstructionThenTraining) +{ + arma::mat myMatrix; + + // Four points, three dimensions. + myMatrix << 0.555950 << 0.274690 << 0.540605 << 0.798938 << arma::endr + << 0.948014 << 0.973234 << 0.216504 << 0.883152 << arma::endr + << 0.023787 << 0.675382 << 0.231751 << 0.450332 << arma::endr; + + arma::Row myTargets("1 0 1 0"); + + regression::LogisticRegression<> lr; + + // Make sure that training doesn't crash with invalid parameter sizes. + BOOST_REQUIRE_NO_THROW(lr.Train(myMatrix, myTargets)); +} + BOOST_AUTO_TEST_SUITE_END(); diff -Nru mlpack-3.2.2/src/mlpack/tests/loss_functions_test.cpp mlpack-3.3.0/src/mlpack/tests/loss_functions_test.cpp --- mlpack-3.2.2/src/mlpack/tests/loss_functions_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/loss_functions_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -3,6 +3,7 @@ * @author Dakshit Agrawal * @author Sourabh Varshney * @author Atharva Khandait + * @author Saksham Rastogi * * Tests for loss functions in mlpack::methods::ann:loss_functions. * @@ -14,13 +15,20 @@ #include #include +#include #include #include #include #include #include #include +#include +#include +#include #include +#include +#include +#include #include #include @@ -34,6 +42,33 @@ BOOST_AUTO_TEST_SUITE(LossFunctionsTest); /** + * Simple Huber Loss test. + */ +BOOST_AUTO_TEST_CASE(HuberLossTest) +{ + arma::mat input, target, output; + HuberLoss<> module; + + // Test the Forward function. + input = arma::mat("17.45 12.91 13.63 29.01 7.12 15.47 31.52 31.97"); + target = arma::mat("16.52 13.11 13.67 29.51 24.31 15.03 30.72 34.07"); + double loss = module.Forward(input, target); + BOOST_REQUIRE_CLOSE_FRACTION(loss, 2.410631, 0.00001); + + // Test the backward function. + module.Backward(input, target, output); + + // Expected Output: + // [0.1162 -0.0250 -0.0050 -0.0625 -0.1250 0.0550 0.1000 -0.1250] + // Sum of Expected Output = -0.07125. + double expectedOutputSum = arma::accu(output); + BOOST_REQUIRE_CLOSE_FRACTION(expectedOutputSum, -0.07125, 0.00001); + + BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows); + BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols); +} + +/** * Simple KL Divergence test. The loss should be zero if input = target. */ BOOST_AUTO_TEST_CASE(SimpleKLDivergenceTest) @@ -45,10 +80,44 @@ // Test the Forward function. Loss should be 0 if input = target. input = arma::ones(10, 1); target = arma::ones(10, 1); - loss = module.Forward(std::move(input), std::move(target)); + loss = module.Forward(input, target); BOOST_REQUIRE_SMALL(loss, 0.00001); } +/* + * Simple test for the mean squared logarithmic error function. + */ +BOOST_AUTO_TEST_CASE(SimpleMeanSquaredLogarithmicErrorTest) +{ + arma::mat input, output, target; + MeanSquaredLogarithmicError<> module; + + // Test the Forward function on a user generator input and compare it against + // the manually calculated result. + input = arma::zeros(1, 8); + target = arma::zeros(1, 8); + double error = module.Forward(input, target); + BOOST_REQUIRE_SMALL(error, 0.00001); + + // Test the Backward function. + module.Backward(input, target, output); + // The output should be equal to 0. + CheckMatrices(input, output); + BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows); + BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols); + + // Test the error function on a single input. + input = arma::mat("2"); + target = arma::mat("3"); + error = module.Forward(input, target); + BOOST_REQUIRE_CLOSE(error, 0.082760974810151655, 0.001); + + // Test the Backward function on a single input. + module.Backward(input, target, output); + BOOST_REQUIRE_CLOSE(arma::accu(output), -0.1917880483011872, 0.001); + BOOST_REQUIRE_EQUAL(output.n_elem, 1); +} + /** * Test to check KL Divergence loss function when we take mean. */ @@ -62,11 +131,11 @@ input = arma::mat("1 1 1 1 1 1 1 1 1 1"); target = arma::exp(arma::mat("2 1 1 1 1 1 1 1 1 1")); - loss = module.Forward(std::move(input), std::move(target)); + loss = module.Forward(input, target); BOOST_REQUIRE_CLOSE_FRACTION(loss, -1.1 , 0.00001); // Test the Backward function. - module.Backward(std::move(input), std::move(target), std::move(output)); + module.Backward(input, target, output); BOOST_REQUIRE_CLOSE_FRACTION(arma::as_scalar(output), -0.1, 0.00001); } @@ -83,11 +152,11 @@ input = arma::mat("1 1 1 1 1 1 1 1 1 1"); target = arma::exp(arma::mat("2 1 1 1 1 1 1 1 1 1")); - loss = module.Forward(std::move(input), std::move(target)); + loss = module.Forward(input, target); BOOST_REQUIRE_CLOSE_FRACTION(loss, -11, 0.00001); // Test the Backward function. - module.Backward(std::move(input), std::move(target), std::move(output)); + module.Backward(input, target, output); BOOST_REQUIRE_CLOSE_FRACTION(arma::as_scalar(output), -1, 0.00001); } @@ -103,11 +172,11 @@ // the manually calculated result. input = arma::mat("1.0 0.0 1.0 0.0 -1.0 0.0 -1.0 0.0"); target = arma::zeros(1, 8); - double error = module.Forward(std::move(input), std::move(target)); + double error = module.Forward(input, target); BOOST_REQUIRE_EQUAL(error, 0.5); // Test the Backward function. - module.Backward(std::move(input), std::move(target), std::move(output)); + module.Backward(input, target, output); // We subtract a zero vector, so according to the used backward formula: // output = 2 * (input - target) / target.n_cols, // output * nofColumns / 2 should be equal to input. @@ -118,11 +187,11 @@ // Test the error function on a single input. input = arma::mat("2"); target = arma::mat("3"); - error = module.Forward(std::move(input), std::move(target)); + error = module.Forward(input, target); BOOST_REQUIRE_EQUAL(error, 1.0); // Test the Backward function on a single input. - module.Backward(std::move(input), std::move(target), std::move(output)); + module.Backward(input, target, output); // Test whether the output is negative. BOOST_REQUIRE_EQUAL(arma::accu(output), -2); BOOST_REQUIRE_EQUAL(output.n_elem, 1); @@ -140,16 +209,16 @@ // the manually calculated result. input1 = arma::mat("0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5"); target1 = arma::zeros(1, 8); - double error1 = module.Forward(std::move(input1), std::move(target1)); + double error1 = module.Forward(input1, target1); BOOST_REQUIRE_SMALL(error1 - 8 * std::log(2), 2e-5); input2 = arma::mat("0 1 1 0 1 0 0 1"); target2 = arma::mat("0 1 1 0 1 0 0 1"); - double error2 = module.Forward(std::move(input2), std::move(target2)); + double error2 = module.Forward(input2, target2); BOOST_REQUIRE_SMALL(error2, 1e-5); // Test the Backward function. - module.Backward(std::move(input1), std::move(target1), std::move(output)); + module.Backward(input1, target1, output); for (double el : output) { // For the 0.5 constant vector we should get 1 / (1 - 0.5) = 2 everywhere. @@ -158,7 +227,7 @@ BOOST_REQUIRE_EQUAL(output.n_rows, input1.n_rows); BOOST_REQUIRE_EQUAL(output.n_cols, input1.n_cols); - module.Backward(std::move(input2), std::move(target2), std::move(output)); + module.Backward(input2, target2, output); for (size_t i = 0; i < 8; ++i) { double el = output.at(0, i); @@ -184,25 +253,25 @@ // the calculated result. input1 = arma::mat("0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5"); target1 = arma::zeros(1, 8); - double error1 = module.Forward(std::move(input1), std::move(target1)); + double error1 = module.Forward(input1, target1); double expected = 0.97407699; // Value computed using tensorflow. BOOST_REQUIRE_SMALL(error1 / input1.n_elem - expected, 1e-7); input2 = arma::mat("1 2 3 4 5"); target2 = arma::mat("0 0 1 0 1"); - double error2 = module.Forward(std::move(input2), std::move(target2)); + double error2 = module.Forward(input2, target2); expected = 1.5027283; BOOST_REQUIRE_SMALL(error2 / input2.n_elem - expected, 1e-6); input3 = arma::mat("0 -1 -1 0 -1 0 0 -1"); target3 = arma::mat("0 -1 -1 0 -1 0 0 -1"); - double error3 = module.Forward(std::move(input3), std::move(target3)); + double error3 = module.Forward(input3, target3); expected = 0.00320443; BOOST_REQUIRE_SMALL(error3 / input3.n_elem - expected, 1e-6); // Test the Backward function. - module.Backward(std::move(input1), std::move(target1), std::move(output)); + module.Backward(input1, target1, output); expected = 0.62245929; for (size_t i = 0; i < output.n_elem; i++) BOOST_REQUIRE_SMALL(output(i) - expected, 1e-5); @@ -211,13 +280,13 @@ expectedOutput = arma::mat( "0.7310586 0.88079709 -0.04742587 0.98201376 -0.00669285"); - module.Backward(std::move(input2), std::move(target2), std::move(output)); + module.Backward(input2, target2, output); for (size_t i = 0; i < output.n_elem; i++) BOOST_REQUIRE_SMALL(output(i) - expectedOutput(i), 1e-5); BOOST_REQUIRE_EQUAL(output.n_rows, input2.n_rows); BOOST_REQUIRE_EQUAL(output.n_cols, input2.n_cols); - module.Backward(std::move(input3), std::move(target3), std::move(output)); + module.Backward(input3, target3, output); expectedOutput = arma::mat("0.5 1.2689414"); for (size_t i = 0; i < 8; ++i) { @@ -243,18 +312,18 @@ // the manually calculated result. input1 = arma::mat("0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5"); target1 = arma::zeros(1, 8); - double error1 = module.Forward(std::move(input1), std::move(target1)); + double error1 = module.Forward(input1, target1); double expected = 0.0; BOOST_REQUIRE_SMALL(error1 / input1.n_elem - expected, 1e-7); input2 = arma::mat("1 2 3 4 5"); target2 = arma::mat("1 0 1 0 1"); - double error2 = module.Forward(std::move(input2), std::move(target2)); + double error2 = module.Forward(input2, target2); expected = -1.8; BOOST_REQUIRE_SMALL(error2 / input2.n_elem - expected, 1e-6); // Test the Backward function. - module.Backward(std::move(input1), std::move(target1), std::move(output)); + module.Backward(input1, target1, output); expected = 0.0; for (size_t i = 0; i < output.n_elem; i++) BOOST_REQUIRE_SMALL(output(i) - expected, 1e-5); @@ -262,7 +331,7 @@ BOOST_REQUIRE_EQUAL(output.n_cols, input1.n_cols); expectedOutput = arma::mat("-1 0 -1 0 -1"); - module.Backward(std::move(input2), std::move(target2), std::move(output)); + module.Backward(input2, target2, output); for (size_t i = 0; i < output.n_elem; i++) BOOST_REQUIRE_SMALL(output(i) - expectedOutput(i), 1e-5); BOOST_REQUIRE_EQUAL(output.n_rows, input2.n_rows); @@ -367,16 +436,16 @@ // Test the Forward function. Loss should be 0 if input = target. input1 = arma::ones(10, 1); target = arma::ones(10, 1); - loss = module.Forward(std::move(input1), std::move(target)); + loss = module.Forward(input1, target); BOOST_REQUIRE_SMALL(loss, 0.00001); // Test the Forward function. Loss should be 0.185185185. input2 = arma::ones(10, 1) * 0.5; - loss = module.Forward(std::move(input2), std::move(target)); + loss = module.Forward(input2, target); BOOST_REQUIRE_CLOSE(loss, 0.185185185, 0.00001); // Test the Backward function for input = target. - module.Backward(std::move(input1), std::move(target), std::move(output)); + module.Backward(input1, target, output); for (double el : output) { // For input = target we should get 0.0 everywhere. @@ -386,7 +455,7 @@ BOOST_REQUIRE_EQUAL(output.n_cols, input1.n_cols); // Test the Backward function. - module.Backward(std::move(input2), std::move(target), std::move(output)); + module.Backward(input2, target, output); for (double el : output) { // For the 0.5 constant vector we should get -0.0877914951989026 everywhere. @@ -396,4 +465,250 @@ BOOST_REQUIRE_EQUAL(output.n_cols, input2.n_cols); } +/* + * Simple test for the mean bias error performance function. + */ +BOOST_AUTO_TEST_CASE(SimpleMeanBiasErrorTest) +{ + arma::mat input, output, target; + MeanBiasError<> module; + + // Test the Forward function on a user generator input and compare it against + // the manually calculated result. + input = arma::mat("1.0 0.0 1.0 -1.0 -1.0 0.0 -1.0 0.0"); + target = arma::zeros(1, 8); + double error = module.Forward(input, target); + BOOST_REQUIRE_EQUAL(error, 0.125); + + // Test the Backward function. + module.Backward(input, target, output); + // We should get a vector with -1 everywhere. + for (double el : output) + { + BOOST_REQUIRE_EQUAL(el, -1); + } + BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows); + BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols); + + // Test the error function on a single input. + input = arma::mat("2"); + target = arma::mat("3"); + error = module.Forward(input, target); + BOOST_REQUIRE_EQUAL(error, 1.0); + + // Test the Backward function on a single input. + module.Backward(input, target, output); + // Test whether the output is negative. + BOOST_REQUIRE_EQUAL(arma::accu(output), -1); + BOOST_REQUIRE_EQUAL(output.n_elem, 1); +} + +/** + * Simple test for the Log-Hyperbolic-Cosine loss function. + */ +BOOST_AUTO_TEST_CASE(LogCoshLossTest) +{ + arma::mat input, target, output; + double loss; + LogCoshLoss<> module(2); + + // Test the Forward function. Loss should be 0 if input = target. + input = arma::ones(10, 1); + target = arma::ones(10, 1); + loss = module.Forward(input, target); + BOOST_REQUIRE_EQUAL(loss, 0); + + // Test the Backward function for input = target. + module.Backward(input, target, output); + for (double el : output) + { + // For input = target we should get 0.0 everywhere. + BOOST_REQUIRE_CLOSE(el, 0.0, 1e-5); + } + + BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows); + BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols); + + // Test the Forward function. Loss should be 0.546621. + input = arma::mat("1 2 3 4 5"); + target = arma::mat("1 2.4 3.4 4.2 5.5"); + loss = module.Forward(input, target); + BOOST_REQUIRE_CLOSE(loss, 0.546621, 1e-3); + + // Test the Backward function. + module.Backward(input, target, output); + BOOST_REQUIRE_CLOSE(arma::accu(output), 2.46962, 1e-3); + BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows); + BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols); +} + +/** + * Simple test for the Hinge Embedding loss function. + */ +BOOST_AUTO_TEST_CASE(HingeEmbeddingLossTest) +{ + arma::mat input, target, output; + double loss; + HingeEmbeddingLoss<> module; + + // Test the Forward function. Loss should be 0 if input = target. + input = arma::ones(10, 1); + target = arma::ones(10, 1); + loss = module.Forward(input, target); + BOOST_REQUIRE_EQUAL(loss, 0); + + // Test the Backward function for input = target. + module.Backward(input, target, output); + for (double el : output) + { + // For input = target we should get 0.0 everywhere. + BOOST_REQUIRE_CLOSE(el, 0.0, 1e-5); + } + + BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows); + BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols); + + // Test the Forward function. Loss should be 0.84. + input = arma::mat("0.1 0.8 0.6 0.0 0.5"); + target = arma::mat("0 1.0 1.0 0 0"); + loss = module.Forward(input, target); + BOOST_REQUIRE_CLOSE(loss, 0.84, 1e-3); + + // Test the Backward function. + module.Backward(input, target, output); + BOOST_REQUIRE_CLOSE(arma::accu(output), -2, 1e-3); + BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows); + BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols); +} + +/** + * Simple test for the Cosine Embedding loss function. + */ +BOOST_AUTO_TEST_CASE(CosineEmbeddingLossTest) +{ + arma::mat input1, input2, y, output; + double loss; + CosineEmbeddingLoss<> module; + + // Test the Forward function. Loss should be 0 if input1 = input2 and y = 1. + input1 = arma::mat(1, 10); + input2 = arma::mat(1, 10); + input1.ones(); + input2.ones(); + y = arma::mat(1, 1); + y.ones(); + loss = module.Forward(input1, input1); + BOOST_REQUIRE_SMALL(loss, 1e-6); + + // Test the Backward function. + module.Backward(input1, input1, output); + BOOST_REQUIRE_SMALL(arma::accu(output), 1e-6); + + // Check for dissimilarity. + module.Similarity() = false; + loss = module.Forward(input1, input1); + BOOST_REQUIRE_CLOSE(loss, 1.0, 1e-4); + + // Test the Backward function. + module.Backward(input1, input1, output); + BOOST_REQUIRE_SMALL(arma::accu(output), 1e-6); + + input1 = arma::mat(3, 2); + input2 = arma::mat(3, 2); + input1.fill(1); + input1(4) = 2; + input2.fill(1); + input2(0) = 2; + input2(1) = 2; + input2(2) = 2; + loss = module.Forward(input1, input2); + // Calculated using torch.nn.CosineEmbeddingLoss(). + BOOST_REQUIRE_CLOSE(loss, 2.897367, 1e-3); + + // Test the Backward function. + module.Backward(input1, input2, output); + BOOST_REQUIRE_CLOSE(arma::accu(output), 0.06324556, 1e-3); + + // Check for correctness for cube. + CosineEmbeddingLoss<> module2(0.5, true); + + arma::cube input3(3, 2, 2); + arma::cube input4(3, 2, 2); + input3.fill(1); + input4.fill(1); + input3(0) = 2; + input3(1) = 2; + input3(4) = 2; + input3(6) = 2; + input3(8) = 2; + input3(10) = 2; + input4(2) = 2; + input4(9) = 2; + input4(11) = 2; + loss = module2.Forward(input3, input4); + // Calculated using torch.nn.CosineEmbeddingLoss(). + BOOST_REQUIRE_CLOSE(loss, 0.55395, 1e-3); + + // Test the Backward function. + module2.Backward(input3, input4, output); + BOOST_REQUIRE_CLOSE(arma::accu(output), -0.36649111, 1e-3); + + // Check Output for mean type of reduction. + CosineEmbeddingLoss<> module3(0.0, true, true); + loss = module3.Forward(input3, input4); + BOOST_REQUIRE_CLOSE(loss, 0.092325, 1e-3); + + // Check correctness for cube. + module3.Similarity() = false; + loss = module3.Forward(input3, input4); + BOOST_REQUIRE_CLOSE(loss, 0.90767498236, 1e-3); + + // Test the Backward function. + module3.Backward(input3, input4, output); + BOOST_REQUIRE_CLOSE(arma::accu(output), 0.36649111, 1e-4); +} + +/* + * Simple test for the Margin Ranking Loss function. + */ +BOOST_AUTO_TEST_CASE(MarginRankingLossTest) +{ + arma::mat input, input1, input2, target, output; + MarginRankingLoss<> module; + + // Test the Forward function on a user generator input and compare it against + // the manually calculated result. + input1 = arma::mat("1 2 5 7 -1 -3"); + input2 = arma::mat("-1 3 -4 11 3 -3"); + input = arma::join_cols(input1, input2); + target = arma::mat("1 -1 -1 1 -1 1"); + double error = module.Forward(input, target); + // Computed using torch.nn.functional.margin_ranking_loss() + BOOST_REQUIRE_CLOSE(error, 2.66667, 1e-3); + + // Test the Backward function. + module.Backward(input, target, output); + + CheckMatrices(output, arma::mat("-0.000000 0.166667 -1.500000 0.666667 " + "0.000000 -0.000000"), 1e-3); + BOOST_REQUIRE_EQUAL(output.n_rows, target.n_rows); + BOOST_REQUIRE_EQUAL(output.n_cols, target.n_cols); + + // Test the error function on another input. + input1 = arma::mat("0.4287 -1.6208 -1.5006 -0.4473 1.5208 -4.5184 9.3574 " + "-4.8090 4.3455 5.2070"); + input2 = arma::mat("-4.5288 -9.2766 -0.5882 -5.6643 -6.0175 8.8506 3.4759 " + "-9.4886 2.2755 8.4951"); + input = arma::join_cols(input1, input2); + target = arma::mat("1 1 -1 1 -1 1 1 1 -1 1"); + error = module.Forward(input, target); + BOOST_REQUIRE_CLOSE(error, 3.03530, 1e-3); + + // Test the Backward function on the second input. + module.Backward(input, target, output); + + CheckMatrices(output, arma::mat("0.000000 0.000000 0.091240 0.000000 " + "-0.753830 1.336900 0.000000 0.000000 -0.207000 0.328810"), 1e-6); +} + BOOST_AUTO_TEST_SUITE_END(); diff -Nru mlpack-3.2.2/src/mlpack/tests/main_tests/adaboost_test.cpp mlpack-3.3.0/src/mlpack/tests/main_tests/adaboost_test.cpp --- mlpack-3.2.2/src/mlpack/tests/main_tests/adaboost_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/main_tests/adaboost_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -77,6 +77,43 @@ } /** + * Check that total number of rows of probabilities matrix is equal to total + * number of rows of input data and that each column of probabilities matrix sums + * up to 1. + */ +BOOST_AUTO_TEST_CASE(AdaBoostProbabilitiesTest) +{ + arma::mat trainData; + if (!data::Load("vc2.csv", trainData)) + BOOST_FAIL("Unable to load train dataset vc2.csv!"); + + arma::Row labels; + if (!data::Load("vc2_labels.txt", labels)) + BOOST_FAIL("Unable to load label dataset vc2_labels.txt!"); + + arma::mat testData; + if (!data::Load("vc2_test.csv", testData)) + BOOST_FAIL("Unable to load test dataset vc2.csv!"); + + size_t testSize = testData.n_cols; + + SetInputParam("training", std::move(trainData)); + SetInputParam("labels", std::move(labels)); + + SetInputParam("test", std::move(testData)); + + mlpackMain(); + + arma::mat probabilities; + probabilities = std::move(CLI::GetParam("probabilities")); + + BOOST_REQUIRE_EQUAL(probabilities.n_cols, testSize); + + for (size_t i = 0; i < testSize; i++) + BOOST_REQUIRE_CLOSE(arma::accu(probabilities.col(i)), 1, 1e-5); +} + +/** * Ensure that saved model can be used again. */ BOOST_AUTO_TEST_CASE(AdaBoostModelReuseTest) diff -Nru mlpack-3.2.2/src/mlpack/tests/main_tests/cf_test.cpp mlpack-3.3.0/src/mlpack/tests/main_tests/cf_test.cpp --- mlpack-3.2.2/src/mlpack/tests/main_tests/cf_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/main_tests/cf_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -616,4 +616,102 @@ BOOST_REQUIRE(arma::any(arma::vectorise(output1 != output3))); } +/** + * Ensure normalization algorithm is one of { "none", "z_score", + * "item_mean", "user_mean" }. + */ +BOOST_AUTO_TEST_CASE(CFNormalizationBoundTest) +{ + mat dataset; + data::Load("GroupLensSmall.csv", dataset); + + const int querySize = 7; + Mat query = arma::linspace>(0, querySize - 1, querySize); + + SetInputParam("neighbor_search", std::string("cosine")); + SetInputParam("algorithm", std::string("NMF")); + + // Normalization algorithm should be valid. + SetInputParam("normalization", std::string("invalid_normalization")); + SetInputParam("training", std::move(dataset)); + SetInputParam("query", query); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Ensure that using normalization techniques make difference. + */ +BOOST_AUTO_TEST_CASE(CFNormalizationTest) +{ + mat dataset; + data::Load("GroupLensSmall.csv", dataset); + + const int querySize = 7; + Mat query = arma::linspace>(0, querySize - 1, querySize); + + // Query with different normalization techniques. + ResetSettings(); + + SetInputParam("training", dataset); + SetInputParam("max_iterations", int(10)); + SetInputParam("query", query); + SetInputParam("algorithm", std::string("NMF")); + + // Using without Normalization. + SetInputParam("normalization", std::string("none")); + SetInputParam("recommendations", 5); + + mlpackMain(); + + const arma::Mat output1 = CLI::GetParam>("output"); + + BOOST_REQUIRE_EQUAL(output1.n_rows, 5); + BOOST_REQUIRE_EQUAL(output1.n_cols, 7); + + // Query with different normalization techniques. + ResetSettings(); + + SetInputParam("training", dataset); + SetInputParam("max_iterations", int(10)); + SetInputParam("query", query); + SetInputParam("algorithm", std::string("NMF")); + + // Using Item Mean normalization. + SetInputParam("normalization", std::string("item_mean")); + SetInputParam("recommendations", 5); + + mlpackMain(); + + const arma::Mat output2 = CLI::GetParam>("output"); + + BOOST_REQUIRE_EQUAL(output2.n_rows, 5); + BOOST_REQUIRE_EQUAL(output2.n_cols, 7); + + // Query with different normalization techniques. + ResetSettings(); + + SetInputParam("training", dataset); + SetInputParam("max_iterations", int(10)); + SetInputParam("query", query); + SetInputParam("algorithm", std::string("NMF")); + + // Using Z-Score normalization. + SetInputParam("normalization", std::string("z_score")); + SetInputParam("recommendations", 5); + + mlpackMain(); + + const arma::Mat output3 = CLI::GetParam>("output"); + + BOOST_REQUIRE_EQUAL(output3.n_rows, 5); + BOOST_REQUIRE_EQUAL(output3.n_cols, 7); + + // The resulting matrices should be different. + BOOST_REQUIRE(arma::any(arma::vectorise(output1 != output2))); + BOOST_REQUIRE(arma::any(arma::vectorise(output1 != output3))); +} + BOOST_AUTO_TEST_SUITE_END(); diff -Nru mlpack-3.2.2/src/mlpack/tests/main_tests/fastmks_test.cpp mlpack-3.3.0/src/mlpack/tests/main_tests/fastmks_test.cpp --- mlpack-3.2.2/src/mlpack/tests/main_tests/fastmks_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/main_tests/fastmks_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -397,7 +397,7 @@ SetInputParam("base", 0.0); // Invalid. Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::invalid_argument); + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; } @@ -464,6 +464,9 @@ CLI::GetSingleton().Parameters()["reference"].wasPassed = false; CLI::GetSingleton().Parameters()["query"].wasPassed = false; CLI::GetSingleton().Parameters()["kernel"].wasPassed = false; + + if (i != nofkerneltypes - 1) + bindings::tests::CleanMemory(); } } diff -Nru mlpack-3.2.2/src/mlpack/tests/main_tests/gmm_train_test.cpp mlpack-3.3.0/src/mlpack/tests/main_tests/gmm_train_test.cpp --- mlpack-3.2.2/src/mlpack/tests/main_tests/gmm_train_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/main_tests/gmm_train_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -249,6 +249,8 @@ GMM* gmm1 = CLI::GetParam("output_model"); BOOST_REQUIRE(CheckDifferent(gmm, gmm1)); + + delete gmm; } // Ensure that Trials affects the final result. @@ -273,7 +275,7 @@ mlpackMain(); - GMM* gmm = std::move(CLI::GetParam("output_model")); + GMM* gmm = CLI::GetParam("output_model"); ResetGmmTrainSetting(); @@ -290,10 +292,12 @@ GMM* gmm1 = CLI::GetParam("output_model"); success = CheckDifferent(gmm, gmm1); + + delete gmm; + if (success) break; - delete gmm; bindings::tests::CleanMemory(); } @@ -332,6 +336,8 @@ GMM* gmm1 = CLI::GetParam("output_model"); BOOST_REQUIRE(CheckDifferent(gmm, gmm1)); + + delete gmm; } // Ensure that the maximum number of k-means iterations affects the result. @@ -375,10 +381,13 @@ ResetGmmTrainSetting(); success = CheckDifferent(gmm, gmm1); + + delete gmm; + delete gmm1; + if (success) break; - delete gmm; bindings::tests::CleanMemory(); } @@ -419,6 +428,8 @@ GMM* gmm1 = CLI::GetParam("output_model"); BOOST_REQUIRE(CheckDifferent(gmm, gmm1)); + + delete gmm; } // Ensure that Sampling affects the final result when refined_start is true. @@ -455,6 +466,8 @@ GMM* gmm1 = CLI::GetParam("output_model"); BOOST_REQUIRE(CheckDifferent(gmm, gmm1)); + + delete gmm; } // Ensure that tolerance affects the final result. @@ -487,6 +500,8 @@ GMM* gmm1 = CLI::GetParam("output_model"); BOOST_REQUIRE(CheckDifferent(gmm, gmm1)); + + delete gmm; } // Ensure that saved model can be used again. diff -Nru mlpack-3.2.2/src/mlpack/tests/main_tests/image_converter_test.cpp mlpack-3.3.0/src/mlpack/tests/main_tests/image_converter_test.cpp --- mlpack-3.2.2/src/mlpack/tests/main_tests/image_converter_test.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/main_tests/image_converter_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,185 @@ +/** + * @file image_converter_test.cpp + * @author Jeffin Sam + * + * Test mlpackMain() of load_save_image_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. + */ +#define BINDING_TYPE BINDING_TYPE_TEST + +#include +static const std::string testName = "ImageConverter"; + +#include +#include + +#include "test_helper.hpp" +#include +#include "../test_tools.hpp" + +using namespace mlpack; + +struct ImageConverterTestFixture +{ + public: + ImageConverterTestFixture() + { + // Cache in the options for this program. + CLI::RestoreSettings(testName); + } + + ~ImageConverterTestFixture() + { + // Clear the settings. + remove("test_image777.png"); + remove("test_image999.png"); + bindings::tests::CleanMemory(); + CLI::ClearSettings(); + } +}; + +BOOST_FIXTURE_TEST_SUITE(ImageConverterMainTest, + ImageConverterTestFixture); + +BOOST_AUTO_TEST_CASE(LoadImageTest) +{ + SetInputParam>("input", {"test_image.png", "test_image.png"}); + + mlpackMain(); + arma::mat output = CLI::GetParam("output"); + // width * height * channels. + BOOST_REQUIRE_EQUAL(output.n_rows, 50 * 50 * 3); + BOOST_REQUIRE_EQUAL(output.n_cols, 2); +} + +BOOST_AUTO_TEST_CASE(SaveImageTest) +{ + arma::mat testimage = arma::conv_to::from( + arma::randi>((5 * 5 * 3), 2)); + SetInputParam>("input", {"test_image777.png", + "test_image999.png"}); + SetInputParam("height", 5); + SetInputParam("width", 5); + SetInputParam("channels", 3); + SetInputParam("save", true); + SetInputParam("dataset", testimage); + mlpackMain(); + + CLI::ClearSettings(); + CLI::RestoreSettings(testName); + + SetInputParam>("input", {"test_image777.png", + "test_image999.png"}); + SetInputParam("height", 5); + SetInputParam("width", 5); + SetInputParam("channels", 3); + + mlpackMain(); + arma::mat output = CLI::GetParam("output"); + BOOST_REQUIRE_EQUAL(output.n_rows, 5 * 5 * 3); + BOOST_REQUIRE_EQUAL(output.n_cols, 2); + for (size_t i = 0; i < output.n_elem; ++i) + BOOST_REQUIRE_CLOSE(testimage[i], output[i], 1e-5); +} + +/** + * Check whether binding throws error if height, width or channel are not + * specified. + */ +BOOST_AUTO_TEST_CASE(IncompleteTest) +{ + arma::mat testimage = arma::conv_to::from( + arma::randi>((5 * 5 * 3), 2)); + SetInputParam>("input", {"test_image777.png", + "test_image999.png"}); + SetInputParam("save", true); + SetInputParam("height", 50); + SetInputParam("width", 50); + SetInputParam("dataset", testimage); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Check for invalid height values. + */ +BOOST_AUTO_TEST_CASE(InvalidInputTest) +{ + arma::mat testimage = arma::conv_to::from( + arma::randi>((5 * 5 * 3), 2)); + SetInputParam>("input", {"test_image777.png", + "test_image999.png"}); + SetInputParam("save", true); + SetInputParam("dataset", testimage); + + SetInputParam("height", -50); + SetInputParam("width", 50); + SetInputParam("channels", 3); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Check for invalid width values. + */ +BOOST_AUTO_TEST_CASE(InvalidWidthTest) +{ + arma::mat testimage = arma::conv_to::from( + arma::randi>((5 * 5 * 3), 2)); + SetInputParam>("input", {"test_image777.png", + "test_image999.png"}); + SetInputParam("save", true); + SetInputParam("dataset", testimage); + SetInputParam("height", 50); + SetInputParam("width", -50); + SetInputParam("channels", 3); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Check for invalid channel values. + */ +BOOST_AUTO_TEST_CASE(InvalidChannelTest) +{ + arma::mat testimage = arma::conv_to::from( + arma::randi>((5 * 5 * 3), 2)); + SetInputParam>("input", {"test_image777.png", + "test_image999.png"}); + SetInputParam("save", true); + SetInputParam("dataset", testimage); + SetInputParam("height", 50); + SetInputParam("width", 50); + SetInputParam("channels", -1); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Check for invalid input values. + */ +BOOST_AUTO_TEST_CASE(EmptyInputTest) +{ + SetInputParam>("input", {}); + SetInputParam("height", 50); + SetInputParam("width", 50); + SetInputParam("channels", 50); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +BOOST_AUTO_TEST_SUITE_END(); diff -Nru mlpack-3.2.2/src/mlpack/tests/main_tests/kde_test.cpp mlpack-3.3.0/src/mlpack/tests/main_tests/kde_test.cpp --- mlpack-3.2.2/src/mlpack/tests/main_tests/kde_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/main_tests/kde_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -30,14 +30,15 @@ public: KDETestFixture() { - // Cache in the options for this program. - CLI::RestoreSettings(testName); + // Cache in the options for this program. + CLI::RestoreSettings(testName); } ~KDETestFixture() { - // Clear the settings. - CLI::ClearSettings(); + // Clear the settings. + bindings::tests::CleanMemory(); + CLI::ClearSettings(); } }; @@ -545,6 +546,8 @@ mlpackMain(); estimations1 = std::move(CLI::GetParam("predictions")); + delete CLI::GetParam("output_model"); + // Compute estimations 2. SetInputParam("reference", reference); SetInputParam("query", query); diff -Nru mlpack-3.2.2/src/mlpack/tests/main_tests/knn_test.cpp mlpack-3.3.0/src/mlpack/tests/main_tests/knn_test.cpp --- mlpack-3.2.2/src/mlpack/tests/main_tests/knn_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/main_tests/knn_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -683,6 +683,7 @@ BOOST_CHECK_EQUAL(output_model->LeafSize(), (int) 1); BOOST_CHECK_EQUAL(CLI::GetParam("output_model")->LeafSize(), (int) 10); - } + delete output_model; +} BOOST_AUTO_TEST_SUITE_END(); diff -Nru mlpack-3.2.2/src/mlpack/tests/main_tests/linear_svm_test.cpp mlpack-3.3.0/src/mlpack/tests/main_tests/linear_svm_test.cpp --- mlpack-3.2.2/src/mlpack/tests/main_tests/linear_svm_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/main_tests/linear_svm_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -414,7 +414,7 @@ } /** - * Ensuring that number classes must not be zero. + * Ensuring that number classes must not be one. */ BOOST_AUTO_TEST_CASE(LinearSVMZeroNumberOfClassesTest) { @@ -429,7 +429,7 @@ SetInputParam("training", std::move(trainData)); SetInputParam("labels", std::move(trainLabels)); - // Number of classes for optimizer is zero. + // Number of classes for optimizer is only one. // It should throw a invalid_argument error. Log::Fatal.ignoreInput = true; BOOST_REQUIRE_THROW(mlpackMain(), std::invalid_argument); diff -Nru mlpack-3.2.2/src/mlpack/tests/main_tests/nmf_test.cpp mlpack-3.3.0/src/mlpack/tests/main_tests/nmf_test.cpp --- mlpack-3.2.2/src/mlpack/tests/main_tests/nmf_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/main_tests/nmf_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -284,4 +284,83 @@ BOOST_REQUIRE_GT(arma::norm(h1 - h2), 1e-5); } +/** + * Test NMF with given initial_w and initial_h. + */ +BOOST_AUTO_TEST_CASE(NMFWHGivenInitTest) +{ + mat v = arma::randu(10, 10); + mat initialW = arma::randu(10, 5); + mat initialH = arma::randu(5, 10); + int r = 5; + + SetInputParam("input", v); + SetInputParam("rank", r); + SetInputParam("initial_w", initialW); + SetInputParam("initial_h", initialH); + + mlpackMain(); + + const mat w = CLI::GetParam("w"); + const mat h = CLI::GetParam("h"); + + // Check the shapes of W and H. + BOOST_REQUIRE_EQUAL(w.n_rows, 10); + BOOST_REQUIRE_EQUAL(w.n_cols, 5); + BOOST_REQUIRE_EQUAL(h.n_rows, 5); + BOOST_REQUIRE_EQUAL(h.n_cols, 10); +} + +/** + * Test NMF with given initial_w. + */ +BOOST_AUTO_TEST_CASE(NMFWGivenInitTest) +{ + mat v = arma::randu(10, 10); + mat initialW = arma::randu(10, 5); + int r = 5; + + SetInputParam("input", v); + SetInputParam("rank", r); + SetInputParam("initial_w", initialW); + + mlpackMain(); + + const mat w = CLI::GetParam("w"); + const mat h = CLI::GetParam("h"); + + // Check the shapes of W and H. + BOOST_REQUIRE_EQUAL(w.n_rows, 10); + BOOST_REQUIRE_EQUAL(w.n_cols, 5); + BOOST_REQUIRE_EQUAL(h.n_rows, 5); + BOOST_REQUIRE_EQUAL(h.n_cols, 10); +} + +/** + * Test NMF with given initial_h. + */ +BOOST_AUTO_TEST_CASE(NMFHGivenInitTest) +{ + mat v = arma::randu(10, 10); + mat initialH = arma::randu(5, 10); + int r = 5; + + SetInputParam("input", v); + SetInputParam("rank", r); + SetInputParam("initial_h", initialH); + + mlpackMain(); + + const mat w = CLI::GetParam("w"); + const mat h = CLI::GetParam("h"); + + // Check the shapes of W and H. + BOOST_REQUIRE_EQUAL(w.n_rows, 10); + BOOST_REQUIRE_EQUAL(w.n_cols, 5); + BOOST_REQUIRE_EQUAL(h.n_rows, 5); + BOOST_REQUIRE_EQUAL(h.n_cols, 10); +} + + BOOST_AUTO_TEST_SUITE_END(); + diff -Nru mlpack-3.2.2/src/mlpack/tests/main_tests/preprocess_scale_test.cpp mlpack-3.3.0/src/mlpack/tests/main_tests/preprocess_scale_test.cpp --- mlpack-3.2.2/src/mlpack/tests/main_tests/preprocess_scale_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/main_tests/preprocess_scale_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -57,16 +57,18 @@ SetInputParam("scaler_method", method); mlpackMain(); - arma::mat max_abs_scaler_output = CLI::GetParam("output"); + arma::mat maxAbsScalerOutput = CLI::GetParam("output"); + + bindings::tests::CleanMemory(); method = "standard_scaler"; SetInputParam("input", dataset); SetInputParam("scaler_method", std::move(method)); mlpackMain(); - arma::mat standard_scaler_output = CLI::GetParam("output"); + arma::mat standardScalerOutput = CLI::GetParam("output"); - CheckMatricesNotEqual(standard_scaler_output, max_abs_scaler_output); + CheckMatricesNotEqual(standardScalerOutput, maxAbsScalerOutput); } /** @@ -83,6 +85,8 @@ mlpackMain(); arma::mat output = CLI::GetParam("output"); + bindings::tests::CleanMemory(); + SetInputParam("input", dataset); SetInputParam("scaler_method", std::move(method)); SetInputParam("min_value", 2); @@ -107,6 +111,8 @@ mlpackMain(); arma::mat scaled = CLI::GetParam("output"); + bindings::tests::CleanMemory(); + SetInputParam("input", dataset); SetInputParam("scaler_method", std::move(method)); SetInputParam("min_value", 2); @@ -177,6 +183,8 @@ mlpackMain(); arma::mat scaled = CLI::GetParam("output"); + bindings::tests::CleanMemory(); + SetInputParam("scaler_method", std::move(method)); SetInputParam("input", dataset); SetInputParam("epsilon", 1.0); diff -Nru mlpack-3.2.2/src/mlpack/tests/main_tests/range_search_test.cpp mlpack-3.3.0/src/mlpack/tests/main_tests/range_search_test.cpp --- mlpack-3.2.2/src/mlpack/tests/main_tests/range_search_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/main_tests/range_search_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -278,7 +278,7 @@ neighbors = ReadData(neighborsFile); distances = ReadData(distanceFile); - RSModel* outputModel = move(CLI::GetParam("output_model")); + RSModel* outputModel = CLI::GetParam("output_model"); CLI::GetSingleton().Parameters()["reference"].wasPassed = false; SetInputParam("input_model", outputModel); @@ -293,7 +293,7 @@ CheckMatrices(distances, distancetemp); BOOST_REQUIRE_EQUAL(ModelToString(outputModel), - ModelToString(CLI::GetParam("output_model"))); + ModelToString(CLI::GetParam("output_model"))); remove(neighborsFile.c_str()); remove(distanceFile.c_str()); @@ -351,8 +351,13 @@ BOOST_REQUIRE_NE(ModelToString(outputModel1), ModelToString(CLI::GetParam("output_model"))); + + if (i != leafSizes.size() - 1) + delete CLI::GetParam("output_model"); } + delete outputModel1; + remove(neighborsFile.c_str()); remove(distanceFile.c_str()); } @@ -419,8 +424,13 @@ CheckMatrices(distances, distancestemp); BOOST_REQUIRE_NE(ModelToString(outputModel1), ModelToString(CLI::GetParam("output_model"))); + + if (i != trees.size() - 1) + delete CLI::GetParam("output_model"); } + delete outputModel1; + remove(neighborsFile.c_str()); remove(distanceFile.c_str()); } @@ -463,6 +473,8 @@ BOOST_REQUIRE_NE(ModelToString(outputModel), ModelToString(CLI::GetParam("output_model"))); + delete outputModel; + remove(neighborsFile.c_str()); remove(distanceFile.c_str()); } @@ -515,6 +527,8 @@ BOOST_REQUIRE_NE(ModelToString(outputModel), ModelToString(CLI::GetParam("output_model"))); + delete outputModel; + remove(neighborsFile.c_str()); remove(distanceFile.c_str()); } @@ -566,6 +580,8 @@ BOOST_REQUIRE_NE(ModelToString(outputModel), ModelToString(CLI::GetParam("output_model"))); + delete outputModel; + remove(neighborsFile.c_str()); remove(distanceFile.c_str()); } diff -Nru mlpack-3.2.2/src/mlpack/tests/mlpack_test.cpp mlpack-3.3.0/src/mlpack/tests/mlpack_test.cpp --- mlpack-3.2.2/src/mlpack/tests/mlpack_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/mlpack_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -14,11 +14,6 @@ #include -// We only need to do this for old Boost versions. -#if BOOST_VERSION < 103600 - #define BOOST_AUTO_TEST_MAIN -#endif - #if BOOST_VERSION >= 105900 #include #include diff -Nru mlpack-3.2.2/src/mlpack/tests/q_learning_test.cpp mlpack-3.3.0/src/mlpack/tests/q_learning_test.cpp --- mlpack-3.2.2/src/mlpack/tests/q_learning_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/q_learning_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -199,7 +199,7 @@ config.Discount() = 0.9; config.TargetNetworkSyncInterval() = 100; config.ExplorationSteps() = 100; - config.DoubleQLearning() = false; + config.DoubleQLearning() = true; config.StepLimit() = 200; // Set up the DQN agent. @@ -215,7 +215,7 @@ averageReturn(episodeReturn); /** - * Reaching running average return 35 is enough to show it works. + * Reaching running average return 40 is enough to show it works. * For the speed of the test case, I didn't set high criterion. */ Log::Debug << "Average return: " << averageReturn.mean() diff -Nru mlpack-3.2.2/src/mlpack/tests/recurrent_network_test.cpp mlpack-3.3.0/src/mlpack/tests/recurrent_network_test.cpp --- mlpack-3.2.2/src/mlpack/tests/recurrent_network_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/recurrent_network_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -114,7 +114,7 @@ BOOST_TEST_CHECKPOINT("Training over"); arma::cube prediction; model.Predict(input, prediction); - BOOST_TEST_CHECKPOINT("Predicion over"); + BOOST_TEST_CHECKPOINT("Prediction over"); size_t error = 0; for (size_t i = 0; i < prediction.n_cols; ++i) @@ -825,7 +825,7 @@ inputTemp = arma::cube(trainInput.at(0, j).memptr(), inputSize, 1, trainInput.at(0, j).n_elem / inputSize, false, true); labelsTemp = arma::cube(trainLabels.at(0, j).memptr(), outputSize, 1, - trainInput.at(0, j).n_elem / outputSize, false, true); + trainLabels.at(0, j).n_elem / outputSize, false, true); model.Train(inputTemp, labelsTemp, opt); } @@ -1413,4 +1413,67 @@ BOOST_REQUIRE_EQUAL(std::isfinite(objVal), true); } +/** + * Test that RNN::Train() does not give an error for large rho. + */ +BOOST_AUTO_TEST_CASE(LargeRhoValueRnnTest) +{ + // Setting rho value greater than sequence length which is 17. + const size_t rho = 100; + const size_t hiddenSize = 128; + const size_t numLetters = 256; + using MatType = arma::cube; + std::vectortrainingData = { "THIS IS THE INPUT 0" , + "THIS IS THE INPUT 1" , + "THIS IS THE INPUT 3"}; + + + RNN<> model(rho); + model.Add>(); + model.Add>(numLetters, hiddenSize, rho); + model.Add>(0.1); + model.Add>(hiddenSize, numLetters); + + const auto makeInput = [numLetters](const char *line) -> MatType + { + const auto strLen = strlen(line); + // Rows: number of dimensions. + // Cols: number of sequences/points. + // Slices: number of steps in sequences. + MatType result(numLetters, 1, strLen, arma::fill::zeros); + for (size_t i = 0; i < strLen; ++i) + { + result.at(static_cast(line[i]), 0, i) = 1.0; + } + return result; + }; + + const auto makeTarget = [] (const char *line) -> MatType + { + const auto strLen = strlen(line); + // Responses for NegativeLogLikelihood should be + // non-one-hot-encoded class IDs (from 1 to num_classes). + MatType result(1, 1, strLen, arma::fill::zeros); + // The response is the *next* letter in the sequence. + for (size_t i = 0; i < strLen - 1; ++i) + { + result.at(0, 0, i) = static_cast(line[i + 1]) + 1.0; + } + // The final response is empty, so we set it to class 0. + result.at(0, 0, strLen - 1) = 1.0; + return result; + }; + + std::vector inputs(trainingData.size()); + std::vector targets(trainingData.size()); + for (size_t i = 0; i < trainingData.size(); ++i) + { + inputs[i] = makeInput(trainingData[i].c_str()); + targets[i] = makeTarget(trainingData[i].c_str()); + } + ens::SGD<> opt(0.01, 1, 100); + double objVal = model.Train(inputs[0], targets[0], opt); + BOOST_TEST_CHECKPOINT("Training over"); +} + BOOST_AUTO_TEST_SUITE_END(); diff -Nru mlpack-3.2.2/src/mlpack/tests/serialization_test.cpp mlpack-3.3.0/src/mlpack/tests/serialization_test.cpp --- mlpack-3.2.2/src/mlpack/tests/serialization_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/serialization_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -666,9 +666,7 @@ labels[i] = 0; for (size_t i = 500; i < 1000; ++i) labels[i] = 1; - SoftmaxRegression sr(dataset, labels, 2); - SoftmaxRegression srXml(dataset.n_rows, 2); SoftmaxRegression srText(dataset.n_rows, 2); SoftmaxRegression srBinary(dataset.n_rows, 2); diff -Nru mlpack-3.2.2/src/mlpack/tests/softmax_regression_test.cpp mlpack-3.3.0/src/mlpack/tests/softmax_regression_test.cpp --- mlpack-3.2.2/src/mlpack/tests/softmax_regression_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/softmax_regression_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -360,8 +360,8 @@ SoftmaxRegression sr(dataset.n_rows, 2); SoftmaxRegression sr2(dataset.n_rows, 2); sr.Parameters() = sr2.Parameters(); - sr.Train(dataset, labels, 2); ens::L_BFGS lbfgs; + sr.Train(dataset, labels, 2, std::move(lbfgs)); sr2.Train(dataset, labels, 2, std::move(lbfgs)); // Ensure that the parameters are the same. diff -Nru mlpack-3.2.2/src/mlpack/tests/string_encoding_test.cpp mlpack-3.3.0/src/mlpack/tests/string_encoding_test.cpp --- mlpack-3.2.2/src/mlpack/tests/string_encoding_test.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/string_encoding_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -0,0 +1,1429 @@ +/** + * @file string_encoding_test.cpp + * @author Jeffin Sam + * @author Mikhail Lozhnikov + * + * Tests for the StringEncoding 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "test_tools.hpp" +#include "serialization.hpp" + +using namespace mlpack; +using namespace mlpack::data; +using namespace std; + +BOOST_AUTO_TEST_SUITE(StringEncodingTest); + +//! Common input for some tests. +static vector stringEncodingInput = { + "mlpack is an intuitive, fast, and flexible C++ machine learning library " + "with bindings to other languages. ", + "It is meant to be a machine learning analog to LAPACK, and aims to " + "implement a wide array of machine learning methods and functions " + "as a \"swiss army knife\" for machine learning researchers.", + "In addition to its powerful C++ interface, mlpack also provides " + "command-line programs and Python bindings." +}; + +//! Common UTF-8 input for some unicode tests. +static vector stringEncodingUtf8Input = { + "mlpack " + "\xE2\x93\x9C\xE2\x93\x9B\xE2\x93\x9F\xE2\x93\x90\xE2\x93\x92\xE2\x93\x9A", + "MLPACK " + "\xE2\x93\x82\xE2\x93\x81\xE2\x93\x85\xE2\x92\xB6\xE2\x92\xB8\xE2\x93\x80 " + "mlpack", + "\xF0\x9F\x84\xBC\xF0\x9F\x84\xBB\xF0\x9F\x84\xBF\xF0\x9F\x84\xB0" + "\xF0\x9F\x84\xB2\xF0\x9F\x84\xBA " + "\xE2\x93\x9C\xE2\x93\x9B\xE2\x93\x9F\xE2\x93\x90\xE2\x93\x92\xE2\x93\x9A " + "MLPACK " + "\xF0\x9F\x84\xBC\xF0\x9F\x84\xBB\xF0\x9F\x84\xBF\xF0\x9F\x84\xB0" + "\xF0\x9F\x84\xB2\xF0\x9F\x84\xBA " + "\xE2\x93\x82\xE2\x93\x81\xE2\x93\x85\xE2\x92\xB6\xE2\x92\xB8\xE2\x93\x80" +}; + +/** + * Check the values of two 2D vectors. + */ +template +void CheckVectors(const vector>& a, + const vector>& b, + const ValueType tolerance = 1e-5) +{ + BOOST_REQUIRE_EQUAL(a.size(), b.size()); + + for (size_t i = 0; i < a.size(); i++) + { + BOOST_REQUIRE_EQUAL(a[i].size(), b[i].size()); + + for (size_t j = 0; j < a[i].size(); j++) + BOOST_REQUIRE_CLOSE(a[i][j], b[i][j], tolerance); + } +} + +/** + * Test the dictionary encoding algorithm. + */ +BOOST_AUTO_TEST_CASE(DictionaryEncodingTest) +{ + using DictionaryType = StringEncodingDictionary; + + arma::mat output; + DictionaryEncoding encoder; + SplitByAnyOf tokenizer(" .,\""); + + encoder.Encode(stringEncodingInput, output, tokenizer); + + const DictionaryType& dictionary = encoder.Dictionary(); + + // Checking that each token has a unique label. + std::unordered_map keysCount; + + for (auto& keyValue : dictionary.Mapping()) + { + keysCount[keyValue.second]++; + + BOOST_REQUIRE_EQUAL(keysCount[keyValue.second], 1); + } + + arma::mat expected = { + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 17, 2, 18, 14, 19, 20, 9, 10, 21, 14, 22, 6, 23, 14, 24, 20, 25, + 26, 27, 9, 10, 28, 6, 29, 30, 20, 31, 32, 33, 34, 9, 10, 35 }, + { 36, 37, 14, 38, 39, 8, 40, 1, 41, 42, 43, 44, 6, 45, 13, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }; + + CheckMatrices(output, expected.t()); +} + +/** + * Test the dictionary encoding algorithm with unicode characters. + */ +BOOST_AUTO_TEST_CASE(UnicodeDictionaryEncodingTest) +{ + using DictionaryType = StringEncodingDictionary; + + arma::mat output; + DictionaryEncoding encoder; + SplitByAnyOf tokenizer(" .,\""); + + encoder.Encode(stringEncodingUtf8Input, output, tokenizer); + + const DictionaryType& dictionary = encoder.Dictionary(); + + // Checking that each token has a unique label. + std::unordered_map keysCount; + + for (auto& keyValue : dictionary.Mapping()) + { + keysCount[keyValue.second]++; + + BOOST_REQUIRE_EQUAL(keysCount[keyValue.second], 1); + } + + arma::mat expected = { + { 1, 2, 0, 0, 0 }, + { 3, 4, 1, 0, 0 }, + { 5, 2, 3, 5, 4 } + }; + + CheckMatrices(output, expected.t()); +} + +/** + * Test the one pass modification of the dictionary encoding algorithm. + */ +BOOST_AUTO_TEST_CASE(OnePassDictionaryEncodingTest) +{ + using DictionaryType = StringEncodingDictionary; + + vector> output; + DictionaryEncoding encoder( + (DictionaryEncodingPolicy())); + SplitByAnyOf tokenizer(" .,\""); + + encoder.Encode(stringEncodingInput, output, tokenizer); + + const DictionaryType& dictionary = encoder.Dictionary(); + + // Checking that each token has a unique label. + std::unordered_map keysCount; + + for (auto& keyValue : dictionary.Mapping()) + { + keysCount[keyValue.second]++; + + BOOST_REQUIRE_EQUAL(keysCount[keyValue.second], 1); + } + + vector> expected = { + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, + { 17, 2, 18, 14, 19, 20, 9, 10, 21, 14, 22, 6, 23, 14, 24, 20, 25, + 26, 27, 9, 10, 28, 6, 29, 30, 20, 31, 32, 33, 34, 9, 10, 35 }, + { 36, 37, 14, 38, 39, 8, 40, 1, 41, 42, 43, 44, 6, 45, 13 } + }; + + BOOST_REQUIRE(output == expected); +} + + +/** + * Test the SplitByAnyOf tokenizer. + */ +BOOST_AUTO_TEST_CASE(SplitByAnyOfTokenizerTest) +{ + std::vector tokens; + boost::string_view line(stringEncodingInput[0]); + SplitByAnyOf tokenizer(" ,."); + boost::string_view token = tokenizer(line); + + while (!token.empty()) + { + tokens.push_back(token); + token = tokenizer(line); + } + + vector expected = { "mlpack", "is", "an", "intuitive", "fast", + "and", "flexible", "C++", "machine", "learning", "library", "with", + "bindings", "to", "other", "languages" + }; + + BOOST_REQUIRE_EQUAL(tokens.size(), expected.size()); + + for (size_t i = 0; i < tokens.size(); i++) + BOOST_REQUIRE_EQUAL(tokens[i], expected[i]); +} + +/** + * Test the SplitByAnyOf tokenizer in case of unicode characters. + */ +BOOST_AUTO_TEST_CASE(SplitByAnyOfTokenizerUnicodeTest) +{ + vector expectedUtf8Tokens = { + "\xF0\x9F\x84\xBC\xF0\x9F\x84\xBB\xF0\x9F\x84\xBF\xF0\x9F\x84\xB0" + "\xF0\x9F\x84\xB2\xF0\x9F\x84\xBA", + "\xE2\x93\x9C\xE2\x93\x9B\xE2\x93\x9F\xE2\x93\x90\xE2\x93\x92\xE2\x93\x9A", + "MLPACK", + "\xF0\x9F\x84\xBC\xF0\x9F\x84\xBB\xF0\x9F\x84\xBF\xF0\x9F\x84\xB0" + "\xF0\x9F\x84\xB2\xF0\x9F\x84\xBA", + "\xE2\x93\x82\xE2\x93\x81\xE2\x93\x85\xE2\x92\xB6\xE2\x92\xB8\xE2\x93\x80" + }; + + std::vector tokens; + boost::string_view line(stringEncodingUtf8Input[2]); + SplitByAnyOf tokenizer(" ,."); + boost::string_view token = tokenizer(line); + + while (!token.empty()) + { + tokens.push_back(token); + token = tokenizer(line); + } + + BOOST_REQUIRE_EQUAL(tokens.size(), expectedUtf8Tokens.size()); + + for (size_t i = 0; i < tokens.size(); i++) + BOOST_REQUIRE_EQUAL(tokens[i], expectedUtf8Tokens[i]); +} + +/** + * Test the CharExtract tokenizer. + */ +BOOST_AUTO_TEST_CASE(DictionaryEncodingIndividualCharactersTest) +{ + vector input = { + "GACCA", + "ABCABCD", + "GAB" + }; + + arma::mat output; + DictionaryEncoding encoder; + + encoder.Encode(input, output, CharExtract()); + + arma::mat target = { + { 1, 2, 3, 3, 2, 0, 0 }, + { 2, 4, 3, 2, 4, 3, 5 }, + { 1, 2, 4, 0, 0, 0, 0 } + }; + CheckMatrices(output, target.t()); +} + +/** + * Test the one pass modification of the dictionary encoding algorithm + * in case of individual character encoding. + */ +BOOST_AUTO_TEST_CASE(OnePassDictionaryEncodingIndividualCharactersTest) +{ + std::vector input = { + "GACCA", + "ABCABCD", + "GAB" + }; + + vector> output; + DictionaryEncoding encoder; + + encoder.Encode(input, output, CharExtract()); + + vector> expected = { + { 1, 2, 3, 3, 2 }, + { 2, 4, 3, 2, 4, 3, 5 }, + { 1, 2, 4 } + }; + + BOOST_REQUIRE(output == expected); +} + +/** + * Test the functionality of copy constructor. + */ +BOOST_AUTO_TEST_CASE(StringEncodingCopyTest) +{ + using DictionaryType = StringEncodingDictionary; + arma::sp_mat output; + DictionaryEncoding encoderCopy; + SplitByAnyOf tokenizer(" ,."); + + vector> naiveDictionary; + + { + DictionaryEncoding encoder; + encoder.Encode(stringEncodingInput, output, tokenizer); + + for (const string& token : encoder.Dictionary().Tokens()) + { + naiveDictionary.emplace_back(token, encoder.Dictionary().Value(token)); + } + + encoderCopy = DictionaryEncoding(encoder); + } + + const DictionaryType& copiedDictionary = encoderCopy.Dictionary(); + + BOOST_REQUIRE_EQUAL(naiveDictionary.size(), copiedDictionary.Size()); + + for (const pair& keyValue : naiveDictionary) + { + BOOST_REQUIRE(copiedDictionary.HasToken(keyValue.first)); + BOOST_REQUIRE_EQUAL(copiedDictionary.Value(keyValue.first), + keyValue.second); + } +} + +/** + * Test the move assignment operator. + */ +BOOST_AUTO_TEST_CASE(StringEncodingMoveTest) +{ + using DictionaryType = StringEncodingDictionary; + arma::sp_mat output; + DictionaryEncoding encoderCopy; + SplitByAnyOf tokenizer(" ,."); + + vector> naiveDictionary; + + { + DictionaryEncoding encoder; + encoder.Encode(stringEncodingInput, output, tokenizer); + + for (const string& token : encoder.Dictionary().Tokens()) + { + naiveDictionary.emplace_back(token, encoder.Dictionary().Value(token)); + } + + encoderCopy = std::move(encoder); + } + + const DictionaryType& copiedDictionary = encoderCopy.Dictionary(); + + BOOST_REQUIRE_EQUAL(naiveDictionary.size(), copiedDictionary.Size()); + + for (const pair& keyValue : naiveDictionary) + { + BOOST_REQUIRE(copiedDictionary.HasToken(keyValue.first)); + BOOST_REQUIRE_EQUAL(copiedDictionary.Value(keyValue.first), + keyValue.second); + } +} + +/** + * The function checks that the given dictionaries contain the same data. + */ +template +void CheckDictionaries(const StringEncodingDictionary& expected, + const StringEncodingDictionary& obtained) +{ + // MapType is equal to std::unordered_map. + using MapType = typename StringEncodingDictionary::MapType; + + const MapType& mapping = obtained.Mapping(); + const MapType& expectedMapping = expected.Mapping(); + + BOOST_REQUIRE_EQUAL(mapping.size(), expectedMapping.size()); + + for (auto& keyVal : expectedMapping) + { + BOOST_REQUIRE_EQUAL(mapping.at(keyVal.first), keyVal.second); + } + + for (auto& keyVal : mapping) + { + BOOST_REQUIRE_EQUAL(expectedMapping.at(keyVal.first), keyVal.second); + } +} + +/** + * This is a specialization of the CheckDictionaries() function for + * the boost::string_view token type. + */ +template<> +void CheckDictionaries( + const StringEncodingDictionary& expected, + const StringEncodingDictionary& obtained) +{ + /* MapType is equal to + * + * std::unordered_map>. + */ + using MapType = + typename StringEncodingDictionary::MapType; + + const std::deque& expectedTokens = expected.Tokens(); + const std::deque& tokens = obtained.Tokens(); + const MapType& expectedMapping = expected.Mapping(); + const MapType& mapping = obtained.Mapping(); + + BOOST_REQUIRE_EQUAL(tokens.size(), expectedTokens.size()); + BOOST_REQUIRE_EQUAL(mapping.size(), expectedMapping.size()); + BOOST_REQUIRE_EQUAL(mapping.size(), tokens.size()); + + for (size_t i = 0; i < tokens.size(); i++) + { + BOOST_REQUIRE_EQUAL(tokens[i], expectedTokens[i]); + BOOST_REQUIRE_EQUAL(expectedMapping.at(tokens[i]), mapping.at(tokens[i])); + } +} + +/** + * This is a specialization of the CheckDictionaries() function for + * the integer token type. + */ +template<> +void CheckDictionaries(const StringEncodingDictionary& expected, + const StringEncodingDictionary& obtained) +{ + // MapType is equal to std::arry. + using MapType = typename StringEncodingDictionary::MapType; + + const MapType& expectedMapping = expected.Mapping(); + const MapType& mapping = obtained.Mapping(); + + BOOST_REQUIRE_EQUAL(expected.Size(), obtained.Size()); + + for (size_t i = 0; i < mapping.size(); i++) + { + BOOST_REQUIRE_EQUAL(mapping[i], expectedMapping[i]); + } +} + +/** + * Serialization test for the general template of the StringEncodingDictionary + * class. + */ +BOOST_AUTO_TEST_CASE(StringEncodingDictionarySerialization) +{ + using DictionaryType = StringEncodingDictionary; + + DictionaryType dictionary; + SplitByAnyOf tokenizer(" ,."); + + for (const string& line : stringEncodingInput) + { + boost::string_view lineView(line); + + boost::string_view token = tokenizer(lineView); + + while (!tokenizer.IsTokenEmpty(token)) + { + dictionary.AddToken(string(token)); + + token = tokenizer(lineView); + } + } + + DictionaryType xmlDictionary, textDictionary, binaryDictionary; + + SerializeObjectAll(dictionary, xmlDictionary, textDictionary, + binaryDictionary); + + CheckDictionaries(dictionary, xmlDictionary); + CheckDictionaries(dictionary, textDictionary); + CheckDictionaries(dictionary, binaryDictionary); +} + +/** + * Serialization test for the dictionary encoding algorithm with + * the SplitByAnyOf tokenizer. + */ +BOOST_AUTO_TEST_CASE(SplitByAnyOfDictionaryEncodingSerialization) +{ + using EncoderType = DictionaryEncoding; + + EncoderType encoder; + SplitByAnyOf tokenizer(" ,."); + arma::mat output; + + encoder.Encode(stringEncodingInput, output, tokenizer); + + EncoderType xmlEncoder, textEncoder, binaryEncoder; + arma::mat xmlOutput, textOutput, binaryOutput; + + SerializeObjectAll(encoder, xmlEncoder, textEncoder, binaryEncoder); + + CheckDictionaries(encoder.Dictionary(), xmlEncoder.Dictionary()); + CheckDictionaries(encoder.Dictionary(), textEncoder.Dictionary()); + CheckDictionaries(encoder.Dictionary(), binaryEncoder.Dictionary()); + + xmlEncoder.Encode(stringEncodingInput, xmlOutput, tokenizer); + textEncoder.Encode(stringEncodingInput, textOutput, tokenizer); + binaryEncoder.Encode(stringEncodingInput, binaryOutput, tokenizer); + + CheckMatrices(output, xmlOutput, textOutput, binaryOutput); +} + +/** + * Serialization test for the dictionary encoding algorithm with + * the CharExtract tokenizer. + */ +BOOST_AUTO_TEST_CASE(CharExtractDictionaryEncodingSerialization) +{ + using EncoderType = DictionaryEncoding; + + EncoderType encoder; + CharExtract tokenizer; + arma::mat output; + + encoder.Encode(stringEncodingInput, output, tokenizer); + + EncoderType xmlEncoder, textEncoder, binaryEncoder; + arma::mat xmlOutput, textOutput, binaryOutput; + + SerializeObjectAll(encoder, xmlEncoder, textEncoder, binaryEncoder); + + CheckDictionaries(encoder.Dictionary(), xmlEncoder.Dictionary()); + CheckDictionaries(encoder.Dictionary(), textEncoder.Dictionary()); + CheckDictionaries(encoder.Dictionary(), binaryEncoder.Dictionary()); + + xmlEncoder.Encode(stringEncodingInput, xmlOutput, tokenizer); + textEncoder.Encode(stringEncodingInput, textOutput, tokenizer); + binaryEncoder.Encode(stringEncodingInput, binaryOutput, tokenizer); + + CheckMatrices(output, xmlOutput, textOutput, binaryOutput); +} + +/** + * Test the Bag of Words encoding algorithm. + */ +BOOST_AUTO_TEST_CASE(BagOfWordsEncodingTest) +{ + using DictionaryType = StringEncodingDictionary; + + arma::mat output; + BagOfWordsEncoding encoder; + SplitByAnyOf tokenizer(" ,."); + + encoder.Encode(stringEncodingInput, output, tokenizer); + + const DictionaryType& dictionary = encoder.Dictionary(); + + // Checking that each token has a unique label. + std::unordered_map keysCount; + + for (auto& keyValue : dictionary.Mapping()) + { + keysCount[keyValue.second]++; + + BOOST_REQUIRE_EQUAL(keysCount[keyValue.second], 1); + } + +/* The expected values were obtained by the following Python script: + + from sklearn.feature_extraction.text import CountVectorizer + from collections import OrderedDict + import re + + string_encoding_input = [ + "mlpack is an intuitive, fast, and flexible C++ machine learning library " + "with bindings to other languages. ", + "It is meant to be a machine learning analog to LAPACK, and aims to " + "implement a wide array of machine learning methods and functions " + "as a \"swiss army knife\" for machine learning researchers.", + "In addition to its powerful C++ interface, mlpack also provides " + "command-line programs and Python bindings." + ] + + dictionary = OrderedDict() + + count = 0 + for line in string_encoding_input: + for word in re.split(' |,|\.', line): + if word and (not (word in dictionary)): + dictionary[word] = count + count += 1 + + def tokenizer(line): + return re.split(' |,|\.', line) + + vectorizer = CountVectorizer(strip_accents=False, lowercase=False, + preprocessor=None, tokenizer=tokenizer, stop_words=None, + vocabulary=dictionary, binary=False) + + X = vectorizer.fit_transform(string_encoding_input) + + for row in X.toarray(): + print("{ " + ", ".join(map(str, row)) + " },") +*/ + + arma::mat expected = { + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 1, 0, 0, 0, 2, 0, 0, 3, 3, 0, 0, 0, 3, 0, 0, 1, 1, 1, 3, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } + }; + + CheckMatrices(output, expected.t()); +} + +/** + * Test the Bag of Words encoding algorithm. The output is saved into a vector. + */ +BOOST_AUTO_TEST_CASE(VectorBagOfWordsEncodingTest) +{ + using DictionaryType = StringEncodingDictionary; + + vector> output; + BagOfWordsEncoding encoder( + (BagOfWordsEncodingPolicy())); + SplitByAnyOf tokenizer(" ,."); + + encoder.Encode(stringEncodingInput, output, tokenizer); + + const DictionaryType& dictionary = encoder.Dictionary(); + + // Checking that each token has a unique label. + std::unordered_map keysCount; + + for (auto& keyValue : dictionary.Mapping()) + { + keysCount[keyValue.second]++; + + BOOST_REQUIRE_EQUAL(keysCount[keyValue.second], 1); + } + + /* The expected values were obtained by the same script as in + BagOfWordsEncodingTest. */ + vector> expected = { + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 1, 0, 0, 0, 2, 0, 0, 3, 3, 0, 0, 0, 3, 0, 0, 1, 1, 1, 3, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } + }; + + BOOST_REQUIRE(output == expected); +} + +/** + * Test the Bag of Words algorithm for individual characters. + */ +BOOST_AUTO_TEST_CASE(BagOfWordsEncodingIndividualCharactersTest) +{ + vector input = { + "GACCA", + "ABCABCD", + "GAB" + }; + + arma::mat output; + BagOfWordsEncoding encoder; + + encoder.Encode(input, output, CharExtract()); + + arma::mat target = { + { 1, 2, 2, 0, 0 }, + { 0, 2, 2, 2, 1 }, + { 1, 1, 0, 1, 0 } + }; + + CheckMatrices(output, target.t()); +} + +/** + * Test the Bag of Words encoding algorithm in case of individual + * characters encoding. The output type is vector>. + */ +BOOST_AUTO_TEST_CASE(VectorBagOfWordsEncodingIndividualCharactersTest) +{ + std::vector input = { + "GACCA", + "ABCABCD", + "GAB" + }; + + vector> output; + BagOfWordsEncoding encoder; + + encoder.Encode(input, output, CharExtract()); + + vector> expected = { + { 1, 2, 2, 0, 0 }, + { 0, 2, 2, 2, 1 }, + { 1, 1, 0, 1, 0 } + }; + + BOOST_REQUIRE(output == expected); +} + +/** + * Test the Tf-Idf encoding algorithm with the raw count term frequency type + * and the smooth inverse document frequency type. These parameters are + * the default ones. + */ +BOOST_AUTO_TEST_CASE(RawCountSmoothIdfEncodingTest) +{ + using DictionaryType = StringEncodingDictionary; + + arma::mat output; + TfIdfEncoding encoder; + SplitByAnyOf tokenizer(" ,."); + + encoder.Encode(stringEncodingInput, output, tokenizer); + const DictionaryType& dictionary = encoder.Dictionary(); + + // Checking that each token has a unique label. + std::unordered_map keysCount; + + for (auto& keyValue : dictionary.Mapping()) + { + keysCount[keyValue.second]++; + + BOOST_REQUIRE_EQUAL(keysCount[keyValue.second], 1); + } + + /* The expected values were obtained by the following Python script: + + from sklearn.feature_extraction.text import TfidfVectorizer + from collections import OrderedDict + import re + + string_encoding_input = [ + "mlpack is an intuitive, fast, and flexible C++ machine learning library " + "with bindings to other languages. ", + "It is meant to be a machine learning analog to LAPACK, and aims to " + "implement a wide array of machine learning methods and functions " + "as a \"swiss army knife\" for machine learning researchers.", + "In addition to its powerful C++ interface, mlpack also provides " + "command-line programs and Python bindings." + ] + + smooth_idf = True + tf_type = 'raw_count' + + dictionary = OrderedDict() + + count = 0 + for line in string_encoding_input: + for word in re.split(' |,|\.', line): + if word and (not (word in dictionary)): + dictionary[word] = count + count += 1 + + def tokenizer(line): + return re.split(' |,|\.', line) + + if tf_type == 'raw_count': + binary = False + sublinear_tf = False + elif tf_type == 'binary': + binary = True + sublinear_tf = False + elif tf_type == 'sublinear_tf': + binary = False + sublinear_tf = True + + vectorizer = TfidfVectorizer(strip_accents=False, lowercase=False, + preprocessor=None, tokenizer=tokenizer, stop_words=None, + vocabulary=dictionary, binary=binary, norm=None, smooth_idf=smooth_idf, + sublinear_tf=sublinear_tf) + + X = vectorizer.fit_transform(string_encoding_input) + + def format_result(value): + if value == int(value): + return str(int(value)) + else: + return "{0:.8f}".format(value) + + for row in X.toarray(): + print("{ " + ", ".join(map(format_result, row)) + " },") + */ + arma::mat expected = { + { 1.28768207, 1.28768207, 1.69314718, 1.69314718, 1.69314718, 1, 1.69314718, + 1.28768207, 1.28768207, 1.28768207, 1.69314718, 1.69314718, 1.28768207, 1, + 1.69314718, 1.69314718, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 1.28768207, 0, 0, 0, 2, 0, 0, 3.86304622, 3.86304622, 0, 0, 0, 3, 0, + 0, 1.69314718, 1.69314718, 1.69314718, 5.07944154, 1.69314718, 1.69314718, + 1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718, + 1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718, + 1.69314718, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1.28768207, 0, 0, 0, 0, 1, 0, 1.28768207, 0, 0, 0, 0, 1.28768207, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.69314718, + 1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718, + 1.69314718, 1.69314718, 1.69314718 } + }; + + CheckMatrices(output, expected.t(), 1e-6); +} + +/** + * Test the Tf-Idf encoding algorithm with the raw count term frequency type + * and the smooth inverse document frequency type. These parameters are + * the default ones. The output type is vector>. + */ +BOOST_AUTO_TEST_CASE(VectorRawCountSmoothIdfEncodingTest) +{ + using DictionaryType = StringEncodingDictionary; + + vector> output; + TfIdfEncoding encoder( + (TfIdfEncodingPolicy())); + SplitByAnyOf tokenizer(" ,."); + + encoder.Encode(stringEncodingInput, output, tokenizer); + + const DictionaryType& dictionary = encoder.Dictionary(); + + // Checking that each token has a unique label. + std::unordered_map keysCount; + + for (auto& keyValue : dictionary.Mapping()) + { + keysCount[keyValue.second]++; + + BOOST_REQUIRE_EQUAL(keysCount[keyValue.second], 1); + } + + /* The expected values were obtained by the same script as in + RawCountSmoothIdfEncodingTest. */ + vector> expected = { + { 1.28768207, 1.28768207, 1.69314718, 1.69314718, 1.69314718, 1, 1.69314718, + 1.28768207, 1.28768207, 1.28768207, 1.69314718, 1.69314718, 1.28768207, 1, + 1.69314718, 1.69314718, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 1.28768207, 0, 0, 0, 2, 0, 0, 3.86304622, 3.86304622, 0, 0, 0, 3, 0, + 0, 1.69314718, 1.69314718, 1.69314718, 5.07944154, 1.69314718, 1.69314718, + 1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718, + 1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718, + 1.69314718, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1.28768207, 0, 0, 0, 0, 1, 0, 1.28768207, 0, 0, 0, 0, 1.28768207, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.69314718, + 1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718, 1.69314718, + 1.69314718, 1.69314718, 1.69314718 } + }; + CheckVectors(output, expected, 1e-6); +} + +/** + * Test the Tf-Idf encoding algorithm for individual characters with the + * raw count term frequency type and the smooth inverse document frequency type. + * These parameters are the default ones. + */ +BOOST_AUTO_TEST_CASE(RawCountSmoothIdfEncodingIndividualCharactersTest) +{ + vector input = { + "GACCA", + "ABCABCD", + "GAB" + }; + + arma::mat output; + TfIdfEncoding encoder; + + encoder.Encode(input, output, CharExtract()); + + /* The expected values were obtained by the following Python script: + + from sklearn.feature_extraction.text import TfidfVectorizer + from collections import OrderedDict + import re + + input_string = [ + "GACCA", + "ABCABCD", + "GAB" + ] + + smooth_idf = True + tf_type = 'raw_count' + + dictionary = OrderedDict() + + count = 0 + for line in input_string: + for word in list(line): + if word and (not (word in dictionary)): + dictionary[word] = count + count += 1 + + def tokenizer(line): + return list(line) + + if tf_type == 'raw_count': + binary = False + sublinear_tf = False + elif tf_type == 'binary': + binary = True + sublinear_tf = False + elif tf_type == 'sublinear_tf': + binary = False + sublinear_tf = True + + vectorizer = TfidfVectorizer(strip_accents=False, lowercase=False, + preprocessor=None, tokenizer=tokenizer, stop_words=None, + vocabulary=dictionary, binary=binary, norm=None, smooth_idf=smooth_idf, + sublinear_tf=sublinear_tf) + + X = vectorizer.fit_transform(input_string) + + def format_result(value): + if value == int(value): + return str(int(value)) + else: + return "{0:.14f}".format(value) + + for row in X.toarray(): + print("{ " + ", ".join(map(format_result, row)) + " },") + */ + arma::mat target = { + { 1.28768207245178, 2, 2.57536414490356, 0, 0 }, + { 0, 2, 2.57536414490356, 2.57536414490356, 1.69314718055995 }, + { 1.28768207245178, 1, 0, 1.28768207245178, 0 } + }; + + CheckMatrices(output, target.t(), 1e-12); +} + +/** + * Test the Tf-Idf encoding algorithm for individual characters with the + * raw count term frequency type and the smooth inverse document frequency type. + * These parameters are the default ones. The output type is + * vector>. + */ +BOOST_AUTO_TEST_CASE(VectorRawCountSmoothIdfEncodingIndividualCharactersTest) +{ + std::vector input = { + "GACCA", + "ABCABCD", + "GAB" + }; + + vector> output; + TfIdfEncoding encoder; + + encoder.Encode(input, output, CharExtract()); + + /* The expected values were obtained by the same script as in + RawCountSmoothIdfEncodingIndividualCharactersTest. */ + vector> expected = { + { 1.28768207245178, 2, 2.57536414490356, 0, 0 }, + { 0, 2, 2.57536414490356, 2.57536414490356, 1.69314718055995 }, + { 1.28768207245178, 1, 0, 1.28768207245178, 0 } + }; + + CheckVectors(output, expected, 1e-12); +} + +/** + * Test the Tf-Idf encoding algorithm with the raw count term frequency type + * and the non-smooth inverse document frequency type. + */ +BOOST_AUTO_TEST_CASE(TfIdfRawCountEncodingTest) +{ + using DictionaryType = StringEncodingDictionary; + + arma::mat output; + TfIdfEncoding encoder( + TfIdfEncodingPolicy(TfIdfEncodingPolicy::TfTypes::RAW_COUNT, false)); + SplitByAnyOf tokenizer(" ,."); + + encoder.Encode(stringEncodingInput, output, tokenizer); + + const DictionaryType& dictionary = encoder.Dictionary(); + + // Checking that each token has a unique label. + std::unordered_map keysCount; + + for (auto& keyValue : dictionary.Mapping()) + { + keysCount[keyValue.second]++; + + BOOST_REQUIRE_EQUAL(keysCount[keyValue.second], 1); + } + + /* The expected values were obtained by almost the same script as in + RawCountSmoothIdfEncodingTest. The only difference is smooth_idf equals + False. */ + arma::mat expected = { + { 1.40546511, 1.40546511, 2.09861229, 2.09861229, 2.09861229, 1, 2.09861229, + 1.40546511, 1.40546511, 1.40546511, 2.09861229, 2.09861229, 1.40546511, 1, + 2.09861229, 2.09861229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 1.40546511, 0, 0, 0, 2, 0, 0, 4.21639532, 4.21639532, 0, 0, 0, 3, 0, 0, + 2.09861229, 2.09861229, 2.09861229, 6.29583687, 2.09861229, 2.09861229, + 2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229, + 2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229, + 2.09861229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1.40546511, 0, 0, 0, 0, 1, 0, 1.40546511, 0, 0, 0, 0, 1.40546511, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.09861229, + 2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229, + 2.09861229, 2.09861229, 2.09861229 } + }; + + CheckMatrices(output, expected.t(), 1e-6); +} + +/** + * Test the Tf-Idf encoding algorithm with the raw count term frequency type + * and the non-smooth inverse document frequency type. The output type is + * vector>. + */ +BOOST_AUTO_TEST_CASE(VectorTfIdfRawCountEncodingTest) +{ + using DictionaryType = StringEncodingDictionary; + + vector> output; + TfIdfEncoding + encoder(TfIdfEncodingPolicy::TfTypes::RAW_COUNT, false); + SplitByAnyOf tokenizer(" ,."); + + encoder.Encode(stringEncodingInput, output, tokenizer); + + const DictionaryType& dictionary = encoder.Dictionary(); + + // Checking that each token has a unique label. + std::unordered_map keysCount; + for (auto& keyValue : dictionary.Mapping()) + { + keysCount[keyValue.second]++; + + BOOST_REQUIRE_EQUAL(keysCount[keyValue.second], 1); + } + + /* The expected values were obtained by almost the same script as in + RawCountSmoothIdfEncodingTest. The only difference is smooth_idf equals + False. */ + vector> expected = { + { 1.40546511, 1.40546511, 2.09861229, 2.09861229, 2.09861229, 1, 2.09861229, + 1.40546511, 1.40546511, 1.40546511, 2.09861229, 2.09861229, 1.40546511, 1, + 2.09861229, 2.09861229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 1.40546511, 0, 0, 0, 2, 0, 0, 4.21639532, 4.21639532, 0, 0, 0, 3, 0, 0, + 2.09861229, 2.09861229, 2.09861229, 6.29583687, 2.09861229, 2.09861229, + 2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229, + 2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229, + 2.09861229, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1.40546511, 0, 0, 0, 0, 1, 0, 1.40546511, 0, 0, 0, 0, 1.40546511, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.09861229, + 2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229, 2.09861229, + 2.09861229, 2.09861229, 2.09861229 } + }; + CheckVectors(output, expected, 1e-6); +} + +/** + * Test the Tf-Idf encoding algorithm for individual characters with the + * raw count term frequency type and the non-smooth inverse document frequency + * type. + */ +BOOST_AUTO_TEST_CASE(RawCountTfIdfEncodingIndividualCharactersTest) +{ + vector input = { + "GACCA", + "ABCABCD", + "GAB" + }; + + arma::mat output; + TfIdfEncoding encoder( + TfIdfEncodingPolicy::TfTypes::RAW_COUNT, false); + + encoder.Encode(input, output, CharExtract()); + + /* The expected values were obtained by almost the same script as in + RawCountSmoothIdfEncodingIndividualCharactersTest. The only difference is + smooth_idf equals False. */ + arma::mat target = { + { 1.40546510810816, 2, 2.81093021621633, 0, 0 }, + { 0, 2, 2.81093021621633, 2.81093021621633, 2.09861228866811 }, + { 1.40546510810816, 1, 0, 1.40546510810816, 0 } + }; + + CheckMatrices(output, target.t(), 1e-12); +} + +/** + * Test the Tf-Idf encoding algorithm for individual characters with the + * raw count term frequency type and the non-smooth inverse document frequency + * type. The output type is vector>. + */ +BOOST_AUTO_TEST_CASE(VectorRawCountTfIdfEncodingIndividualCharactersTest) +{ + std::vector input = { + "GACCA", + "ABCABCD", + "GAB" + }; + + vector> output; + TfIdfEncoding encoder( + TfIdfEncodingPolicy::TfTypes::RAW_COUNT, false); + + encoder.Encode(input, output, CharExtract()); + + /* The expected values were obtained by almost the same script as in + RawCountSmoothIdfEncodingIndividualCharactersTest. The only difference is + smooth_idf equals False. */ + vector> expected = { + { 1.40546510810816, 2, 2.81093021621633, 0, 0 }, + { 0, 2, 2.81093021621633, 2.81093021621633, 2.09861228866811 }, + { 1.40546510810816, 1, 0, 1.40546510810816, 0 } + }; + + CheckVectors(output, expected, 1e-12); +} + +/** + * Test the Tf-Idf encoding algorithm for individual characters with the + * binary term frequency type and the smooth inverse document frequency type. + */ +BOOST_AUTO_TEST_CASE(BinarySmoothIdfEncodingIndividualCharactersTest) +{ + vector input = { + "GACCA", + "ABCABCD", + "GAB" + }; + + arma::mat output; + TfIdfEncoding encoder( + TfIdfEncodingPolicy::TfTypes::BINARY, true); + + encoder.Encode(input, output, CharExtract()); + + /* The expected values were obtained by almost the same script as in + RawCountSmoothIdfEncodingIndividualCharactersTest. The only difference is + tf_type equals 'binary'. */ + arma::mat target = { + { 1.28768207245178, 1, 1.28768207245178, 0, 0 }, + { 0, 1, 1.28768207245178, 1.28768207245178, 1.69314718055995 }, + { 1.28768207245178, 1, 0, 1.28768207245178, 0 } + }; + + CheckMatrices(output, target.t(), 1e-12); +} + +/** + * Test the Tf-Idf encoding algorithm for individual characters with the + * binary term frequency type and the smooth inverse document frequency type. + * The output type is vector>. + */ +BOOST_AUTO_TEST_CASE(VectorBinarySmoothIdfEncodingIndividualCharactersTest) +{ + std::vector input = { + "GACCA", + "ABCABCD", + "GAB" + }; + + vector> output; + TfIdfEncoding + encoder(TfIdfEncodingPolicy::TfTypes::BINARY, true); + + encoder.Encode(input, output, CharExtract()); + + /* The expected values were obtained by almost the same script as in + RawCountSmoothIdfEncodingIndividualCharactersTest. The only difference is + tf_type equals 'binary'. */ + vector> expected = { + { 1.28768207245178, 1, 1.28768207245178, 0, 0 }, + { 0, 1, 1.28768207245178, 1.28768207245178, 1.69314718055995 }, + { 1.28768207245178, 1, 0, 1.28768207245178, 0 } + }; + + CheckVectors(output, expected, 1e-12); +} + +/** + * Test the Tf-Idf encoding algorithm for individual characters with the + * binary term frequency type and the non-smooth inverse document frequency + * type. + */ +BOOST_AUTO_TEST_CASE(BinaryTfIdfEncodingIndividualCharactersTest) +{ + vector input = { + "GACCA", + "ABCABCD", + "GAB" + }; + + arma::mat output; + TfIdfEncoding encoder( + TfIdfEncodingPolicy::TfTypes::BINARY, false); + + encoder.Encode(input, output, CharExtract()); + + /* The expected values were obtained by almost the same script as in + RawCountSmoothIdfEncodingIndividualCharactersTest. The only difference is + tf_type equals 'binary' and smooth_idf equals False. */ + arma::mat target = { + { 1.40546510810816, 1, 1.40546510810816, 0, 0 }, + { 0, 1, 1.40546510810816, 1.40546510810816, 2.09861228866811 }, + { 1.40546510810816, 1, 0, 1.40546510810816, 0 } + }; + + CheckMatrices(output, target.t(), 1e-12); +} + +/** + * Test the Tf-Idf encoding algorithm for individual characters with the + * sublinear term frequency type and the smooth inverse document frequency + * type. + */ +BOOST_AUTO_TEST_CASE(SublinearSmoothIdfEncodingIndividualCharactersTest) +{ + vector input = { + "GACCA", + "ABCABCD", + "GAB" + }; + + arma::mat output; + TfIdfEncoding encoder( + TfIdfEncodingPolicy::TfTypes::SUBLINEAR_TF, true); + + encoder.Encode(input, output, CharExtract()); + + /* The expected values were obtained by almost the same script as in + RawCountSmoothIdfEncodingIndividualCharactersTest. The only difference is + tf_type equals 'sublinear_tf'. */ + arma::mat target = { + { 1.28768207245178, 1.69314718055995, 2.18023527042932, 0, 0 }, + { 0, 1.69314718055995, 2.18023527042932, 2.18023527042932, + 1.69314718055995 }, + { 1.28768207245178, 1, 0, 1.28768207245178, 0 } + }; + + CheckMatrices(output, target.t(), 1e-12); +} + +/** + * Test the Tf-Idf encoding algorithm for individual characters with the + * sublinear term frequency type and the non-smooth inverse document frequency + * type. + */ +BOOST_AUTO_TEST_CASE(SublinearTfIdfEncodingIndividualCharactersTest) +{ + vector input = { + "GACCA", + "ABCABCD", + "GAB" + }; + + arma::mat output; + TfIdfEncoding + encoder(TfIdfEncodingPolicy::TfTypes::SUBLINEAR_TF, false); + + encoder.Encode(input, output, CharExtract()); + + /* The expected values were obtained by almost the same script as in + RawCountSmoothIdfEncodingIndividualCharactersTest. The only difference is + tf_type equals 'sublinear_tf' and smooth_idf equals False. */ + arma::mat target = { + { 1.40546510810816, 1.69314718055995, 2.37965928516872, 0, 0 }, + { 0, 1.69314718055995, 2.37965928516872, 2.37965928516872, + 2.09861228866811 }, + { 1.40546510810816, 1, 0, 1.40546510810816, 0 } + }; + + CheckMatrices(output, target.t(), 1e-12); +} + +/** + * Test the Tf-Idf encoding algorithm for individual characters with the + * standard term frequency type and the smooth inverse document frequency + * type. + */ +BOOST_AUTO_TEST_CASE(TermFrequencySmoothIdfEncodingIndividualCharactersTest) +{ + vector input = { + "GACCA", + "ABCABCD", + "GAB" + }; + + arma::mat output; + TfIdfEncoding encoder( + TfIdfEncodingPolicy::TfTypes::TERM_FREQUENCY, true); + + encoder.Encode(input, output, CharExtract()); + + /* The expected values were obtained by the following Python script: + + from sklearn.feature_extraction.text import CountVectorizer + from sklearn.feature_extraction.text import TfidfTransformer + from collections import OrderedDict + import numpy as np + import re + + input_string = [ + "GACCA", + "ABCABCD", + "GAB" + ] + + smooth_idf = True + + dictionary = OrderedDict() + + count = 0 + for line in input_string: + for word in list(line): + if word and (not (word in dictionary)): + dictionary[word] = count + count += 1 + + def tokenizer(line): + return list(line) + + vectorizer = CountVectorizer(strip_accents=False, lowercase=False, + preprocessor=None, tokenizer=tokenizer, stop_words=None, + vocabulary=dictionary, binary=False) + + count = vectorizer.fit_transform(input_string) + + lens = np.array(list(map(len, input_string))).reshape(len(input_string), 1) + + tf = count.toarray() / lens + + transformer = TfidfTransformer(norm=None, smooth_idf=smooth_idf, + sublinear_tf=False) + + X = transformer.fit_transform(tf) + + def format_result(value): + if value == int(value): + return str(int(value)) + else: + return "{0:.16}".format(value) + + for row in X.toarray(): + print("{ " + ", ".join(map(format_result, row)) + " },") + */ + arma::mat target = { + { 0.2575364144903562, 0.4, 0.5150728289807124, 0, 0 }, + { 0, 0.2857142857142857, 0.3679091635576516, 0.3679091635576516, + 0.2418781686514208 }, + { 0.4292273574839269, 0.3333333333333333, 0, 0.4292273574839269, 0 } + }; + + CheckMatrices(output, target.t(), 1e-12); +} + +/** + * Test the Tf-Idf encoding algorithm for individual characters with the + * standard term frequency type and the non-smooth inverse document frequency + * type. + */ +BOOST_AUTO_TEST_CASE(TermFrequencyTfIdfEncodingIndividualCharactersTest) +{ + vector input = { + "GACCA", + "ABCABCD", + "GAB" + }; + + arma::mat output; + TfIdfEncoding encoder( + TfIdfEncodingPolicy::TfTypes::TERM_FREQUENCY, false); + + encoder.Encode(input, output, CharExtract()); + + /* The expected values were obtained by almost the same script as in + TermFrequencySmoothIdfEncodingIndividualCharactersTest. The only difference + is smooth_idf equals False. */ + arma::mat target = { + { 0.2810930216216329, 0.4, 0.5621860432432658, 0, 0 }, + { 0, 0.2857142857142857, 0.4015614594594755, 0.4015614594594755, + 0.2998017555240157 }, + { 0.4684883693693881, 0.3333333333333333, 0, 0.4684883693693881, 0 } + }; + + CheckMatrices(output, target.t(), 1e-12); +} + +/** + * Serialization test for the Tf-Idf encoding algorithm with + * the SplitByAnyOf tokenizer. + */ +BOOST_AUTO_TEST_CASE(SplitByAnyOfTfIdfEncodingSerialization) +{ + using EncoderType = TfIdfEncoding; + + EncoderType encoder; + SplitByAnyOf tokenizer(" ,.\""); + arma::mat output; + + encoder.Encode(stringEncodingInput, output, tokenizer); + + EncoderType xmlEncoder, textEncoder, binaryEncoder; + arma::mat xmlOutput, textOutput, binaryOutput; + + SerializeObjectAll(encoder, xmlEncoder, textEncoder, binaryEncoder); + + CheckDictionaries(encoder.Dictionary(), xmlEncoder.Dictionary()); + CheckDictionaries(encoder.Dictionary(), textEncoder.Dictionary()); + CheckDictionaries(encoder.Dictionary(), binaryEncoder.Dictionary()); + + xmlEncoder.Encode(stringEncodingInput, xmlOutput, tokenizer); + textEncoder.Encode(stringEncodingInput, textOutput, tokenizer); + binaryEncoder.Encode(stringEncodingInput, binaryOutput, tokenizer); + + CheckMatrices(output, xmlOutput, textOutput, binaryOutput); +} + +BOOST_AUTO_TEST_SUITE_END(); + diff -Nru mlpack-3.2.2/src/mlpack/tests/tree_test.cpp mlpack-3.3.0/src/mlpack/tests/tree_test.cpp --- mlpack-3.2.2/src/mlpack/tests/tree_test.cpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/src/mlpack/tests/tree_test.cpp 2020-04-07 13:17:16.000000000 +0000 @@ -2129,12 +2129,15 @@ TreeType b(data); b.Begin() = 10; b.Count() = 50; + b.Left() = new TreeType(data); b.Left()->Begin() = 10; b.Left()->Count() = 30; + b.Left()->Parent() = &b; b.Right() = new TreeType(data); b.Right()->Begin() = 40; b.Right()->Count() = 20; + b.Right()->Parent() = &b; // Copy the tree. TreeType c(b); @@ -2159,6 +2162,11 @@ BOOST_REQUIRE_EQUAL(b.Right()->Left(), c.Right()->Left()); BOOST_REQUIRE_EQUAL(b.Right()->Right(), (TreeType*) NULL); BOOST_REQUIRE_EQUAL(b.Right()->Right(), c.Right()->Right()); + + // Clean memory (we built the tree by hand, so this is what we have to do + // since the destructor won't free the children's datasets). + delete &b.Left()->Dataset(); + delete &b.Right()->Dataset(); } //! Count the number of leaves under this node. diff -Nru mlpack-3.2.2/.travis/config.hpp mlpack-3.3.0/.travis/config.hpp --- mlpack-3.2.2/.travis/config.hpp 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/.travis/config.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,271 +0,0 @@ -// Copyright 2008-2016 Conrad Sanderson (http://conradsanderson.id.au) -// Copyright 2008-2016 National ICT Australia (NICTA) -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ------------------------------------------------------------------------ - - - -#if !defined(ARMA_USE_LAPACK) -#define ARMA_USE_LAPACK -//// Comment out the above line if you don't have LAPACK or a high-speed replacement for LAPACK, -//// such as Intel MKL, AMD ACML, or the Accelerate framework. -//// LAPACK is required for matrix decompositions (eg. SVD) and matrix inverse. -#endif - -#if !defined(ARMA_USE_BLAS) -#define ARMA_USE_BLAS -//// Comment out the above line if you don't have BLAS or a high-speed replacement for BLAS, -//// such as OpenBLAS, GotoBLAS, Intel MKL, AMD ACML, or the Accelerate framework. -//// BLAS is used for matrix multiplication. -//// Without BLAS, matrix multiplication will still work, but might be slower. -#endif - -#if !defined(ARMA_USE_NEWARP) -#define ARMA_USE_NEWARP -//// Uncomment the above line to enable the built-in partial emulation of ARPACK. -//// This is used for eigen decompositions of real (non-complex) sparse matrices, eg. eigs_sym(), svds() -#endif - -#if !defined(ARMA_USE_ARPACK) -// #define ARMA_USE_ARPACK -//// Uncomment the above line if you have ARPACK or a high-speed replacement for ARPACK. -//// ARPACK is required for eigen decompositions of complex sparse matrices -#endif - -#if !defined(ARMA_USE_SUPERLU) -// #define ARMA_USE_SUPERLU -//// Uncomment the above line if you have SuperLU. -//// SuperLU is used for solving sparse linear systems via spsolve() -//// Caveat: only SuperLU version 5.2 can be used! -#endif - -#if !defined(ARMA_SUPERLU_INCLUDE_DIR) -// #define ARMA_SUPERLU_INCLUDE_DIR /usr/include/ -//// If you're using SuperLU and want to explicitly include the SuperLU headers, -//// uncomment the above define and specify the appropriate include directory. -//// Make sure the directory has a trailing / -#endif - -#define ARMA_USE_WRAPPER -//// Comment out the above line if you're getting linking errors when compiling your programs, -//// or if you prefer to directly link with LAPACK, BLAS + etc instead of the Armadillo runtime library. -//// You will then need to link your programs directly with -llapack -lblas instead of -larmadillo - -// #define ARMA_BLAS_CAPITALS -//// Uncomment the above line if your BLAS and LAPACK libraries have capitalised function names (eg. ACML on 64-bit Windows) - -#define ARMA_BLAS_UNDERSCORE -//// Uncomment the above line if your BLAS and LAPACK libraries have function names with a trailing underscore. -//// Conversely, comment it out if the function names don't have a trailing underscore. - -// #define ARMA_BLAS_LONG -//// Uncomment the above line if your BLAS and LAPACK libraries use "long" instead of "int" - -// #define ARMA_BLAS_LONG_LONG -//// Uncomment the above line if your BLAS and LAPACK libraries use "long long" instead of "int" - -// #define ARMA_USE_TBB_ALLOC -//// Uncomment the above line if you want to use Intel TBB scalable_malloc() and scalable_free() instead of standard malloc() and free() - -// #define ARMA_USE_MKL_ALLOC -//// Uncomment the above line if you want to use Intel MKL mkl_malloc() and mkl_free() instead of standard malloc() and free() - -// #define ARMA_USE_ATLAS -// #define ARMA_ATLAS_INCLUDE_DIR /usr/include/ -//// If you're using ATLAS and the compiler can't find cblas.h and/or clapack.h -//// uncomment the above define and specify the appropriate include directory. -//// Make sure the directory has a trailing / - -#if !defined(ARMA_USE_CXX11) -#define ARMA_USE_CXX11 -//// Uncomment the above line to forcefully enable use of C++11 features (eg. initialiser lists). -//// Note that ARMA_USE_CXX11 is automatically enabled when a C++11 compiler is detected. -#endif - -#if !defined(ARMA_USE_OPENMP) -// #define ARMA_USE_OPENMP -//// Uncomment the above line to forcefully enable use of OpenMP for parallelisation. -//// Note that ARMA_USE_OPENMP is automatically enabled when a compiler supporting OpenMP 3.1 is detected. -#endif - -#if !defined(ARMA_64BIT_WORD) -#define ARMA_64BIT_WORD -//// Uncomment the above line if you require matrices/vectors capable of holding more than 4 billion elements. -//// Your machine and compiler must have support for 64 bit integers (eg. via "long" or "long long"). -//// Note that ARMA_64BIT_WORD is automatically enabled when a C++11 compiler is detected. -#endif - -#if !defined(ARMA_USE_HDF5) -// #define ARMA_USE_HDF5 -//// Uncomment the above line to allow the ability to save and load matrices stored in HDF5 format; -//// the hdf5.h header file must be available on your system, -//// and you will need to link with the hdf5 library (eg. -lhdf5) -#endif - -// #define ARMA_USE_HDF5_ALT -#if defined(ARMA_USE_HDF5_ALT) && defined(ARMA_USE_WRAPPER) - #undef ARMA_USE_HDF5 - #define ARMA_USE_HDF5 - - // #define ARMA_HDF5_INCLUDE_DIR /usr/include/ -#endif - -#if !defined(ARMA_MAT_PREALLOC) - #define ARMA_MAT_PREALLOC 16 -#endif -//// This is the number of preallocated elements used by matrices and vectors; -//// it must be an integer that is at least 1. -//// If you mainly use lots of very small vectors (eg. <= 4 elements), -//// change the number to the size of your vectors. - -#if !defined(ARMA_OPENMP_THRESHOLD) - #define ARMA_OPENMP_THRESHOLD 320 -#endif -//// The minimum number of elements in a matrix to allow OpenMP based parallelisation; -//// it must be an integer that is at least 1. - -#if !defined(ARMA_OPENMP_THREADS) - #define ARMA_OPENMP_THREADS 10 -#endif -//// The maximum number of threads to use for OpenMP based parallelisation; -//// it must be an integer that is at least 1. - -#if !defined(ARMA_SPMAT_CHUNKSIZE) - #define ARMA_SPMAT_CHUNKSIZE 256 -#endif -//// This is the minimum increase in the amount of memory (in terms of elements) allocated by a sparse matrix; -//// it must be an integer that is at least 1. -//// The minimum recommended size is 16. - -// #define ARMA_NO_DEBUG -//// Uncomment the above line if you want to disable all run-time checks. -//// This will result in faster code, but you first need to make sure that your code runs correctly! -//// We strongly recommend to have the run-time checks enabled during development, -//// as this greatly aids in finding mistakes in your code, and hence speeds up development. -//// We recommend that run-time checks be disabled _only_ for the shipped version of your program. - -// #define ARMA_EXTRA_DEBUG -//// Uncomment the above line if you want to see the function traces of how Armadillo evaluates expressions. -//// This is mainly useful for debugging of the library. - - -#if defined(ARMA_DEFAULT_OSTREAM) - #pragma message ("WARNING: support for ARMA_DEFAULT_OSTREAM is deprecated and will be removed;") - #pragma message ("WARNING: use ARMA_COUT_STREAM and ARMA_CERR_STREAM instead") -#endif - - -#if !defined(ARMA_COUT_STREAM) - #if defined(ARMA_DEFAULT_OSTREAM) - // for compatibility with earlier versions of Armadillo - #define ARMA_COUT_STREAM ARMA_DEFAULT_OSTREAM - #else - #define ARMA_COUT_STREAM std::cout - #endif -#endif - -#if !defined(ARMA_CERR_STREAM) - #if defined(ARMA_DEFAULT_OSTREAM) - // for compatibility with earlier versions of Armadillo - #define ARMA_CERR_STREAM ARMA_DEFAULT_OSTREAM - #else - #define ARMA_CERR_STREAM std::cerr - #endif -#endif - - -#if !defined(ARMA_PRINT_ERRORS) -#define ARMA_PRINT_ERRORS -//// Comment out the above line if you don't want errors and warnings printed (eg. failed decompositions) -#endif - -#if !defined(ARMA_PRINT_HDF5_ERRORS) -// #define ARMA_PRINT_HDF5_ERRORS -#endif - -#if defined(ARMA_DONT_USE_LAPACK) - #undef ARMA_USE_LAPACK -#endif - -#if defined(ARMA_DONT_USE_BLAS) - #undef ARMA_USE_BLAS -#endif - -#if defined(ARMA_DONT_USE_NEWARP) || !defined(ARMA_USE_LAPACK) - #undef ARMA_USE_NEWARP -#endif - -#if defined(ARMA_DONT_USE_ARPACK) - #undef ARMA_USE_ARPACK -#endif - -#if defined(ARMA_DONT_USE_SUPERLU) - #undef ARMA_USE_SUPERLU - #undef ARMA_SUPERLU_INCLUDE_DIR -#endif - -#if defined(ARMA_DONT_USE_ATLAS) - #undef ARMA_USE_ATLAS - #undef ARMA_ATLAS_INCLUDE_DIR -#endif - -#if defined(ARMA_DONT_USE_WRAPPER) - #undef ARMA_USE_WRAPPER - #undef ARMA_USE_HDF5_ALT -#endif - -#if defined(ARMA_DONT_USE_CXX11) - #undef ARMA_USE_CXX11 - #undef ARMA_USE_EXTERN_CXX11_RNG -#endif - -#if defined(ARMA_DONT_USE_OPENMP) - #undef ARMA_USE_OPENMP -#endif - -#if defined(ARMA_USE_WRAPPER) - #if defined(ARMA_USE_CXX11) - #if !defined(ARMA_USE_EXTERN_CXX11_RNG) - // #define ARMA_USE_EXTERN_CXX11_RNG - #endif - #endif -#endif - -#if defined(ARMA_DONT_USE_EXTERN_CXX11_RNG) - #undef ARMA_USE_EXTERN_CXX11_RNG -#endif - -#if defined(ARMA_32BIT_WORD) - #undef ARMA_64BIT_WORD -#endif - -#if defined(ARMA_DONT_USE_HDF5) - #undef ARMA_USE_HDF5 - #undef ARMA_USE_HDF5_ALT -#endif - -#if defined(ARMA_DONT_PRINT_ERRORS) - #undef ARMA_PRINT_ERRORS -#endif - -#if defined(ARMA_DONT_PRINT_HDF5_ERRORS) - #undef ARMA_PRINT_HDF5_ERRORS -#endif - - -// if Armadillo was installed on this system via CMake and ARMA_USE_WRAPPER is not defined, -// ARMA_AUX_LIBS lists the libraries required by Armadillo on this system, and -// ARMA_AUX_INCDIRS lists the include directories required by Armadillo on this system. -// Do not use these unless you know what you are doing. -#define ARMA_AUX_LIBS -#define ARMA_AUX_INCDIRS diff -Nru mlpack-3.2.2/.travis.yml mlpack-3.3.0/.travis.yml --- mlpack-3.2.2/.travis.yml 2019-11-26 15:26:58.000000000 +0000 +++ mlpack-3.3.0/.travis.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -language: cpp - -matrix: - include: - - os: linux - dist: xenial - env: CMAKE_OPTIONS="-DDEBUG=OFF -DPROFILE=OFF -DPYTHON_EXECUTABLE=/usr/bin/python" - before_install: - - sudo apt-get update - - sudo apt-get install -y --allow-unauthenticated libopenblas-dev liblapack-dev g++ libboost-all-dev python-pip cython python-numpy python-pandas xz-utils - - sudo pip install --upgrade --ignore-installed setuptools cython - - curl https://ftp.fau.de/macports/distfiles/armadillo/armadillo-8.400.0.tar.xz | tar -xvJ && cd armadillo* - - cmake . && make && sudo make install && cd .. - - sudo cp .travis/config.hpp /usr/include/armadillo_bits/config.hpp - - - os: linux - dist: xenial - env: CMAKE_OPTIONS="-DDEBUG=OFF -DPROFILE=OFF -DPYTHON_EXECUTABLE=/usr/bin/python3" - before_install: - - sudo apt-get update - - sudo apt-get install -y --allow-unauthenticated libopenblas-dev liblapack-dev g++ libboost-all-dev python3-pip cython3 python3-numpy xz-utils - - sudo pip3 install --upgrade --ignore-installed setuptools cython pandas - - curl https://ftp.fau.de/macports/distfiles/armadillo/armadillo-8.400.0.tar.xz | tar -xvJ && cd armadillo* - - cmake . && make && sudo make install && cd .. - - sudo cp .travis/config.hpp /usr/include/armadillo_bits/config.hpp - - - os: linux - dist: xenial - env: CMAKE_OPTIONS="-DDEBUG=ON -DPROFILE=OFF -DBUILD_PYTHON_BINDINGS=OFF" - before_install: - - sudo apt-get update - - sudo apt-get install -y --allow-unauthenticated libopenblas-dev liblapack-dev g++ libboost-all-dev xz-utils - - curl https://ftp.fau.de/macports/distfiles/armadillo/armadillo-8.400.0.tar.xz | tar -xvJ && cd armadillo* - - cmake . && make && sudo make install && cd .. - - sudo cp .travis/config.hpp /usr/include/armadillo_bits/config.hpp - - - os: osx - osx_image: xcode9.4 # Maybe we can try some different ones? - env: CMAKE_OPTIONS="-DDEBUG=ON -DPROFILE=OFF -DBUILD_PYTHON_BINDINGS=OFF" - before_install: - - brew install openblas armadillo || brew install openblas armadillo - -install: - - mkdir build && cd build && cmake $CMAKE_OPTIONS .. && travis_wait 75 make -j2 - -script: - - CTEST_OUTPUT_ON_FAILURE=1 travis_wait 30 ctest -j2 - -notifications: - email: - - mlpack-git@lists.mlpack.org - irc: - channels: - - "chat.freenode.net#mlpack" - on_success: change - on_failure: always