diff --git a/.appveyor.yml b/.appveyor.yml
deleted file mode 100644
index 722a597468..0000000000
--- a/.appveyor.yml
+++ /dev/null
@@ -1,219 +0,0 @@
-clone_depth: 10
-
-environment:
- BOOST_MATH : "C:/projects/mlpack/\
- boost_math_c99-vc140.1.60.0.0/lib/native/address-model-64/lib/*.*"
- BOOST_RANDOM : "C:/projects/mlpack/\
- boost_random-vc140.1.60.0.0/lib/native/address-model-64/lib/*.*"
- ARMADILLO_DOWNLOAD : "https://data.kurg.org/armadillo-8.400.0.tar.xz"
- ARMADILLO_LIBRARY : "C:/projects/mlpack/armadillo-8.400.0/\
- build/Debug/armadillo.lib"
- BLAS_LIBRARY : "%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/\
- libopenblas.dll.a"
- BOOST_INCLUDE : "C:/projects/mlpack/boost.1.60.0.0/lib/native/include"
- JENKINS_DOC_DOWNLOAD : "http://ci.mlpack.org/job/mlpack%20-%20doxygen%20\
- build/lastSuccessfulBuild/artifact/build/doc/html/*zip*/html.zip"
- JENKINS_DOC : "C:/projects/mlpack/dist/win-installer/jenkinsdoc.zip"
- GIT_VERSION_FILE : "C:/projects/mlpack/src/mlpack/core/util/gitversion.hpp"
- matrix:
- - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
- VSVER: Visual Studio 16 2019
- MSBUILD: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe
-
-# We have removed the VS studio 15 2017 build since it is not possible to complete
-# or finish the build due to the `compiler out of heap space issues`.
-# Therefore, in the meanwhile, we are only doing the installation for VS 16 2019.
-
-configuration: Release
-
-os: Visual Studio 2019
-
-install:
- - ps: nuget install boost -o "${env:APPVEYOR_BUILD_FOLDER}" -Version 1.60.0
- - ps: >
- nuget install boost_random-vc140
- -o "${env:APPVEYOR_BUILD_FOLDER}" -Version 1.60.0
- - ps: >
- nuget install boost_math_c99-vc140
- -o "${env:APPVEYOR_BUILD_FOLDER}" -Version 1.60.0
- - ps: >
- nuget install unofficial-flayan-cereal
- -o "${env:APPVEYOR_BUILD_FOLDER}"
- - ps: nuget install OpenBLAS -o "${env:APPVEYOR_BUILD_FOLDER}"
- - set path=C:\Program Files (x86)\WiX Toolset v3.11\bin;%path%
-
-build_script:
- - mkdir boost_libs
- - ps: cp ${env:BOOST_MATH} C:\projects\mlpack\boost_libs\
- - ps: cp ${env:BOOST_RANDOM} C:\projects\mlpack\boost_libs\
- - echo TEST_ARMA is %ARMADILLO_DOWNLOAD%
- - >
- appveyor DownloadFile %ARMADILLO_DOWNLOAD%
- -FileName armadillo.tar.xz
- - 7z x armadillo.tar.xz -so -txz | 7z x -si -ttar > nul
- - cd armadillo-8.400.0 && mkdir build && cd build
- - >
- cmake -G "%VSVER%"
- -DBLAS_LIBRARY:FILEPATH=%BLAS_LIBRARY%
- -DLAPACK_LIBRARY:FILEPATH=%BLAS_LIBRARY%
- -DCMAKE_PREFIX:FILEPATH="%APPVEYOR_BUILD_FOLDER%/armadillo"
- -DBUILD_SHARED_LIBS=OFF
- -DCMAKE_BUILD_TYPE=Release ..
- - >
- "%MSBUILD%" "C:\projects\mlpack\armadillo-8.400.0\build\armadillo.sln"
- /m /verbosity:quiet /p:Configuration=Release;Platform=x64
- - cd C:\projects\mlpack && mkdir build && cd build
- - >
- cmake -G "%VSVER%"
- -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%
- -DCEREAL_INCLUDE_DIR="C:/projects/mlpack/unofficial-flayan-cereal.1.2.2/build/native/include"
- -DBOOST_INCLUDEDIR:PATH=%BOOST_INCLUDE%
- -DDEBUG=OFF
- -DPROFILE=OFF
- -DBUILD_PYTHON_BINDINGS=OFF
- -DBUILD_GO_BINDINGS=OFF
- -DBUILD_R_BINDINGS=OFF
- -DBUILD_TESTS=OFF
- -DCMAKE_BUILD_TYPE=Release ..
- - >
- "%MSBUILD%" "C:\projects\mlpack\build\mlpack.sln"
- /m /verbosity:minimal /nologo /p:BuildInParallel=true
- /p:Configuration=Release;Platform=x64
-
- # Zip Artifacts.
- - >
- 7z a mlpack-windows-no-libs.zip
- "%APPVEYOR_BUILD_FOLDER%\build\Release\*.exe"
- - >
- 7z a mlpack-windows.zip
- "%APPVEYOR_BUILD_FOLDER%\build\Release\*.*"
- "%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/*.*"
-
- # Pulling documentation for the installer.
- - ps: >
- try{(new-object net.webclient).DownloadFile(${env:JENKINS_DOC_DOWNLOAD},
- 'C:\projects\mlpack\dist\win-installer\jenkinsdoc.zip')}
- catch{Write-Output "Unable to pull jenkins doc, skipping!"}
- - ps: >
- try{(Add-Type -AssemblyName System.IO.Compression.FileSystem);
- [System.IO.Compression.ZipFile]::ExtractToDirectory(${env:JENKINS_DOC},
- 'C:\projects\mlpack\dist\win-installer\staging\doc')}
- catch{Write-Output "Unable to add doc to installer, skipping!"}
-
- # Preparing installer staging.
- - cd C:\projects\mlpack\dist\win-installer\staging && mkdir lib
- - ps: >
- cp C:\projects\mlpack\build\Release\*.lib
- C:\projects\mlpack\dist\win-installer\staging\lib\
- - ps: >
- cp C:\projects\mlpack\build\Release\*.exp
- C:\projects\mlpack\dist\win-installer\staging\lib\
- - ps: >
- cp C:\projects\mlpack\build\Release\*.dll
- C:\projects\mlpack\dist\win-installer\staging\
- - ps: >
- cp C:\projects\mlpack\build\Release\*.exe
- C:\projects\mlpack\dist\win-installer\staging\
- - ps: >
- cp C:\projects\mlpack\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.dll
- C:\projects\mlpack\dist\win-installer\staging\
- - ps: >
- cp C:\projects\mlpack\build\include\mlpack
- C:\projects\mlpack\dist\win-installer\staging -recurse
- - ps: >
- cp C:\projects\mlpack\doc\examples
- C:\projects\mlpack\dist\win-installer\staging -recurse
- - ps: >
- cp C:\projects\mlpack\src\mlpack\tests\data\german.csv
- C:\projects\mlpack\dist\win-installer\staging\examples\sample-ml-app\sample-ml-app\data\
-
- # Checking current gitversion or mlpack version.
- - ps: >
- $ver = (Get-Content
- "${env:APPVEYOR_BUILD_FOLDER}\src\mlpack\core\util\version.hpp" |
- where {$_ -like "*MLPACK_VERSION*"});
- $env:MLPACK_VERSION += $ver[0].substring($ver[0].length - 1, 1) + '.';
- $env:MLPACK_VERSION += $ver[1].substring($ver[1].length - 1, 1) + '.';
- $env:MLPACK_VERSION += $ver[2].substring($ver[2].length - 1, 1);
-
- if (Test-Path ${env:GIT_VERSION_FILE})
- {
- $ver = (Get-Content ${env:GIT_VERSION_FILE});
- $env:INSTALL_VERSION = $ver.Split('"')[1].Split(' ')[1];
- }
- else
- {
- $env:INSTALL_VERSION = $env:MLPACK_VERSION;
- }
- - echo INSTALL_VERSION is %INSTALL_VERSION%
-
- # Building MSI installer.
- - cd C:\projects\mlpack\dist\win-installer\mlpack-win-installer
- - >
- heat dir ..\staging
- -cg HeatGenerated
- -dr INSTALLFOLDER
- -sreg
- -srd
- -var var.HarvestPath
- -ag
- -sfrag
- -out HeatGeneratedFileList.wxs
- - >
- candle -dHarvestPath=..\staging
- -dConfiguration=Release
- -dOutDir=bin\x64\Release\
- -dPlatform=x64
- -dProjectDir=.
- -dProjectExt=.wixproj
- -dProjectFileName=mlpack-win-installer.wixproj
- -dProjectName=mlpack-win-installer
- -dProjectPath=mlpack-win-installer.wixproj
- -dTargetDir=.\bin\x64\Release\
- -dTargetExt=.msi
- -dTargetFileName=mlpack-windows.msi
- -dTargetName=mlpack-windows
- -dTargetPath=.\bin\x64\Release\mlpack-windows.msi
- -out obj\x64\Release\
- -arch x64
- -ext "C:\Program Files (x86)\WiX Toolset v3.11\bin\\WixUIExtension.dll"
- Product.wxs HeatGeneratedFileList.wxs
- - >
- light -out .\bin\x64\Release\mlpack-%INSTALL_VERSION%.msi
- -pdbout .\bin\x64\Release\mlpack-windows.wixpdb
- -cultures:null
- -loc mlpack-localization.wxl
- -ext "C:\Program Files (x86)\WiX Toolset v3.11\bin\\WixUIExtension.dll"
- -contentsfile
- obj\x64\Release\mlpack-win-installer.wixproj.BindContentsFileListnull.txt
- -outputsfile
- obj\x64\Release\mlpack-win-installer.wixproj.BindOutputsFileListnull.txt
- -builtoutputsfile
- obj\x64\Release\mlpack-win-installer.wixproj.BindBuiltOutputsFileListnull.txt
- -wixprojectfile
- mlpack-win-installer.wixproj
- obj\x64\Release\Product.wixobj
- obj\x64\Release\HeatGeneratedFileList.wixobj
-
-artifacts:
- - path: 'build\*.zip'
- name: mlpack-windows-zip
-
- - path: 'dist\win-installer\mlpack-win-installer\bin\x64\Release\*.msi'
- name: mlpack-windows-installer
-
-notifications:
-- provider: Email
- to:
- - mlpack-git@lists.mlpack.org
- on_build_success: true
- on_build_failure: true
- on_build_status_changed: true
-
-cache:
- - packages -> **\packages.config
- - armadillo.tar.xz -> appveyor.yaml
-
diff --git a/CMake/FindMatlabMex.cmake b/CMake/FindMatlabMex.cmake
deleted file mode 100644
index 43b342c4a5..0000000000
--- a/CMake/FindMatlabMex.cmake
+++ /dev/null
@@ -1,110 +0,0 @@
-# This module looks for mex, the MATLAB compiler.
-# The following variables are defined when the script completes:
-# MATLAB_MEX: location of mex compiler
-# MATLAB_ROOT: root of MATLAB installation
-# MATLABMEX_FOUND: 0 if not found, 1 if found
-
-set(MATLABMEX_FOUND 0)
-
-if(WIN32)
- # This is untested but taken from the older FindMatlab.cmake script as well as
- # the modifications by Ramon Casero and Tom Doel for Gerardus.
-
- # Search for a version of Matlab available, starting from the most modern one
- # to older versions.
- foreach(MATVER "7.20" "7.19" "7.18" "7.17" "7.16" "7.15" "7.14" "7.13" "7.12"
-"7.11" "7.10" "7.9" "7.8" "7.7" "7.6" "7.5" "7.4")
- if((NOT DEFINED MATLAB_ROOT)
- OR ("${MATLAB_ROOT}" STREQUAL "")
- OR ("${MATLAB_ROOT}" STREQUAL "/registry"))
- get_filename_component(MATLAB_ROOT
- "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB\\${MATVER};MATLABROOT]"
- ABSOLUTE)
- set(MATLAB_VERSION ${MATVER})
- endif()
- OR ("${MATLAB_ROOT}" STREQUAL "")
- OR ("${MATLAB_ROOT}" STREQUAL "/registry"))
- endforeach()
-
- find_program(MATLAB_MEX
- mex
- ${MATLAB_ROOT}/bin
- )
-else()
- # Check if this is a Mac.
- if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
- # This code is untested but taken from the older FindMatlab.cmake script as
- # well as the modifications by Ramon Casero and Tom Doel for Gerardus.
-
- set(LIBRARY_EXTENSION .dylib)
-
- # If this is a Mac and the attempts to find MATLAB_ROOT have so far failed,~
- # we look in the applications folder
- if((NOT DEFINED MATLAB_ROOT) OR ("${MATLAB_ROOT}" STREQUAL ""))
-
- # Search for a version of Matlab available, starting from the most modern
- # one to older versions
- foreach(MATVER "R2013b" "R2013a" "R2012b" "R2012a" "R2011b" "R2011a"
-"R2010b" "R2010a" "R2009b" "R2009a" "R2008b")
- if((NOT DEFINED MATLAB_ROOT) OR ("${MATLAB_ROOT}" STREQUAL ""))
- if(EXISTS /Applications/MATLAB_${MATVER}.app)
- set(MATLAB_ROOT /Applications/MATLAB_${MATVER}.app)
-
- endif()
- endif()
- endforeach()
-
- endif()
-
- find_program(MATLAB_MEX
- mex
- PATHS
- ${MATLAB_ROOT}/bin
- )
-
- else()
- # On a Linux system. The goal is to find MATLAB_ROOT.
- set(LIBRARY_EXTENSION .so)
-
- find_program(MATLAB_MEX_POSSIBLE_LINK
- mex
- PATHS
- ${MATLAB_ROOT}/bin
- /opt/matlab/bin
- /usr/local/matlab/bin
- $ENV{HOME}/matlab/bin
- # Now all the versions
- /opt/matlab/[rR]20[0-9][0-9][abAB]/bin
- /usr/local/matlab/[rR]20[0-9][0-9][abAB]/bin
- /opt/matlab-[rR]20[0-9][0-9][abAB]/bin
- /opt/matlab_[rR]20[0-9][0-9][abAB]/bin
- /usr/local/matlab-[rR]20[0-9][0-9][abAB]/bin
- /usr/local/matlab_[rR]20[0-9][0-9][abAB]/bin
- $ENV{HOME}/matlab/[rR]20[0-9][0-9][abAB]/bin
- $ENV{HOME}/matlab-[rR]20[0-9][0-9][abAB]/bin
- $ENV{HOME}/matlab_[rR]20[0-9][0-9][abAB]/bin
- )
-
- get_filename_component(MATLAB_MEX "${MATLAB_MEX_POSSIBLE_LINK}" REALPATH)
- get_filename_component(MATLAB_BIN_ROOT "${MATLAB_MEX}" PATH)
- # Strip ./bin/.
- get_filename_component(MATLAB_ROOT "${MATLAB_BIN_ROOT}" PATH)
- endif()
-endif()
-
-if(NOT EXISTS "${MATLAB_MEX}" AND "${MatlabMex_FIND_REQUIRED}")
- message(FATAL_ERROR "Could not find MATLAB mex compiler; try specifying MATLAB_ROOT.")
-else()
- if(EXISTS "${MATLAB_MEX}")
- message(STATUS "Found MATLAB mex compiler: ${MATLAB_MEX}")
- message(STATUS "MATLAB root: ${MATLAB_ROOT}")
- set(MATLABMEX_FOUND 1)
- endif()
-endif()
-
-mark_as_advanced(
- MATLAB_MEX
- MATLABMEX_FOUND
- MATLAB_ROOT
-)
-
diff --git a/CMake/go/AppendModel.cmake b/CMake/go/AppendModel.cmake
index eeb28f7ada..ec85510239 100644
--- a/CMake/go/AppendModel.cmake
+++ b/CMake/go/AppendModel.cmake
@@ -44,8 +44,8 @@ function(append_model SERIALIZATION_FILE PROGRAM_MAIN_FILE)
else ()
string(APPEND GOMODEL_SAFE_TYPE ${MODEL_CHAR})
endif()
- endif()
- endforeach()
+ endforeach()
+ endif()
# See if the model type already exists.
file(READ "${SERIALIZATION_FILE}" SERIALIZATION_FILE_CONTENTS)
@@ -77,7 +77,7 @@ function(append_model SERIALIZATION_FILE PROGRAM_MAIN_FILE)
" C.mlpackSet${MODEL_SAFE_TYPE}"
"Ptr(C.CString(identifier), (unsafe.Pointer)(ptr.mem))\n"
"}\n\n")
- endif ()
+ endif()
endforeach ()
endif()
endfunction()
diff --git a/CMake/mlpack_coverage.in b/CMake/mlpack_coverage.in
deleted file mode 100755
index b67ecf3cc1..0000000000
--- a/CMake/mlpack_coverage.in
+++ /dev/null
@@ -1,135 +0,0 @@
-#!/bin/bash
-# This script gets the test coverage for mlpack_test.
-test_case="ALL"
-gcov_loc=""
-token=""
-clean=true
-current_log_file=`date +'%Y.%h.%d:%H:%M:%S-coverage.log'`
-current_coverage_file=`date +'%Y.%h.%d:%H:%M:%S-coverage.info'`
-max_cov_count=50000
-
-# default directories
-root_dir="../"
-
-# Extract arguments.
-for i in "$@"
-do
-case $i in
- -h|--help)
- echo "Usage: mlpack_coverage --help|-h"
- echo " mlpack_coverage [-r=test_suite] [-g=gcov_tool_location]"
- echo " [--token=coveralls_token]"
- echo "Optional parameters:"
- echo " -n|--no_test Do not run test before coverage computation"
- echo " -r|--run_test Run tests with specific test suite"
- echo " --no_clean Do not remove existing gcda file"
- echo " -g|--gcov_tool_location Gcov location if not default"
- echo " -t|--token Upload to coveralls with given token"
- echo " --max_cov_count Max line coverage count (default 50000)"
- echo " --root_dir Set the root directory from which gcov will be called. (default ../)"
- exit 0
- shift
- ;;
- -n|--no_test)
- test_case=""
- shift
- ;;
- -r=*|--run_test=*)
- test_case="${i#*=}"
- shift # past argument=value
- ;;
- --no_clean)
- clean=false
- shift
- ;;
- -g=*|--gcov_tool_location=*)
- gcov_loc="${i#*=}"
- shift # past argument=value
- ;;
- -t=*|--token=*)
- token="${i#*=}"
- shift # past argument=value
- ;;
- --max_cov_count)
- max_cov_count="${i#*=}"
- shift
- ;;
- --root_dir=*)
- root_dir="${i#*=}"
- shift
- ;;
- *)
- # unknown option
- ;;
-esac
-done
-
-if [ "$clean" = true ]; then
- echo "Deleting existing coverage data..."
- find ./ -name "*.gcda" -type f -delete
-fi
-
-# Initial pass.
-echo "Generating primary coverage report."
-[[ -d ./coveragehistory/ ]] || mkdir coveragehistory
-lcov -b . -c -i -d ./ -o .coverage.wtest.base > ./coveragehistory/$current_log_file
-
-# Run the tests.
-if [ "$test_case" = "ALL" ]; then
- echo "Running all the tests..."
- "@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
-fi
-
-# Generate coverage based on executed tests.
-echo "Computing coverage..."
-if [ "$gcov_loc" = "" ];
-then lcov -b . -c -d ./ -o .coverage.wtest.run >> ./coveragehistory/$current_log_file
-else
- lcov -b . -c -d ./ -o .coverage.wtest.run --gcov-tool=$gcov_loc >> ./coveragehistory/$current_log_file
-fi
-
-echo "Filtering coverage files..."
-# Clear negative entries in coverage file
-sed -E 's/-([0-9]+)/$max_cov_count/g' -i .coverage.wtest.run
-# Merge coverage tracefiles.
-lcov -a .coverage.wtest.base -a .coverage.wtest.run -o .coverage.total >> ./coveragehistory/$current_log_file
-
-# Filtering, extracting project files.
-lcov -e .coverage.total "@CMAKE_CURRENT_SOURCE_DIR@/src/mlpack/*" -o .coverage.total.filtered >> ./coveragehistory/$current_log_file
-
-# Filtering, removing test-files and main.cpp.
-lcov -r .coverage.total.filtered "@CMAKE_CURRENT_SOURCE_DIR@/src/mlpack/*/*_main.cpp" -o .coverage.total.filtered >> ./coveragehistory/$current_log_file
-lcov -r .coverage.total.filtered "@CMAKE_CURRENT_SOURCE_DIR@/src/mlpack/tests/*" -o .coverage.total.filtered >> ./coveragehistory/$current_log_file
-
-# Remove untestable files.
-lcov -r .coverage.total.filtered "@CMAKE_CURRENT_SOURCE_DIR@/src/mlpack/core/util/gitversion.hpp" -o .coverage.total.filtered >> ./coveragehistory/$current_log_file
-lcov -r .coverage.total.filtered "@CMAKE_CURRENT_SOURCE_DIR@/src/mlpack/core/util/arma_config.hpp" -o .coverage.total.filtered >> ./coveragehistory/$current_log_file
-
-# Extra: Replace /build/ with /src/ to unify directories.
-cat .coverage.total.filtered > .coverage.total
-
-# Extra: Clear up previous data, create html folder.
-if [[ -d ./coverage/ ]] ; then
- rm -rf ./coverage/*
-else
- mkdir coverage
-fi
-
-# Step 9: Generate webpage.
-genhtml -o ./coverage/ .coverage.total
-
-# Extra: Preserve coverage file in coveragehistory folder.
-coverage_file=$current_coverage_file
-cp .coverage.total ./coveragehistory/$current_coverage_file
-
-# Clean temporary coverage files.
-#rm .coverage.*
-
-# Upload the result to coveralls if token is provided.
-if ! [ "$token" = "" ]; then
- cpp-coveralls -n -r $root_dir -b $root_dir -l ./coveragehistory/$current_coverage_file -t "$token" --max-cov-count $max_cov_count
-fi
-
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2ecd13769c..73937c2a4b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,7 +9,6 @@ include(CMake/CheckHash.cmake)
option(DEBUG "Compile with debugging information." OFF)
option(PROFILE "Compile with profiling information." OFF)
option(ARMA_EXTRA_DEBUG "Compile with extra Armadillo debugging symbols." OFF)
-option(MATLAB_BINDINGS "Compile MATLAB bindings if MATLAB is found." OFF)
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)
@@ -80,8 +79,6 @@ option(BUILD_R_BINDINGS "Build R bindings." OFF)
# generation.
option(BUILD_MARKDOWN_BINDINGS "Build Markdown bindings for website documentation." OFF)
-option(BUILD_WITH_COVERAGE
- "Build with support for code coverage tools (gcc only)." OFF)
option(MATHJAX
"Use MathJax for HTML Doxygen output (disabled by default)." OFF)
option(FORCE_CXX11
@@ -196,38 +193,6 @@ if(CMAKE_COMPILER_IS_GNUCC)
${CMAKE_THREAD_LIBS_INIT})
endif()
-# Setup build for test coverage
-if(BUILD_WITH_COVERAGE)
- # Currently coverage only works with GNU g++.
- if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
- # Find gcov and lcov
- find_program(GCOV gcov)
- find_program(LCOV lcov)
-
- if(NOT GCOV)
- message(FATAL_ERROR
- "gcov not found! gcov is required when BUILD_WITH_COVERAGE=ON.")
- 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
- set(DEBUG ON)
-
- if(LCOV)
- configure_file(CMake/mlpack_coverage.in mlpack_coverage @ONLY)
- add_custom_target(mlpack_coverage DEPENDS mlpack_test COMMAND ${PROJECT_BINARY_DIR}/mlpack_coverage)
- else()
- message(WARNING "'lcov' not found; local coverage report is disabled. "
- "Install 'lcov' and rerun cmake to generate local coverage report.")
- endif()
- else()
- message(FATAL_ERROR "BUILD_WITH_COVERAGE can only work with GNU environment.")
- endif()
-endif()
-
# Debugging CFLAGS. Turn optimizations off; turn debugging symbols on.
if(DEBUG)
if (NOT MSVC)
diff --git a/HISTORY.md b/HISTORY.md
index f0b696d6ac..2f7aab9538 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,5 +1,8 @@
### mlpack ?.?.?
###### ????-??-??
+ * Added warm start feature to Random Forest (#2881); this feature is
+ accessible from mlpack's bindings to different languages.
+
* Added Pixel Shuffle layer (#2563).
* Add "check_input_matrices" option to python bindings that checks
@@ -37,6 +40,12 @@
* Add `Lambda1()`, `Lambda2()`, `UseCholesky()`, and `Tolerance()` members to
`LARS` so parameters for training can be modified (#2861).
+ * Remove unused `ElemType` template parameter from `DecisionTree` and
+ `RandomForest` (#2874).
+
+ * Fix Python binding build when the CMake variable `USE_OPENMP` is set to
+ `OFF` (#2884).
+
### mlpack 3.4.2
###### 2020-10-26
* Added Mean Absolute Percentage Error.
diff --git a/README.md b/README.md
index bb8ba1be6c..21b9e09e7e 100644
--- a/README.md
+++ b/README.md
@@ -14,8 +14,7 @@ src="https://cdn.rawgit.com/mlpack/mlpack.org/e7d36ed8/mlpack-black.svg" style="
-
-
+
@@ -142,10 +141,10 @@ If you are compiling Armadillo by hand, ensure that LAPACK and BLAS are enabled.
### 4. Building mlpack from source
-This document discusses how to build mlpack from source. These build directions
+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,
+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 the mlpack library and command-line executables (e.g.
mlpack_pca, mlpack_kmeans etc.) with the following command:
@@ -183,7 +182,7 @@ sufficient.
The next step is to run CMake to configure the project. Running CMake is the
equivalent to running `./configure` with autotools. If you run CMake with no
-options, it will configure the project to build with no debugging symbols and
+options, it will configure the project to build with no debugging symbols and
no profiling information:
$ cmake ../
@@ -239,7 +238,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
+If you do not want to build everything in the library, individual components
of the build can be specified:
$ make mlpack_pca mlpack_knn mlpack_kfn
@@ -252,7 +251,7 @@ and submit an issue. The mlpack developers will quickly help you figure it out:
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
+and `/usr/local/bin/`, make sure you have root privileges (or write permissions
to those three directories), and simply type
$ make install
diff --git a/doc/guide/build.hpp b/doc/guide/build.hpp
index 9996f5132d..9356f725cc 100644
--- a/doc/guide/build.hpp
+++ b/doc/guide/build.hpp
@@ -191,8 +191,6 @@ The full list of options mlpack allows:
- 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_INSTALL_PREFIX=(/path/to/python/): Path to root of Python installation
- JULIA_EXECUTABLE=(/path/to/julia): Path to specific Julia executable
diff --git a/doc/tutorials/linear_regression/linear_regression.txt b/doc/tutorials/linear_regression/linear_regression.txt
index a0baec8ec3..751ff0c935 100644
--- a/doc/tutorials/linear_regression/linear_regression.txt
+++ b/doc/tutorials/linear_regression/linear_regression.txt
@@ -46,6 +46,7 @@ A list of all the sections this tutorial contains.
- \ref cli_ex2_lrtut
- \ref cli_ex3_lrtut
- \ref cli_ex4_lrtut
+ - \ref cli_ex5_lrtut
- \ref linreg_lrtut
- \ref linreg_ex1_lrtut
- \ref linreg_ex2_lrtut
@@ -113,22 +114,23 @@ $ cat dataset.csv
4,4
$ cat lr.xml
-
-
-
-
-
- 2
- 1
- 2
- 1
- - -3.97205464519563669e-16
- - 1.00000000000000022e+00
-
- 0.00000000000000000e+00
- 1
-
-
+
+
+
+ 0
+
+ 2
+ 1
+ 1
+ 0
+ 1
+
+ 0
+ true
+
+
+
+
@endcode
As you can see, the function for this input is \f$f(y)=0+1x_1\f$. We can see
@@ -141,36 +143,102 @@ dataset is one dimensional, and the last column has the \f$y\f$ values, or
responses, for each row. You can specify these responses in a separate file if
you want, using the \c --input_responses, or \c -r, option.
-@subsection cli_ex2_lrtut Compute model and predict at the same time
+@subsection cli_ex2_lrtut Train a multivariate linear regression model
+
+Multivariate linear regression means that the response variable is predicted by
+more than just one input variable. In this example we will try to fit a
+multivariate linear regression model to data that contains four variables, stored in
+\c dataset_2.csv.
@code
-$ mlpack_linear_regression --training_file dataset.csv --test_file predict.csv \
+$ cat dataset_2.csv
+0,0,0,0,14
+1,1,1,1,24
+2,1,0,2,27
+1,2,2,2,32
+-1,-3,0,2,17
+@endcode
+
+Now let's run \c mlpack_linear_regression as usual:
+
+@code
+$ mlpack_linear_regression --training_file dataset_2.csv -v -M lr.xml
+[INFO ] Loading 'dataset_2.csv' as CSV data. Size is 5 x 5.
+[INFO ]
+[INFO ] Execution parameters:
+[INFO ] help: 0
+[INFO ] info:
+[INFO ] input_model_file:
+[INFO ] lambda: 0
+[INFO ] output_model_file: lr.xml
+[INFO ] output_predictions_file:
+[INFO ] test_file:
+[INFO ] training_file: dataset_2.csv
+[INFO ] training_responses_file:
+[INFO ] verbose: 1
+[INFO ] version: 0
+[INFO ] Program timers:
+[INFO ] load_regressors: 0.000060s
+[INFO ] loading_data: 0.000050s
+[INFO ] regression: 0.000049s
+[INFO ] total_time: 0.000118s
+
+$ cat lr.xml
+
+
+
+ 0
+
+ 5
+ 1
+ 1
+ 14.00000000000002
+ 1.9999999999999447
+ 1.0000000000000431
+ 2.9999999999999516
+ 4.0000000000000249
+
+ 0
+ true
+
+
+@endcode
+
+If we take a look at the \c lr.xml output we can see the \c \ part has five elements which
+the first corresponds to \f$\beta_0\f$ , the second corresponds to \f$\beta_1\f$ , and so on. This is equivalent
+to \f$f(y) = \beta_0 + \beta_1x_1 + \beta_2x_2 + \beta_3x_3 + \beta_4x_4\f$ or \f$f(y)=14+2x_1+1x_2+3x_3+4x_4\f$.
+
+@subsection cli_ex3_lrtut Compute model and predict at the same time
+
+@code
+$ mlpack_linear_regression --training_file dataset.csv --test_file predict.csv --output_predictions_file predictions.csv \
> -v
+[WARN ] '--output_predictions_file (-o)' ignored because '--test_file (-T)' is specified!
[INFO ] Loading 'dataset.csv' as CSV data. Size is 2 x 5.
[INFO ] Loading 'predict.csv' as raw ASCII formatted data. Size is 1 x 3.
[INFO ] Saving CSV data to 'predictions.csv'.
-[INFO ]
+[INFO ]
[INFO ] Execution parameters:
-[INFO ] help: false
-[INFO ] info: ""
-[INFO ] input_model_file: ""
+[INFO ] help: 0
+[INFO ] info:
+[INFO ] input_model_file:
[INFO ] lambda: 0
-[INFO ] output_model_file: ""
-[INFO ] output_predictions: predictions.csv
-[INFO ] test_file: predict.csv
-[INFO ] training_file: dataset.csv
-[INFO ] training_responses: ""
-[INFO ] verbose: true
-[INFO ] version: false
-[INFO ]
+[INFO ] output_model_file:
+[INFO ] output_predictions_file: 'predictions.csv' (1x3 matrix)
+[INFO ] test_file: 'predict.csv' (0x0 matrix)
+[INFO ] training_file: 'dataset.csv' (0x0 matrix)
+[INFO ] training_responses_file: ''
+[INFO ] verbose: 1
+[INFO ] version: 0
[INFO ] Program timers:
-[INFO ] load_regressors: 0.000371s
-[INFO ] load_test_points: 0.000229s
-[INFO ] loading_data: 0.000491s
-[INFO ] prediction: 0.000075s
-[INFO ] regression: 0.000449s
-[INFO ] saving_data: 0.000186s
-[INFO ] total_time: 0.002731s
+[INFO ] load_regressors: 0.000069s
+[INFO ] load_test_points: 0.000031s
+[INFO ] loading_data: 0.000079s
+[INFO ] prediction: 0.000001s
+[INFO ] regression: 0.000054s
+[INFO ] saving_data: 0.000055s
+[INFO ] total_time: 0.000203s
+
$ cat dataset.csv
0,0
@@ -195,51 +263,52 @@ about the \c predict.csv dataset is that it has the same dimensionality as the
dataset used to create the model, one. If the model generating dataset has
\f$d\f$ dimensions, so must the dataset we want to predict for.
-@subsection cli_ex3_lrtut Prediction using a precomputed model
+@subsection cli_ex4_lrtut Prediction using a precomputed model
@code
-$ mlpack_linear_regression --input_model_file lr.xml --test_file predict.csv -v
+$ mlpack_linear_regression --input_model_file lr.xml --test_file predict.csv --output_predictions_file predictions.csv -v
+[WARN ] '--output_predictions_file (-o)' ignored because '--test_file (-T)' is specified!
[INFO ] Loading 'predict.csv' as raw ASCII formatted data. Size is 1 x 3.
[INFO ] Saving CSV data to 'predictions.csv'.
-[INFO ]
+[INFO ]
[INFO ] Execution parameters:
-[INFO ] help: false
-[INFO ] info: ""
+[INFO ] help: 0
+[INFO ] info:
[INFO ] input_model_file: lr.xml
[INFO ] lambda: 0
-[INFO ] output_model_file: ""
-[INFO ] output_predictions: predictions.csv
-[INFO ] test_file: predict.csv
-[INFO ] training_file: ""
-[INFO ] training_responses: ""
-[INFO ] verbose: true
-[INFO ] version: false
-[INFO ]
+[INFO ] output_model_file:
+[INFO ] output_predictions_file: 'predictions.csv' (1x3 matrix)
+[INFO ] test_file: 'predict.csv' (0x0 matrix)
+[INFO ] training_file: ''
+[INFO ] training_responses_file: ''
+[INFO ] verbose: 1
+[INFO ] version: 0
[INFO ] Program timers:
-[INFO ] load_model: 0.000264s
-[INFO ] load_test_points: 0.000186s
-[INFO ] loading_data: 0.000157s
-[INFO ] prediction: 0.000098s
-[INFO ] saving_data: 0.000157s
-[INFO ] total_time: 0.001688s
+[INFO ] load_model: 0.000051s
+[INFO ] load_test_points: 0.000052s
+[INFO ] loading_data: 0.000044s
+[INFO ] prediction: 0.000010s
+[INFO ] saving_data: 0.000079s
+[INFO ] total_time: 0.000160s
+
$ cat lr.xml
-
-
-
-
-
- 2
- 1
- 2
- 1
- - -3.97205464519563669e-16
- - 1.00000000000000022e+00
-
- 0.00000000000000000e+00
- 1
-
-
+
+
+
+ 0
+
+ 2
+ 1
+ 1
+ 0
+ 1
+
+ 0
+ true
+
+
+
$ cat predict.csv
2
@@ -252,7 +321,7 @@ $ cat predictions.csv
4.0000000000e+00
@endcode
-@subsection cli_ex4_lrtut Using ridge regression
+@subsection cli_ex5_lrtut Using ridge regression
Sometimes, the input matrix of predictors has a covariance matrix that is not
invertible, or the system is overdetermined. In this case, ridge regression is
diff --git a/doc/tutorials/reinforcement_learning/reinforcement_learning.txt b/doc/tutorials/reinforcement_learning/reinforcement_learning.txt
index d8fb6cec58..e53edd0c74 100644
--- a/doc/tutorials/reinforcement_learning/reinforcement_learning.txt
+++ b/doc/tutorials/reinforcement_learning/reinforcement_learning.txt
@@ -153,19 +153,22 @@ the output shape is represented by the number of possible actions, which in this
(`foward` and `backward`).
We can also use mlpack's ann module to setup a custom FFN network. For example, here we use a single
-hidden layer.
+hidden layer. However, the Q-Learning agent expects the object to have a `ResetNoise` method which `SimpleDQN` has.
+We can't pass mlpack's FFN network directly. Instead, we have to wrap it into `SimpleDQN` object.
@code
int main()
{
// Set up the network.
- FFN, GaussianInitialization> model(MeanSquaredError<>(),
+ FFN, GaussianInitialization> network(MeanSquaredError<>(),
GaussianInitialization(0, 0.001));
- model.Add>(4, 128);
- model.Add>();
- model.Add>(128, 128);
- model.Add>();
- model.Add>(128, 2);
+ network.Add>(4, 128);
+ network.Add>();
+ network.Add>(128, 128);
+ network.Add>();
+ network.Add>(128, 2);
+
+ SimpleDQN<> model(network);
@endcode
@@ -323,7 +326,7 @@ auto measure = [&returns, &position, &episode](double episodeReturn)
std::cout << "Episode No.: " << episode
<< "; Episode Return: " << episodeReturn
- << "; Average Return: " << arma::mean(returns) << endl;
+ << "; Average Return: " << arma::mean(returns) << std::endl;
};
@endcode
@@ -389,7 +392,7 @@ int main()
std::cout << "Episode No.: " << episode
<< "; Episode Return: " << episodeReturn
- << "; Average Return: " << arma::mean(returns) << endl;
+ << "; Average Return: " << arma::mean(returns) << std::endl;
};
for (int i = 0; i < 100; i++)
diff --git a/src/mlpack/bindings/R/CMakeLists.txt b/src/mlpack/bindings/R/CMakeLists.txt
index b1c7daab0a..73ebe3cd1a 100644
--- a/src/mlpack/bindings/R/CMakeLists.txt
+++ b/src/mlpack/bindings/R/CMakeLists.txt
@@ -284,6 +284,11 @@ if (BUILD_R_BINDINGS)
DESTINATION
"${CMAKE_CURRENT_BINARY_DIR}/mlpack/")
+ file(COPY
+ "${CMAKE_CURRENT_SOURCE_DIR}/mlpack/configure"
+ DESTINATION
+ "${CMAKE_CURRENT_BINARY_DIR}/mlpack/")
+
# Do the actual build.
add_custom_target(r_build ALL)
diff --git a/src/mlpack/bindings/R/mlpack/DESCRIPTION.in b/src/mlpack/bindings/R/mlpack/DESCRIPTION.in
index dc583f0dd9..1c64a50a72 100644
--- a/src/mlpack/bindings/R/mlpack/DESCRIPTION.in
+++ b/src/mlpack/bindings/R/mlpack/DESCRIPTION.in
@@ -20,6 +20,5 @@ Suggests: testthat (>= 2.1.0)
URL: https://www.mlpack.org/doc/mlpack-@PACKAGE_VERSION@/r_documentation.html,
https://github.com/mlpack/mlpack
BugReports: https://github.com/mlpack/mlpack/issues
-LazyData: true
RoxygenNote: 7.1.0
Encoding: UTF-8
diff --git a/src/mlpack/bindings/R/mlpack/configure b/src/mlpack/bindings/R/mlpack/configure
new file mode 100755
index 0000000000..608e27d17e
--- /dev/null
+++ b/src/mlpack/bindings/R/mlpack/configure
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+if test `uname` = "SunOS" ;
+then
+sed '1 s/$/ -ftrack-macro-expansion=0 -pipe --param ggc-min-expand=10 --param ggc-min-heapsize=8192/' ./src/Makevars > ./src/Makevars.tmp && cat ./src/Makevars.tmp > ./src/Makevars && rm ./src/Makevars.tmp
+fi
+
+exit 0
diff --git a/src/mlpack/bindings/R/mlpack/src/Makevars.win b/src/mlpack/bindings/R/mlpack/src/Makevars.win
index bb6a88cc84..12f71348e6 100644
--- a/src/mlpack/bindings/R/mlpack/src/Makevars.win
+++ b/src/mlpack/bindings/R/mlpack/src/Makevars.win
@@ -1,3 +1,3 @@
-PKG_CXXFLAGS = -DBOOST_MATH_PROMOTE_DOUBLE_POLICY=false -I. $(SHLIB_OPENMP_CXXFLAGS)
+PKG_CXXFLAGS = -DBOOST_MATH_PROMOTE_DOUBLE_POLICY=false -I. $(SHLIB_OPENMP_CXXFLAGS) -ftrack-macro-expansion=0 -pipe --param ggc-min-expand=10 --param ggc-min-heapsize=8192
PKG_LIBS = $(SHLIB_OPENMP_CXXFLAGS) $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)
CXX_STD = CXX11
diff --git a/src/mlpack/bindings/R/mlpack/src/rcpp_mlpack.h b/src/mlpack/bindings/R/mlpack/src/rcpp_mlpack.h
index 8c285e2193..a66e7ed637 100644
--- a/src/mlpack/bindings/R/mlpack/src/rcpp_mlpack.h
+++ b/src/mlpack/bindings/R/mlpack/src/rcpp_mlpack.h
@@ -15,7 +15,7 @@
#include
-// To suppress Found ‘__assert_fail’, possibly from ‘assert’ (C).
+// To suppress Found '__assert_fail', possibly from 'assert' (C).
#define BOOST_DISABLE_ASSERTS
// Rcpp has its own stream object which cooperates more nicely with R's i/o
diff --git a/src/mlpack/bindings/cli/print_type_doc_impl.hpp b/src/mlpack/bindings/cli/print_type_doc_impl.hpp
index e6aa78d915..51e3106de5 100644
--- a/src/mlpack/bindings/cli/print_type_doc_impl.hpp
+++ b/src/mlpack/bindings/cli/print_type_doc_impl.hpp
@@ -98,8 +98,9 @@ std::string PrintTypeDoc(
"of the data is detected by the extension of the filename. The storage"
" should be such that one row corresponds to one point, and one column "
"corresponds to one dimension (this is the typical storage format for "
- "on-disk data). All values of the matrix will be loaded as double-"
- "precision floating point data.";
+ "on-disk data). CSV files will be checked for a header; if no header "
+ "is found, the first row will be loaded as a data point. All values of"
+ " the matrix will be loaded as double-precision floating point data.";
}
else if (std::is_same>::value)
{
@@ -111,8 +112,10 @@ std::string PrintTypeDoc(
"compiled with HDF5 support. The type of the data is detected by the "
"extension of the filename. The storage should be such that one row "
"corresponds to one point, and one column corresponds to one dimension "
- "(this is the typical storage format for on-disk data). All values of "
- "the matrix will be loaded as unsigned integers.";
+ "(this is the typical storage format for on-disk data). CSV files will"
+ " be checked for a header; if no header is found, the first row will be"
+ " loaded as a data point. All values of the matrix will be loaded as "
+ "unsigned integers.";
}
else if (std::is_same::value ||
std::is_same::value)
diff --git a/src/mlpack/bindings/python/setup.py.in b/src/mlpack/bindings/python/setup.py.in
index 4762f3194b..f049f0e002 100644
--- a/src/mlpack/bindings/python/setup.py.in
+++ b/src/mlpack/bindings/python/setup.py.in
@@ -52,18 +52,15 @@ if os.getenv('NO_BUILD') == '1':
else:
cxx_flags = '${CMAKE_CXX_FLAGS}'.strip()
cxx_flags = re.sub(' +', ' ', cxx_flags)
+ extra_args = ['-DBINDING_TYPE=BINDING_TYPE_PYX', '-std=c++11']
+ if '${OpenMP_CXX_FLAGS}' != '':
+ extra_args.append('${OpenMP_CXX_FLAGS}')
if cxx_flags:
- extra_args = ['-DBINDING_TYPE=BINDING_TYPE_PYX',
- '-std=c++11',
- '${OpenMP_CXX_FLAGS}'] + cxx_flags.split(' ')
- else:
- extra_args = ['-DBINDING_TYPE=BINDING_TYPE_PYX',
- '-std=c++11',
- '${OpenMP_CXX_FLAGS}']
+ extra_args.extend(cxx_flags.split(' '))
# Extra options for MSVC compiler.
if platform.system() == 'Windows':
- extra_args = extra_args + ['/MD', '/O2', '/Ob2', '/DNDEBUG']
+ extra_args.extend(['/MD', '/O2', '/Ob2', '/DNDEBUG'])
# This is used for parallel builds; CMake will set PYX_TO_BUILD accordingly.
if module is not None:
diff --git a/src/mlpack/core.hpp b/src/mlpack/core.hpp
index 34cf60dd09..d29a174724 100644
--- a/src/mlpack/core.hpp
+++ b/src/mlpack/core.hpp
@@ -1,4 +1,4 @@
-/**
+/**
* @file core.hpp
*
* Include all of the base components required to write mlpack methods, and the
diff --git a/src/mlpack/core/data/detect_file_type.cpp b/src/mlpack/core/data/detect_file_type.cpp
index 740ffabd93..c00954f1c0 100644
--- a/src/mlpack/core/data/detect_file_type.cpp
+++ b/src/mlpack/core/data/detect_file_type.cpp
@@ -47,6 +47,10 @@ std::string GetStringType(const arma::file_type& type)
* from Armadillo's function guess_file_type_internal(), but we avoid using
* internal Armadillo functionality.
*
+ * If the file is detected as a CSV, and the CSV is detected to have a header
+ * row, the stream `f` will be fast-forwarded to point at the second line of the
+ * file.
+ *
* @param f Opened istream to look into to guess the file type.
*/
arma::file_type GuessFileType(std::istream& f)
@@ -114,6 +118,53 @@ arma::file_type GuessFileType(std::istream& f)
}
}
+ if (hasComma && (hasBracket == false))
+ {
+ // If we believe we have a CSV file, then we want to try to skip any header
+ // row. We'll detect a header row by simply seeing if anything in the first
+ // line doesn't parse as a number.
+ //
+ // TODO: this is not a foolproof algorithm, so there should eventually be a
+ // way added for the user to explicitly indicate that there is or isn't a
+ // header.
+ std::string firstLine;
+ std::getline(f, firstLine);
+
+ std::stringstream str(firstLine);
+ std::string token;
+ bool allNumeric = true;
+ // We'll abuse 'getline()' to split on commas.
+ while (std::getline(str, token, ','))
+ {
+ // Let's see if we can parse the token into a number.
+ double num;
+ std::string rest;
+
+ // Try to parse into a number.
+ std::stringstream s(token);
+ s >> num;
+ if (s.fail())
+ {
+ allNumeric = false;
+ break;
+ }
+
+ // Now check to see there isn't anything else. (This catches cases like,
+ // e.g., "1a".)
+ s >> rest;
+ if (rest.length() > 0)
+ {
+ allNumeric = false;
+ break;
+ }
+ }
+
+ // If we could parse everything into a number, then let's rewind `f` so that
+ // it's at the start of the file.
+ if (allNumeric)
+ f.seekg(pos1);
+ }
+
delete[] dataMem;
if (hasBinary)
@@ -131,12 +182,14 @@ arma::file_type GuessFileType(std::istream& f)
* necessary. (For instance, a .csv file could be delimited by spaces, commas,
* or tabs.) This is meant to be used during loading.
*
+ * If the file is detected as a CSV, and the CSV is detected to have a header
+ * row, `stream` will be fast-forwarded to point at the second line of the file.
+ *
* @param stream Opened file stream to look into for autodetection.
* @param filename Name of the file.
* @return The detected file type.
*/
-arma::file_type AutoDetect(std::fstream& stream,
- const std::string& filename)
+arma::file_type AutoDetect(std::fstream& stream, const std::string& filename)
{
// Get the extension.
std::string extension = Extension(filename);
diff --git a/src/mlpack/core/data/detect_file_type.hpp b/src/mlpack/core/data/detect_file_type.hpp
index ab387ad0ba..8856de29fe 100644
--- a/src/mlpack/core/data/detect_file_type.hpp
+++ b/src/mlpack/core/data/detect_file_type.hpp
@@ -30,6 +30,10 @@ std::string GetStringType(const arma::file_type& type);
* from Armadillo's function guess_file_type_internal(), but we avoid using
* internal Armadillo functionality.
*
+ * If the file is detected as a CSV, and the CSV is detected to have a header
+ * row, the stream `f` will be fast-forwarded to point at the second line of the
+ * file.
+ *
* @param f Opened istream to look into to guess the file type.
*/
arma::file_type GuessFileType(std::istream& f);
@@ -40,6 +44,9 @@ arma::file_type GuessFileType(std::istream& f);
* necessary. (For instance, a .csv file could be delimited by spaces, commas,
* or tabs.) This is meant to be used during loading.
*
+ * If the file is detected as a CSV, and the CSV is detected to have a header
+ * row, `stream` will be fast-forwarded to point at the second line of the file.
+ *
* @param stream Opened file stream to look into for autodetection.
* @param filename Name of the file.
* @return The detected file type. arma::file_type_unknown if unknown.
diff --git a/src/mlpack/core/data/load.hpp b/src/mlpack/core/data/load.hpp
index d6681d5dce..9b54f43ce1 100644
--- a/src/mlpack/core/data/load.hpp
+++ b/src/mlpack/core/data/load.hpp
@@ -48,6 +48,10 @@ namespace data /** Functions to load and save matrices and models. */ {
* `inputLoadType` parameter with the correct type above (e.g.
* `arma::csv_ascii`.)
*
+ * If the detected file type is CSV (`arma::csv_ascii`), the first row will be
+ * checked for a CSV header. If a CSV header is not detected, the first row
+ * will be treated as data; otherwise, the first row will be skipped.
+ *
* If the parameter 'fatal' is set to true, a std::runtime_error exception will
* be thrown if the matrix does not load successfully. The parameter
* 'transpose' controls whether or not the matrix is transposed after loading.
diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp
index 42b7e03b3a..f9b0c1558f 100644
--- a/src/mlpack/core/data/split_data.hpp
+++ b/src/mlpack/core/data/split_data.hpp
@@ -18,11 +18,57 @@
namespace mlpack {
namespace data {
+/**
+ * This helper function splits any `input` data into training and testing parts.
+ * In order to shuffle the input data before spliting, an array of shuffled
+ * indices of the input data is passed in the form of argument `order`.
+ */
+template
+void SplitHelper(const InputType& input,
+ InputType& train,
+ InputType& test,
+ const double testRatio,
+ const arma::uvec& order = arma::uvec())
+{
+ const size_t testSize = static_cast(input.n_cols * testRatio);
+ const size_t trainSize = input.n_cols - testSize;
+
+ // Initialising the sizes of outputs if not already initialized.
+ train.set_size(input.n_rows, trainSize);
+ test.set_size(input.n_rows, testSize);
+
+ // Shuffling and spliting simultaneously.
+ if (!order.is_empty())
+ {
+ if (trainSize > 0)
+ {
+ for (size_t i = 0; i < trainSize; ++i)
+ train.col(i) = input.col(order(i));
+ }
+ if (trainSize < input.n_cols)
+ {
+ for (size_t i = trainSize; i < input.n_cols; ++i)
+ test.col(i - trainSize) = input.col(order(i));
+ }
+ }
+ // Spliting only.
+ else
+ {
+ if (trainSize > 0)
+ train = input.cols(0, trainSize - 1);
+
+ if (trainSize < input.n_cols)
+ test = input.cols(trainSize, input.n_cols - 1);
+ }
+}
+
/**
* Given an input dataset and labels, stratify into a training set and test set.
* It is recommended to have the input labels between the range [0, n) where n
* is the number of different labels. The NormalizeLabels() function in
* mlpack::data can be used for this.
+ * Expects labels to be of type arma::Row<> or arma::Col<>.
+ * Throws a runtime error if this is not the case.
* Example usage below. This overload places the stratified dataset into the
* four output parameters given (trainData, testData, trainLabel,
* and testLabel).
@@ -52,13 +98,14 @@ namespace data {
* @param shuffleData If true, the sample order is shuffled; otherwise, each
* sample is visited in linear order. (Default true.)
*/
-template
+template::value> >
void StratifiedSplit(const arma::Mat& input,
- const arma::Row& inputLabel,
+ const LabelsType& inputLabel,
arma::Mat& trainData,
arma::Mat& testData,
- arma::Row& trainLabel,
- arma::Row& testLabel,
+ LabelsType& trainLabel,
+ LabelsType& testLabel,
const double testRatio,
const bool shuffleData = true)
{
@@ -95,29 +142,24 @@ void StratifiedSplit(const arma::Mat& input,
* 0
* 1 1
*/
+ const bool typeCheck = (arma::is_Row::value)
+ || (arma::is_Col::value);
+ if (!typeCheck)
+ throw std::runtime_error("data::Split(): when stratified sampling is done, "
+ "labels must have type `arma::Row<>`!");
size_t trainIdx = 0;
size_t testIdx = 0;
size_t trainSize = 0;
size_t testSize = 0;
arma::uvec labelCounts;
arma::uvec testLabelCounts;
- U maxLabel = inputLabel.max();
+ typename LabelsType::elem_type maxLabel = inputLabel.max();
labelCounts.zeros(maxLabel+1);
testLabelCounts.zeros(maxLabel+1);
- arma::uvec order =
- arma::linspace(0, input.n_cols - 1, input.n_cols);
-
- if (shuffleData)
- {
- order = arma::shuffle(order);
- }
-
- for (U label : inputLabel)
- {
+ for (typename LabelsType::elem_type label : inputLabel)
++labelCounts[label];
- }
for (arma::uword labelCount : labelCounts)
{
@@ -127,24 +169,50 @@ void StratifiedSplit(const arma::Mat& input,
trainData.set_size(input.n_rows, trainSize);
testData.set_size(input.n_rows, testSize);
- trainLabel.set_size(trainSize);
- testLabel.set_size(testSize);
+ trainLabel.set_size(inputLabel.n_rows, trainSize);
+ testLabel.set_size(inputLabel.n_rows, testSize);
- for (arma::uword i : order)
+ if (shuffleData)
{
- U label = inputLabel[i];
- if (testLabelCounts[label] < floor(labelCounts[label] * testRatio))
+ arma::uvec order = arma::shuffle(
+ arma::linspace(0, input.n_cols - 1, input.n_cols));
+
+ for (arma::uword i : order)
{
- testLabelCounts[label] += 1;
- testData.col(testIdx) = input.col(i);
- testLabel[testIdx] = inputLabel[i];
- testIdx += 1;
+ typename LabelsType::elem_type label = inputLabel[i];
+ if (testLabelCounts[label] < floor(labelCounts[label] * testRatio))
+ {
+ testLabelCounts[label] += 1;
+ testData.col(testIdx) = input.col(i);
+ testLabel[testIdx] = inputLabel[i];
+ testIdx += 1;
+ }
+ else
+ {
+ trainData.col(trainIdx) = input.col(i);
+ trainLabel[trainIdx] = inputLabel[i];
+ trainIdx += 1;
+ }
}
- else
+ }
+ else
+ {
+ for (arma::uword i = 0; i < input.n_cols; i++)
{
- trainData.col(trainIdx) = input.col(i);
- trainLabel[trainIdx] = inputLabel[i];
- trainIdx += 1;
+ typename LabelsType::elem_type label = inputLabel[i];
+ if (testLabelCounts[label] < floor(labelCounts[label] * testRatio))
+ {
+ testLabelCounts[label] += 1;
+ testData.col(testIdx) = input.col(i);
+ testLabel[testIdx] = inputLabel[i];
+ testIdx += 1;
+ }
+ else
+ {
+ trainData.col(trainIdx) = input.col(i);
+ trainLabel[trainIdx] = inputLabel[i];
+ trainIdx += 1;
+ }
}
}
}
@@ -169,6 +237,9 @@ void StratifiedSplit(const arma::Mat& input,
* testData, trainLabel, testLabel, 0.3);
* @endcode
*
+ * @tparam T Type of the elements of the input matrix.
+ * @tparam LabelsType Type of input labels. It can be arma::Mat, arma::Row,
+ * arma::Cube or arma::SpMat.
* @param input Input dataset to split.
* @param inputLabel Input labels to split.
* @param trainData Matrix to store training data into.
@@ -179,50 +250,28 @@ void StratifiedSplit(const arma::Mat& input,
* @param shuffleData If true, the sample order is shuffled; otherwise, each
* sample is visited in linear order. (Default true.)
*/
-template
+template::value> >
void Split(const arma::Mat& input,
- const arma::Row& inputLabel,
+ const LabelsType& inputLabel,
arma::Mat& trainData,
arma::Mat& testData,
- arma::Row& trainLabel,
- arma::Row& testLabel,
+ LabelsType& trainLabel,
+ LabelsType& testLabel,
const double testRatio,
const bool shuffleData = true)
{
- const size_t testSize = static_cast(input.n_cols * testRatio);
- const size_t trainSize = input.n_cols - testSize;
- trainData.set_size(input.n_rows, trainSize);
- testData.set_size(input.n_rows, testSize);
- trainLabel.set_size(trainSize);
- testLabel.set_size(testSize);
-
if (shuffleData)
{
- arma::uvec order = arma::shuffle(arma::linspace(
- 0, input.n_cols - 1, input.n_cols));
- if (trainSize > 0)
- {
- trainData = input.cols(order.subvec(0, trainSize - 1));
- trainLabel = inputLabel.cols(order.subvec(0, trainSize - 1));
- }
- if (trainSize < input.n_cols)
- {
- testData = input.cols(order.subvec(trainSize, input.n_cols - 1));
- testLabel = inputLabel.cols(order.subvec(trainSize, input.n_cols - 1));
- }
+ arma::uvec order = arma::shuffle(arma::linspace(0,
+ input.n_cols - 1, input.n_cols));
+ SplitHelper(input, trainData, testData, testRatio, order);
+ SplitHelper(inputLabel, trainLabel, testLabel, testRatio, order);
}
else
{
- if (trainSize > 0)
- {
- trainData = input.cols(0, trainSize - 1);
- trainLabel = inputLabel.subvec(0, trainSize - 1);
- }
- if (trainSize < input.n_cols)
- {
- testData = input.cols(trainSize , input.n_cols - 1);
- testLabel = inputLabel.subvec(trainSize , input.n_cols - 1);
- }
+ SplitHelper(input, trainData, testData, testRatio);
+ SplitHelper(inputLabel, trainLabel, testLabel, testRatio);
}
}
@@ -256,29 +305,15 @@ void Split(const arma::Mat& input,
const double testRatio,
const bool shuffleData = true)
{
- const size_t testSize = static_cast(input.n_cols * testRatio);
- const size_t trainSize = input.n_cols - testSize;
- trainData.set_size(input.n_rows, trainSize);
- testData.set_size(input.n_rows, testSize);
-
if (shuffleData)
{
- arma::uvec order = arma::shuffle(arma::linspace(
- 0, input.n_cols - 1, input.n_cols));
-
- if (trainSize > 0)
- trainData = input.cols(order.subvec(0, trainSize - 1));
-
- if (trainSize < input.n_cols)
- testData = input.cols(order.subvec(trainSize, input.n_cols - 1));
+ arma::uvec order = arma::shuffle(arma::linspace(0,
+ input.n_cols - 1, input.n_cols));
+ SplitHelper(input, trainData, testData, testRatio, order);
}
else
{
- if (trainSize > 0)
- trainData = input.cols(0, trainSize - 1);
-
- if (trainSize < input.n_cols)
- testData = input.cols(trainSize , input.n_cols - 1);
+ SplitHelper(input, trainData, testData, testRatio);
}
}
@@ -295,6 +330,9 @@ void Split(const arma::Mat& input,
* auto splitResult = Split(input, label, 0.2);
* @endcode
*
+ * @tparam T Type of the elements of the input matrix.
+ * @tparam LabelsType Type of input labels. It can be arma::Mat, arma::Row,
+ * arma::Cube or arma::SpMat.
* @param input Input dataset to split.
* @param inputLabel Input labels to split.
* @param testRatio Percentage of dataset to use for test set (between 0 and 1).
@@ -302,22 +340,24 @@ void Split(const arma::Mat& input,
* sample is visited in linear order. (Default true).
* @param stratifyData If true, the train and test splits are stratified
* so that the ratio of each class in the training and test sets is the same
- * as in the original dataset.
+ * as in the original dataset. Expects labels to be of type arma::Row<> or
+ * arma::Col<>.
* @return std::tuple containing trainData (arma::Mat), testData
* (arma::Mat), trainLabel (arma::Row), and testLabel (arma::Row).
*/
-template
-std::tuple, arma::Mat, arma::Row, arma::Row>
+template::value> >
+std::tuple, arma::Mat, LabelsType, LabelsType>
Split(const arma::Mat& input,
- const arma::Row& inputLabel,
+ const LabelsType& inputLabel,
const double testRatio,
const bool shuffleData = true,
const bool stratifyData = false)
{
arma::Mat trainData;
arma::Mat testData;
- arma::Row trainLabel;
- arma::Row testLabel;
+ LabelsType trainLabel;
+ LabelsType testLabel;
if (stratifyData)
{
@@ -368,6 +408,208 @@ Split(const arma::Mat& input,
std::move(testData));
}
+/**
+ * Given an input dataset and labels, split into a training set and test set.
+ * Example usage below. This overload places the split dataset into the four
+ * output parameters given (trainData, testData, trainLabel, and testLabel).
+ *
+ * The input dataset must be of type arma::field. It should have the shape -
+ * (n_rows = 1, n_cols = Number of samples, n_slices = 1).
+ *
+ * NOTE: Here FieldType could be arma::field or arma::field.
+ *
+ * @code
+ * arma::field input = loadData();
+ * arma::field label = loadLabel();
+ * arma::field trainData;
+ * arma::field testData;
+ * arma::field trainLabel;
+ * arma::field testLabel;
+ * math::RandomSeed(100); // Set the seed if you like.
+ *
+ * // Split the dataset into a training and test set, with 30% of the data being
+ * // held out for the test set.
+ * Split(input, label, trainData, testData, trainLabel, testLabel, 0.3);
+ * @endcode
+ *
+ * @param input Input dataset to split.
+ * @param inputLabel Input labels to split.
+ * @param trainData FieldType to store training data into.
+ * @param testData FieldType test data into.
+ * @param trainLabel Field vector to store training labels into.
+ * @param testLabel Field vector to store test labels into.
+ * @param testRatio Percentage of dataset to use for test set (between 0 and 1).
+ * @param shuffleData If true, the sample order is shuffled; otherwise, each
+ * sample is visited in linear order. (Default true.)
+ */
+template ::value ||
+ arma::is_Mat_only::value>>
+void Split(const FieldType& input,
+ const arma::field& inputLabel,
+ FieldType& trainData,
+ arma::field& trainLabel,
+ FieldType& testData,
+ arma::field& testLabel,
+ const double testRatio,
+ const bool shuffleData = true)
+{
+ if (shuffleData)
+ {
+ arma::uvec order = arma::shuffle(arma::linspace(0,
+ input.n_cols - 1, input.n_cols));
+ SplitHelper(input, trainData, testData, testRatio, order);
+ SplitHelper(inputLabel, trainLabel, testLabel, testRatio, order);
+ }
+ else
+ {
+ SplitHelper(input, trainData, testData, testRatio);
+ SplitHelper(inputLabel, trainLabel, testLabel, testRatio);
+ }
+}
+
+/**
+ * Given an input dataset, split into a training set and test set.
+ * Example usage below. This overload places the split dataset into the two
+ * output parameters given (trainData, testData).
+ *
+ * The input dataset must be of type arma::field. It should have the shape -
+ * (n_rows = 1, n_cols = Number of samples, n_slices = 1)
+ *
+ * NOTE: Here FieldType could be arma::field or arma::field
+ *
+ * @code
+ * arma::field input = loadData();
+ * arma::field trainData;
+ * arma::field testData;
+ * math::RandomSeed(100); // Set the seed if you like.
+ *
+ * // Split the dataset into a training and test set, with 30% of the data being
+ * // held out for the test set.
+ * Split(input, trainData, testData, 0.3);
+ * @endcode
+ *
+ * @param input Input dataset to split.
+ * @param trainData FieldType to store training data into.
+ * @param testData FieldType test data into.
+ * @param testRatio Percentage of dataset to use for test set (between 0 and 1).
+ * @param shuffleData If true, the sample order is shuffled; otherwise, each
+ * sample is visited in linear order. (Default true).
+ */
+template ::value ||
+ arma::is_Mat_only::value>>
+void Split(const FieldType& input,
+ FieldType& trainData,
+ FieldType& testData,
+ const double testRatio,
+ const bool shuffleData = true)
+{
+ if (shuffleData)
+ {
+ arma::uvec order = arma::shuffle(arma::linspace(0,
+ input.n_cols - 1, input.n_cols));
+ SplitHelper(input, trainData, testData, testRatio, order);
+ }
+ else
+ {
+ SplitHelper(input, trainData, testData, testRatio);
+ }
+}
+
+/**
+ * Given an input dataset and labels, split into a training set and test set.
+ * Example usage below. This overload returns the split dataset as a std::tuple
+ * with four elements: an FieldType containing the training data, an
+ * FieldType containing the test data, an arma::field containing the
+ * training labels, and an arma::field containing the test labels.
+ *
+ * The input dataset must be of type arma::field. It should have the shape -
+ * (n_rows = 1, n_cols = Number of samples, n_slices = 1)
+ *
+ * NOTE: Here FieldType could be arma::field or arma::field
+ *
+ * @code
+ * arma::field input = loadData();
+ * arma::field label = loadLabel();
+ * auto splitResult = Split(input, label, 0.2);
+ * @endcode
+ *
+ * @param input Input dataset to split.
+ * @param inputLabel Input labels to split.
+ * @param testRatio Percentage of dataset to use for test set (between 0 and 1).
+ * @param shuffleData If true, the sample order is shuffled; otherwise, each
+ * sample is visited in linear order. (Default true).
+ * @return std::tuple containing trainData (FieldType), testData
+ * (FieldType), trainLabel (arma::field), and
+ * testLabel (arma::field).
+ */
+template ::value ||
+ arma::is_Mat_only::value>>
+std::tuple, arma::field>
+Split(const FieldType& input,
+ const arma::field& inputLabel,
+ const double testRatio,
+ const bool shuffleData = true)
+{
+ FieldType trainData;
+ FieldType testData;
+ arma::field trainLabel;
+ arma::field testLabel;
+
+ Split(input, inputLabel, trainData, trainLabel, testData, testLabel,
+ testRatio, shuffleData);
+
+ return std::make_tuple(std::move(trainData),
+ std::move(testData),
+ std::move(trainLabel),
+ std::move(testLabel));
+}
+
+/**
+ * Given an input dataset, split into a training set and test set.
+ * Example usage below. This overload returns the split dataset as a std::tuple
+ * with two elements: an FieldType containing the training data and an
+ * FieldType containing the test data.
+ *
+ * The input dataset must be of type arma::field. It should have the shape -
+ * (n_rows = 1, n_cols = Number of samples, n_slices = 1)
+ *
+ * NOTE: Here FieldType could be arma::field or arma::field
+ *
+ * @code
+ * arma::field input = loadData();
+ * auto splitResult = Split(input, 0.2);
+ * @endcode
+ *
+ * @param input Input dataset to split.
+ * @param testRatio Percentage of dataset to use for test set (between 0 and 1).
+ * @param shuffleData If true, the sample order is shuffled; otherwise, each
+ * sample is visited in linear order. (Default true).
+ * @return std::tuple containing trainData (FieldType)
+ * and testData (FieldType).
+ */
+template ::value ||
+ arma::is_Mat_only::value>>
+std::tuple
+Split(const FieldType& input,
+ const double testRatio,
+ const bool shuffleData = true)
+{
+ FieldType trainData;
+ FieldType testData;
+ Split(input, trainData, testData, testRatio, shuffleData);
+
+ return std::make_tuple(std::move(trainData),
+ std::move(testData));
+}
+
} // namespace data
} // namespace mlpack
diff --git a/src/mlpack/core/dists/gaussian_distribution.hpp b/src/mlpack/core/dists/gaussian_distribution.hpp
index d7d3800c06..2d47f7d686 100644
--- a/src/mlpack/core/dists/gaussian_distribution.hpp
+++ b/src/mlpack/core/dists/gaussian_distribution.hpp
@@ -90,11 +90,11 @@ class GaussianDistribution
*/
void Probability(const arma::mat& x, arma::vec& probabilities) const
{
- probabilities.set_size(x.n_cols);
- for (size_t i = 0; i < x.n_cols; ++i)
- {
- probabilities(i) = Probability(x.unsafe_col(i));
- }
+ // Use LogProbability(), then transform the log-probabilities out of
+ // logspace.
+ arma::vec logProbs;
+ LogProbability(x, logProbs);
+ probabilities = arma::exp(logProbs);
}
/**
@@ -110,17 +110,11 @@ class GaussianDistribution
// Column i of 'diffs' is the difference between x.col(i) and the mean.
arma::mat diffs = x;
diffs.each_col() -= mean;
- // Now, we only want to calculate the diagonal elements of (diffs' * cov^-1
- // * diffs). We just don't need any of the other elements. We can
- // calculate the right hand part of the equation (instead of the left side)
- // so that later we are referencing columns, not rows -- that is faster.
- const arma::mat rhs = -0.5 * invCov * diffs;
- arma::vec logExponents(diffs.n_cols); // We will now fill this.
- for (size_t i = 0; i < diffs.n_cols; ++i)
- logExponents(i) = accu(diffs.unsafe_col(i) % rhs.unsafe_col(i));
+ // Now, we only want to calculate the diagonal elements of (diffs' * cov^-1
+ // * diffs). We just don't need any of the other elements.
logProbabilities = -0.5 * x.n_rows * log2pi - 0.5 * logDetCov +
- logExponents;
+ sum(diffs % (-0.5 * invCov * diffs), 0).t();
}
/**
diff --git a/src/mlpack/core/math/log_add.hpp b/src/mlpack/core/math/log_add.hpp
index 51497f8d0d..6613954f11 100644
--- a/src/mlpack/core/math/log_add.hpp
+++ b/src/mlpack/core/math/log_add.hpp
@@ -28,7 +28,7 @@ template
T LogAdd(T x, T y);
/**
- * Sum a vector of log values. (T should be an Armadillo type.)
+ * Log-sum a vector of log values. (T should be an Armadillo type.)
*
* @param x vector of log values
* @return log(e^x0 + e^x1 + ...)
@@ -36,6 +36,38 @@ T LogAdd(T x, T y);
template
typename T::elem_type AccuLog(const T& x);
+/**
+ * Compute the sum of exponentials of each element in each column, then compute
+ * the log of that. If InPlace is true, then the values of `y` will also be
+ * added to the sum.
+ *
+ * That is, if InPlace is false, then this method will set `y` such that:
+ *
+ * `y_i = log(sum(exp(x.col(i))))`
+ *
+ * and if InPlace is true, then `y` will be set such that:
+ *
+ * `y_i = log(sum(exp(x.col(i))) + exp(y_i))`.
+ */
+template
+void LogSumExp(const T& x, arma::Col& y);
+
+/**
+ * Compute the sum of exponentials of each element in each row, then compute the
+ * log of that. If InPlace is true, then the values of `y` will also be added
+ * to the sum.
+ *
+ * That is, if InPlace is false, then this method will set `y` such that:
+ *
+ * `y_i = log(sum(exp(x.row(i))))`
+ *
+ * and if InPlace is true, then `y` will be set such that:
+ *
+ * `y_i = log(sum(exp(x.row(i))) + exp(y_i))`.
+ */
+template
+void LogSumExpT(const T& x, arma::Col& y);
+
} // namespace math
} // namespace mlpack
diff --git a/src/mlpack/core/math/log_add_impl.hpp b/src/mlpack/core/math/log_add_impl.hpp
index f86dce4cd9..6be66b91b9 100644
--- a/src/mlpack/core/math/log_add_impl.hpp
+++ b/src/mlpack/core/math/log_add_impl.hpp
@@ -47,8 +47,10 @@ T LogAdd(T x, T y)
r = y;
}
- return (r == -std::numeric_limits::infinity() ||
- d == -std::numeric_limits::infinity()) ? r : r + log(1 + exp(d));
+ if (std::isinf(d) || std::isinf(r))
+ return r;
+
+ return r + log(1 + exp(d));
}
/**
@@ -60,15 +62,77 @@ T LogAdd(T x, T y)
template
typename T::elem_type AccuLog(const T& x)
{
- typename T::elem_type sum =
- -std::numeric_limits::infinity();
+ typename T::elem_type maxVal = max(x);
+ if (maxVal == -std::numeric_limits::infinity())
+ return maxVal;
- for (size_t i = 0; i < x.n_elem; ++i)
+ return maxVal + log(sum(exp(x - maxVal)));;
+}
+
+/**
+ * Compute the sum of exponentials of each element in each column, then compute
+ * the log of that. If InPlace is true, then the values of `y` will also be
+ * added to the sum.
+ */
+template
+void LogSumExp(const T& x, arma::Col& y)
+{
+ arma::Col maxs;
+
+ if (InPlace)
{
- sum = LogAdd(sum, x[i]);
+ // Compute the maximum in each column (treating y as a column too).
+ maxs = max(max(x, 1), y);
+
+ y = maxs + log(sum(exp(x - repmat(maxs, 1, x.n_cols)), 1) +
+ exp(y - maxs));
+ }
+ else
+ {
+ // Compute the maximum element in each column.
+ maxs = max(x, 1);
+
+ y = maxs + log(sum(exp(x - repmat(maxs, 1, x.n_cols)), 1));
}
- return sum;
+ if (maxs.has_inf())
+ {
+ y.replace(-std::numeric_limits::quiet_NaN(),
+ -std::numeric_limits::infinity());
+ }
+}
+
+/**
+ * Compute the sum of exponentials of each element in each row, then compute the
+ * log of that. If InPlace is true, then the values of `y` will also be added
+ * to the sum.
+ */
+template
+void LogSumExpT(const T& x, arma::Col& y)
+{
+ arma::Row maxs;
+
+ if (InPlace)
+ {
+ // Compute the maximum element in each column.
+ maxs = max(max(x, 0), y.t());
+
+ y = maxs.t() + log(sum(exp(x - repmat(maxs, x.n_rows, 1)), 0) +
+ exp(y.t() - maxs)).t();
+ }
+ else
+ {
+ // Compute the maximum element in each column.
+ arma::Row maxs = max(x, 0);
+
+ y = (maxs + log(sum(exp(x - repmat(maxs, x.n_rows, 1)), 0))).t();
+ }
+
+ if (maxs.has_inf())
+ {
+ y.replace(-std::numeric_limits::quiet_NaN(),
+ -std::numeric_limits::infinity());
+ }
}
} // namespace math
diff --git a/src/mlpack/core/math/random.hpp b/src/mlpack/core/math/random.hpp
index 738702f4b0..5091a08ff3 100644
--- a/src/mlpack/core/math/random.hpp
+++ b/src/mlpack/core/math/random.hpp
@@ -42,7 +42,7 @@ inline void RandomSeed(const size_t seed)
#if (!defined(BINDING_TYPE) || BINDING_TYPE != BINDING_TYPE_TEST)
randGen.seed((uint32_t) seed);
#if (BINDING_TYPE == BINDING_TYPE_R)
- // To suppress Found ‘srand’, possibly from ‘srand’ (C).
+ // To suppress Found 'srand', possibly from 'srand' (C).
(void) seed;
#else
srand((unsigned int) seed);
diff --git a/src/mlpack/core/util/timers.hpp b/src/mlpack/core/util/timers.hpp
index fc83b4984a..8316695377 100644
--- a/src/mlpack/core/util/timers.hpp
+++ b/src/mlpack/core/util/timers.hpp
@@ -129,23 +129,23 @@ class Timers
void PrintTimer(const std::string& timerName);
/**
- * Initializes a timer, available like a normal value specified on
- * the command line. Timers are of type timeval. If a timer is started, then
+ * Initializes a timer, available like a normal value specified on
+ * the command line. Timers are of type timeval. If a timer is started, then
* stopped, then re-started, then stopped, the final timer value will be the
* length of both runs of the timer.
- *
- * @param timerName The name of the timer in question.
+ *
+ * @param timerName The name of the timer in question.
* @param threadId Id of the thread accessing the timer.
- */
+ */
void StartTimer(const std::string& timerName,
const std::thread::id& threadId = std::thread::id());
/**
- * Halts the timer, and replaces its value with the delta time from its start.
- *
- * @param timerName The name of the timer in question.
+ * Halts the timer, and replaces its value with the delta time from its start.
+ *
+ * @param timerName The name of the timer in question.
* @param threadId Id of the thread accessing the timer.
- */
+ */
void StopTimer(const std::string& timerName,
const std::thread::id& threadId = std::thread::id());
diff --git a/src/mlpack/core/util/to_lower.hpp b/src/mlpack/core/util/to_lower.hpp
index f427449baf..0e420a45a2 100644
--- a/src/mlpack/core/util/to_lower.hpp
+++ b/src/mlpack/core/util/to_lower.hpp
@@ -16,10 +16,10 @@ namespace mlpack {
namespace util {
/**
- * Convert a string to lowercase letters.
- *
- * @param input The string to convert.
- */
+ * Convert a string to lowercase letters.
+ *
+ * @param input The string to convert.
+ */
inline std::string ToLower(const std::string& input)
{
std::string output;
diff --git a/src/mlpack/methods/amf/update_rules/nmf_mult_div.hpp b/src/mlpack/methods/amf/update_rules/nmf_mult_div.hpp
index f744dd0b38..8a318a2ad1 100644
--- a/src/mlpack/methods/amf/update_rules/nmf_mult_div.hpp
+++ b/src/mlpack/methods/amf/update_rules/nmf_mult_div.hpp
@@ -31,7 +31,7 @@ namespace amf {
* }
* @endcode
*
- * This is a multiplicative rule that ensures that the Kullback–Leibler
+ * This is a multiplicative rule that ensures that the Kullback-Leibler
* divergence
*
* \f[
diff --git a/src/mlpack/methods/ann/activation_functions/CMakeLists.txt b/src/mlpack/methods/ann/activation_functions/CMakeLists.txt
index d5c0868c1c..1639817716 100644
--- a/src/mlpack/methods/ann/activation_functions/CMakeLists.txt
+++ b/src/mlpack/methods/ann/activation_functions/CMakeLists.txt
@@ -20,6 +20,7 @@ set(SOURCES
poisson1_function.hpp
gaussian_function.hpp
hard_swish_function.hpp
+ tanh_exponential_function.hpp
)
# Add directory name to sources.
diff --git a/src/mlpack/methods/ann/activation_functions/tanh_exponential_function.hpp b/src/mlpack/methods/ann/activation_functions/tanh_exponential_function.hpp
new file mode 100644
index 0000000000..cabe427a88
--- /dev/null
+++ b/src/mlpack/methods/ann/activation_functions/tanh_exponential_function.hpp
@@ -0,0 +1,96 @@
+/**
+ * @file methods/ann/activation_functions/tanh_exponential_function.hpp
+ * @author Mayank Raj
+ *
+ * Definition and implementation of the Tanh exponential function.
+ *
+ * For more information see the following paper
+ *
+ * @code
+ * @misc{The Institution of Engineering and Technology 2015 ,
+ * title = {TanhExp: A Smooth Activation Function with High Convergence Speed for Lightweight Neural Networks},
+ * author = {Xinyu Liu and Xiaoguang Di},
+ * year = {2020},
+ * url = {https://arxiv.org/pdf/2003.09855v2.pdf},
+ * eprint = {2003.09855v2},
+ * archivePrefix = {arXiv},
+ * primaryClass = {cs.LG} }
+ * @endcode
+ *
+ * mlpack is free software; you may redistribute it and/or modify it under the
+ * terms of the 3-clause BSD license. You should have received a copy of the
+ * 3-clause BSD license along with mlpack. If not, see
+ * http://www.opensource.org/licenses/BSD-3-Clause for more information.
+ */
+#ifndef MLPACK_METHODS_ANN_ACTIVATION_FUNCTIONS_TANH_EXPONENTIAL_FUNCTION_HPP
+#define MLPACK_METHODS_ANN_ACTIVATION_FUNCTIONS_TANH_EXPONENTIAL_FUNCTION_HPP
+
+#include
+
+namespace mlpack {
+namespace ann /** Artificial Neural Network. */ {
+
+/**
+ * The TanhExp function, defined by
+ *
+ * @f{eqnarray*}{
+ * f(x) = x * tanh(e^x)\\
+ * f'(x) = tanh(e^x) - x*e^x*(tanh(e^x)^2 - 1)\\
+ * @f}
+ */
+ class TanhExpFunction
+{
+ public:
+ /**
+ * Computes the TanhExp function.
+ *
+ * @param x Input data.
+ * @return f(x).
+ */
+ static double Fn(const double x)
+ {
+ return x * std::tanh(std::exp(x));
+ }
+
+ /**
+ * Computes the TanhExp function.
+ *
+ * @param x Input data.
+ * @param y The resulting output activation.
+ */
+ template
+ static void Fn(const InputVecType& x, OutputVecType& y)
+ {
+ y = x % arma::tanh(arma::exp(x));
+ }
+
+ /**
+ * Computes the first derivative of the TanhExp function.
+ *
+ * @param y Input activation.
+ * @return f'(x)
+ */
+ static double Deriv(const double y)
+ {
+ return std::tanh(std::exp(y)) - y * std::exp(y) *
+ (std::pow(std::tanh(std::exp(y)), 2) - 1);
+ }
+
+ /**
+ * Computes the first derivatives of the tanh function.
+ *
+ * @param y Input activations.
+ * @param x The resulting derivatives.
+ */
+ template
+ static void Deriv(const InputVecType& y, OutputVecType& x)
+ {
+ x = arma::tanh(arma::exp(y)) - y % arma::exp(y) %
+ (arma::pow(arma::tanh(arma::exp(y)), 2) - 1);
+ }
+}; // class TanhExpFunction
+
+} // namespace ann
+} // namespace mlpack
+
+#endif
diff --git a/src/mlpack/methods/ann/layer/base_layer.hpp b/src/mlpack/methods/ann/layer/base_layer.hpp
index ae49f30fe6..7169d5f474 100644
--- a/src/mlpack/methods/ann/layer/base_layer.hpp
+++ b/src/mlpack/methods/ann/layer/base_layer.hpp
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
@@ -52,6 +53,7 @@ namespace ann /** Artificial Neural Network. */ {
* - ElliotLayer
* - GaussianLayer
* - HardSwishLayer
+ * - TanhExpLayer
*
* @tparam ActivationFunction Activation function used for the embedding layer.
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
@@ -290,6 +292,17 @@ template <
using HardSwishFunctionLayer = BaseLayer<
ActivationFunction, InputDataType, OutputDataType>;
+/**
+ * Standard TanhExp-Layer using the TanhExp activation function.
+ */
+template <
+ class ActivationFunction = TanhExpFunction,
+ typename InputDataType = arma::mat,
+ typename OutputDataType = arma::mat
+>
+using TanhExpFunctionLayer = BaseLayer<
+ ActivationFunction, InputDataType, OutputDataType>;
+
} // namespace ann
} // namespace mlpack
diff --git a/src/mlpack/methods/ann/layer/constant.hpp b/src/mlpack/methods/ann/layer/constant.hpp
index b908a0018e..9a0956ddf8 100644
--- a/src/mlpack/methods/ann/layer/constant.hpp
+++ b/src/mlpack/methods/ann/layer/constant.hpp
@@ -79,6 +79,12 @@ class Constant
//! Get the output size.
size_t OutSize() const { return outSize; }
+ //! Get the size of the weights.
+ size_t WeightSize() const
+ {
+ return 0;
+ }
+
/**
* Serialize the layer.
*/
diff --git a/src/mlpack/methods/ann/layer/linear_no_bias.hpp b/src/mlpack/methods/ann/layer/linear_no_bias.hpp
index 7182e84238..5426f1ff4f 100644
--- a/src/mlpack/methods/ann/layer/linear_no_bias.hpp
+++ b/src/mlpack/methods/ann/layer/linear_no_bias.hpp
@@ -123,6 +123,12 @@ class LinearNoBias
//! Modify the gradient.
OutputDataType& Gradient() { return gradient; }
+ //! Get the size of the weights.
+ size_t WeightSize() const
+ {
+ return inSize * outSize;
+ }
+
//! Get the shape of the input.
size_t InputShape() const
{
diff --git a/src/mlpack/methods/ann/layer/linear_no_bias_impl.hpp b/src/mlpack/methods/ann/layer/linear_no_bias_impl.hpp
index 032552f599..dbea56e94f 100644
--- a/src/mlpack/methods/ann/layer/linear_no_bias_impl.hpp
+++ b/src/mlpack/methods/ann/layer/linear_no_bias_impl.hpp
@@ -38,7 +38,7 @@ LinearNoBias::LinearNoBias(
outSize(outSize),
regularizer(regularizer)
{
- weights.set_size(outSize * inSize, 1);
+ weights.set_size(WeightSize(), 1);
}
template input.n_rows - 1)
+ rowEnd = input.n_rows - 1;
+ if (colEnd > input.n_cols - 1)
+ colEnd = input.n_cols - 1;
+
arma::mat subInput = input(
- arma::span(rowidx, rowidx + kernelWidth - 1 - offset),
- arma::span(colidx, colidx + kernelHeight - 1 - offset));
+ arma::span(rowidx, rowEnd),
+ arma::span(colidx, colEnd));
output(i, j) = arma::mean(arma::mean(subInput));
}
@@ -186,22 +194,36 @@ class MeanPooling
const arma::Mat& error,
arma::Mat& output)
{
- const size_t rStep = input.n_rows / error.n_rows - offset;
- const size_t cStep = input.n_cols / error.n_cols - offset;
arma::Mat unpooledError;
- for (size_t j = 0; j < input.n_cols - cStep; j += cStep)
+ for (size_t j = 0, colidx = 0; j < input.n_cols; j += strideHeight, colidx++)
{
- for (size_t i = 0; i < input.n_rows - rStep; i += rStep)
- {
- const arma::Mat& inputArea = input(arma::span(i, i + rStep - 1),
- arma::span(j, j + cStep - 1));
+ for (size_t i = 0, rowidx = 0; i < input.n_rows; i += strideWidth, rowidx++)
+ {
+ size_t rowEnd = i + kernelWidth - 1;
+ size_t colEnd = j + kernelHeight - 1;
- unpooledError = arma::Mat(inputArea.n_rows, inputArea.n_cols);
- unpooledError.fill(error(i / rStep, j / cStep) / inputArea.n_elem);
+ if (rowEnd > input.n_rows - 1)
+ {
+ if (floor)
+ continue;
+ rowEnd = input.n_rows - 1;
+ }
- output(arma::span(i, i + rStep - 1 - offset),
- arma::span(j, j + cStep - 1 - offset)) += unpooledError;
+ if (colEnd > input.n_cols - 1)
+ {
+ if (floor)
+ continue;
+ colEnd = input.n_cols - 1;
+ }
+
+ arma::mat InputArea = input(arma::span(i, rowEnd), arma::span(j, colEnd));
+
+ unpooledError = arma::Mat(InputArea.n_rows, InputArea.n_cols);
+ unpooledError.fill(error(rowidx, colidx) / InputArea.n_elem);
+
+ output(arma::span(i, i + InputArea.n_rows - 1),
+ arma::span(j, j + InputArea.n_cols - 1)) += unpooledError;
}
}
}
@@ -245,9 +267,6 @@ class MeanPooling
//! If true use maximum a posteriori during the forward pass.
bool deterministic;
- //! Locally-stored stored rounding offset.
- size_t offset;
-
//! Locally-stored number of input units.
size_t batchSize;
diff --git a/src/mlpack/methods/ann/layer/mean_pooling_impl.hpp b/src/mlpack/methods/ann/layer/mean_pooling_impl.hpp
index ce4e6c7895..ad4a8e6943 100644
--- a/src/mlpack/methods/ann/layer/mean_pooling_impl.hpp
+++ b/src/mlpack/methods/ann/layer/mean_pooling_impl.hpp
@@ -45,7 +45,6 @@ MeanPooling::MeanPooling(
outputHeight(0),
reset(false),
deterministic(false),
- offset(0),
batchSize(0)
{
// Nothing to do here.
@@ -67,8 +66,6 @@ void MeanPooling::Forward(
(double) kernelWidth) / (double) strideWidth + 1);
outputHeight = std::floor((inputHeight -
(double) kernelHeight) / (double) strideHeight + 1);
-
- offset = 0;
}
else
{
@@ -76,8 +73,6 @@ void MeanPooling::Forward(
(double) kernelWidth) / (double) strideWidth + 1);
outputHeight = std::ceil((inputHeight -
(double) kernelHeight) / (double) strideHeight + 1);
-
- offset = 1;
}
outputTemp = arma::zeros >(outputWidth, outputHeight,
diff --git a/src/mlpack/methods/ann/layer/radial_basis_function.hpp b/src/mlpack/methods/ann/layer/radial_basis_function.hpp
index 2387d612ab..6f84303360 100644
--- a/src/mlpack/methods/ann/layer/radial_basis_function.hpp
+++ b/src/mlpack/methods/ann/layer/radial_basis_function.hpp
@@ -110,6 +110,12 @@ class RBF
//! Modify the delta.
OutputDataType& Delta() { return delta; }
+ //! Get the size of the weights.
+ size_t WeightSize() const
+ {
+ return 0;
+ }
+
//! Get the shape of the input.
size_t InputShape() const
{
diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp
index 10a5f92bd5..c163d0d148 100644
--- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp
+++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.cpp
@@ -18,12 +18,12 @@ using namespace mlpack::regression;
BayesianLinearRegression::BayesianLinearRegression(const bool centerData,
const bool scaleData,
- const size_t nIterMax,
- const double tol) :
+ const size_t maxIterations,
+ const double tolerance) :
centerData(centerData),
scaleData(scaleData),
- nIterMax(nIterMax),
- tol(tol),
+ maxIterations(maxIterations),
+ tolerance(tolerance),
responsesOffset(0.0),
alpha(0.0),
beta(0.0),
@@ -60,7 +60,7 @@ double BayesianLinearRegression::Train(const arma::mat& data,
unsigned short i = 0;
double deltaAlpha = 1.0, deltaBeta = 1.0, crit = 1.0;
- while ((crit > tol) && (i < nIterMax))
+ while ((crit > tolerance) && (i < maxIterations))
{
deltaAlpha = -alpha;
deltaBeta = -beta;
diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp
index a15ce1ced1..417e795bff 100644
--- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp
+++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp
@@ -21,30 +21,30 @@ namespace mlpack {
namespace regression {
/**
- * A Bayesian approach to the maximum likelihood estimation of the parameters
- * \f$ \omega \f$ of the linear regression model. The Complexity is governed by
- * the addition of a gaussian isotropic prior of precision \f$ \alpha \f$ over
- * \f$ \omega \f$:
+ * A Bayesian approach to the maximum likelihood estimation of the parameters
+ * \f$ \omega \f$ of the linear regression model. The Complexity is governed by
+ * the addition of a gaussian isotropic prior of precision \f$ \alpha \f$ over
+ * \f$ \omega \f$:
*
* \f[
* p(\omega|\alpha) = \mathcal{N}(\omega|0, \alpha^{-1}I)
* \f]
- *
- * The optimization procedure calculates the posterior distribution of
- * \f$ \omega \f$ knowing the data by maximizing an approximation of the log
- * marginal likelihood derived from a type II maximum likelihood approximation.
+ *
+ * The optimization procedure calculates the posterior distribution of
+ * \f$ \omega \f$ knowing the data by maximizing an approximation of the log
+ * marginal likelihood derived from a type II maximum likelihood approximation.
* The determination of \f$ alpha \f$ and of the noise precision \f$ beta \f$
- * is part of the optimization process, leading to an automatic determination of
- * w. The model being entirely based on probabilty distributions, uncertainties
+ * is part of the optimization process, leading to an automatic determination of
+ * w. The model being entirely based on probabilty distributions, uncertainties
* are available and easly computed for both the parameters and the predictions.
*
- * The advantage over linear regression and ridge regression is that the
+ * The advantage over linear regression and ridge regression is that the
* regularization is determined from all the training data alone without any
- * require to an hold out method.
+ * require to an hold out method.
*
- * The code below is an implementation of the maximization of the evidence
+ * The code below is an implementation of the maximization of the evidence
* function described in the section 3.5.2 of the C.Bishop book, Pattern
- * Recognition and Machine Learning.
+ * Recognition and Machine Learning.
*
* @code
* @article{MacKay91bayesianinterpolation,
@@ -60,36 +60,37 @@ namespace regression {
* @code
* @book{Bishop:2006:PRM:1162264,
* author = {Bishop, Christopher M.},
- * title = {Pattern Recognition and Machine Learning (Information Science
+ * title = {Pattern Recognition and Machine Learning (Information Science
* and Statistics)},
* chapter = {3}
* year = {2006},
* isbn = {0387310738},
* publisher = {Springer-Verlag},
* address = {Berlin, Heidelberg},
- * }
+ * }
* @endcode
- *
+ *
* Example of use:
*
* @code
* arma::mat xTrain; // Train data matrix. Column-major.
* arma::rowvec yTrain; // Train target values.
-
+ *
* // Train the model. Regularization strength is optimally tunned with the
* // training data alone by applying the Train method.
- * BayesianLinearRegression estimator(); // Instanciate the estimator with default option.
+ * // Instantiate the estimator with default option.
+ * BayesianLinearRegression estimator;
* estimator.Train(xTrain, yTrain);
-
+ *
* // Prediction on test points.
* arma::mat xTest; // Test data matrix. Column-major.
* arma::rowvec predictions;
-
+ *
* estimator.Predict(xTest, prediction);
-
+ *
* arma::rowvec yTest; // Test target values.
* estimator.RMSE(xTest, yTest); // Evaluate using the RMSE score.
-
+ *
* // Compute the standard deviations of the predictions.
* arma::rowvec stds;
* estimator.Predict(xTest, responses, stds)
@@ -107,19 +108,20 @@ class BayesianLinearRegression
* examples.
* @param scaleData Whether or not scale the data according to the
* standard deviation of each feature.
- * @param nIterMax Maximum number of iterations for convergency.
- * @param tol Level from which the solution is considered sufficientlly
- * stable.
+ * @param maxIterations Maximum number of iterations for convergency.
+ * @param tolerance Level from which the solution is considered sufficientlly
+ * stable.
*/
BayesianLinearRegression(const bool centerData = true,
const bool scaleData = false,
- const size_t nIterMax = 50,
- const double tol = 1e-4);
+ const size_t maxIterations = 50,
+ const double tolerance = 1e-4);
/**
- * Run BayesianLinearRegression. The input matrix (like all mlpack matrices) should be
- * column-major -- each column is an observation and each row is a dimension.
- *
+ * Run BayesianLinearRegression. The input matrix (like all mlpack matrices)
+ * should be column-major -- each column is an observation and each row is a
+ * dimension.
+ *
* @param data Column-major input data, dim(P, N).
* @param responses A vector of targets, dim(N).
* @return Root mean squared error.
@@ -139,12 +141,13 @@ class BayesianLinearRegression
arma::rowvec& predictions) const;
/**
- * Predict \f$y_{i}\f$ and the standard deviation of the predictive posterior
+ * Predict \f$y_{i}\f$ and the standard deviation of the predictive posterior
* distribution for each data point in the given data matrix, using the
* currently-trained Bayesian Ridge estimator.
*
* @param points The data point to apply the model.
- * @param predictions Vector which will contain calculated values on completion.
+ * @param predictions Vector which will contain calculated values on
+ * completion.
* @param std Standard deviations of the predictions.
*/
void Predict(const arma::mat& points,
@@ -163,7 +166,7 @@ class BayesianLinearRegression
const arma::rowvec& responses) const;
/**
- * Get the solution vector.
+ * Get the solution vector.
*
* @return omega Solution vector.
*/
@@ -187,7 +190,7 @@ class BayesianLinearRegression
/**
* Get the estimated variance. Train() must be called before.
- *
+ *
* @return 1.0 / \f$ \beta \f$
*/
double Variance() const { return 1.0 / Beta(); }
@@ -200,7 +203,7 @@ class BayesianLinearRegression
const arma::colvec& DataOffset() const { return dataOffset; }
/**
- * Get the vector of standard deviations computed on the features over the
+ * Get the vector of standard deviations computed on the features over the
* training points.
*
* @return dataOffset
@@ -214,9 +217,31 @@ class BayesianLinearRegression
*/
double ResponsesOffset() const { return responsesOffset; }
+ //! Get whether the data will be centered during training.
+ bool CenterData() const { return centerData; }
+ //! Modify whether the data will be centered during training.
+ bool& CenterData() { return centerData; }
+
+ //! Get whether the data will be scaled by standard deviations during
+ //! training.
+ bool ScaleData() const { return scaleData; }
+ //! Modify whether the data will be scaled by standard deviations during
+ //! training.
+ bool& ScaleData() { return scaleData; }
+
+ //! Get the maximum number of iterations for training.
+ size_t MaxIterations() const { return maxIterations; }
+ //! Modify the maximum number of iterations for training.
+ size_t& MaxIterations() { return maxIterations; }
+
+ //! Get the tolerance for training to converge.
+ double Tolerance() const { return tolerance; }
+ //! Modify the tolerance for training to converge.
+ double& Tolerance() { return tolerance; }
+
/**
* Serialize the BayesianLinearRegression model.
- **/
+ */
template
void serialize(Archive& ar, const uint32_t version);
@@ -227,11 +252,11 @@ class BayesianLinearRegression
//! Scale the data by standard deviations if true.
bool scaleData;
- //! Maximum number of iterations for convergency.
- size_t nIterMax;
+ //! Maximum number of iterations for convergence.
+ size_t maxIterations;
//! Level from which the solution is considered sufficientlly stable.
- double tol;
+ double tolerance;
//! Mean vector computed over the points.
arma::colvec dataOffset;
@@ -251,7 +276,7 @@ class BayesianLinearRegression
//! Effective number of parameters.
double gamma;
- //! Solution vector
+ //! Solution vector.
arma::colvec omega;
//! Covariance matrix of the solution vector omega.
diff --git a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_impl.hpp b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_impl.hpp
index d0881dd06a..65a4d70998 100644
--- a/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_impl.hpp
+++ b/src/mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_impl.hpp
@@ -26,8 +26,8 @@ void BayesianLinearRegression::serialize(Archive& ar,
{
ar(CEREAL_NVP(centerData));
ar(CEREAL_NVP(scaleData));
- ar(CEREAL_NVP(nIterMax));
- ar(CEREAL_NVP(tol));
+ ar(CEREAL_NVP(maxIterations));
+ ar(CEREAL_NVP(tolerance));
ar(CEREAL_NVP(dataOffset));
ar(CEREAL_NVP(dataScale));
ar(CEREAL_NVP(responsesOffset));
diff --git a/src/mlpack/methods/block_krylov_svd/randomized_block_krylov_svd.cpp b/src/mlpack/methods/block_krylov_svd/randomized_block_krylov_svd.cpp
index ff2377f312..101d7cd477 100644
--- a/src/mlpack/methods/block_krylov_svd/randomized_block_krylov_svd.cpp
+++ b/src/mlpack/methods/block_krylov_svd/randomized_block_krylov_svd.cpp
@@ -83,7 +83,7 @@ void RandomizedBlockKrylovSVD::Apply(const arma::mat& data,
arma::qr_econ(Q, R, K);
- // Approximate eigenvalues and eigenvectors using Rayleigh–Ritz method.
+ // Approximate eigenvalues and eigenvectors using Rayleigh-Ritz method.
arma::svd_econ(u, s, v, Q.t() * data);
// Do economical singular value decomposition and compute only the
diff --git a/src/mlpack/methods/decision_tree/all_categorical_split.hpp b/src/mlpack/methods/decision_tree/all_categorical_split.hpp
index 2a9de942a9..faa8f16c6b 100644
--- a/src/mlpack/methods/decision_tree/all_categorical_split.hpp
+++ b/src/mlpack/methods/decision_tree/all_categorical_split.hpp
@@ -29,7 +29,6 @@ class AllCategoricalSplit
{
public:
// No extra info needed for split.
- template
class AuxiliarySplitInfo { };
/**
@@ -64,8 +63,8 @@ class AllCategoricalSplit
const WeightVecType& weights,
const size_t minimumLeafSize,
const double minimumGainSplit,
- arma::Col& classProbabilities,
- AuxiliarySplitInfo& aux);
+ arma::vec& classProbabilities,
+ AuxiliarySplitInfo& aux);
/**
* Return the number of children in the split.
@@ -73,9 +72,8 @@ class AllCategoricalSplit
* @param classProbabilities Auxiliary information for the split.
* @param * (aux) Auxiliary information for the split (Unused).
*/
- template
- static size_t NumChildren(const arma::Col& classProbabilities,
- const AuxiliarySplitInfo& /* aux */);
+ static size_t NumChildren(const arma::vec& classProbabilities,
+ const AuxiliarySplitInfo& /* aux */);
/**
* Calculate the direction a point should percolate to.
@@ -87,8 +85,8 @@ class AllCategoricalSplit
template
static size_t CalculateDirection(
const ElemType& point,
- const arma::Col& classProbabilities,
- const AuxiliarySplitInfo& /* aux */);
+ const arma::vec& classProbabilities,
+ const AuxiliarySplitInfo& /* aux */);
};
} // namespace tree
diff --git a/src/mlpack/methods/decision_tree/all_categorical_split_impl.hpp b/src/mlpack/methods/decision_tree/all_categorical_split_impl.hpp
index 12ac592ad4..00135625ab 100644
--- a/src/mlpack/methods/decision_tree/all_categorical_split_impl.hpp
+++ b/src/mlpack/methods/decision_tree/all_categorical_split_impl.hpp
@@ -26,8 +26,8 @@ double AllCategoricalSplit::SplitIfBetter(
const WeightVecType& weights,
const size_t minimumLeafSize,
const double minimumGainSplit,
- arma::Col& classProbabilities,
- AuxiliarySplitInfo& /* aux */)
+ arma::vec& classProbabilities,
+ AuxiliarySplitInfo& /* aux */)
{
// Count the number of elements in each potential child.
const double epsilon = 1e-7; // Tolerance for floating-point errors.
@@ -110,20 +110,19 @@ double AllCategoricalSplit::SplitIfBetter(
}
template
-template
size_t AllCategoricalSplit::NumChildren(
- const arma::Col& classProbabilities,
- const AuxiliarySplitInfo& /* aux */)
+ const arma::vec& classProbabilities,
+ const AuxiliarySplitInfo& /* aux */)
{
- return classProbabilities[0];
+ return size_t(classProbabilities[0]);
}
template
template
size_t AllCategoricalSplit::CalculateDirection(
const ElemType& point,
- const arma::Col& /* classProbabilities */,
- const AuxiliarySplitInfo& /* aux */)
+ const arma::vec& /* classProbabilities */,
+ const AuxiliarySplitInfo& /* aux */)
{
return (size_t) point;
}
diff --git a/src/mlpack/methods/decision_tree/best_binary_numeric_split.hpp b/src/mlpack/methods/decision_tree/best_binary_numeric_split.hpp
index 976b810c63..ab081c84fc 100644
--- a/src/mlpack/methods/decision_tree/best_binary_numeric_split.hpp
+++ b/src/mlpack/methods/decision_tree/best_binary_numeric_split.hpp
@@ -28,7 +28,6 @@ class BestBinaryNumericSplit
{
public:
// No extra info needed for split.
- template
class AuxiliarySplitInfo { };
/**
@@ -37,6 +36,10 @@ class BestBinaryNumericSplit
* return the value 'bestGain'. If a split is made, then classProbabilities
* and aux may be modified.
*
+ * It's not necessary that `ElemType` is the same as the type of the data in
+ * `VecType`---if they are different, casting will be done to store the
+ * auxiliary information.
+ *
* @param bestGain Best gain seen so far (we'll only split if we find gain
* better than this).
* @param data The dimension of data points to check for a split in.
@@ -60,15 +63,14 @@ class BestBinaryNumericSplit
const WeightVecType& weights,
const size_t minimumLeafSize,
const double minimumGainSplit,
- arma::Col& classProbabilities,
- AuxiliarySplitInfo& aux);
+ arma::vec& classProbabilities,
+ AuxiliarySplitInfo& aux);
/**
* Returns 2, since the binary split always has two children.
*/
- template
- static size_t NumChildren(const arma::Col& /* classProbabilities */,
- const AuxiliarySplitInfo& /* aux */)
+ static size_t NumChildren(const arma::vec& /* classProbabilities */,
+ const AuxiliarySplitInfo& /* aux */)
{
return 2;
}
@@ -83,8 +85,8 @@ class BestBinaryNumericSplit
template
static size_t CalculateDirection(
const ElemType& point,
- const arma::Col& classProbabilities,
- const AuxiliarySplitInfo& /* aux */);
+ const arma::vec& classProbabilities,
+ const AuxiliarySplitInfo& /* aux */);
};
} // namespace tree
diff --git a/src/mlpack/methods/decision_tree/best_binary_numeric_split_impl.hpp b/src/mlpack/methods/decision_tree/best_binary_numeric_split_impl.hpp
index f5b38220ca..14bd0e3fb9 100644
--- a/src/mlpack/methods/decision_tree/best_binary_numeric_split_impl.hpp
+++ b/src/mlpack/methods/decision_tree/best_binary_numeric_split_impl.hpp
@@ -25,8 +25,8 @@ double BestBinaryNumericSplit::SplitIfBetter(
const WeightVecType& weights,
const size_t minimumLeafSize,
const double minimumGainSplit,
- arma::Col& classProbabilities,
- AuxiliarySplitInfo& /* aux */)
+ arma::vec& classProbabilities,
+ AuxiliarySplitInfo& /* aux */)
{
// First sanity check: if we don't have enough points, we can't split.
if (data.n_elem < (minimumLeafSize * 2))
@@ -189,8 +189,8 @@ template
template
size_t BestBinaryNumericSplit::CalculateDirection(
const ElemType& point,
- const arma::Col& classProbabilities,
- const AuxiliarySplitInfo& /* aux */)
+ const arma::vec& classProbabilities,
+ const AuxiliarySplitInfo& /* aux */)
{
if (point <= classProbabilities[0])
return 0; // Go left.
diff --git a/src/mlpack/methods/decision_tree/decision_tree.hpp b/src/mlpack/methods/decision_tree/decision_tree.hpp
index 9ab8599aec..fee81909e3 100644
--- a/src/mlpack/methods/decision_tree/decision_tree.hpp
+++ b/src/mlpack/methods/decision_tree/decision_tree.hpp
@@ -30,18 +30,20 @@ namespace tree {
*
* The class inherits from the auxiliary split information in order to prevent
* an empty auxiliary split information struct from taking any extra size.
+ *
+ * Note that `ElemType` is a template parameter controlling the type that is
+ * used to store split information. In general, you would want to set this to
+ * be the same as the type of the data that you will be using, but it's not
+ * required to do that.
*/
template class NumericSplitType = BestBinaryNumericSplit,
template class CategoricalSplitType = AllCategoricalSplit,
typename DimensionSelectionType = AllDimensionSelect,
- typename ElemType = double,
bool NoRecursion = false>
class DecisionTree :
- public NumericSplitType::template
- AuxiliarySplitInfo,
- public CategoricalSplitType::template
- AuxiliarySplitInfo
+ public NumericSplitType::AuxiliarySplitInfo,
+ public CategoricalSplitType::AuxiliarySplitInfo
{
public:
//! Allow access to the numeric split type.
@@ -500,9 +502,9 @@ class DecisionTree :
//! Note that this class will also hold the members of the NumericSplit and
//! CategoricalSplit AuxiliarySplitInfo classes, since it inherits from them.
//! We'll define some convenience typedefs here.
- typedef typename NumericSplit::template AuxiliarySplitInfo
+ typedef typename NumericSplit::AuxiliarySplitInfo
NumericAuxiliarySplitInfo;
- typedef typename CategoricalSplit::template AuxiliarySplitInfo
+ typedef typename CategoricalSplit::AuxiliarySplitInfo
CategoricalAuxiliarySplitInfo;
/**
@@ -578,13 +580,11 @@ class DecisionTree :
template class NumericSplitType = BestBinaryNumericSplit,
template class CategoricalSplitType = AllCategoricalSplit,
- typename DimensionSelectType = AllDimensionSelect,
- typename ElemType = double>
+ typename DimensionSelectType = AllDimensionSelect>
using DecisionStump = DecisionTree;
/**
@@ -595,7 +595,6 @@ typedef DecisionTree ID3DecisionStump;
} // namespace tree
} // namespace mlpack
diff --git a/src/mlpack/methods/decision_tree/decision_tree_impl.hpp b/src/mlpack/methods/decision_tree/decision_tree_impl.hpp
index b99075f5b2..e4cd77851b 100644
--- a/src/mlpack/methods/decision_tree/decision_tree_impl.hpp
+++ b/src/mlpack/methods/decision_tree/decision_tree_impl.hpp
@@ -22,14 +22,12 @@ template class NumericSplitType,
template class CategoricalSplitType,
typename DimensionSelectionType,
- typename ElemType,
bool NoRecursion>
template
DecisionTree::DecisionTree(
MatType data,
const data::DatasetInfo& datasetInfo,
@@ -62,14 +60,12 @@ template class NumericSplitType,
template class CategoricalSplitType,
typename DimensionSelectionType,
- typename ElemType,
bool NoRecursion>
template
DecisionTree::DecisionTree(
MatType data,
LabelsType labels,
@@ -100,14 +96,12 @@ template class NumericSplitType,
template class CategoricalSplitType,
typename DimensionSelectionType,
- typename ElemType,
bool NoRecursion>
template
DecisionTree::DecisionTree(
MatType data,
const data::DatasetInfo& datasetInfo,
@@ -144,14 +138,12 @@ template class NumericSplitType,
template class CategoricalSplitType,
typename DimensionSelectionType,
- typename ElemType,
bool NoRecursion>
template
DecisionTree::DecisionTree(
const DecisionTree& other,
MatType data,
@@ -185,14 +177,12 @@ template class NumericSplitType,
template class CategoricalSplitType,
typename DimensionSelectionType,
- typename ElemType,
bool NoRecursion>
template
DecisionTree::DecisionTree(
MatType data,
LabelsType labels,
@@ -229,14 +219,12 @@ template class NumericSplitType,
template class CategoricalSplitType,
typename DimensionSelectionType,
- typename ElemType,
bool NoRecursion>
template
DecisionTree::DecisionTree(
const DecisionTree& other,
MatType data,
@@ -275,13 +263,11 @@ template class NumericSplitType,
template class CategoricalSplitType,
typename DimensionSelectionType,
- typename ElemType,
bool NoRecursion>
DecisionTree::DecisionTree(const size_t numClasses) :
splitDimension(0),
dimensionTypeOrMajorityClass(0),
@@ -296,13 +282,11 @@ template class NumericSplitType,
template class CategoricalSplitType,
typename DimensionSelectionType,
- typename ElemType,
bool NoRecursion>
DecisionTree::DecisionTree(const DecisionTree& other) :
NumericAuxiliarySplitInfo(other),
CategoricalAuxiliarySplitInfo(other),
@@ -320,13 +304,11 @@ template class NumericSplitType,
template class CategoricalSplitType,
typename DimensionSelectionType,
- typename ElemType,
bool NoRecursion>
DecisionTree::DecisionTree(DecisionTree&& other) :
NumericAuxiliarySplitInfo(std::move(other)),
CategoricalAuxiliarySplitInfo(std::move(other)),
@@ -344,19 +326,16 @@ template class NumericSplitType,
template class CategoricalSplitType,
typename DimensionSelectionType,
- typename ElemType,
bool NoRecursion>
DecisionTree&
DecisionTree::operator=(const DecisionTree& other)
{
if (this == &other)
@@ -388,19 +367,16 @@ template class NumericSplitType,
template class CategoricalSplitType,
typename DimensionSelectionType,
- typename ElemType,
bool NoRecursion>
DecisionTree&
DecisionTree::operator=(DecisionTree&& other)
{
if (this == &other)
@@ -432,13 +408,11 @@ template class NumericSplitType,
template class CategoricalSplitType,
typename DimensionSelectionType,
- typename ElemType,
bool NoRecursion>
DecisionTree