diff --git a/CMake/COOT_FindCLBLAS.cmake b/CMake/COOT_FindCLBLAS.cmake new file mode 100644 index 000000000..6aa62fe58 --- /dev/null +++ b/CMake/COOT_FindCLBLAS.cmake @@ -0,0 +1,44 @@ +# - Find clBLAS (includes and library) +# This module defines +# CLBLAS_INCLUDE_DIR +# CLBLAS_LIBRARIES +# CLBLAS_FOUND +# also defined, but not for general use are +# CLBLAS_LIBRARY, where to find the library. + +find_path(CLBLAS_INCLUDE_DIR clBLAS.h +/usr/include/ +/usr/local/include/ +) + +set(CLBLAS_NAMES ${CLBLAS_NAMES} clBLAS) +find_library(CLBLAS_LIBRARY + NAMES ${CLBLAS_NAMES} + PATHS /usr/lib64/ /usr/local/lib64/ /usr/lib /usr/local/lib + ) + +if (CLBLAS_LIBRARY AND CLBLAS_INCLUDE_DIR) + set(CLBLAS_LIBRARIES ${CLBLAS_LIBRARY}) + set(CLBLAS_FOUND "YES") +else () + set(CLBLAS_FOUND "NO") +endif () + +if (CLBLAS_FOUND) + if (NOT CLBLAS_FIND_QUIETLY) + message(STATUS "Found a clBLAS library: ${CLBLAS_LIBRARIES}") + endif () +else () + if (CLBLAS_FIND_REQUIRED) + message(FATAL_ERROR "Could not find a clBLAS library") + endif () +endif () + +# Deprecated declarations. +set (NATIVE_CLBLAS_INCLUDE_PATH ${CLBLAS_INCLUDE_DIR} ) +get_filename_component (NATIVE_CLBLAS_LIB_PATH ${CLBLAS_LIBRARY} PATH) + +mark_as_advanced( + CLBLAS_LIBRARY + CLBLAS_INCLUDE_DIR + ) diff --git a/CMake/COOT_FindCLBlast.cmake b/CMake/COOT_FindCLBlast.cmake new file mode 100644 index 000000000..c26d82d05 --- /dev/null +++ b/CMake/COOT_FindCLBlast.cmake @@ -0,0 +1,44 @@ +# - Find clBlast (includes and library) +# This module defines +# CLBLAST_INCLUDE_DIR +# CLBLAST_LIBRARIES +# CLBLAST_FOUND +# also defined, but not for general use are +# CLBLAST_LIBRARY, where to find the library. + +find_path(CLBLAST_INCLUDE_DIR clblast.h +/usr/include/ +/usr/local/include/ +) + +set(CLBLAST_NAMES ${CLBLAST_NAMES} clblast) +find_library(CLBLAST_LIBRARY + NAMES ${CLBLAST_NAMES} + PATHS /usr/lib64/ /usr/local/lib64/ /usr/lib /usr/local/lib + ) + +if (CLBLAST_LIBRARY AND CLBLAST_INCLUDE_DIR) + set(CLBLAST_LIBRARIES ${CLBLAST_LIBRARY}) + set(CLBLAST_FOUND "YES") +else () + set(CLBLAST_FOUND "NO") +endif () + +if (CLBLAST_FOUND) + if (NOT CLBLAST_FIND_QUIETLY) + message(STATUS "Found a clBlast library: ${CLBLAST_LIBRARIES}") + endif () +else () + if (CLBLAST_FIND_REQUIRED) + message(FATAL_ERROR "Could not find a clBlast library") + endif () +endif () + +# Deprecated declarations. +set (NATIVE_CLBLAST_INCLUDE_PATH ${CLBLAST_INCLUDE_DIR} ) +get_filename_component (NATIVE_CLBLAST_LIB_PATH ${CLBLAST_LIBRARY} PATH) + +mark_as_advanced( + CLBLAST_LIBRARY + CLBLAST_INCLUDE_DIR + ) diff --git a/CMake/COOT_FindNVRTC.cmake b/CMake/COOT_FindNVRTC.cmake new file mode 100644 index 000000000..854fc98d6 --- /dev/null +++ b/CMake/COOT_FindNVRTC.cmake @@ -0,0 +1,35 @@ +# - Find clBlast (includes and library) +# This module defines +# CLBLAST_INCLUDE_DIR +# CLBLAST_LIBRARIES +# CLBLAST_FOUND +# also defined, but not for general use are +# CLBLAST_LIBRARY, where to find the library. + +set(NVRTC_NAMES ${NVRTC_NAMES} nvrtc) +find_library(NVRTC_LIBRARY + NAMES ${NVRTC_NAMES} + PATHS /usr/lib64/ /usr/local/lib64/ /usr/lib /usr/local/lib /usr/lib/x86_64-linux-gnu/ + ) + +if (NVRTC_LIBRARY) + set(NVRTC_LIBRARIES ${NVRTC_LIBRARY}) + set(NVRTC_FOUND "YES") +else () + set(NVRTC_FOUND "NO") +endif () + +if (NVRTC_FOUND) + if (NOT NVRTC_FIND_QUIETLY) + message(STATUS "Found NVRTC library: ${NVRTC_LIBRARIES}") + endif () +else () + if (NVRTC_FIND_REQUIRED) + message(FATAL_ERROR "Could not find NVRTC library") + endif () +endif () + +# Deprecated declarations. +get_filename_component (NATIVE_NVRTC_LIB_PATH ${NVRTC_LIBRARY} PATH) + +mark_as_advanced(NVRTC_LIBRARY) diff --git a/CMake/FindArmadillo.cmake b/CMake/FindArmadillo.cmake index ee458e22b..3327417f4 100644 --- a/CMake/FindArmadillo.cmake +++ b/CMake/FindArmadillo.cmake @@ -83,7 +83,7 @@ if(EXISTS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/config.hpp") # ARMA_USE_BLAS string(REGEX MATCH "\r?\n[\t ]*#if[\t ]+!defined[(]ARMA_USE_BLAS[)][\t ]*\r?\n[\t ]*#define[ \t]+ARMA_USE_BLAS[ \t]*\r?\n" ARMA_USE_BLAS "${_armadillo_CONFIG_CONTENTS}") - # ARMA_USE_ARPACK + # ARMA_USE_ARPACK string(REGEX MATCH "\r?\n[\t ]*#if[\t ]+!defined[(]ARMA_USE_ARPACK[)][\t ]*\r?\n[\t ]*#define[ \t]+ARMA_USE_ARPACK[ \t]*\r?\n" ARMA_USE_ARPACK "${_armadillo_CONFIG_CONTENTS}") diff --git a/CMake/FindBandicoot.cmake b/CMake/FindBandicoot.cmake new file mode 100644 index 000000000..242762e52 --- /dev/null +++ b/CMake/FindBandicoot.cmake @@ -0,0 +1,333 @@ +# - Find Bandicoot +# Find Bandicoot: GPU accelerator add-on for the Armadillo C++ linear algebra +# library +# +# Using Bandicoot: +# find_package(Bandicoot REQUIRED) +# include_directories(${BANDICOOT_INCLUDE_DIRS}) +# add_executable(foo foo.cc) +# target_link_libraries(foo ${BANDICOOT_LIBRARIES}) +# This module sets the following variables: +# BANDICOOT_FOUND - set to true if the library is found +# BANDICOOT_INCLUDE_DIRS - list of required include directories +# BANDICOOT_LIBRARIES - list of libraries to be linked +# BANDICOOT_VERSION_MAJOR - major version number +# BANDICOOT_VERSION_MINOR - minor version number +# BANDICOOT_VERSION_PATCH - patch version number +# BANDICOOT_VERSION_STRING - version number as a string (ex: "1.0.4") +# BANDICOOT_VERSION_NOTE - name of the version (ex: "unstable development version") + +find_path(BANDICOOT_INCLUDE_DIR + NAMES bandicoot + PATHS "$ENV{ProgramFiles}/Bandicoot/include" + ) + +if(BANDICOOT_INCLUDE_DIR) + # Extract version information. + file(READ "${BANDICOOT_INCLUDE_DIR}/bandicoot_bits/coot_version.hpp" _bandicoot_HEADER_CONTENTS) + string(REGEX REPLACE ".*#define COOT_VERSION_MAJOR ([0-9]+).*" "\\1" BANDICOOT_VERSION_MAJOR "${_bandicoot_HEADER_CONTENTS}") + string(REGEX REPLACE ".*#define COOT_VERSION_MINOR ([0-9]+).*" "\\1" BANDICOOT_VERSION_MINOR "${_bandicoot_HEADER_CONTENTS}") + string(REGEX REPLACE ".*#define COOT_VERSION_PATCH ([0-9]+).*" "\\1" BANDICOOT_VERSION_PATCH "${_bandicoot_HEADER_CONTENTS}") + string(REGEX REPLACE ".*#define COOT_VERSION_NOTE\ +\"([0-9a-zA-Z\ _-]+)\".*" "\\1" BANDICOOT_VERSION_NOTE "${_bandicoot_HEADER_CONTENTS}") + + set(BANDICOOT_VERSION_STRING "${BANDICOOT_VERSION_MAJOR}.${BANDICOOT_VERSION_MINOR}.${BANDICOOT_VERSION_PATCH}") +endif () + +# Determine what support libraries are being used, and whether or not we need to +# link against them. We need to look in config.hpp. +set(SUPPORT_INCLUDE_DIRS "") +set(SUPPORT_LIBRARIES "") +set(COOT_NEED_LIBRARY true) # Assume true. +if(EXISTS "${BANDICOOT_INCLUDE_DIR}/bandicoot_bits/config.hpp") + file(READ "${BANDICOOT_INCLUDE_DIR}/bandicoot_bits/config.hpp" _bandicoot_CONFIG_CONTENTS) + # COOT_USE_WRAPPER + string(REGEX MATCH "\r?\n[\t ]*#define[ \t]+COOT_USE_WRAPPER[ \t]*\r?\n" COOT_USE_WRAPPER "${_bandicoot_CONFIG_CONTENTS}") + + # COOT_USE_OPENCL + string(REGEX MATCH "\r?\n[\t ]*#if[\t ]+!defined[(]COOT_USE_OPENCL[)][\t ]*\r?\n[\t + ]*#define[ \t]+COOT_USE_OPENCL[ \t]*\r?\n" COOT_USE_OPENCL "${_bandicoot_CONFIG_CONTENTS}") + + # COOT_USE_CUDA + string(REGEX MATCH "\r?\n[\t ]*#if[\t ]+!defined[(]COOT_USE_CUDA[)][\t ]*\r?\n[\t + ]*#define[ \t]+COOT_USE_CUDA[ \t]*\r?\n" COOT_USE_CUDA "${_bandicoot_CONFIG_CONTENTS}") + + # COOT_USE_LAPACK + string(REGEX MATCH "\r?\n[\t ]*#if[\t ]+!defined[(]COOT_USE_LAPACK[)][\t ]*\r?\n[\t ]*#define[ \t]+COOT_USE_LAPACK[ \t]*\r?\n" COOT_USE_LAPACK "${_bandicoot_CONFIG_CONTENTS}") + + # COOT_USE_BLAS + string(REGEX MATCH "\r?\n[\t ]*#if[\t ]+!defined[(]COOT_USE_BLAS[)][\t ]*\r?\n[\t ]*#define[ \t]+COOT_USE_BLAS[ \t]*\r?\n" COOT_USE_BLAS "${_bandicoot_CONFIG_CONTENTS}") + + # If we aren't wrapping, things get a little more complex. + if("${COOT_USE_WRAPPER}" STREQUAL "") + set(COOT_NEED_LIBRARY false) + message(STATUS "COOT_USE_WRAPPER is not defined, so all dependencies of " + "Bandicoot must be manually linked.") + + set(HAVE_OPENCL false) + set(HAVE_CUDA false) + set(HAVE_LAPACK false) + set(HAVE_BLAS false) + + # Search for OpenCL. + if (NOT "${COOT_USE_OPENCL}" STREQUAL "" AND NOT HAVE_OPENCL) + set(OpenCL_FIND_QUIETLY true) + include(FindOpenCL) + + if (OpenCL_FOUND) + message(STATUS "OpenCL includes: ${OpenCL_INCLUDE_DIRS}") + message(STATUS "OpenCL libraries: ${OpenCL_LIBRARIES}") + + set(SUPPORT_INCLUDE_DIRS "${SUPPORT_INCLUDE_DIRS}" + "${OpenCL_INCLUDE_DIRS}") + set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${OpenCL_LIBRARIES}") + set(HAVE_OPENCL true) + endif () + + # Search for clBLAS. + set(CLBLAS_FIND_QUIETLY true) + include(COOT_FindCLBLAS) + + if (CLBLAS_FOUND) + message(STATUS "clBLAS includes: ${CLBLAS_INCLUDE_DIR}") + message(STATUS "clBLAS libraries: ${CLBLAS_LIBRARIES}") + + set(SUPPORT_INCLUDE_DIRS "${SUPPORT_INCLUDE_DIRS}" + "${CLBLAS_INCLUDE_DIR}") + set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${CLBLAS_LIBRARIES}") + set(HAVE_CLBLAS true) + endif () + + # Search for clBlast. + set(CLBLAST_FIND_QUIETLY true) + include(COOT_FindCLBlast) + + if (CLBLAST_FOUND) + message(STATUS "clBlast includes: ${CLBLAST_INCLUDE_DIR}") + message(STATUS "clBlast libraries: ${CLBLAST_LIBRARIES}") + + set(SUPPORT_INCLUDE_DIRS "${SUPPORT_INCLUDE_DIRS}" + "${CLBLAST_INCLUDE_DIR}") + set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${CLBLAST_LIBRARIES}") + set(HAVE_CLBLAST true) + endif () + endif () + + # Search for CUDA. + if (NOT "${COOT_USE_CUDA}" STREQUAL "" AND NOT HAVE_CUDA) + # FindCUDA is deprecated since version 3.10 and replaced with + # FindCUDAToolkit wich was added in CMake 3.17. + message(STATUS "${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}") + if ("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS "3.67") + set(CUDA_FIND_QUIETLY true) + find_package(CUDA) + + if (CUDA_FOUND) + message(STATUS "CUDA includes: ${CUDA_INCLUDE_DIRS}") + message(STATUS "CUDA libraries: ${CUDA_LIBRARIES}") + + # We also need NVRTC and also libcuda itself, which the old FindCUDA package do not find. + find_library(CUDA_cuda_LIBRARY cuda + HINTS ${CUDA_TOOLKIT_ROOT_DIR} ${CUDA_TOOLKIT_ROOT_DIR}/lib ${CUDA_TOOLKIT_ROOT_DIR}/lib64) + find_library(CUDA_nvrtc_LIBRARY nvrtc + HINTS ${CUDA_TOOLKIT_ROOT_DIR} ${CUDA_TOOLKIT_ROOT_DIR}/lib ${CUDA_TOOLKIT_ROOT_DIR}/lib64) + + include(COOT_FindNVRTC) + + if (NVRTC_FOUND) + message(STATUS "NVRTC libraries: ${NVRTC_LIBRARIES}") + set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${NVRTC_LIBRARIES}") + endif () + + set(SUPPORT_INCLUDE_DIRS "${SUPPORT_INCLUDE_DIRS}" + "${CUDA_INCLUDE_DIRS}") + set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" + "${CUDA_LIBRARIES}" + "${CUDA_nvrtc_LIBRARY}" + "${CUDA_CUDA_LIBRARY}" + "${CUDA_CUBLAS_LIBRARIES}" + "${CUDA_curand_LIBRARY}" + "${CUDA_cusolver_LIBRARY}") + set(CUDA_INCLUDE_DIRS "") + set(HAVE_CUDA true) + + endif () + else () + set(CUDA_TOOLKIT_FIND_QUIETLY true) + find_package(CUDAToolkit REQUIRED) + + if (CUDAToolkit_FOUND) + message(STATUS "CUDA! includes: ${CUDAToolkit_INCLUDE_DIRS}") + message(STATUS "CUDA libraries: ${CUDAToolkit_LIBRARY_DIR}") + + set(CUDA_LIBRARIES CUDA::cudart CUDA::cuda_driver) + set(CUDA_CUBLAS_LIBRARIES CUDA::cublas) + set(CUDA_curand_LIBRARY CUDA::curand) + set(CUDA_cusolver_LIBRARY CUDA::cusolver) + set(CUDA_nvrtc_LIBRARY CUDA::nvrtc) + + set(SUPPORT_INCLUDE_DIRS "${SUPPORT_INCLUDE_DIRS}" + "${CUDAToolkit_INCLUDE_DIRS}") + set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" + CUDA_LIBRARIES + CUDA_CUBLAS_LIBRARIES + CUDA_curand_LIBRARY + CUDA_cusolver_LIBRARY + CUDA_nvrtc_LIBRARY) + set(HAVE_CUDA true) + endif() + endif () + endif () + + # Search for LAPACK/BLAS (or replacement). + if ((NOT "${COOT_USE_LAPACK}" STREQUAL "") AND + (NOT "${COOT_USE_BLAS}" STREQUAL "")) + # In order of preference: MKL, ACML, OpenBLAS, ATLAS + set(MKL_FIND_QUIETLY true) + include(ARMA_FindMKL) + set(ACMLMP_FIND_QUIETLY true) + include(ARMA_FindACMLMP) + set(ACML_FIND_QUIETLY true) + include(ARMA_FindACML) + + if (MKL_FOUND) + message(STATUS "Using MKL for LAPACK/BLAS: ${MKL_LIBRARIES}") + + set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${MKL_LIBRARIES}") + set(HAVE_LAPACK true) + set(HAVE_BLAS true) + elseif (ACMLMP_FOUND) + message(STATUS "Using multi-core ACML libraries for LAPACK/BLAS: + ${ACMLMP_LIBRARIES}") + + set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${ACMLMP_LIBRARIES}") + set(HAVE_LAPACK true) + set(HAVE_BLAS true) + elseif (ACML_FOUND) + message(STATUS "Using ACML for LAPACK/BLAS: ${ACML_LIBRARIES}") + + set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${ACML_LIBRARIES}") + set(HAVE_LAPACK true) + set(HAVE_BLAS true) + endif () + endif () + + # If we haven't found BLAS, try. + if (NOT "${COOT_USE_BLAS}" STREQUAL "" AND NOT HAVE_BLAS) + # Search for BLAS. + set(OpenBLAS_FIND_QUIETLY false) + include(ARMA_FindOpenBLAS) + set(CBLAS_FIND_QUIETLY true) + include(ARMA_FindCBLAS) + set(BLAS_FIND_QUIETLY true) + include(ARMA_FindBLAS) + + if (OpenBLAS_FOUND) + # Warn if ATLAS is found also. + if (CBLAS_FOUND) + message(STATUS "Warning: both OpenBLAS and ATLAS have been found; " + "ATLAS will not be used.") + endif () + message(STATUS "Using OpenBLAS for BLAS: ${OpenBLAS_LIBRARIES}") + + set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${OpenBLAS_LIBRARIES}") + set(HAVE_BLAS true) + elseif (CBLAS_FOUND) + message(STATUS "Using ATLAS for BLAS: ${CBLAS_LIBRARIES}") + + set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${CBLAS_LIBRARIES}") + set(SUPPORT_INCLUDE_DIRS "${SUPPORT_INCLUDE_DIRS}" + "${CBLAS_INCLUDE_DIR}") + set(HAVE_BLAS true) + elseif (BLAS_FOUND) + message(STATUS "Using standard BLAS: ${BLAS_LIBRARIES}") + + set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${BLAS_LIBRARIES}") + set(HAVE_BLAS true) + endif () + endif () + + # If we haven't found LAPACK, try. + if (NOT "${COOT_USE_LAPACK}" STREQUAL "" AND NOT HAVE_LAPACK) + # Search for LAPACK. + set(CLAPACK_FIND_QUIETLY true) + include(ARMA_FindCLAPACK) + set(LAPACK_FIND_QUIETLY true) + include(ARMA_FindLAPACK) + + # Only use ATLAS if OpenBLAS isn't being used. + if (CLAPACK_FOUND AND NOT OpenBLAS_FOUND) + message(STATUS "Using ATLAS for LAPACK: ${CLAPACK_LIBRARIES}") + + set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${CLAPACK_LIBRARIES}") + set(SUPPORT_INCLUDE_DIRS "${SUPPORT_INCLUDE_DIRS}" + "${CLAPACK_INCLUDE_DIR}") + set(HAVE_LAPACK true) + elseif (LAPACK_FOUND) + message(STATUS "Using standard LAPACK: ${LAPACK_LIBRARIES}") + + set(SUPPORT_LIBRARIES "${SUPPORT_LIBRARIES}" "${LAPACK_LIBRARIES}") + set(HAVE_LAPACK true) + endif () + endif () + + if (NOT "${COOT_USE_LAPACK}" STREQUAL "" AND NOT HAVE_LAPACK) + message(FATAL_ERROR "Cannot find LAPACK library, but COOT_USE_LAPACK is " + "set. Try specifying LAPACK libraries manually by setting the " + "LAPACK_LIBRARY variable.") + endif () + + if (NOT "${COOT_USE_BLAS}" STREQUAL "" AND NOT HAVE_BLAS) + message(FATAL_ERROR "Cannot find BLAS library, but COOT_USE_BLAS is set. " + "Try specifying BLAS libraries manually by setting the BLAS_LIBRARY " + "variable.") + endif () + + endif() +else() + message(STATUS "${BANDICOOT_INCLUDE_DIR}/bandicoot_bits/config.hpp not " + "found! Cannot determine what to link against.") +endif() + +if (COOT_NEED_LIBRARY) + # UNIX paths are standard, no need to write. + find_library(BANDICOOT_LIBRARY + NAMES armadillo + PATHS "$ENV{ProgramFiles}/Bandicoot/lib" "$ENV{ProgramFiles}/Bandicoot/lib64" "$ENV{ProgramFiles}/Bandicoot" + ) + + # Checks 'REQUIRED', 'QUIET' and versions. + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Bandicoot + REQUIRED_VARS BANDICOOT_LIBRARY BANDICOOT_INCLUDE_DIR + VERSION_VAR BANDICOOT_VERSION_STRING) +else () + # Checks 'REQUIRED', 'QUIET' and versions. + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Bandicoot + REQUIRED_VARS BANDICOOT_INCLUDE_DIR + VERSION_VAR BANDICOOT_VERSION_STRING) +endif () + +if (BANDICOOT_FOUND) + # Also include support include directories. + set(BANDICOOT_INCLUDE_DIRS ${BANDICOOT_INCLUDE_DIR} ${SUPPORT_INCLUDE_DIRS}) + # Also include support libraries to link against. + if (COOT_NEED_LIBRARY) + set(BANDICOOT_LIBRARIES ${BANDICOOT_LIBRARY} ${SUPPORT_LIBRARIES}) + else () + set(BANDICOOT_LIBRARIES ${SUPPORT_LIBRARIES}) + endif () + message(STATUS "Bandicoot libraries: ${BANDICOOT_LIBRARIES}") + message(STATUS "Bandicoot includes: ${BANDICOOT_INCLUDE_DIR}") +endif () + +# Hide internal variables +mark_as_advanced( + BANDICOOT_INCLUDE_DIR + BANDICOOT_LIBRARIES) + +if (BANDICOOT_FOUND AND NOT TARGET Bandicoot:Bandicoot) + add_library(Bandicoot::Bandicoot INTERFACE IMPORTED) + set_target_properties(Bandicoot::Bandicoot PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${BANDICOOT_INCLUDE_DIR}" + INTERFACE_LINK_LIBRARIES "${BANDICOOT_LIBRARIES}") +endif() diff --git a/CMake/FindCBLAS.cmake b/CMake/FindCBLAS.cmake new file mode 100644 index 000000000..fa97ce9fc --- /dev/null +++ b/CMake/FindCBLAS.cmake @@ -0,0 +1,75 @@ + +# ================================================================================================== +# This file is part of the CLBlast project. The project is licensed under Apache Version 2.0. This +# project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max- +# width of 100 characters per line. +# +# Author(s): +# Cedric Nugteren +# +# ================================================================================================== +# +# Defines the following variables: +# CBLAS_FOUND Boolean holding whether or not the Netlib BLAS library was found +# CBLAS_INCLUDE_DIRS The Netlib BLAS include directory +# CBLAS_LIBRARIES The Netlib BLAS library +# +# In case BLAS is not installed in the default directory, set the CBLAS_ROOT variable to point to +# the root of BLAS, such that 'cblas.h' can be found in $CBLAS_ROOT/include. This can either be +# done using an environmental variable (e.g. export CBLAS_ROOT=/path/to/BLAS) or using a CMake +# variable (e.g. cmake -DCBLAS_ROOT=/path/to/BLAS ..). +# +# ================================================================================================== + +# Sets the possible install locations +set(CBLAS_HINTS + ${CBLAS_ROOT} + $ENV{CBLAS_ROOT} +) +set(CBLAS_PATHS + /usr + /usr/local + /usr/local/opt + /System/Library/Frameworks +) + +# Finds the include directories +find_path(CBLAS_INCLUDE_DIRS + NAMES cblas.h + HINTS ${CBLAS_HINTS} + PATH_SUFFIXES + include inc include/x86_64 include/x64 + openblas/include include/blis blis/include blis/include/blis + Accelerate.framework/Versions/Current/Frameworks/vecLib.framework/Versions/Current/Headers + PATHS ${CBLAS_PATHS} + DOC "Netlib BLAS include header cblas.h" +) +mark_as_advanced(CBLAS_INCLUDE_DIRS) + +# Finds the library +find_library(CBLAS_LIBRARIES + NAMES cblas blas blis openblas accelerate + HINTS ${CBLAS_HINTS} + PATH_SUFFIXES + lib lib64 lib/x86_64 lib/x64 lib/x86 lib/Win32 lib/import lib64/import + openblas/lib blis/lib lib/atlas-base + PATHS ${CBLAS_PATHS} + DOC "Netlib BLAS library" +) +mark_as_advanced(CBLAS_LIBRARIES) + +# ================================================================================================== + +# Notification messages +if(NOT CBLAS_INCLUDE_DIRS) + message(STATUS "Could NOT find 'cblas.h', install a CPU Netlib BLAS or set CBLAS_ROOT") +endif() +if(NOT CBLAS_LIBRARIES) + message(STATUS "Could NOT find a CPU Netlib BLAS library, install it or set CBLAS_ROOT") +endif() + +# Determines whether or not BLAS was found +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(CBLAS DEFAULT_MSG CBLAS_INCLUDE_DIRS CBLAS_LIBRARIES) + +# ================================================================================================== diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f21ce4c5..10ce9f6a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,9 @@ set(VERSION "${ENSMALLEN_VERSION_MAJOR}.${ENSMALLEN_VERSION_MINOR}.${ENSMALLEN_V add_library(ensmallen INTERFACE) target_include_directories(ensmallen INTERFACE $ - $) + $ + /usr/local/cuda/include + ) # Set warning flags for target. if(MSVC) @@ -59,6 +61,16 @@ if(USE_OPENMP) target_link_libraries(ensmallen INTERFACE OpenMP::OpenMP_CXX) endif() +# Find Bandicoot and link it. +find_package(Bandicoot 0.100.0) +if(BANDICOOT_FOUND AND NOT TARGET Bandicoot:Bandicoot) + target_link_libraries(ensmallen INTERFACE Bandicoot::Bandicoot) + target_include_directories(ensmallen INTERFACE ${BANDICOOT_INCLUDE_DIR}) + + set(USE_COOT "1") + add_definitions(-DUSE_COOT) +endif() + # Find Armadillo and link it. find_package(Armadillo 10.8.2 REQUIRED) target_link_libraries(ensmallen INTERFACE Armadillo::Armadillo) diff --git a/include/ensmallen.hpp b/include/ensmallen.hpp index a6ca139dd..1e010c030 100644 --- a/include/ensmallen.hpp +++ b/include/ensmallen.hpp @@ -34,6 +34,10 @@ #include +#ifdef USE_COOT + #include +#endif + #if ((ARMA_VERSION_MAJOR < 10) || ((ARMA_VERSION_MAJOR == 10) && (ARMA_VERSION_MINOR < 8))) #error "need Armadillo version 10.8 or newer" #endif @@ -70,6 +74,8 @@ #include "ensmallen_bits/utility/any.hpp" #include "ensmallen_bits/utility/arma_traits.hpp" +#include "ensmallen_bits/utility/coot_traits.hpp" +#include "ensmallen_bits/utility/proxies.hpp" #include "ensmallen_bits/utility/indicators/epsilon.hpp" #include "ensmallen_bits/utility/indicators/igd.hpp" #include "ensmallen_bits/utility/indicators/igd_plus.hpp" diff --git a/include/ensmallen_bits/ada_belief/ada_belief.hpp b/include/ensmallen_bits/ada_belief/ada_belief.hpp index 1a4b13c65..191ecfe0a 100644 --- a/include/ensmallen_bits/ada_belief/ada_belief.hpp +++ b/include/ensmallen_bits/ada_belief/ada_belief.hpp @@ -97,8 +97,8 @@ class AdaBelief typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks) diff --git a/include/ensmallen_bits/ada_belief/ada_belief_update.hpp b/include/ensmallen_bits/ada_belief/ada_belief_update.hpp index f7689879b..a9c4af104 100644 --- a/include/ensmallen_bits/ada_belief/ada_belief_update.hpp +++ b/include/ensmallen_bits/ada_belief/ada_belief_update.hpp @@ -113,13 +113,13 @@ class AdaBeliefUpdate m += (1 - parent.beta1) * gradient; s *= parent.beta2; - s += (1 - parent.beta2) * arma::pow(gradient - m, 2.0) + parent.epsilon; + s += (1 - parent.beta2) * pow(gradient - m, 2.0) + parent.epsilon; - const double biasCorrection1 = 1.0 - std::pow(parent.beta1, iteration); - const double biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration); + const double biasCorrection1 = 1.0 - pow(parent.beta1, iteration); + const double biasCorrection2 = 1.0 - pow(parent.beta2, iteration); // And update the iterate. - iterate -= ((m / biasCorrection1) * stepSize) / (arma::sqrt(s / + iterate -= ((m / biasCorrection1) * stepSize) / (sqrt(s / biasCorrection2) + parent.epsilon); } diff --git a/include/ensmallen_bits/ada_bound/ada_bound.hpp b/include/ensmallen_bits/ada_bound/ada_bound.hpp index 94283c356..a74a33139 100644 --- a/include/ensmallen_bits/ada_bound/ada_bound.hpp +++ b/include/ensmallen_bits/ada_bound/ada_bound.hpp @@ -107,8 +107,8 @@ class AdaBoundType typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(DecomposableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks) diff --git a/include/ensmallen_bits/ada_bound/ada_bound_update.hpp b/include/ensmallen_bits/ada_bound/ada_bound_update.hpp index 3a84d8713..1fd2009df 100644 --- a/include/ensmallen_bits/ada_bound/ada_bound_update.hpp +++ b/include/ensmallen_bits/ada_bound/ada_bound_update.hpp @@ -149,9 +149,9 @@ class AdaBoundUpdate const ElemType lower = fl * (1.0 - 1.0 / (parent.gamma * iteration + 1)); const ElemType upper = fl * (1.0 + 1.0 / (parent.gamma * iteration)); - // Applies bounds on actual learning rate. - iterate -= arma::clamp((stepSize * - std::sqrt(biasCorrection2) / biasCorrection1) / (arma::sqrt(v) + + // Applies bounds on actual learning rate. + iterate -= clamp((stepSize * + sqrt(biasCorrection2) / biasCorrection1) / (sqrt(v) + parent.epsilon), lower, upper) % m; } diff --git a/include/ensmallen_bits/ada_bound/ams_bound_update.hpp b/include/ensmallen_bits/ada_bound/ams_bound_update.hpp index 270f8eb5b..b29464e62 100644 --- a/include/ensmallen_bits/ada_bound/ams_bound_update.hpp +++ b/include/ensmallen_bits/ada_bound/ams_bound_update.hpp @@ -151,12 +151,11 @@ class AMSBoundUpdate const ElemType upper = fl * (1.0 + 1.0 / (parent.gamma * iteration)); // Element wise maximum of past and present squared gradients. - vImproved = arma::max(vImproved, v); + vImproved = max(vImproved, v); // Applies bounds on actual learning rate. - iterate -= arma::clamp((stepSize * - std::sqrt(biasCorrection2) / biasCorrection1) / - (arma::sqrt(vImproved) + parent.epsilon), lower, upper) % m; + iterate -= clamp((stepSize * sqrt(biasCorrection2) / biasCorrection1) / + (sqrt(vImproved) + parent.epsilon), lower, upper) % m; } private: diff --git a/include/ensmallen_bits/ada_delta/ada_delta.hpp b/include/ensmallen_bits/ada_delta/ada_delta.hpp index d958ee24a..b58ef14bb 100644 --- a/include/ensmallen_bits/ada_delta/ada_delta.hpp +++ b/include/ensmallen_bits/ada_delta/ada_delta.hpp @@ -98,8 +98,8 @@ class AdaDelta typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks) diff --git a/include/ensmallen_bits/ada_delta/ada_delta_update.hpp b/include/ensmallen_bits/ada_delta/ada_delta_update.hpp index 26c6dd774..fe46cff0b 100644 --- a/include/ensmallen_bits/ada_delta/ada_delta_update.hpp +++ b/include/ensmallen_bits/ada_delta/ada_delta_update.hpp @@ -104,7 +104,7 @@ class AdaDeltaUpdate // Accumulate gradient. meanSquaredGradient *= parent.rho; meanSquaredGradient += (1 - parent.rho) * (gradient % gradient); - GradType dx = arma::sqrt((meanSquaredGradientDx + parent.epsilon) / + GradType dx = sqrt((meanSquaredGradientDx + parent.epsilon) / (meanSquaredGradient + parent.epsilon)) % gradient; // Accumulate updates. diff --git a/include/ensmallen_bits/ada_grad/ada_grad.hpp b/include/ensmallen_bits/ada_grad/ada_grad.hpp index 677d300cc..0617ee83a 100644 --- a/include/ensmallen_bits/ada_grad/ada_grad.hpp +++ b/include/ensmallen_bits/ada_grad/ada_grad.hpp @@ -94,8 +94,8 @@ class AdaGrad typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks) diff --git a/include/ensmallen_bits/ada_grad/ada_grad_update.hpp b/include/ensmallen_bits/ada_grad/ada_grad_update.hpp index b096dd475..c02d65030 100644 --- a/include/ensmallen_bits/ada_grad/ada_grad_update.hpp +++ b/include/ensmallen_bits/ada_grad/ada_grad_update.hpp @@ -96,7 +96,7 @@ class AdaGradUpdate const GradType& gradient) { squaredGradient += (gradient % gradient); - iterate -= (stepSize * gradient) / (arma::sqrt(squaredGradient) + + iterate -= (stepSize * gradient) / (sqrt(squaredGradient) + parent.epsilon); } diff --git a/include/ensmallen_bits/ada_sqrt/ada_sqrt.hpp b/include/ensmallen_bits/ada_sqrt/ada_sqrt.hpp index 7f1788c56..b951cabfd 100644 --- a/include/ensmallen_bits/ada_sqrt/ada_sqrt.hpp +++ b/include/ensmallen_bits/ada_sqrt/ada_sqrt.hpp @@ -89,8 +89,8 @@ class AdaSqrt typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks) diff --git a/include/ensmallen_bits/ada_sqrt/ada_sqrt_update.hpp b/include/ensmallen_bits/ada_sqrt/ada_sqrt_update.hpp index feae24ca2..0dafdbd4c 100644 --- a/include/ensmallen_bits/ada_sqrt/ada_sqrt_update.hpp +++ b/include/ensmallen_bits/ada_sqrt/ada_sqrt_update.hpp @@ -93,9 +93,9 @@ class AdaSqrtUpdate { ++iteration; - squaredGradient += arma::square(gradient); + squaredGradient += square(gradient); - iterate -= stepSize * std::sqrt(iteration) * gradient / + iterate -= stepSize * sqrt(iteration) * gradient / (squaredGradient + parent.epsilon); } diff --git a/include/ensmallen_bits/adam/adam.hpp b/include/ensmallen_bits/adam/adam.hpp index 13c2f967d..4d958eb68 100644 --- a/include/ensmallen_bits/adam/adam.hpp +++ b/include/ensmallen_bits/adam/adam.hpp @@ -120,8 +120,8 @@ class AdamType typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks) diff --git a/include/ensmallen_bits/adam/adam_update.hpp b/include/ensmallen_bits/adam/adam_update.hpp index de7f61e7f..4f6dc587f 100644 --- a/include/ensmallen_bits/adam/adam_update.hpp +++ b/include/ensmallen_bits/adam/adam_update.hpp @@ -117,7 +117,7 @@ class AdamUpdate m += (1 - parent.beta1) * gradient; v *= parent.beta2; - v += (1 - parent.beta2) * (gradient % gradient); + v += (1 - parent.beta2) * square(gradient); const double biasCorrection1 = 1.0 - std::pow(parent.beta1, iteration); const double biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration); @@ -128,7 +128,7 @@ class AdamUpdate * m / (arma::sqrt(v) + (arma::sqrt(biasCorrection2) * eps). */ iterate -= (stepSize * std::sqrt(biasCorrection2) / biasCorrection1) * - m / (arma::sqrt(v) + parent.epsilon); + m / (sqrt(v) + parent.epsilon); } private: diff --git a/include/ensmallen_bits/adam/adamax_update.hpp b/include/ensmallen_bits/adam/adamax_update.hpp index a6c9f2f03..f8c196e43 100644 --- a/include/ensmallen_bits/adam/adamax_update.hpp +++ b/include/ensmallen_bits/adam/adamax_update.hpp @@ -120,7 +120,7 @@ class AdaMaxUpdate // Update the exponentially weighted infinity norm. u *= parent.beta2; - u = arma::max(u, arma::abs(gradient)); + u = max(u, abs(gradient)); const double biasCorrection1 = 1.0 - std::pow(parent.beta1, iteration); diff --git a/include/ensmallen_bits/adam/amsgrad_update.hpp b/include/ensmallen_bits/adam/amsgrad_update.hpp index f1f420e91..ff94eb805 100644 --- a/include/ensmallen_bits/adam/amsgrad_update.hpp +++ b/include/ensmallen_bits/adam/amsgrad_update.hpp @@ -2,7 +2,7 @@ * @file amsgrad_update.hpp * @author Haritha Nair * - * Implementation of AMSGrad optimizer. AMSGrad is an exponential moving average + * Implementation of AMSGrad optimizer. AMSGrad is an exponential moving average * optimizer that dynamically adapts over time with guaranteed convergence. * * ensmallen is free software; you may redistribute it and/or modify it under @@ -119,10 +119,10 @@ class AMSGradUpdate const double biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration); // Element wise maximum of past and present squared gradients. - vImproved = arma::max(vImproved, v); + vImproved = max(vImproved, v); iterate -= (stepSize * std::sqrt(biasCorrection2) / biasCorrection1) * - m / (arma::sqrt(vImproved) + parent.epsilon); + m / (sqrt(vImproved) + parent.epsilon); } private: diff --git a/include/ensmallen_bits/adam/nadam_update.hpp b/include/ensmallen_bits/adam/nadam_update.hpp index 24f105ccb..6e1e1a52d 100644 --- a/include/ensmallen_bits/adam/nadam_update.hpp +++ b/include/ensmallen_bits/adam/nadam_update.hpp @@ -140,7 +140,7 @@ class NadamUpdate */ iterate -= (stepSize * (((1 - beta1T) / biasCorrection1) * gradient + (beta1T1 / biasCorrection3) * m) * sqrt(biasCorrection2)) - / (arma::sqrt(v) + parent.epsilon); + / (sqrt(v) + parent.epsilon); } private: diff --git a/include/ensmallen_bits/adam/nadamax_update.hpp b/include/ensmallen_bits/adam/nadamax_update.hpp index f0d9b0c14..ad276d88a 100644 --- a/include/ensmallen_bits/adam/nadamax_update.hpp +++ b/include/ensmallen_bits/adam/nadamax_update.hpp @@ -120,7 +120,7 @@ class NadaMaxUpdate m *= parent.beta1; m += (1 - parent.beta1) * gradient; - u = arma::max(u * parent.beta2, arma::abs(gradient)); + u = max(u * parent.beta2, abs(gradient)); double beta1T = parent.beta1 * (1 - (0.5 * std::pow(0.96, iteration * parent.scheduleDecay))); diff --git a/include/ensmallen_bits/adam/optimisticadam_update.hpp b/include/ensmallen_bits/adam/optimisticadam_update.hpp index 426a5bb6e..d99390a76 100644 --- a/include/ensmallen_bits/adam/optimisticadam_update.hpp +++ b/include/ensmallen_bits/adam/optimisticadam_update.hpp @@ -117,12 +117,12 @@ class OptimisticAdamUpdate m += (1 - parent.beta1) * gradient; v *= parent.beta2; - v += (1 - parent.beta2) * arma::square(gradient); + v += (1 - parent.beta2) * square(gradient); GradType mCorrected = m / (1.0 - std::pow(parent.beta1, iteration)); GradType vCorrected = v / (1.0 - std::pow(parent.beta2, iteration)); - GradType update = mCorrected / (arma::sqrt(vCorrected) + parent.epsilon); + GradType update = mCorrected / (sqrt(vCorrected) + parent.epsilon); iterate -= (2 * stepSize * update - stepSize * g); diff --git a/include/ensmallen_bits/bigbatch_sgd/adaptive_stepsize.hpp b/include/ensmallen_bits/bigbatch_sgd/adaptive_stepsize.hpp index a7e2816ae..59a2f6bb7 100644 --- a/include/ensmallen_bits/bigbatch_sgd/adaptive_stepsize.hpp +++ b/include/ensmallen_bits/bigbatch_sgd/adaptive_stepsize.hpp @@ -132,8 +132,8 @@ class AdaptiveStepsize delta0 = delta1 + (functionGradient - delta1) / k; // Compute sample variance. - vB += arma::norm(functionGradient - delta1, 2.0) * - arma::norm(functionGradient - delta0, 2.0); + vB += norm(functionGradient - delta1, 2.0) * + norm(functionGradient - delta0, 2.0); delta1 = delta0; gradient += functionGradient; @@ -145,13 +145,13 @@ class AdaptiveStepsize // Update sample variance & norm of the gradient. sampleVariance = vB; - gradientNorm = std::pow(arma::norm(gradient / backtrackingBatchSize, 2), + gradientNorm = std::pow(norm(gradient / backtrackingBatchSize, 2), 2.0); // Compute curvature. - double v = arma::trace(arma::trans(iterate - iteratePrev) * + double v = trace(trans(iterate - iteratePrev) * (gradient - gradPrevIterate)) / - std::pow(arma::norm(iterate - iteratePrev, 2), 2.0); + std::pow(norm(iterate - iteratePrev, 2), 2.0); // Update previous iterate. iteratePrev = iterate; diff --git a/include/ensmallen_bits/bigbatch_sgd/bigbatch_sgd.hpp b/include/ensmallen_bits/bigbatch_sgd/bigbatch_sgd.hpp index 4d670f2da..29ed0732e 100644 --- a/include/ensmallen_bits/bigbatch_sgd/bigbatch_sgd.hpp +++ b/include/ensmallen_bits/bigbatch_sgd/bigbatch_sgd.hpp @@ -125,8 +125,8 @@ class BigBatchSGD typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks); diff --git a/include/ensmallen_bits/bigbatch_sgd/bigbatch_sgd_impl.hpp b/include/ensmallen_bits/bigbatch_sgd/bigbatch_sgd_impl.hpp index cd88660e2..7b8e71fa0 100644 --- a/include/ensmallen_bits/bigbatch_sgd/bigbatch_sgd_impl.hpp +++ b/include/ensmallen_bits/bigbatch_sgd/bigbatch_sgd_impl.hpp @@ -50,7 +50,8 @@ template -typename std::enable_if::value, +typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type BigBatchSGD::Optimize( SeparableFunctionType& function, @@ -137,13 +138,13 @@ BigBatchSGD::Optimize( delta0 = delta1 + (functionGradient - delta1) / k; // Compute sample variance. - vB += arma::norm(functionGradient - delta1, 2.0) * - arma::norm(functionGradient - delta0, 2.0); + vB += norm(functionGradient - delta1, 2.0) * + norm(functionGradient - delta0, 2.0); delta1 = delta0; gradient += functionGradient; } - double gB = std::pow(arma::norm(gradient / effectiveBatchSize, 2), 2.0); + double gB = std::pow(norm(gradient / effectiveBatchSize, 2), 2.0); // Reset the batch size update process counter. reset = false; @@ -174,13 +175,13 @@ BigBatchSGD::Optimize( delta0 = delta1 + (functionGradient - delta1) / (k + 1); // Compute sample variance. - vB += arma::norm(functionGradient - delta1, 2.0) * - arma::norm(functionGradient - delta0, 2.0); + vB += norm(functionGradient - delta1, 2.0) * + norm(functionGradient - delta0, 2.0); delta1 = delta0; gradient += functionGradient; } - gB = std::pow(arma::norm(gradient / (batchSize + batchOffset), 2), 2.0); + gB = std::pow(norm(gradient / (batchSize + batchOffset), 2), 2.0); // Update the batchSize. batchSize += batchOffset; diff --git a/include/ensmallen_bits/cd/cd.hpp b/include/ensmallen_bits/cd/cd.hpp index 062a210bc..ff64e4880 100644 --- a/include/ensmallen_bits/cd/cd.hpp +++ b/include/ensmallen_bits/cd/cd.hpp @@ -94,8 +94,8 @@ class CD typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(ResolvableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks); diff --git a/include/ensmallen_bits/cd/cd_impl.hpp b/include/ensmallen_bits/cd/cd_impl.hpp index 8f57e2749..bb54b2c69 100644 --- a/include/ensmallen_bits/cd/cd_impl.hpp +++ b/include/ensmallen_bits/cd/cd_impl.hpp @@ -39,7 +39,8 @@ template -typename std::enable_if::value, +typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type CD::Optimize( ResolvableFunctionType& function, @@ -84,7 +85,8 @@ CD::Optimize( break; // Update the decision variable with the partial gradient. - iterate.col(featureIdx) -= stepSize * gradient.col(featureIdx); + /* iterate.col(featureIdx) -= stepSize * gradient.col(featureIdx); */ + iterate.col(featureIdx) -= gradient.col(featureIdx); terminate |= Callback::StepTaken(*this, function, iterate, callbacks...); // Check for convergence. diff --git a/include/ensmallen_bits/cd/descent_policies/random_descent.hpp b/include/ensmallen_bits/cd/descent_policies/random_descent.hpp index e5eaeb12b..6e85ba034 100644 --- a/include/ensmallen_bits/cd/descent_policies/random_descent.hpp +++ b/include/ensmallen_bits/cd/descent_policies/random_descent.hpp @@ -52,8 +52,8 @@ class RandomDescent const MatType& /* iterate */, const ResolvableFunctionType& function) { - return arma::as_scalar(arma::randi( - 1, arma::distr_param(0, function.NumFeatures() - 1))); + return randi( + arma::distr_param(0, function.NumFeatures() - 1)); } }; diff --git a/include/ensmallen_bits/cmaes/cmaes_impl.hpp b/include/ensmallen_bits/cmaes/cmaes_impl.hpp index 73a5c7f02..c52c31cd7 100644 --- a/include/ensmallen_bits/cmaes/cmaes_impl.hpp +++ b/include/ensmallen_bits/cmaes/cmaes_impl.hpp @@ -381,4 +381,4 @@ typename MatType::elem_type CMAES + template void Reproduce(std::vector& population, const MatType& fitnessValues, - arma::uvec& index); + IndexType& index); //! Modify weights with some noise for the evolution of next generation. - template - void Mutate(std::vector& population, arma::uvec& index); + template + void Mutate(std::vector& population, IndexType& index); /** * Crossover parents and create new childs. Two parents create two new childs. diff --git a/include/ensmallen_bits/cne/cne_impl.hpp b/include/ensmallen_bits/cne/cne_impl.hpp index 24d18125d..b7c69ea1a 100644 --- a/include/ensmallen_bits/cne/cne_impl.hpp +++ b/include/ensmallen_bits/cne/cne_impl.hpp @@ -47,6 +47,7 @@ typename MatType::elem_type CNE::Optimize(ArbitraryFunctionType& function, // Convenience typedefs. typedef typename MatType::elem_type ElemType; typedef typename MatTypeTraits::BaseMatType BaseMatType; + typedef typename ForwardColType::ColType IndexType; // Make sure that we have the methods that we need. Long name... traits::CheckArbitraryFunctionTypeAPI population; for (size_t i = 0 ; i < populationSize; ++i) { - population.push_back(arma::randn(iterate.n_rows, + population.push_back(randn(iterate.n_rows, iterate.n_cols) + iterate); } @@ -164,50 +165,50 @@ typename MatType::elem_type CNE::Optimize(ArbitraryFunctionType& function, } //! Reproduce candidates to create the next generation. -template +template inline void CNE::Reproduce(std::vector& population, const MatType& fitnessValues, - arma::uvec& index) + IndexType& index) { - // Sort fitness values. Smaller fitness value means better performance. - index = arma::sort_index(fitnessValues); - - // First parent. - size_t mom; - - // Second parent. - size_t dad; - - for (size_t i = numElite; i < populationSize - 1; i++) - { - // Select 2 different parents from elite group randomly [0, numElite). - mom = arma::as_scalar(arma::randi( - 1, arma::distr_param(0, numElite - 1))); - - dad = arma::as_scalar(arma::randi( - 1, arma::distr_param(0, numElite - 1))); - - // Making sure both parents are not the same. - if (mom == dad) - { - if (dad != numElite - 1) - { - dad++; - } - else - { - dad--; - } - } - - // Parents generate 2 children replacing the dropped-out candidates. - // Also finding the index of these candidates in the population matrix. - Crossover(population, index[mom], index[dad], index[i], index[i + 1]); - } - - // Mutating the weights with small noise values. - // This is done to bring change in the next generation. - Mutate(population, index); + // // Sort fitness values. Smaller fitness value means better performance. + // index = sort_index(fitnessValues); + + // // First parent. + // size_t mom; + + // // Second parent. + // size_t dad; + + // for (size_t i = numElite; i < populationSize - 1; i++) + // { + // // Select 2 different parents from elite group randomly [0, numElite). + // mom = arma::as_scalar(arma::randi( + // 1, arma::distr_param(0, numElite - 1))); + + // dad = arma::as_scalar(arma::randi( + // 1, arma::distr_param(0, numElite - 1))); + + // // Making sure both parents are not the same. + // if (mom == dad) + // { + // if (dad != numElite - 1) + // { + // dad++; + // } + // else + // { + // dad--; + // } + // } + + // // Parents generate 2 children replacing the dropped-out candidates. + // // Also finding the index of these candidates in the population matrix. + // Crossover(population, index[mom], index[dad], index[i], index[i + 1]); + // } + + // // Mutating the weights with small noise values. + // // This is done to bring change in the next generation. + // Mutate(population, index); } //! Crossover parents to create new children. @@ -218,41 +219,41 @@ inline void CNE::Crossover(std::vector& population, const size_t child1, const size_t child2) { - // Replace the candidates with parents at their place. - population[child1] = population[mom]; - population[child2] = population[dad]; - - // Randomly alter mom and dad genome weights to get two different children. - for (size_t i = 0; i < elements; i++) - { - // Using it to alter the weights of the children. - const double random = arma::randu(); - if (random > 0.5) - { - population[child1](i) = population[mom](i); - population[child2](i) = population[dad](i); - } - else - { - population[child1](i) = population[dad](i); - population[child2](i) = population[mom](i); - } - } + // // Replace the candidates with parents at their place. + // population[child1] = population[mom]; + // population[child2] = population[dad]; + + // // Randomly alter mom and dad genome weights to get two different children. + // for (size_t i = 0; i < elements; i++) + // { + // // Using it to alter the weights of the children. + // const double random = arma::randu(); + // if (random > 0.5) + // { + // population[child1](i) = population[mom](i); + // population[child2](i) = population[dad](i); + // } + // else + // { + // population[child1](i) = population[dad](i); + // population[child2](i) = population[mom](i); + // } + // } } //! Modify weights with some noise for the evolution of next generation. -template -inline void CNE::Mutate(std::vector& population, arma::uvec& index) +template +inline void CNE::Mutate(std::vector& population, IndexType& index) { - // Mutate the whole matrix with the given rate and probability. - // The best candidate is not altered. - for (size_t i = 1; i < populationSize; i++) - { - population[index(i)] += (arma::randu(population[index(i)].n_rows, - population[index(i)].n_cols) < mutationProb) % - (mutationSize * arma::randn(population[index(i)].n_rows, - population[index(i)].n_cols)); - } + // // Mutate the whole matrix with the given rate and probability. + // // The best candidate is not altered. + // for (size_t i = 1; i < populationSize; i++) + // { + // population[index(i)] += (randu(population[index(i)].n_rows, + // population[index(i)].n_cols) < mutationProb) % + // (mutationSize * randn(population[index(i)].n_rows, + // population[index(i)].n_cols)); + // } } } // namespace ens diff --git a/include/ensmallen_bits/de/de_impl.hpp b/include/ensmallen_bits/de/de_impl.hpp index 09e55a0bb..030c78629 100644 --- a/include/ensmallen_bits/de/de_impl.hpp +++ b/include/ensmallen_bits/de/de_impl.hpp @@ -46,8 +46,10 @@ typename MatType::elem_type DE::Optimize(FunctionType& function, // Population matrix. Each column is a candidate. std::vector population; population.resize(populationSize); + // Vector of fitness values corresponding to each candidate. - arma::Col fitnessValues; + typedef typename ForwardColType::ColType ColType; + ColType fitnessValues; // Make sure that we have the methods that we need. Long name... traits::CheckArbitraryFunctionTypeAPI< @@ -100,13 +102,13 @@ typename MatType::elem_type DE::Optimize(FunctionType& function, size_t l = 0, m = 0; do { - l = arma::randi(arma::distr_param(0, populationSize - 1)); + l = rand() % populationSize; } while (l == member); do { - m = arma::randi(arma::distr_param(0, populationSize - 1)); + m = rand() % populationSize; } while (m == member && m == l); @@ -115,12 +117,13 @@ typename MatType::elem_type DE::Optimize(FunctionType& function, (population[l] - population[m]); // Perform crossover. - const BaseMatType cr = arma::randu(iterate.n_rows); + BaseMatType cr; + cr.randu(iterate.n_rows, 1); for (size_t it = 0; it < iterate.n_rows; it++) { if (cr[it] >= crossoverRate) { - mutant[it] = iterate[it]; + mutant(it) = ElemType(iterate(it)); } } diff --git a/include/ensmallen_bits/eve/eve.hpp b/include/ensmallen_bits/eve/eve.hpp index cc38591b0..0354dc595 100644 --- a/include/ensmallen_bits/eve/eve.hpp +++ b/include/ensmallen_bits/eve/eve.hpp @@ -106,8 +106,8 @@ class Eve typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks); diff --git a/include/ensmallen_bits/eve/eve_impl.hpp b/include/ensmallen_bits/eve/eve_impl.hpp index 3237a4eab..a1b4d3054 100644 --- a/include/ensmallen_bits/eve/eve_impl.hpp +++ b/include/ensmallen_bits/eve/eve_impl.hpp @@ -49,7 +49,8 @@ template -typename std::enable_if::value, +typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Eve::Optimize(SeparableFunctionType& function, MatType& iterateIn, @@ -148,7 +149,7 @@ Eve::Optimize(SeparableFunctionType& function, lastObjective = objective; iterate -= stepSize / dt * (m / biasCorrection1) / - (arma::sqrt(v / biasCorrection2) + epsilon); + (sqrt(v / biasCorrection2) + epsilon); terminate |= Callback::StepTaken(*this, f, iterate, callbacks...); diff --git a/include/ensmallen_bits/ftml/ftml.hpp b/include/ensmallen_bits/ftml/ftml.hpp index 26c418396..2e20cfbbc 100644 --- a/include/ensmallen_bits/ftml/ftml.hpp +++ b/include/ensmallen_bits/ftml/ftml.hpp @@ -98,8 +98,8 @@ class FTML typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks) diff --git a/include/ensmallen_bits/ftml/ftml_update.hpp b/include/ensmallen_bits/ftml/ftml_update.hpp index 5db2b05d3..7711cc969 100644 --- a/include/ensmallen_bits/ftml/ftml_update.hpp +++ b/include/ensmallen_bits/ftml/ftml_update.hpp @@ -117,7 +117,7 @@ class FTMLUpdate MatType sigma = -parent.beta1 * d; d = biasCorrection1 / stepSize * - (arma::sqrt(v / biasCorrection2) + parent.epsilon); + (sqrt(v / biasCorrection2) + parent.epsilon); sigma += d; z *= parent.beta1; diff --git a/include/ensmallen_bits/function/arma_traits.hpp b/include/ensmallen_bits/function/arma_traits.hpp index e13297b8e..68db83ac4 100644 --- a/include/ensmallen_bits/function/arma_traits.hpp +++ b/include/ensmallen_bits/function/arma_traits.hpp @@ -45,6 +45,191 @@ struct MatTypeTraits> typedef arma::SpMat BaseMatType; }; +/** + * Get the Cube type based on the given matrix type (i.e. arma::Mat, returns a + * arma::Cube, coot::Mat returns a coot::Cube. + */ + +template +struct ForwardMatCubeType +{ + typedef MatType CubeType; +}; + +template +struct ForwardMatCubeType> +{ + typedef arma::Cube CubeType; +}; + +template +struct ForwardMatCubeType> +{ + typedef arma::Cube CubeType; +}; + +#ifdef USE_COOT +template +struct ForwardMatCubeType> +{ + typedef coot::Cube CubeType; +}; +#endif + +/** + * Get the Cube type based on the given matrix type (i.e. arma::Mat, returns a + * arma::Cube, coot::Mat returns a coot::Cube. + */ + +template +struct ForwardCubeMatType +{ + typedef CubeType MatType; +}; + +template +struct ForwardCubeMatType> +{ + typedef arma::Mat MatType; +}; + +#ifdef USE_COOT +template +struct ForwardCubeMatType> +{ + typedef coot::Mat MatType; +}; +#endif + +/** + * Get the Mat type based on the given matrix type (i.e. arma::Mat, returns a + * arma::Cube, coot::Mat returns a coot::Cube. + */ + +template +struct ForwardSpMatMatType +{ + typedef SpMatType MatType; +}; + +template +struct ForwardSpMatMatType> +{ + typedef arma::Mat MatType; +}; + +/** + * Get the Mat type based on the given matrix type (i.e. arma::Cube, returns a + * arma::Mat, coot::Cube returns a coot::Mat. + */ + +template +struct ForwardCubeColType +{ + typedef CubeType ColType; +}; + +template +struct ForwardCubeColType> +{ + typedef arma::Col ColType; +}; + +#ifdef USE_COOT +template +struct ForwardCubeColType> +{ + typedef coot::Col ColType; +}; +#endif + +/** + * Get the Mat type based on the given matrix type (i.e. arma::Cube, returns a + * arma::Mat, coot::Cube returns a coot::Mat. + */ + +template +struct ForwardColType +{ + #ifdef USE_COOT + typedef typename std::conditional::value, + arma::Col, coot::Col>::type ColType; + #else + typedef arma::Col ColType; + #endif +}; + +template +struct ForwardRowType +{ + #ifdef USE_COOT + typedef typename std::conditional::value, + arma::Row, coot::Row>::type RowType; + #else + typedef arma::Row RowType; + #endif +}; + +template +struct ForwardMatType +{ + #ifdef USE_COOT + typedef typename std::conditional::value, + arma::Mat, coot::Mat>::type MatType; + #else + typedef arma::Mat MatType; + #endif +}; + +/* template */ +/* struct ForwardMatColType> */ +/* { */ +/* typedef arma::Col ColType; */ +/* }; */ + +/* template */ +/* struct ForwardMatColType> */ +/* { */ +/* typedef arma::Col ColType; */ +/* }; */ + +/* template */ +/* struct ForwardMatColType> */ +/* { */ +/* typedef coot::Col ColType; */ +/* }; */ + +/** + * Get the Mat type based on the given matrix type (i.e. arma::Cube, returns a + * arma::Mat, coot::Cube returns a coot::Mat. + */ + +template +struct ForwardMatRowType +{ + typedef MatType RowType; +}; + +template +struct ForwardMatRowType> +{ + typedef arma::Row RowType; +}; + +template +struct ForwardMatRowType> +{ + typedef arma::Row RowType; +}; + +#ifdef USE_COOT +template +struct ForwardMatRowType> +{ + typedef coot::Row RowType; +}; +#endif + /** * Disable usage of arma::subviews and related types for optimizers. It might * be nice to also explicitly disable Armadillo expressions, but we'll hope for @@ -76,7 +261,6 @@ struct MatTypeTraits> "or a matrix alias instead!"); }; - template struct MatTypeTraits> { @@ -123,6 +307,13 @@ inline void RequireDenseFloatingPointType() { } template<> inline void RequireDenseFloatingPointType() { } +#ifdef USE_COOT +template<> +inline void RequireDenseFloatingPointType() { } +template<> +inline void RequireDenseFloatingPointType() { } +#endif + template void RequireFloatingPointType() { @@ -145,6 +336,13 @@ inline void RequireFloatingPointType() { } template<> inline void RequireFloatingPointType() { } +#ifdef USE_COOT +template<> +inline void RequireFloatingPointType() { } +template<> +inline void RequireFloatingPointType() { } +#endif + /** * Require that the internal element type of the matrix type and gradient type * are the same. A static_assert() will fail if not. diff --git a/include/ensmallen_bits/gradient_descent/gradient_descent.hpp b/include/ensmallen_bits/gradient_descent/gradient_descent.hpp index b9c08a32c..595fc1c9d 100644 --- a/include/ensmallen_bits/gradient_descent/gradient_descent.hpp +++ b/include/ensmallen_bits/gradient_descent/gradient_descent.hpp @@ -77,8 +77,8 @@ class GradientDescent typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(FunctionType& function, MatType& iterate, CallbackTypes&&... callbacks); diff --git a/include/ensmallen_bits/gradient_descent/gradient_descent_impl.hpp b/include/ensmallen_bits/gradient_descent/gradient_descent_impl.hpp index 5301002f0..d88dc827e 100644 --- a/include/ensmallen_bits/gradient_descent/gradient_descent_impl.hpp +++ b/include/ensmallen_bits/gradient_descent/gradient_descent_impl.hpp @@ -34,7 +34,8 @@ template -typename std::enable_if::value, +typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type GradientDescent::Optimize(FunctionType& function, MatType& iterateIn, diff --git a/include/ensmallen_bits/iqn/iqn.hpp b/include/ensmallen_bits/iqn/iqn.hpp index 3bd4f635a..e1906b82f 100644 --- a/include/ensmallen_bits/iqn/iqn.hpp +++ b/include/ensmallen_bits/iqn/iqn.hpp @@ -87,11 +87,11 @@ class IQN typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, - MatType& iterate, - CallbackTypes&&... callbacks); + MatType& iterate, + CallbackTypes&&... callbacks); //! Forward the MatType as GradType. template -typename std::enable_if::value, +typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type IQN::Optimize(SeparableFunctionType& functionIn, MatType& iterateIn, @@ -46,6 +48,7 @@ IQN::Optimize(SeparableFunctionType& functionIn, typedef typename MatType::elem_type ElemType; typedef typename MatTypeTraits::BaseMatType BaseMatType; typedef typename MatTypeTraits::BaseMatType BaseGradType; + typedef typename ForwardMatType::MatType ProxyMatType; typedef Function FullFunctionType; @@ -81,7 +84,7 @@ IQN::Optimize(SeparableFunctionType& functionIn, iterate.n_cols)); std::vector Q(numBatches, BaseMatType(iterate.n_elem, iterate.n_elem)); - BaseMatType initialIterate = arma::randn>(iterate.n_rows, + BaseMatType initialIterate = randn(iterate.n_rows, iterate.n_cols); BaseGradType B(iterate.n_elem, iterate.n_elem); B.eye(); @@ -124,7 +127,7 @@ IQN::Optimize(SeparableFunctionType& functionIn, const size_t effectiveBatchSize = std::min(batchSize, numFunctions - it * batchSize); - if (arma::norm(iterate - t[it]) > 0) + if (norm(iterate - t[it]) > 0) { function.Gradient(iterate, it * batchSize, gradient, effectiveBatchSize); @@ -133,73 +136,73 @@ IQN::Optimize(SeparableFunctionType& functionIn, terminate |= Callback::Gradient(*this, function, iterate, gradient, callbacks...); - const BaseMatType s = arma::vectorise(iterate - t[it]); - const BaseGradType yy = arma::vectorise(gradient - y[it]); + const BaseMatType s = vectorise(iterate - t[it]); + const BaseGradType yy = vectorise(gradient - y[it]); - const BaseGradType stochasticHessian = Q[it] + yy * yy.t() / - arma::as_scalar(yy.t() * s) - Q[it] * s * s.t() * - Q[it] / arma::as_scalar(s.t() * Q[it] * s); + // const BaseGradType stochasticHessian = Q[it] + yy * yy.t() / + // as_scalar(yy.t() * s) - Q[it] * s * s.t() * + // Q[it] / as_scalar(s.t() * Q[it] * s); - // Update aggregate Hessian approximation. - B += (1.0 / numBatches) * (stochasticHessian - Q[it]); + // // Update aggregate Hessian approximation. + // B += (1.0 / numBatches) * (stochasticHessian - Q[it]); - // Update aggregate Hessian-variable product. - u += arma::reshape((1.0 / numBatches) * (stochasticHessian * - arma::vectorise(iterate) - Q[it] * arma::vectorise(t[it])), - u.n_rows, u.n_cols);; + // // Update aggregate Hessian-variable product. + // u += reshape((1.0 / numBatches) * (stochasticHessian * + // vectorise(iterate) - Q[it] * vectorise(t[it])), + // u.n_rows, u.n_cols);; - // Update aggregate gradient. - g += (1.0 / numBatches) * (gradient - y[it]); + // // Update aggregate gradient. + // g += (1.0 / numBatches) * (gradient - y[it]); - // Update the function information tables. - Q[it] = std::move(stochasticHessian); - y[it] = std::move(gradient); - t[it] = iterate; + // // Update the function information tables. + // Q[it] = std::move(stochasticHessian); + // y[it] = std::move(gradient); + // t[it] = iterate; - iterate = arma::reshape(stepSize * B.i() * (u.t() - arma::vectorise(g)), - iterate.n_rows, iterate.n_cols) + (1 - stepSize) * iterate; + // iterate = reshape(stepSize * B.i() * (u.t() - vectorise(g)), + // iterate.n_rows, iterate.n_cols) + (1 - stepSize) * iterate; - terminate |= Callback::StepTaken(*this, function, iterate, - callbacks...); + // terminate |= Callback::StepTaken(*this, function, iterate, + // callbacks...); } f += effectiveBatchSize; } - overallObjective = 0; - for (size_t f = 0; f < numFunctions; f += batchSize) - { - const size_t effectiveBatchSize = std::min(batchSize, numFunctions - f); - const ElemType objective = function.Evaluate(iterate, f, - effectiveBatchSize); - overallObjective += objective; - - terminate |= Callback::Evaluate(*this, function, iterate, objective, - callbacks...); - } - overallObjective /= numFunctions; - - // Output current objective function. - Info << "IQN: iteration " << i << ", objective " << overallObjective - << "." << std::endl; - - if (std::isnan(overallObjective) || std::isinf(overallObjective)) - { - Warn << "IQN: converged to " << overallObjective << "; terminating" - << " with failure. Try a smaller step size?" << std::endl; - - Callback::EndOptimization(*this, function, iterate, callbacks...); - return overallObjective; - } - - if (overallObjective < tolerance) - { - Info << "IQN: minimized within tolerance " << tolerance << "; " - << "terminating optimization." << std::endl; - - Callback::EndOptimization(*this, function, iterate, callbacks...); - return overallObjective; - } + // overallObjective = 0; + // for (size_t f = 0; f < numFunctions; f += batchSize) + // { + // const size_t effectiveBatchSize = std::min(batchSize, numFunctions - f); + // const ElemType objective = function.Evaluate(iterate, f, + // effectiveBatchSize); + // overallObjective += objective; + + // terminate |= Callback::Evaluate(*this, function, iterate, objective, + // callbacks...); + // } + // overallObjective /= numFunctions; + + // // Output current objective function. + // Info << "IQN: iteration " << i << ", objective " << overallObjective + // << "." << std::endl; + + // if (std::isnan(overallObjective) || std::isinf(overallObjective)) + // { + // Warn << "IQN: converged to " << overallObjective << "; terminating" + // << " with failure. Try a smaller step size?" << std::endl; + + // Callback::EndOptimization(*this, function, iterate, callbacks...); + // return overallObjective; + // } + + // if (overallObjective < tolerance) + // { + // Info << "IQN: minimized within tolerance " << tolerance << "; " + // << "terminating optimization." << std::endl; + + // Callback::EndOptimization(*this, function, iterate, callbacks...); + // return overallObjective; + // } } Info << "IQN: maximum iterations (" << maxIterations << ") reached; " diff --git a/include/ensmallen_bits/katyusha/katyusha.hpp b/include/ensmallen_bits/katyusha/katyusha.hpp index d416f8ab6..662c1f6bc 100644 --- a/include/ensmallen_bits/katyusha/katyusha.hpp +++ b/include/ensmallen_bits/katyusha/katyusha.hpp @@ -93,8 +93,8 @@ class KatyushaType typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks); diff --git a/include/ensmallen_bits/katyusha/katyusha_impl.hpp b/include/ensmallen_bits/katyusha/katyusha_impl.hpp index 53c30438c..a770bf219 100644 --- a/include/ensmallen_bits/katyusha/katyusha_impl.hpp +++ b/include/ensmallen_bits/katyusha/katyusha_impl.hpp @@ -45,7 +45,8 @@ template -typename std::enable_if::value, +typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type KatyushaType::Optimize( SeparableFunctionType& function, diff --git a/include/ensmallen_bits/lbfgs/lbfgs.hpp b/include/ensmallen_bits/lbfgs/lbfgs.hpp index 8f58eee01..972b7baff 100644 --- a/include/ensmallen_bits/lbfgs/lbfgs.hpp +++ b/include/ensmallen_bits/lbfgs/lbfgs.hpp @@ -80,8 +80,8 @@ class L_BFGS typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(FunctionType& function, MatType& iterate, CallbackTypes&&... callbacks); diff --git a/include/ensmallen_bits/lbfgs/lbfgs_impl.hpp b/include/ensmallen_bits/lbfgs/lbfgs_impl.hpp index 5d15401a0..3b9a11792 100644 --- a/include/ensmallen_bits/lbfgs/lbfgs_impl.hpp +++ b/include/ensmallen_bits/lbfgs/lbfgs_impl.hpp @@ -123,22 +123,23 @@ void L_BFGS::SearchDirection(const MatType& gradient, const CubeType& y, MatType& searchDirection) { + typedef typename CubeType::elem_type CubeElemType; + // Start from this point. searchDirection = gradient; // See "A Recursive Formula to Compute H * g" in "Updating quasi-Newton // matrices with limited storage" (Nocedal, 1980). - typedef typename CubeType::elem_type CubeElemType; // Temporary variables. - arma::Col rho(numBasis); - arma::Col alpha(numBasis); + typedef typename ForwardCubeColType::ColType ColType; + ColType rho(numBasis); + ColType alpha(numBasis); size_t limit = (numBasis > iterationNum) ? 0 : (iterationNum - numBasis); for (size_t i = iterationNum; i != limit; i--) { int translatedPosition = (i + (numBasis - 1)) % numBasis; - const arma::Mat& sMat = s.slice(translatedPosition); const arma::Mat& yMat = y.slice(translatedPosition); @@ -159,7 +160,7 @@ void L_BFGS::SearchDirection(const MatType& gradient, { int translatedPosition = i % numBasis; double beta = rho[iterationNum - i - 1] * - arma::dot(y.slice(translatedPosition), searchDirection); + dot(y.slice(translatedPosition), searchDirection); searchDirection += (alpha[iterationNum - i - 1] - beta) * s.slice(translatedPosition); } @@ -232,7 +233,7 @@ bool L_BFGS::LineSearch(FunctionType& function, // The initial linear term approximation in the direction of the // search direction. ElemType initialSearchDirectionDotGradient = - arma::dot(gradient, searchDirection); + dot(gradient, searchDirection); // If it is not a descent direction, just report failure. if ( (initialSearchDirectionDotGradient > 0.0) @@ -292,7 +293,7 @@ bool L_BFGS::LineSearch(FunctionType& function, else { // Check Wolfe's condition. - ElemType searchDirectionDotGradient = arma::dot(gradient, + ElemType searchDirectionDotGradient = dot(gradient, searchDirection); if (searchDirectionDotGradient < wolfe * @@ -346,7 +347,8 @@ template -typename std::enable_if::value, +typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type L_BFGS::Optimize(FunctionType& function, MatType& iterateIn, @@ -376,8 +378,10 @@ L_BFGS::Optimize(FunctionType& function, const size_t cols = iterate.n_cols; BaseMatType newIterateTmp(rows, cols); - arma::Cube s(rows, cols, numBasis); - arma::Cube y(rows, cols, numBasis); + + typedef typename ForwardMatCubeType::CubeType CubeType; + CubeType s(rows, cols, numBasis); + CubeType y(rows, cols, numBasis); // The old iterate to be saved. BaseMatType oldIterate(iterate.n_rows, iterate.n_cols); @@ -417,7 +421,7 @@ L_BFGS::Optimize(FunctionType& function, // least one descent step. // TODO: to speed this up, investigate use of arma::norm2est() in Armadillo // 12.4 - if (arma::norm(gradient, 2) < minGradientNorm) + if (norm(gradient, 2) < minGradientNorm) { Info << "L-BFGS gradient norm too small (terminating successfully)." << std::endl; diff --git a/include/ensmallen_bits/lookahead/lookahead.hpp b/include/ensmallen_bits/lookahead/lookahead.hpp index d7cd2cf09..e08a1cd26 100644 --- a/include/ensmallen_bits/lookahead/lookahead.hpp +++ b/include/ensmallen_bits/lookahead/lookahead.hpp @@ -131,8 +131,8 @@ class Lookahead typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks); diff --git a/include/ensmallen_bits/lookahead/lookahead_impl.hpp b/include/ensmallen_bits/lookahead/lookahead_impl.hpp index cdb42b657..c623c7d27 100644 --- a/include/ensmallen_bits/lookahead/lookahead_impl.hpp +++ b/include/ensmallen_bits/lookahead/lookahead_impl.hpp @@ -72,7 +72,8 @@ template -typename std::enable_if::value, +typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Lookahead::Optimize( SeparableFunctionType& function, diff --git a/include/ensmallen_bits/padam/padam_update.hpp b/include/ensmallen_bits/padam/padam_update.hpp index a4a69243e..8759bbd0e 100644 --- a/include/ensmallen_bits/padam/padam_update.hpp +++ b/include/ensmallen_bits/padam/padam_update.hpp @@ -127,10 +127,10 @@ class PadamUpdate const double biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration); // Element wise maximum of past and present squared gradients. - vImproved = arma::max(vImproved, v); + vImproved = max(vImproved, v); iterate -= (stepSize * std::sqrt(biasCorrection2) / biasCorrection1) * - m / arma::pow(vImproved + parent.epsilon, parent.partial); + m / pow(vImproved + parent.epsilon, parent.partial); } private: diff --git a/include/ensmallen_bits/problems/fonseca_fleming_function.hpp b/include/ensmallen_bits/problems/fonseca_fleming_function.hpp index 34bc95b0f..5e2ced46c 100644 --- a/include/ensmallen_bits/problems/fonseca_fleming_function.hpp +++ b/include/ensmallen_bits/problems/fonseca_fleming_function.hpp @@ -74,11 +74,12 @@ class FonsecaFlemingFunction { typename MatType::elem_type Evaluate(const MatType& coords) { - return 1.0 - exp( - -pow(static_cast(coords[0]) - 1.0 / sqrt(3.0), 2.0) - -pow(static_cast(coords[1]) - 1.0 / sqrt(3.0), 2.0) - -pow(static_cast(coords[2]) - 1.0 / sqrt(3.0), 2.0) - ); + return 0; + // return 1.0 - exp( + // -pow(static_cast(coords[0]) - 1.0 / sqrt(3.0), 2.0) + // -pow(static_cast(coords[1]) - 1.0 / sqrt(3.0), 2.0) + // -pow(static_cast(coords[2]) - 1.0 / sqrt(3.0), 2.0) + // ); } } objectiveA; @@ -86,11 +87,12 @@ class FonsecaFlemingFunction { typename MatType::elem_type Evaluate(const MatType& coords) { - return 1.0 - exp( - -pow(static_cast(coords[0]) + 1.0 / sqrt(3.0), 2.0) - -pow(static_cast(coords[1]) + 1.0 / sqrt(3.0), 2.0) - -pow(static_cast(coords[2]) + 1.0 / sqrt(3.0), 2.0) - ); + return 0; + // return 1.0 - exp( + // -pow(static_cast(coords[0]) + 1.0 / sqrt(3.0), 2.0) + // -pow(static_cast(coords[1]) + 1.0 / sqrt(3.0), 2.0) + // -pow(static_cast(coords[2]) + 1.0 / sqrt(3.0), 2.0) + // ); } } objectiveB; diff --git a/include/ensmallen_bits/problems/generalized_rosenbrock_function.hpp b/include/ensmallen_bits/problems/generalized_rosenbrock_function.hpp index 3ec963fd4..e215b88c3 100644 --- a/include/ensmallen_bits/problems/generalized_rosenbrock_function.hpp +++ b/include/ensmallen_bits/problems/generalized_rosenbrock_function.hpp @@ -42,6 +42,7 @@ namespace test { * } * @endcode */ +template> class GeneralizedRosenbrockFunction { public: @@ -68,7 +69,6 @@ class GeneralizedRosenbrockFunction * @param begin The first function. * @param batchSize Number of points to process. */ - template typename MatType::elem_type Evaluate(const MatType& coordinates, const size_t begin, const size_t batchSize = 1) const; @@ -78,7 +78,6 @@ class GeneralizedRosenbrockFunction * * @param coordinates The function coordinates. */ - template typename MatType::elem_type Evaluate(const MatType& coordinates) const; /** @@ -89,7 +88,7 @@ class GeneralizedRosenbrockFunction * @param gradient The function gradient. * @param batchSize Number of points to process. */ - template + template void Gradient(const MatType& coordinates, const size_t begin, GradType& gradient, @@ -101,7 +100,7 @@ class GeneralizedRosenbrockFunction * @param coordinates The function coordinates. * @param gradient The function gradient. */ - template + template void Gradient(const MatType& coordinates, GradType& gradient) const; // Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not @@ -110,17 +109,19 @@ class GeneralizedRosenbrockFunction // infrastructure. //! Get the starting point. - template - const MatType GetInitialPoint() const + template + const InputMatType GetInitialPoint() const { - return arma::conv_to::from(initialPoint); + return conv_to::from(initialPoint); } //! Get the final point. - template - const MatType GetFinalPoint() const + template + const InputMatType GetFinalPoint() const { - return arma::ones(initialPoint.n_rows, initialPoint.n_cols); + InputMatType finalPoint(initialPoint.n_rows, initialPoint.n_cols); + finalPoint.ones(); + return finalPoint; } //! Get the final objective. @@ -128,13 +129,13 @@ class GeneralizedRosenbrockFunction private: //! Locally-stored Initial point. - arma::mat initialPoint; + MatType initialPoint; - //! //! Number of dimensions for the function. + //! Number of dimensions for the function. size_t n; //! For shuffling. - arma::Row visitationOrder; + LabelsType visitationOrder; }; } // namespace test diff --git a/include/ensmallen_bits/problems/generalized_rosenbrock_function_impl.hpp b/include/ensmallen_bits/problems/generalized_rosenbrock_function_impl.hpp index b332f1325..3c73b01a5 100644 --- a/include/ensmallen_bits/problems/generalized_rosenbrock_function_impl.hpp +++ b/include/ensmallen_bits/problems/generalized_rosenbrock_function_impl.hpp @@ -19,10 +19,12 @@ namespace ens { namespace test { -inline GeneralizedRosenbrockFunction::GeneralizedRosenbrockFunction( +template +GeneralizedRosenbrockFunction< + MatType, LabelsType>::GeneralizedRosenbrockFunction( const size_t n) : n(n), - visitationOrder(arma::linspace >(0, n - 1, n)) + visitationOrder(linspace(0, n - 1, n)) { initialPoint.set_size(n, 1); @@ -39,14 +41,15 @@ inline GeneralizedRosenbrockFunction::GeneralizedRosenbrockFunction( } } -inline void GeneralizedRosenbrockFunction::Shuffle() +template +void GeneralizedRosenbrockFunction::Shuffle() { - visitationOrder = arma::shuffle(arma::linspace>(0, n - 2, - n - 1)); + visitationOrder = shuffle(linspace(0, n - 2, n - 1)); } -template -typename MatType::elem_type GeneralizedRosenbrockFunction::Evaluate( +template +typename MatType::elem_type GeneralizedRosenbrockFunction< + MatType, LabelsType>::Evaluate( const MatType& coordinates, const size_t begin, const size_t batchSize) const @@ -62,8 +65,9 @@ typename MatType::elem_type GeneralizedRosenbrockFunction::Evaluate( return objective; } -template -typename MatType::elem_type GeneralizedRosenbrockFunction::Evaluate( +template +typename MatType::elem_type GeneralizedRosenbrockFunction< + MatType, LabelsType>::Evaluate( const MatType& coordinates) const { typename MatType::elem_type fval = 0; @@ -76,8 +80,9 @@ typename MatType::elem_type GeneralizedRosenbrockFunction::Evaluate( return fval; } -template -inline void GeneralizedRosenbrockFunction::Gradient( +template +template +void GeneralizedRosenbrockFunction::Gradient( const MatType& coordinates, const size_t begin, GradType& gradient, @@ -93,8 +98,9 @@ inline void GeneralizedRosenbrockFunction::Gradient( } } -template -inline void GeneralizedRosenbrockFunction::Gradient( +template +template +void GeneralizedRosenbrockFunction::Gradient( const MatType& coordinates, GradType& gradient) const { diff --git a/include/ensmallen_bits/problems/gradient_descent_test_function_impl.hpp b/include/ensmallen_bits/problems/gradient_descent_test_function_impl.hpp index cf38ee6a7..b1c447f20 100644 --- a/include/ensmallen_bits/problems/gradient_descent_test_function_impl.hpp +++ b/include/ensmallen_bits/problems/gradient_descent_test_function_impl.hpp @@ -21,7 +21,7 @@ template inline typename MatType::elem_type GDTestFunction::Evaluate( const MatType& coordinates) const { - MatType temp = arma::trans(coordinates) * coordinates; + MatType temp = trans(coordinates) * coordinates; return temp(0, 0); } diff --git a/include/ensmallen_bits/problems/logistic_regression_function.hpp b/include/ensmallen_bits/problems/logistic_regression_function.hpp index 53c69df54..2d3df516e 100644 --- a/include/ensmallen_bits/problems/logistic_regression_function.hpp +++ b/include/ensmallen_bits/problems/logistic_regression_function.hpp @@ -22,16 +22,16 @@ namespace test { * This is used by various ensmallen optimizers to train a logistic regression * model. */ -template +template> class LogisticRegressionFunction { public: LogisticRegressionFunction(MatType& predictors, - arma::Row& responses, + LabelsType& responses, const double lambda = 0); LogisticRegressionFunction(MatType& predictors, - arma::Row& responses, + LabelsType& responses, MatType& initialPoint, const double lambda = 0); @@ -48,7 +48,7 @@ class LogisticRegressionFunction //! Return the matrix of predictors. const MatType& Predictors() const { return predictors; } //! Return the vector of responses. - const arma::Row& Responses() const { return responses; } + const LabelsType& Responses() const { return responses; } /** * Shuffle the order of function visitation. This may be called by the @@ -130,9 +130,10 @@ class LogisticRegressionFunction * be computed. * @param gradient Sparse matrix to output gradient into. */ + template void PartialGradient(const MatType& parameters, const size_t j, - arma::sp_mat& gradient) const; + arma::SpMat& gradient) const; /** * Evaluate the objective function and gradient of the logistic regression @@ -175,7 +176,7 @@ class LogisticRegressionFunction * @return Percentage of responses that are predicted correctly. */ double ComputeAccuracy(const MatType& predictors, - const arma::Row& responses, + const LabelsType& responses, const MatType& parameters, const double decisionBoundary = 0.5) const; @@ -192,7 +193,7 @@ class LogisticRegressionFunction * @param decisionBoundary Decision boundary (default 0.5). */ void Classify(const MatType& dataset, - arma::Row& labels, + LabelsType& labels, const MatType& parameters, const double decisionBoundary = 0.5) const; @@ -204,7 +205,7 @@ class LogisticRegressionFunction MatType& predictors; //! The vector of responses to the input data points. This is an alias until //! shuffling is done. - arma::Row& responses; + LabelsType& responses; //! The regularization parameter for L2-regularization. double lambda; }; diff --git a/include/ensmallen_bits/problems/logistic_regression_function_impl.hpp b/include/ensmallen_bits/problems/logistic_regression_function_impl.hpp index e9a914816..f0b5015b1 100644 --- a/include/ensmallen_bits/problems/logistic_regression_function_impl.hpp +++ b/include/ensmallen_bits/problems/logistic_regression_function_impl.hpp @@ -18,10 +18,10 @@ namespace ens { namespace test { -template -LogisticRegressionFunction::LogisticRegressionFunction( +template +LogisticRegressionFunction::LogisticRegressionFunction( MatType& predictors, - arma::Row& responses, + LabelsType& responses, const double lambda) : // We promise to be well-behaved... the elements won't be modified. predictors(predictors), @@ -43,10 +43,10 @@ LogisticRegressionFunction::LogisticRegressionFunction( } } -template -LogisticRegressionFunction::LogisticRegressionFunction( +template +LogisticRegressionFunction::LogisticRegressionFunction( MatType& predictors, - arma::Row& responses, + LabelsType& responses, MatType& initialPoint, const double lambda) : initialPoint(initialPoint), @@ -64,19 +64,22 @@ LogisticRegressionFunction::LogisticRegressionFunction( /** * Shuffle the datapoints. */ -template -void LogisticRegressionFunction::Shuffle() +template +void LogisticRegressionFunction::Shuffle() { MatType newPredictors; - arma::Row newResponses; + LabelsType newResponses; arma::uvec ordering = arma::shuffle(arma::linspace(0, predictors.n_cols - 1, predictors.n_cols)); newPredictors.set_size(predictors.n_rows, predictors.n_cols); + newResponses.set_size(responses.n_elem); for (size_t i = 0; i < predictors.n_cols; ++i) + { newPredictors.col(i) = predictors.col(ordering[i]); - newResponses = responses.cols(ordering); + newResponses[i] = (typename LabelsType::elem_type) responses[ordering[i]]; + } // Take ownership of the new data. predictors = std::move(newPredictors); @@ -87,8 +90,8 @@ void LogisticRegressionFunction::Shuffle() * Evaluate the logistic regression objective function given the estimated * parameters. */ -template -typename MatType::elem_type LogisticRegressionFunction::Evaluate( +template +typename MatType::elem_type LogisticRegressionFunction::Evaluate( const MatType& parameters) const { // The objective function is the log-likelihood function (w is the parameters @@ -98,18 +101,19 @@ typename MatType::elem_type LogisticRegressionFunction::Evaluate( // We want to minimize this function. L2-regularization is just lambda // multiplied by the squared l2-norm of the parameters then divided by two. typedef typename MatType::elem_type ElemType; + typedef typename ForwardRowType::RowType RowType; // For the regularization, we ignore the first term, which is the intercept // term and take every term except the last one in the decision variable. const ElemType regularization = 0.5 * lambda * - arma::dot(parameters.tail_cols(parameters.n_elem - 1), + dot(parameters.tail_cols(parameters.n_elem - 1), parameters.tail_cols(parameters.n_elem - 1)); // Calculate vectors of sigmoids. The intercept term is parameters(0, 0) and // does not need to be multiplied by any of the predictors. - const arma::Row sigmoid = 1.0 / (1.0 + - arma::exp(-(parameters(0, 0) + - parameters.tail_cols(parameters.n_elem - 1) * predictors))); + const RowType sigmoid = 1.0 / (1.0 + + exp(-(parameters(0, 0) + + parameters.tail_cols(parameters.n_elem - 1) * predictors))); // Assemble full objective function. Often the objective function and the // regularization as given are divided by the number of features, but this @@ -117,9 +121,9 @@ typename MatType::elem_type LogisticRegressionFunction::Evaluate( // terms for computational efficiency. Note that the conversion causes some // copy and slowdown, but this is so negligible compared to the rest of the // calculation it is not worth optimizing for. - const ElemType result = arma::accu(arma::log(1.0 - - arma::conv_to>::from(responses) + sigmoid % - (2 * arma::conv_to>::from(responses) - 1.0))); + const ElemType result = accu(log(1.0 - + conv_to::from(responses) + sigmoid % + (2 * conv_to::from(responses) - 1.0))); // Invert the result, because it's a minimization. return regularization - result; @@ -129,30 +133,31 @@ typename MatType::elem_type LogisticRegressionFunction::Evaluate( * Evaluate the logistic regression objective function given the estimated * parameters for a given batch from a given point. */ -template -typename MatType::elem_type LogisticRegressionFunction::Evaluate( +template +typename MatType::elem_type LogisticRegressionFunction::Evaluate( const MatType& parameters, const size_t begin, const size_t batchSize) const { typedef typename MatType::elem_type ElemType; + typedef typename ForwardRowType::RowType RowType; // Calculate the regularization term. const ElemType regularization = lambda * (batchSize / (2.0 * predictors.n_cols)) * - arma::dot(parameters.tail_cols(parameters.n_elem - 1), + dot(parameters.tail_cols(parameters.n_elem - 1), parameters.tail_cols(parameters.n_elem - 1)); // Calculate the sigmoid function values. - const arma::Row sigmoid = 1.0 / (1.0 + - arma::exp(-(parameters(0, 0) + - parameters.tail_cols(parameters.n_elem - 1) * - predictors.cols(begin, begin + batchSize - 1)))); + const RowType sigmoid = 1.0 / (1.0 + + exp(-(parameters(0, 0) + + parameters.tail_cols(parameters.n_elem - 1) * + predictors.cols(begin, begin + batchSize - 1)))); // Compute the objective for the given batch size from a given point. - arma::Row respD = arma::conv_to>::from( + RowType respD = conv_to::from( responses.subvec(begin, begin + batchSize - 1)); - const ElemType result = arma::accu(arma::log(1.0 - respD + sigmoid % + const ElemType result = accu(log(1.0 - respD + sigmoid % (2 * respD - 1.0))); // Invert the result, because it's a minimization. @@ -160,54 +165,56 @@ typename MatType::elem_type LogisticRegressionFunction::Evaluate( } //! Evaluate the gradient of the logistic regression objective function. -template +template template -void LogisticRegressionFunction::Gradient( +void LogisticRegressionFunction::Gradient( const MatType& parameters, GradType& gradient) const { - typedef typename MatType::elem_type ElemType; - // Regularization term. - MatType regularization; - regularization = lambda * parameters.tail_cols(parameters.n_elem - 1); - - const arma::Row sigmoids = (1 / (1 + arma::exp(-parameters(0, 0) - - parameters.tail_cols(parameters.n_elem - 1) * predictors))); - - gradient.set_size(arma::size(parameters)); - gradient[0] = -arma::accu(responses - sigmoids); - gradient.tail_cols(parameters.n_elem - 1) = (sigmoids - responses) * - predictors.t() + regularization; + exit(0); +// typedef typename MatType::elem_type ElemType; +// // Regularization term. +// MatType regularization; +// regularization = lambda * parameters.tail_cols(parameters.n_elem - 1); + +// const arma::Row sigmoids = (1 / (1 + arma::exp(-parameters(0, 0) +// - parameters.tail_cols(parameters.n_elem - 1) * predictors))); + +// gradient.set_size(arma::size(parameters)); +// gradient[0] = -arma::accu(responses - sigmoids); +// gradient.tail_cols(parameters.n_elem - 1) = (sigmoids - responses) * +// predictors.t() + regularization; } //! Evaluate the gradient of the logistic regression objective function for a //! given batch size. -template +template template -void LogisticRegressionFunction::Gradient( +void LogisticRegressionFunction::Gradient( const MatType& parameters, const size_t begin, GradType& gradient, const size_t batchSize) const { typedef typename MatType::elem_type ElemType; + typedef typename ForwardRowType::RowType RowType; // Regularization term. MatType regularization; regularization = lambda * parameters.tail_cols(parameters.n_elem - 1) / predictors.n_cols * batchSize; - const arma::Row exponents = parameters(0, 0) + + const RowType exponents = parameters(0, 0) + parameters.tail_cols(parameters.n_elem - 1) * predictors.cols(begin, begin + batchSize - 1); // Calculating the sigmoid function values. - const arma::Row sigmoids = 1.0 / (1.0 + arma::exp(-exponents)); + const RowType sigmoids = 1.0 / (1.0 + exp(-exponents)); gradient.set_size(parameters.n_rows, parameters.n_cols); - gradient[0] = -arma::accu(responses.subvec(begin, begin + batchSize - 1) - + gradient[0] = -accu(conv_to::from(responses.subvec(begin, begin + batchSize - 1)) - sigmoids); gradient.tail_cols(parameters.n_elem - 1) = (sigmoids - - responses.subvec(begin, begin + batchSize - 1)) * + conv_to::from(responses.subvec(begin, begin + batchSize - 1))) * predictors.cols(begin, begin + batchSize - 1).t() + regularization; } @@ -215,11 +222,12 @@ void LogisticRegressionFunction::Gradient( * Evaluate the partial gradient of the logistic regression objective * function with respect to the individual features in the parameter. */ -template -void LogisticRegressionFunction::PartialGradient( +template +template +void LogisticRegressionFunction::PartialGradient( const MatType& parameters, const size_t j, - arma::sp_mat& gradient) const + arma::SpMat& gradient) const { const arma::Row diffs = responses - (1 / (1 + arma::exp(-parameters(0, 0) - @@ -239,52 +247,54 @@ void LogisticRegressionFunction::PartialGradient( } } -template +template template typename MatType::elem_type -LogisticRegressionFunction::EvaluateWithGradient( +LogisticRegressionFunction::EvaluateWithGradient( const MatType& parameters, GradType& gradient) const { - typedef typename MatType::elem_type ElemType; - - // Regularization term. - MatType regularization = lambda * - parameters.tail_cols(parameters.n_elem - 1); - - const ElemType objectiveRegularization = lambda / 2.0 * - arma::dot(parameters.tail_cols(parameters.n_elem - 1), - parameters.tail_cols(parameters.n_elem - 1)); - - // Calculate the sigmoid function values. - const arma::Row sigmoids = 1.0 / (1.0 + - arma::exp(-(parameters(0, 0) + - parameters.tail_cols(parameters.n_elem - 1) * predictors))); - - gradient.set_size(arma::size(parameters)); - gradient[0] = -arma::accu(responses - sigmoids); - gradient.tail_cols(parameters.n_elem - 1) = (sigmoids - responses) * - predictors.t() + regularization; - - // Now compute the objective function using the sigmoids. - ElemType result = arma::accu(arma::log(1.0 - - arma::conv_to>::from(responses) + sigmoids % - (2 * arma::conv_to>::from(responses) - 1.0))); - - // Invert the result, because it's a minimization. - return objectiveRegularization - result; + exit(0); +// typedef typename MatType::elem_type ElemType; + +// // Regularization term. +// MatType regularization = lambda * +// parameters.tail_cols(parameters.n_elem - 1); + +// const ElemType objectiveRegularization = lambda / 2.0 * +// arma::dot(parameters.tail_cols(parameters.n_elem - 1), +// parameters.tail_cols(parameters.n_elem - 1)); + +// // Calculate the sigmoid function values. +// const arma::Row sigmoids = 1.0 / (1.0 + +// arma::exp(-(parameters(0, 0) + +// parameters.tail_cols(parameters.n_elem - 1) * predictors))); + +// gradient.set_size(arma::size(parameters)); +// gradient[0] = -arma::accu(responses - sigmoids); +// gradient.tail_cols(parameters.n_elem - 1) = (sigmoids - responses) * +// predictors.t() + regularization; + +// // Now compute the objective function using the sigmoids. +// ElemType result = arma::accu(arma::log(1.0 - +// arma::conv_to>::from(responses) + sigmoids % +// (2 * arma::conv_to>::from(responses) - 1.0))); + +// // Invert the result, because it's a minimization. +// return objectiveRegularization - result; } -template +template template typename MatType::elem_type -LogisticRegressionFunction::EvaluateWithGradient( +LogisticRegressionFunction::EvaluateWithGradient( const MatType& parameters, const size_t begin, GradType& gradient, const size_t batchSize) const { typedef typename MatType::elem_type ElemType; + typedef typename ForwardRowType::RowType RowType; // Regularization term. MatType regularization = @@ -293,56 +303,56 @@ LogisticRegressionFunction::EvaluateWithGradient( const ElemType objectiveRegularization = lambda * (batchSize / (2.0 * predictors.n_cols)) * - arma::dot(parameters.tail_cols(parameters.n_elem - 1), + dot(parameters.tail_cols(parameters.n_elem - 1), parameters.tail_cols(parameters.n_elem - 1)); // Calculate the sigmoid function values. - const arma::Row sigmoids = 1.0 / (1.0 + - arma::exp(-(parameters(0, 0) + + const RowType sigmoids = 1.0 / (1.0 + + exp(-(parameters(0, 0) + parameters.tail_cols(parameters.n_elem - 1) * predictors.cols(begin, begin + batchSize - 1)))); gradient.set_size(parameters.n_rows, parameters.n_cols); - gradient[0] = -arma::accu(responses.subvec(begin, begin + batchSize - 1) - - sigmoids); + gradient[0] = -accu(conv_to::from( + responses.subvec(begin, begin + batchSize - 1)) - sigmoids); gradient.tail_cols(parameters.n_elem - 1) = (sigmoids - - responses.subvec(begin, begin + batchSize - 1)) * + conv_to::from(responses.subvec(begin, begin + batchSize - 1))) * predictors.cols(begin, begin + batchSize - 1).t() + regularization; // Now compute the objective function using the sigmoids. - arma::Row respD = arma::conv_to>::from( + RowType respD = conv_to::from( responses.subvec(begin, begin + batchSize - 1)); - const ElemType result = arma::accu(arma::log(1.0 - respD + sigmoids % + const ElemType result = accu(log(1.0 - respD + sigmoids % (2 * respD - 1.0))); // Invert the result, because it's a minimization. return objectiveRegularization - result; } -template -void LogisticRegressionFunction::Classify( +template +void LogisticRegressionFunction::Classify( const MatType& dataset, - arma::Row& labels, + LabelsType& labels, const MatType& parameters, const double decisionBoundary) const { // Calculate sigmoid function for each point. The (1.0 - decisionBoundary) // term correctly sets an offset so that floor() returns 0 or 1 correctly. - labels = arma::conv_to>::from((1.0 / - (1.0 + arma::exp(-parameters(0) - + labels = conv_to::from((1.0 / + (1.0 + exp(-parameters(0) - parameters.tail_cols(parameters.n_elem - 1) * dataset))) + (1.0 - decisionBoundary)); } -template -double LogisticRegressionFunction::ComputeAccuracy( +template +double LogisticRegressionFunction::ComputeAccuracy( const MatType& predictors, - const arma::Row& responses, + const LabelsType& responses, const MatType& parameters, const double decisionBoundary) const { // Predict responses using the current model. - arma::Row tempResponses; + LabelsType tempResponses; Classify(predictors, tempResponses, parameters, decisionBoundary); // Count the number of responses that were correct. @@ -359,4 +369,4 @@ double LogisticRegressionFunction::ComputeAccuracy( } // namespace test } // namespace ens -#endif +#endif \ No newline at end of file diff --git a/include/ensmallen_bits/problems/rosenbrock_wood_function.hpp b/include/ensmallen_bits/problems/rosenbrock_wood_function.hpp index b42422a37..601856714 100644 --- a/include/ensmallen_bits/problems/rosenbrock_wood_function.hpp +++ b/include/ensmallen_bits/problems/rosenbrock_wood_function.hpp @@ -24,6 +24,7 @@ namespace test { * four dimensions. In this function we are actually optimizing a 2x4 matrix of * coordinates, not a vector. */ +template> class RosenbrockWoodFunction { public: @@ -46,7 +47,6 @@ class RosenbrockWoodFunction * @param begin The first function. * @param batchSize Number of points to process. */ - template typename MatType::elem_type Evaluate(const MatType& coordinates, const size_t begin, const size_t batchSize) const; @@ -56,7 +56,6 @@ class RosenbrockWoodFunction * * @param coordinates The function coordinates. */ - template typename MatType::elem_type Evaluate(const MatType& coordinates) const; /** @@ -67,7 +66,7 @@ class RosenbrockWoodFunction * @param gradient The function gradient. * @param batchSize Number of points to process. */ - template + template void Gradient(const MatType& coordinates, const size_t begin, GradType& gradient, @@ -79,7 +78,7 @@ class RosenbrockWoodFunction * @param coordinates The function coordinates. * @param gradient The function gradient. */ - template + template void Gradient(const MatType& coordinates, GradType& gradient) const; // Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not @@ -88,17 +87,19 @@ class RosenbrockWoodFunction // infrastructure. //! Get the starting point. - template + template const MatType GetInitialPoint() const { - return arma::conv_to::from(initialPoint); + return conv_to::from(initialPoint); } //! Get the final point. - template + template MatType GetFinalPoint() const { - return arma::ones(initialPoint.n_rows, initialPoint.n_cols); + MatType finalPoint(initialPoint.n_rows, initialPoint.n_cols); + finalPoint.fill(1); + return finalPoint; } //! Get the final objective. @@ -106,10 +107,10 @@ class RosenbrockWoodFunction private: //! Locally-stored initial point. - arma::mat initialPoint; + MatType initialPoint; //! Locally-stored Generalized-Rosenbrock function. - GeneralizedRosenbrockFunction rf; + GeneralizedRosenbrockFunction rf; //! Locally-stored Wood function. WoodFunction wf; diff --git a/include/ensmallen_bits/problems/rosenbrock_wood_function.hpp.bak b/include/ensmallen_bits/problems/rosenbrock_wood_function.hpp.bak new file mode 100644 index 000000000..73f588c00 --- /dev/null +++ b/include/ensmallen_bits/problems/rosenbrock_wood_function.hpp.bak @@ -0,0 +1,125 @@ +/** + * @file rosenbrock_wood_function.hpp + * @author Ryan Curtin + * @author Marcus Edel + * + * Definition of the Rosenbrock-Wood function. + * + * ensmallen 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 ensmallen. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ +#ifndef ENSMALLEN_PROBLEMS_ROSENBROCK_WOOD_FUNCTION_HPP +#define ENSMALLEN_PROBLEMS_ROSENBROCK_WOOD_FUNCTION_HPP + +#include "generalized_rosenbrock_function.hpp" +#include "wood_function.hpp" + +namespace ens { +namespace test { + +/** + * The Generalized Rosenbrock function in 4 dimensions with the Wood Function in + * four dimensions. In this function we are actually optimizing a 2x4 matrix of + * coordinates, not a vector. + */ +template> +class RosenbrockWoodFunction +{ + public: + //! Initialize the RosenbrockWoodFunction. + RosenbrockWoodFunction(); + + /** + * Shuffle the order of function visitation. This may be called by the + * optimizer. + */ + void Shuffle(); + + //! Return 1 (the number of functions). + size_t NumFunctions() const { return 1; } + + /** + * Evaluate a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param batchSize Number of points to process. + */ + typename MatType::elem_type Evaluate(const MatType& coordinates, + const size_t begin, + const size_t batchSize) const; + + /** + * Evaluate a function with the given coordinates. + * + * @param coordinates The function coordinates. + */ + typename MatType::elem_type Evaluate(const MatType& coordinates) const; + + /** + * Evaluate the gradient of a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param gradient The function gradient. + * @param batchSize Number of points to process. + */ + template + void Gradient(const MatType& coordinates, + const size_t begin, + GradType& gradient, + const size_t batchSize) const; + + /** + * Evaluate the gradient of a function with the given coordinates. + * + * @param coordinates The function coordinates. + * @param gradient The function gradient. + */ + template + void Gradient(const MatType& coordinates, GradType& gradient) const; + + // Note: GetInitialPoint(), GetFinalPoint(), and GetFinalObjective() are not + // required for using ensmallen to optimize this function! They are + // specifically used as a convenience just for ensmallen's testing + // infrastructure. + + //! Get the starting point. + template + const MatType GetInitialPoint() const + { + return conv_to::from(initialPoint); + } + + //! Get the final point. + template + MatType GetFinalPoint() const + { + InMatType finalPoint(initialPoint.n_rows, initialPoint.n_cols); + finalPoint.zeros(); + return finalPoint; + } + + //! Get the final objective. + double GetFinalObjective() const { return 0.0; } + + private: + //! Locally-stored initial point. + MatType initialPoint; + + //! Locally-stored Generalized-Rosenbrock function. + GeneralizedRosenbrockFunction rf; + + //! Locally-stored Wood function. + WoodFunction wf; +}; + +} // namespace test +} // namespace ens + +// Include implementation. +#include "rosenbrock_wood_function_impl.hpp" + +#endif // ENSMALLEN_PROBLEMS_ROSENBROCK_WOOD_FUNCTION_HPP diff --git a/include/ensmallen_bits/problems/rosenbrock_wood_function_impl.hpp b/include/ensmallen_bits/problems/rosenbrock_wood_function_impl.hpp index 071682e0b..5debb7ee9 100644 --- a/include/ensmallen_bits/problems/rosenbrock_wood_function_impl.hpp +++ b/include/ensmallen_bits/problems/rosenbrock_wood_function_impl.hpp @@ -20,55 +20,64 @@ namespace ens { namespace test { -inline RosenbrockWoodFunction::RosenbrockWoodFunction() : rf(4), wf() +template +RosenbrockWoodFunction::RosenbrockWoodFunction() : + rf(4), wf() { initialPoint.set_size(4, 2); initialPoint.col(0) = rf.GetInitialPoint(); - initialPoint.col(1) = wf.GetInitialPoint(); + initialPoint.col(1) = wf.GetInitialPoint(); } -inline void RosenbrockWoodFunction::Shuffle() { /* Nothing to do here */ } +template +void RosenbrockWoodFunction::Shuffle() +{ /* Nothing to do here */ } -template -typename MatType::elem_type RosenbrockWoodFunction::Evaluate( +template +typename MatType::elem_type RosenbrockWoodFunction< + MatType, LabelsType>::Evaluate( const MatType& coordinates, const size_t /* begin */, const size_t /* batchSize */) const { - return rf.Evaluate(coordinates.col(0)) + wf.Evaluate(coordinates.col(1)); + return rf.Evaluate(MatType(coordinates.col(0))) + + wf.Evaluate(MatType(coordinates.col(1))); } -template -typename MatType::elem_type RosenbrockWoodFunction::Evaluate( - const MatType& coordinates) const +template +typename MatType::elem_type RosenbrockWoodFunction< + MatType, LabelsType>::Evaluate(const MatType& coordinates) const { return Evaluate(coordinates, 0, NumFunctions()); } -template -inline void RosenbrockWoodFunction::Gradient(const MatType& coordinates, - const size_t /* begin */, - GradType& gradient, - const size_t /* batchSize */) const +template +template +void RosenbrockWoodFunction::Gradient( + const MatType& coordinates, + const size_t /* begin */, + GradType& gradient, + const size_t /* batchSize */) const { // Convenience typedef. - typedef typename MatType::elem_type ElemType; + typedef typename ForwardColType::ColType ColType; gradient.set_size(4, 2); - arma::Col grf(4); - arma::Col gwf(4); + ColType grf(4); + ColType gwf(4); - rf.Gradient(coordinates.col(0), grf); - wf.Gradient(coordinates.col(1), gwf); + rf.Gradient(MatType(coordinates.col(0)), grf); + wf.Gradient(MatType(coordinates.col(1)), gwf); gradient.col(0) = grf; gradient.col(1) = gwf; } -template -inline void RosenbrockWoodFunction::Gradient(const MatType& coordinates, - GradType& gradient) const +template +template +inline void RosenbrockWoodFunction::Gradient( + const MatType& coordinates, GradType& gradient) const { Gradient(coordinates, 0, gradient, 1); } diff --git a/include/ensmallen_bits/problems/rosenbrock_wood_function_impl.hpp.bak b/include/ensmallen_bits/problems/rosenbrock_wood_function_impl.hpp.bak new file mode 100644 index 000000000..73b9a1ebe --- /dev/null +++ b/include/ensmallen_bits/problems/rosenbrock_wood_function_impl.hpp.bak @@ -0,0 +1,87 @@ +/** + * @file rosenbrock_wood_function_impl.hpp + * @author Ryan Curtin + * @author Marcus Edel + * + * Implementation of the Rosenbrock-Wood function. + * + * ensmallen 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 ensmallen. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ + +#ifndef ENSMALLEN_PROBLEMS_ROSENBROCK_WOOD_FUNCTION_IMPL_HPP +#define ENSMALLEN_PROBLEMS_ROSENBROCK_WOOD_FUNCTION_IMPL_HPP + +// In case it hasn't been included yet. +#include "rosenbrock_wood_function.hpp" + +namespace ens { +namespace test { + +template +inline RosenbrockWoodFunction::RosenbrockWoodFunction() : + rf(4), wf() +{ + initialPoint.set_size(4, 2); + initialPoint.col(0) = rf.GetInitialPoint(); + initialPoint.col(1) = wf.GetInitialPoint(); +} + +template +inline void RosenbrockWoodFunction::Shuffle() +{ /* Nothing to do here */ } + +template +typename MatType::elem_type RosenbrockWoodFunction< + MatType, LabelsType>::Evaluate( + const MatType& coordinates, + const size_t /* begin */, + const size_t /* batchSize */) const +{ + return rf.Evaluate(coordinates.col(0)) + + wf.Evaluate(MatType(coordinates.col(1))); +} + +template +typename MatType::elem_type RosenbrockWoodFunction< + MatType, LabelsType>::Evaluate(const MatType& coordinates) const +{ + return Evaluate(coordinates, 0, NumFunctions()); +} + +template +template +inline void RosenbrockWoodFunction::Gradient( + const MatType& coordinates, + const size_t /* begin */, + GradType& gradient, + const size_t /* batchSize */) const +{ + gradient.set_size(4, 2); + + typedef typename ForwardMatColType::ColType ColType; + ColType grf(4); + ColType gwf(4); + + rf.Gradient(MatType(coordinates.col(0)), grf); + wf.Gradient(MatType(coordinates.col(1)), gwf); + + gradient.col(0) = grf; + gradient.col(1) = gwf; +} + +template +template +inline void RosenbrockWoodFunction::Gradient( + const MatType& coordinates, + GradType& gradient) const +{ + Gradient(coordinates, 0, gradient, 1); +} + +} // namespace test +} // namespace ens + +#endif diff --git a/include/ensmallen_bits/problems/sgd_test_function.hpp b/include/ensmallen_bits/problems/sgd_test_function.hpp index 02babc182..00c1a6889 100644 --- a/include/ensmallen_bits/problems/sgd_test_function.hpp +++ b/include/ensmallen_bits/problems/sgd_test_function.hpp @@ -19,10 +19,12 @@ namespace test { //! functions. The gradient is not very steep far away from the optimum, so a //! larger step size may be required to optimize it in a reasonable number of //! iterations. +template< + typename LabelsType = arma::Row> class SGDTestFunction { private: - arma::Col visitationOrder; + LabelsType visitationOrder; public: //! Initialize the SGDTestFunction. diff --git a/include/ensmallen_bits/problems/sgd_test_function_impl.hpp b/include/ensmallen_bits/problems/sgd_test_function_impl.hpp index ac5e3d872..29ea46a37 100644 --- a/include/ensmallen_bits/problems/sgd_test_function_impl.hpp +++ b/include/ensmallen_bits/problems/sgd_test_function_impl.hpp @@ -19,19 +19,22 @@ namespace ens { namespace test { -inline SGDTestFunction::SGDTestFunction() : - visitationOrder(arma::linspace>(0, NumFunctions() - 1, +template +SGDTestFunction::SGDTestFunction() : + visitationOrder(linspace(0, NumFunctions() - 1, NumFunctions())) { } -inline void SGDTestFunction::Shuffle() +template +void SGDTestFunction::Shuffle() { - visitationOrder = arma::shuffle(arma::linspace >(0, + visitationOrder = shuffle(linspace(0, (NumFunctions() - 1), NumFunctions())); } +template template -typename MatType::elem_type SGDTestFunction::Evaluate( +typename MatType::elem_type SGDTestFunction::Evaluate( const MatType& coordinates, const size_t begin, const size_t batchSize) const @@ -60,11 +63,13 @@ typename MatType::elem_type SGDTestFunction::Evaluate( return objective; } +template template -void SGDTestFunction::Gradient(const MatType& coordinates, - const size_t begin, - GradType& gradient, - const size_t batchSize) const +void SGDTestFunction::Gradient( + const MatType& coordinates, + const size_t begin, + GradType& gradient, + const size_t batchSize) const { gradient.zeros(3); diff --git a/include/ensmallen_bits/problems/sphere_function.hpp b/include/ensmallen_bits/problems/sphere_function.hpp index a5039e86f..8071c38e6 100644 --- a/include/ensmallen_bits/problems/sphere_function.hpp +++ b/include/ensmallen_bits/problems/sphere_function.hpp @@ -37,6 +37,8 @@ namespace test { * } * @endcode */ +template< + typename PointMatType = arma::mat, typename LabelsType = arma::Row> class SphereFunction { public: @@ -108,14 +110,16 @@ class SphereFunction template MatType GetInitialPoint() const { - return arma::conv_to::from(initialPoint); + return conv_to::from(initialPoint); } //! Get the final point. template MatType GetFinalPoint() const { - return arma::zeros(initialPoint.n_rows, initialPoint.n_cols); + MatType finalPoint(initialPoint.n_rows, initialPoint.n_cols); + finalPoint.zeros(); + return finalPoint; } //! Get the final objective. @@ -126,10 +130,10 @@ class SphereFunction size_t n; //! For shuffling. - arma::Row visitationOrder; + LabelsType visitationOrder; //! Initial starting point. - arma::mat initialPoint; + PointMatType initialPoint; }; } // namespace test diff --git a/include/ensmallen_bits/problems/sphere_function_impl.hpp b/include/ensmallen_bits/problems/sphere_function_impl.hpp index c83a2b0cf..cdbb3a447 100644 --- a/include/ensmallen_bits/problems/sphere_function_impl.hpp +++ b/include/ensmallen_bits/problems/sphere_function_impl.hpp @@ -18,9 +18,10 @@ namespace ens { namespace test { -inline SphereFunction::SphereFunction(const size_t n) : +template +SphereFunction::SphereFunction(const size_t n) : n(n), - visitationOrder(arma::linspace >(0, n - 1, n)) + visitationOrder(linspace(0, n - 1, n)) { initialPoint.set_size(n, 1); @@ -33,14 +34,15 @@ inline SphereFunction::SphereFunction(const size_t n) : } } -inline void SphereFunction::Shuffle() +template +void SphereFunction::Shuffle() { - visitationOrder = arma::shuffle( - arma::linspace >(0, n - 1, n)); + visitationOrder = shuffle(linspace(0, n - 1, n)); } +template template -typename MatType::elem_type SphereFunction::Evaluate( +typename MatType::elem_type SphereFunction::Evaluate( const MatType& coordinates, const size_t begin, const size_t batchSize) const @@ -49,24 +51,27 @@ typename MatType::elem_type SphereFunction::Evaluate( for (size_t j = begin; j < begin + batchSize; ++j) { const size_t p = visitationOrder[j]; - objective += std::pow(coordinates(p), 2); + objective += pow(coordinates(p), 2); } return objective; } +template template -typename MatType::elem_type SphereFunction::Evaluate( +typename MatType::elem_type SphereFunction::Evaluate( const MatType& coordinates) const { return Evaluate(coordinates, 0, NumFunctions()); } +template template -void SphereFunction::Gradient(const MatType& coordinates, - const size_t begin, - GradType& gradient, - const size_t batchSize) const +void SphereFunction::Gradient( + const MatType& coordinates, + const size_t begin, + GradType& gradient, + const size_t batchSize) const { gradient.zeros(n, 1); @@ -77,9 +82,10 @@ void SphereFunction::Gradient(const MatType& coordinates, } } +template template -void SphereFunction::Gradient(const MatType& coordinates, - GradType& gradient) +void SphereFunction::Gradient( + const MatType& coordinates, GradType& gradient) { Gradient(coordinates, 0, gradient, NumFunctions()); } diff --git a/include/ensmallen_bits/problems/styblinski_tang_function.hpp b/include/ensmallen_bits/problems/styblinski_tang_function.hpp index 0009a3a2d..8ab2db48c 100644 --- a/include/ensmallen_bits/problems/styblinski_tang_function.hpp +++ b/include/ensmallen_bits/problems/styblinski_tang_function.hpp @@ -38,6 +38,8 @@ namespace test { * } * @endcode */ +template< + typename PointMatType = arma::mat, typename LabelsType = arma::Row> class StyblinskiTangFunction { public: @@ -109,7 +111,7 @@ class StyblinskiTangFunction template MatType GetInitialPoint() const { - return arma::conv_to::from(initialPoint); + return conv_to::from(initialPoint); } //! Get the final point. @@ -130,10 +132,10 @@ class StyblinskiTangFunction size_t n; //! For shuffling. - arma::Row visitationOrder; + LabelsType visitationOrder; //! Initial starting point. - arma::mat initialPoint; + PointMatType initialPoint; }; } // namespace test diff --git a/include/ensmallen_bits/problems/styblinski_tang_function_impl.hpp b/include/ensmallen_bits/problems/styblinski_tang_function_impl.hpp index 671de3549..7c590b450 100644 --- a/include/ensmallen_bits/problems/styblinski_tang_function_impl.hpp +++ b/include/ensmallen_bits/problems/styblinski_tang_function_impl.hpp @@ -18,23 +18,27 @@ namespace ens { namespace test { -inline StyblinskiTangFunction::StyblinskiTangFunction(const size_t n) : +template +StyblinskiTangFunction::StyblinskiTangFunction( + const size_t n) : n(n), - visitationOrder(arma::linspace >(0, n - 1, n)) + visitationOrder(linspace(0, n - 1, n)) { initialPoint.set_size(n, 1); initialPoint.fill(-5); } -inline void StyblinskiTangFunction::Shuffle() +template +void StyblinskiTangFunction::Shuffle() { - visitationOrder = arma::shuffle( - arma::linspace >(0, n - 1, n)); + visitationOrder = shuffle(linspace(0, n - 1, n)); } +template template -typename MatType::elem_type StyblinskiTangFunction::Evaluate( +typename MatType::elem_type StyblinskiTangFunction< + PointMatType, LabelsType>::Evaluate( const MatType& coordinates, const size_t begin, const size_t batchSize) const @@ -51,18 +55,21 @@ typename MatType::elem_type StyblinskiTangFunction::Evaluate( return objective; } +template template -typename MatType::elem_type StyblinskiTangFunction::Evaluate( +typename MatType::elem_type StyblinskiTangFunction::Evaluate( const MatType& coordinates) const { return Evaluate(coordinates, 0, NumFunctions()); } +template template -void StyblinskiTangFunction::Gradient(const MatType& coordinates, - const size_t begin, - GradType& gradient, - const size_t batchSize) const +void StyblinskiTangFunction::Gradient( + const MatType& coordinates, + const size_t begin, + GradType& gradient, + const size_t batchSize) const { gradient.zeros(n, 1); @@ -74,9 +81,10 @@ void StyblinskiTangFunction::Gradient(const MatType& coordinates, } } +template template -void StyblinskiTangFunction::Gradient(const MatType& coordinates, - GradType& gradient) +void StyblinskiTangFunction::Gradient( + const MatType& coordinates, GradType& gradient) { Gradient(coordinates, 0, gradient, NumFunctions()); } diff --git a/include/ensmallen_bits/qhadam/qhadam.hpp b/include/ensmallen_bits/qhadam/qhadam.hpp index e29d4f25d..92113b120 100644 --- a/include/ensmallen_bits/qhadam/qhadam.hpp +++ b/include/ensmallen_bits/qhadam/qhadam.hpp @@ -100,8 +100,8 @@ class QHAdam typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks) diff --git a/include/ensmallen_bits/qhadam/qhadam_update.hpp b/include/ensmallen_bits/qhadam/qhadam_update.hpp index f408377b6..90aaea026 100644 --- a/include/ensmallen_bits/qhadam/qhadam_update.hpp +++ b/include/ensmallen_bits/qhadam/qhadam_update.hpp @@ -140,7 +140,7 @@ class QHAdamUpdate // QHAdam recovers Adam when v2 = v1 = 1. iterate -= stepSize * ((((1 - parent.v1) * gradient) + parent.v1 * mDash) / - (arma::sqrt(((1 - parent.v2) * (gradient % gradient)) + + (sqrt(((1 - parent.v2) * square(gradient)) + parent.v2 * vDash) + parent.epsilon)); } diff --git a/include/ensmallen_bits/rmsprop/rmsprop.hpp b/include/ensmallen_bits/rmsprop/rmsprop.hpp index 9c3607af6..5c14118f1 100644 --- a/include/ensmallen_bits/rmsprop/rmsprop.hpp +++ b/include/ensmallen_bits/rmsprop/rmsprop.hpp @@ -109,8 +109,8 @@ class RMSProp typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks) diff --git a/include/ensmallen_bits/rmsprop/rmsprop_update.hpp b/include/ensmallen_bits/rmsprop/rmsprop_update.hpp index c8507ba39..f996c2b2e 100644 --- a/include/ensmallen_bits/rmsprop/rmsprop_update.hpp +++ b/include/ensmallen_bits/rmsprop/rmsprop_update.hpp @@ -104,7 +104,7 @@ class RMSPropUpdate { meanSquaredGradient *= parent.alpha; meanSquaredGradient += (1 - parent.alpha) * (gradient % gradient); - iterate -= stepSize * gradient / (arma::sqrt(meanSquaredGradient) + + iterate -= stepSize * gradient / (sqrt(meanSquaredGradient) + parent.epsilon); } diff --git a/include/ensmallen_bits/sarah/sarah.hpp b/include/ensmallen_bits/sarah/sarah.hpp index 074f462d7..8e58203ab 100644 --- a/include/ensmallen_bits/sarah/sarah.hpp +++ b/include/ensmallen_bits/sarah/sarah.hpp @@ -97,8 +97,8 @@ class SARAHType typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks); diff --git a/include/ensmallen_bits/sarah/sarah_impl.hpp b/include/ensmallen_bits/sarah/sarah_impl.hpp index 3b001cd3f..8b740fc35 100644 --- a/include/ensmallen_bits/sarah/sarah_impl.hpp +++ b/include/ensmallen_bits/sarah/sarah_impl.hpp @@ -45,7 +45,8 @@ template -typename std::enable_if::value, +typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type SARAHType::Optimize( SeparableFunctionType& functionIn, @@ -153,7 +154,7 @@ SARAHType::Optimize( // Update iterate with full gradient (v). iterate -= stepSize * v; - const ElemType vNorm = arma::norm(v); + const ElemType vNorm = norm(v); for (size_t f = 0, currentFunction = 0; f < innerIterations; /* incrementing done manually */) diff --git a/include/ensmallen_bits/sarah/sarah_plus_update.hpp b/include/ensmallen_bits/sarah/sarah_plus_update.hpp index 2ddf64aba..869b49fef 100644 --- a/include/ensmallen_bits/sarah/sarah_plus_update.hpp +++ b/include/ensmallen_bits/sarah/sarah_plus_update.hpp @@ -55,7 +55,7 @@ class SARAHPlusUpdate v += (gradient - gradient0) / (double) batchSize; iterate -= stepSize * v; - if (arma::norm(v) <= gamma * vNorm) + if (norm(v) <= gamma * vNorm) return true; return false; diff --git a/include/ensmallen_bits/sgd/sgd.hpp b/include/ensmallen_bits/sgd/sgd.hpp index 3b8a92a7d..02eb0d88f 100644 --- a/include/ensmallen_bits/sgd/sgd.hpp +++ b/include/ensmallen_bits/sgd/sgd.hpp @@ -124,8 +124,8 @@ class SGD typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks); diff --git a/include/ensmallen_bits/sgd/sgd_impl.hpp b/include/ensmallen_bits/sgd/sgd_impl.hpp index d34115b63..ae591c1b8 100644 --- a/include/ensmallen_bits/sgd/sgd_impl.hpp +++ b/include/ensmallen_bits/sgd/sgd_impl.hpp @@ -58,7 +58,8 @@ template -typename std::enable_if::value, +typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type SGD::Optimize( SeparableFunctionType& function, diff --git a/include/ensmallen_bits/sgd/update_policies/momentum_update.hpp b/include/ensmallen_bits/sgd/update_policies/momentum_update.hpp index 5c19e6377..e9a3f9512 100644 --- a/include/ensmallen_bits/sgd/update_policies/momentum_update.hpp +++ b/include/ensmallen_bits/sgd/update_policies/momentum_update.hpp @@ -93,10 +93,10 @@ class MomentumUpdate * @param cols Number of columns in the gradient matrix. */ Policy(const MomentumUpdate& parent, const size_t rows, const size_t cols) : - parent(parent), - velocity(arma::zeros(rows, cols)) + parent(parent) { - // Nothing to do. + velocity.set_size(rows, cols); + velocity.zeros(); } /** diff --git a/include/ensmallen_bits/sgd/update_policies/nesterov_momentum_update.hpp b/include/ensmallen_bits/sgd/update_policies/nesterov_momentum_update.hpp index 540cb55f5..46d842d05 100644 --- a/include/ensmallen_bits/sgd/update_policies/nesterov_momentum_update.hpp +++ b/include/ensmallen_bits/sgd/update_policies/nesterov_momentum_update.hpp @@ -69,10 +69,10 @@ class NesterovMomentumUpdate Policy(const NesterovMomentumUpdate& parent, const size_t rows, const size_t cols) : - parent(parent), - velocity(arma::zeros(rows, cols)) + parent(parent) { - // Nothing to do. + velocity.set_size(rows, cols); + velocity.zeros(); } /** @@ -90,7 +90,6 @@ class NesterovMomentumUpdate const GradType& gradient) { velocity = parent.momentum * velocity - stepSize * gradient; - iterate += parent.momentum * velocity - stepSize * gradient; } diff --git a/include/ensmallen_bits/sgdr/sgdr.hpp b/include/ensmallen_bits/sgdr/sgdr.hpp index de2f6c2b2..a5f8cc764 100644 --- a/include/ensmallen_bits/sgdr/sgdr.hpp +++ b/include/ensmallen_bits/sgdr/sgdr.hpp @@ -103,8 +103,8 @@ class SGDR typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks); diff --git a/include/ensmallen_bits/sgdr/sgdr_impl.hpp b/include/ensmallen_bits/sgdr/sgdr_impl.hpp index defbad8c3..942710ce2 100644 --- a/include/ensmallen_bits/sgdr/sgdr_impl.hpp +++ b/include/ensmallen_bits/sgdr/sgdr_impl.hpp @@ -49,7 +49,8 @@ SGDR::SGDR( template template -typename std::enable_if::value, +typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type SGDR::Optimize( SeparableFunctionType& function, diff --git a/include/ensmallen_bits/sgdr/snapshot_sgdr.hpp b/include/ensmallen_bits/sgdr/snapshot_sgdr.hpp index 018758494..2413d23b5 100644 --- a/include/ensmallen_bits/sgdr/snapshot_sgdr.hpp +++ b/include/ensmallen_bits/sgdr/snapshot_sgdr.hpp @@ -120,8 +120,8 @@ class SnapshotSGDR typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks); diff --git a/include/ensmallen_bits/sgdr/snapshot_sgdr_impl.hpp b/include/ensmallen_bits/sgdr/snapshot_sgdr_impl.hpp index 38f39c169..b71ec5572 100644 --- a/include/ensmallen_bits/sgdr/snapshot_sgdr_impl.hpp +++ b/include/ensmallen_bits/sgdr/snapshot_sgdr_impl.hpp @@ -57,7 +57,8 @@ template -typename std::enable_if::value, +typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type SnapshotSGDR::Optimize( SeparableFunctionType& function, diff --git a/include/ensmallen_bits/smorms3/smorms3.hpp b/include/ensmallen_bits/smorms3/smorms3.hpp index e45f5edc9..2edbdf76e 100644 --- a/include/ensmallen_bits/smorms3/smorms3.hpp +++ b/include/ensmallen_bits/smorms3/smorms3.hpp @@ -92,8 +92,8 @@ class SMORMS3 typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks) diff --git a/include/ensmallen_bits/smorms3/smorms3_update.hpp b/include/ensmallen_bits/smorms3/smorms3_update.hpp index 98f49b643..18d333bf8 100644 --- a/include/ensmallen_bits/smorms3/smorms3_update.hpp +++ b/include/ensmallen_bits/smorms3/smorms3_update.hpp @@ -85,6 +85,12 @@ class SMORMS3Update const double stepSize, const GradType& gradient) { + if (lr.is_empty() || lr(0) != stepSize) + { + lr.set_size(gradient.n_rows, gradient.n_cols); + lr.fill(stepSize); + } + // Update the iterate. MatType r = 1 / (mem + 1); @@ -94,26 +100,24 @@ class SMORMS3Update g2 = (1 - r) % g2; g2 += r % (gradient % gradient); - MatType x = (g % g) / (g2 + parent.epsilon); - - x.transform( [stepSize](typename MatType::elem_type &v) - { return std::min(v, (typename MatType::elem_type) stepSize); } ); - - iterate -= gradient % x / (arma::sqrt(g2) + parent.epsilon); + MatType x = min((g % g) / (g2 + parent.epsilon), lr); + iterate -= gradient % x / (sqrt(g2) + parent.epsilon); mem %= (1 - x); mem += 1; } private: - // Instantiated parent object. + //! Instantiated parent object. SMORMS3Update& parent; - // Memory parameter. + //! Memory parameter. MatType mem; - // Gradient estimate parameter. + //! Gradient estimate parameter. GradType g; - // Squared gradient estimate parameter. + //! Squared gradient estimate parameter. GradType g2; + //! Current learning rate matrix. + MatType lr; }; private: diff --git a/include/ensmallen_bits/spalera_sgd/spalera_sgd.hpp b/include/ensmallen_bits/spalera_sgd/spalera_sgd.hpp index fad6f009b..af5bdb9c7 100644 --- a/include/ensmallen_bits/spalera_sgd/spalera_sgd.hpp +++ b/include/ensmallen_bits/spalera_sgd/spalera_sgd.hpp @@ -135,8 +135,8 @@ class SPALeRASGD typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks); diff --git a/include/ensmallen_bits/spalera_sgd/spalera_sgd_impl.hpp b/include/ensmallen_bits/spalera_sgd/spalera_sgd_impl.hpp index e0cac7de1..993a1358e 100644 --- a/include/ensmallen_bits/spalera_sgd/spalera_sgd_impl.hpp +++ b/include/ensmallen_bits/spalera_sgd/spalera_sgd_impl.hpp @@ -58,7 +58,8 @@ template -typename std::enable_if::value, +typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type SPALeRASGD::Optimize( SeparableFunctionType& function, diff --git a/include/ensmallen_bits/spalera_sgd/spalera_stepsize.hpp b/include/ensmallen_bits/spalera_sgd/spalera_stepsize.hpp index 7b8e7ace8..1d04f4a98 100644 --- a/include/ensmallen_bits/spalera_sgd/spalera_stepsize.hpp +++ b/include/ensmallen_bits/spalera_sgd/spalera_stepsize.hpp @@ -172,7 +172,9 @@ class SPALeRAStepsize // Faster. learningRates /= 2; - if (arma::any(arma::vectorise(learningRates) <= 1e-15)) + //if (any(vectorise(learningRates) <= 1e-15)) + /* if (min(vectorise(learningRates)) <= 1e-15) */ + if (learningRates.min() <= 1e-15) { // Stop because learning rate too low. return false; @@ -191,13 +193,13 @@ class SPALeRAStepsize std::sqrt(iterate.n_elem); const typename MatType::elem_type normGradient = - std::sqrt(arma::accu(arma::pow(gradient, 2))); + sqrt(accu(square(gradient))); relaxedSums *= (1 - parent.alpha); if (normGradient > parent.epsilon) relaxedSums += gradient * (parent.alpha / normGradient); - learningRates %= arma::exp((arma::pow(relaxedSums, 2) - paramMean) * + learningRates %= exp((square(relaxedSums) - paramMean) * (parent.adaptRate / paramStd)); previousIterate = iterate; diff --git a/include/ensmallen_bits/spsa/spsa_impl.hpp b/include/ensmallen_bits/spsa/spsa_impl.hpp index 4cb010229..452f43df2 100644 --- a/include/ensmallen_bits/spsa/spsa_impl.hpp +++ b/include/ensmallen_bits/spsa/spsa_impl.hpp @@ -43,9 +43,10 @@ typename MatType::elem_type SPSA::Optimize(ArbitraryFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks) { - // Convenience typedefs. + // Convenience typedefs. typedef typename MatType::elem_type ElemType; typedef typename MatTypeTraits::BaseMatType BaseMatType; + typedef typename ForwardMatType::MatType ProxyMatType; // Make sure that we have the methods that we need. traits::CheckArbitraryFunctionTypeAPI(); BaseMatType gradient(iterate.n_rows, iterate.n_cols); - arma::Mat spVector(iterate.n_rows, iterate.n_cols); + ProxyMatType spVector(iterate.n_rows, iterate.n_cols); // To keep track of where we are and how things are going. ElemType overallObjective = 0; @@ -94,8 +95,7 @@ typename MatType::elem_type SPSA::Optimize(ArbitraryFunctionType& function, const double ck = evaluationStepSize / std::pow(k + 1, gamma); // Choose stochastic directions. - spVector = arma::conv_to>::from( - arma::randi(iterate.n_rows, iterate.n_cols, + spVector = conv_to::from(randi(iterate.n_rows, iterate.n_cols, arma::distr_param(0, 1))) * 2 - 1; iterate += ck * spVector; diff --git a/include/ensmallen_bits/svrg/barzilai_borwein_decay.hpp b/include/ensmallen_bits/svrg/barzilai_borwein_decay.hpp index 49c437e18..0d48b488d 100644 --- a/include/ensmallen_bits/svrg/barzilai_borwein_decay.hpp +++ b/include/ensmallen_bits/svrg/barzilai_borwein_decay.hpp @@ -96,8 +96,8 @@ class BarzilaiBorweinDecay if (!fullGradient0.is_empty()) { // Step size selection based on Barzilai-Borwein (BB). - stepSize = std::pow(arma::norm(iterate - iterate0), 2.0) / - (arma::dot(iterate - iterate0, fullGradient - fullGradient0) + + stepSize = std::pow(norm(iterate - iterate0), 2.0) / + (dot(iterate - iterate0, fullGradient - fullGradient0) + parent.epsilon) / (double) numBatches; stepSize = std::min(stepSize, parent.maxStepSize); diff --git a/include/ensmallen_bits/svrg/svrg.hpp b/include/ensmallen_bits/svrg/svrg.hpp index 0c121c7bf..d81292f82 100644 --- a/include/ensmallen_bits/svrg/svrg.hpp +++ b/include/ensmallen_bits/svrg/svrg.hpp @@ -143,8 +143,8 @@ class SVRGType typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks); diff --git a/include/ensmallen_bits/svrg/svrg_impl.hpp b/include/ensmallen_bits/svrg/svrg_impl.hpp index 032bfd438..b06adb750 100644 --- a/include/ensmallen_bits/svrg/svrg_impl.hpp +++ b/include/ensmallen_bits/svrg/svrg_impl.hpp @@ -55,7 +55,7 @@ template -typename std::enable_if::value, +typename std::enable_if::value || IsCootType::value, typename MatType::elem_type>::type SVRGType::Optimize( SeparableFunctionType& functionIn, diff --git a/include/ensmallen_bits/swats/swats.hpp b/include/ensmallen_bits/swats/swats.hpp index 1230d1987..b2c1df202 100644 --- a/include/ensmallen_bits/swats/swats.hpp +++ b/include/ensmallen_bits/swats/swats.hpp @@ -98,8 +98,8 @@ class SWATS typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks) diff --git a/include/ensmallen_bits/swats/swats_update.hpp b/include/ensmallen_bits/swats/swats_update.hpp index 0a80a77ee..36b042c95 100644 --- a/include/ensmallen_bits/swats/swats_update.hpp +++ b/include/ensmallen_bits/swats/swats_update.hpp @@ -149,13 +149,13 @@ class SWATSUpdate const double biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration); GradType delta = stepSize * m / biasCorrection1 / - (arma::sqrt(v / biasCorrection2) + parent.epsilon); + (sqrt(v / biasCorrection2) + parent.epsilon); iterate -= delta; - const double deltaGradient = arma::dot(delta, gradient); + const double deltaGradient = dot(delta, gradient); if (deltaGradient != 0) { - const double rate = arma::dot(delta, delta) / deltaGradient; + const double rate = dot(delta, delta) / deltaGradient; parent.sgdLambda = parent.beta2 * parent.sgdLambda + (1 - parent.beta2) * rate; parent.sgdRate = parent.sgdLambda / biasCorrection2; diff --git a/include/ensmallen_bits/utility/coot_traits.hpp b/include/ensmallen_bits/utility/coot_traits.hpp new file mode 100644 index 000000000..ec6cb1236 --- /dev/null +++ b/include/ensmallen_bits/utility/coot_traits.hpp @@ -0,0 +1,94 @@ +/** + * @file arma_traits.hpp + * @author Ryan Curtin + * @author Marcus Edel + * + * Some traits used for template metaprogramming (SFINAE) with Bandicoot types. + * + * ensmallen 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 ensmallen. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ +#ifndef ENSMALLEN_UTILITY_COOT_TRAITS_HPP +#define ENSMALLEN_UTILITY_COOT_TRAITS_HPP + +namespace ens { + +// Structs have public members by default (that's why they are chosen over +// classes). + +/** + * If value == true, then MatType is some sort of Bandicoot vector or subview. + * You might use this struct like this: + * + * @code + * // Only accepts VecTypes that are actually Bandicoot vector types. + * template + * void Function(const MatType& argumentA, + * typename std::enable_if_t::value>* = 0); + * @endcode + * + * The use of the enable_if_t object allows the compiler to instantiate + * Function() only if VecType is one of the Bandicoot vector types. It has a + * default argument because it isn't meant to be used in either the function + * call or the function body. + */ +template +struct IsCootType +{ + const static bool value = false; +}; + +#ifdef USE_COOT + +// Commenting out the first template per case, because +// Visual Studio doesn't like this instantiaion pattern (error C2910). +// template<> +template +struct IsCootType > +{ + const static bool value = true; +}; + +// template<> +template +struct IsCootType > +{ + const static bool value = true; +}; + +// template<> +template +struct IsCootType > +{ + const static bool value = true; +}; + +// template<> +template +struct IsCootType > +{ + const static bool value = true; +}; + +// template<> +template +struct IsCootType > +{ + const static bool value = true; +}; + +// template<> +template +struct IsCootType > +{ + const static bool value = true; +}; + +#endif + + +} // namespace ens + +#endif diff --git a/include/ensmallen_bits/utility/indicators/epsilon.hpp b/include/ensmallen_bits/utility/indicators/epsilon.hpp index d33236d73..c4575d63f 100644 --- a/include/ensmallen_bits/utility/indicators/epsilon.hpp +++ b/include/ensmallen_bits/utility/indicators/epsilon.hpp @@ -3,9 +3,8 @@ * @author Rahul Ganesh Prabhu * @author Nanubala Gnana Sai * - * Epsilon indicator - * A binary quality indicator that is capable of detecting whether one - * approximation set is better than another. + * Epsilon indicator: A binary quality indicator that is capable of detecting + * whether one approximation set is better than another. * * ensmallen 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 @@ -19,12 +18,12 @@ namespace ens { /** - * The epsilon indicator is one of the binary quality indicators that was proposed by - * Zitzler et. al.. The indicator originally calculates a weak dominance relation - * between two approximation sets. It returns "epsilon" which is the factor by which - * the given approximation set is worse than the reference front with respect to - * all the objectives. - * + * The epsilon indicator is one of the binary quality indicators that was + * proposed by Zitzler et. al.. The indicator originally calculates a weak + * dominance relation between two approximation sets. It returns "epsilon" which + * is the factor by which the given approximation set is worse than the + * reference front with respect to all the objectives. + * * \f[ I_{\epsilon}(A,B) = \max_{z^2 \in B} \ * \min_{z^1 \in A} \ * \max_{1 \leq i \leq n} \ \frac{z^1_i}{z^2_i}\ @@ -43,49 +42,53 @@ namespace ens { * } * @endcode */ - class Epsilon +class Epsilon +{ + public: + /** + * Default constructor does nothing, but is required to satisfy the Indicator + * policy. + */ + Epsilon() { } + + /** + * Find the epsilon value of the front with respect to the given reference + * front. + * + * @tparam CubeType The cube data type of front. + * @param front The given approximation front. + * @param referenceFront The given reference front. + * @return The epsilon value of the front. + */ + template + static typename CubeType::elem_type Evaluate(const CubeType& front, + const CubeType& referenceFront) { - public: - /** - * Default constructor does nothing, but is required to satisfy the Indicator - * policy. - */ - Epsilon() { } + // Convenience typedefs. + typedef typename CubeType::elem_type ElemType; + ElemType eps = 0; - /** - * Find the epsilon value of the front with respect to the given reference - * front. - * - * @tparam CubeType The cube data type of front. - * @param front The given approximation front. - * @param referenceFront The given reference front. - * @return The epsilon value of the front. - */ - template - static typename CubeType::elem_type Evaluate(const CubeType& front, - const CubeType& referenceFront) + for (size_t i = 0; i < referenceFront.n_slices; ++i) { - // Convenience typedefs. - typedef typename CubeType::elem_type ElemType; - ElemType eps = 0; - for (size_t i = 0; i < referenceFront.n_slices; i++) + ElemType epsjMin = std::numeric_limits::max(); + for (size_t j = 0; j < front.n_slices; ++j) { - ElemType epsjMin = std::numeric_limits::max(); - for (size_t j = 0; j < front.n_slices; j++) - { - arma::Mat frontRatio = front.slice(j) / referenceFront.slice(i); - frontRatio.replace(arma::datum::inf, -1.); // Handle zero division case. - ElemType epsj = frontRatio.max(); - if (epsj < epsjMin) - epsjMin = epsj; - } - if (epsjMin > eps) - eps = epsjMin; - } + arma::Mat frontRatio = front.slice(j) / + referenceFront.slice(i); + // Handle zero division case. + frontRatio.replace(arma::datum::inf, -1.0); + ElemType epsj = frontRatio.max(); - return eps; + if (epsj < epsjMin) + epsjMin = epsj; + } + if (epsjMin > eps) + eps = epsjMin; } - }; + + return eps; + } +}; } // namespace ens diff --git a/include/ensmallen_bits/utility/indicators/igd_plus.hpp b/include/ensmallen_bits/utility/indicators/igd_plus.hpp index d8f674eeb..06fe90d30 100644 --- a/include/ensmallen_bits/utility/indicators/igd_plus.hpp +++ b/include/ensmallen_bits/utility/indicators/igd_plus.hpp @@ -18,10 +18,10 @@ namespace ens { /** - * The IGD indicator returns the average distance from each point in the reference - * front to the nearest point to it's solution. IGD+ is an improvement upon - * the IGD indicator, which fixes misleading results given by IGD in certain - * cases via a different distance metric: + * The IGD indicator returns the average distance from each point in the + * reference front to the nearest point to it's solution. IGD+ is an improvement + * upon the IGD indicator, which fixes misleading results given by IGD in + * certain cases via a different distance metric: * * \f[ d^{+}(z,a) = \sqrt{\sum_{i = 1}^{n}( \max\{a_i - z_i, 0\})^2 \ } \ * \f] @@ -39,56 +39,60 @@ namespace ens { * } * @endcode */ - class IGDPlus +class IGDPlus +{ + public: + /** + * Default constructor does nothing, but is required to satisfy the + * Indicator policy. + */ + IGDPlus() { - public: - /** - * Default constructor does nothing, but is required to satisfy the Indicator - * policy. - */ - IGDPlus() { } + // Nothing to do. + } - /** - * Find the IGD+ value of the front with respect to the given reference - * front. - * - * @tparam CubeType The cube data type of front. - * @param front The given approximation front. - * @param referenceFront The given reference front. - * @return The IGD value of the front. - */ - template - static typename CubeType::elem_type Evaluate(const CubeType& front, - const CubeType& referenceFront) + /** + * Find the IGD+ value of the front with respect to the given reference front. + * + * @tparam CubeType The cube data type of front. + * @param front The given approximation front. + * @param referenceFront The given reference front. + * @return The IGD value of the front. + */ + template + static typename CubeType::elem_type Evaluate(const CubeType& front, + const CubeType& referenceFront) + { + // Convenience typedefs. + typedef typename CubeType::elem_type ElemType; + + ElemType igd = 0; + for (size_t i = 0; i < referenceFront.n_slices; ++i) { - // Convenience typedefs. - typedef typename CubeType::elem_type ElemType; - ElemType igd = 0; - for (size_t i = 0; i < referenceFront.n_slices; i++) + ElemType min = std::numeric_limits::max(); + for (size_t j = 0; j < front.n_slices; ++j) { - ElemType min = std::numeric_limits::max(); - for (size_t j = 0; j < front.n_slices; j++) + ElemType dist = 0; + for (size_t k = 0; k < front.slice(j).n_rows; ++k) { - ElemType dist = 0; - for (size_t k = 0; k < front.slice(j).n_rows; k++) - { - ElemType z = referenceFront(k, 0, i); - ElemType a = front(k, 0, j); - // Assuming minimization of all objectives. - dist += std::pow(std::max(a - z, 0), 2); - } - dist = std::sqrt(dist); - if (dist < min) - min = dist; + ElemType z = referenceFront(k, 0, i); + ElemType a = front(k, 0, j); + // Assuming minimization of all objectives. + dist += std::pow(std::max(a - z, 0), 2); } - igd += min; - } - igd /= referenceFront.n_slices; - return igd; + dist = std::sqrt(dist); + if (dist < min) + min = dist; + } + igd += min; } - }; + igd /= referenceFront.n_slices; + + return igd; + } +}; } // namespace ens -#endif \ No newline at end of file +#endif diff --git a/include/ensmallen_bits/utility/proxies.hpp b/include/ensmallen_bits/utility/proxies.hpp new file mode 100644 index 000000000..b1cdeced9 --- /dev/null +++ b/include/ensmallen_bits/utility/proxies.hpp @@ -0,0 +1,148 @@ +/** + * @file proxies.hpp + * @author Marcus Edel + * + * Simple proxies that based on the data type forwards to `coot` or `arma`. + * + * ensmallen 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 ensmallen. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ +#ifndef ENSMALLEN_UTILITY_PROXIES_HPP +#define ENSMALLEN_UTILITY_PROXIES_HPP + +namespace ens { + +template +typename std::enable_if::value, ElemType>::type +randu(const size_t rows, const size_t cols) +{ + #ifdef USE_COOT + return coot::randu(rows, cols); + #else + return arma::randu(rows, cols); + #endif +} + +template +typename std::enable_if::value, ElemType>::type +randu(const size_t rows, const size_t cols) +{ + return arma::randu(rows, cols); +} + +template +typename std::enable_if::value, ElemType>::type +randn(const size_t rows, const size_t cols) +{ + #ifdef USE_COOT + return coot::randn(rows, cols); + #else + return arma::randn(rows, cols); + #endif +} + +template +typename std::enable_if::value, ElemType>::type +randn(const size_t rows, const size_t cols) +{ + return arma::randn(rows, cols); +} + +template +typename std::enable_if::value, ElemType>::type +randi(const size_t rows, const size_t cols, const arma::distr_param& param) +{ + #ifdef USE_COOT + return coot::randi(rows, cols, + coot::distr_param(param.a_int, param.b_int)); + #else + return arma::randi(rows, cols, param); + #endif +} + +template +typename std::enable_if::value, ElemType>::type +randi(const size_t rows, const size_t cols, const arma::distr_param& param) +{ + return arma::randi(rows, cols, param); +} + +template +inline static typename std::enable_if< + !arma::is_arma_type::value, OutputType>::type +linspace(const double start, const double end, const size_t num = 100u) +{ + #ifdef USE_COOT + return coot::linspace(start, end, num); + #else + return arma::linspace(start, end, num); + #endif +} + +template +inline static typename std::enable_if< + arma::is_arma_type::value, OutputType>::type +linspace(const double start, const double end, const size_t num = 100u) +{ + return arma::linspace(start, end, num); +} + +template +inline static typename std::enable_if< + !arma::is_arma_type::value && + ens::IsCootType::value, InputType>::type +shuffle(const InputType& input) +{ + #ifdef USE_COOT + return coot::shuffle(input); + #else + return arma::shuffle(input); + #endif +} + +/** + * A utility class that based on the data type forwards to `coot::conv_to` or + * `arma::conv_to`. + * + * @tparam OutputType The data type to convert to. + */ +template +class conv_to +{ + public: + /** + * Convert from one matrix type to another by forwarding to `coot::conv_to`. + * + * @param input The input that is converted. + */ + template + inline static typename std::enable_if< + !IsArmaType::value, OutputType>::type + from(const InputType& input) + { + #ifdef USE_COOT + return coot::conv_to::from(input); + #else + return arma::conv_to::from(input); + #endif + } + + /** + * Convert from one matrix type to another by forwarding to `arma::conv_to`. + * + * @param input The input that is converted. + */ + template + inline static typename std::enable_if< + IsArmaType::value, OutputType>::type + from(const InputType& input) + { + return arma::conv_to::from(input); + } +}; + +} // namespace ens + +#endif diff --git a/include/ensmallen_bits/wn_grad/wn_grad.hpp b/include/ensmallen_bits/wn_grad/wn_grad.hpp index 9b31a3fe0..cb3692efa 100644 --- a/include/ensmallen_bits/wn_grad/wn_grad.hpp +++ b/include/ensmallen_bits/wn_grad/wn_grad.hpp @@ -87,8 +87,8 @@ class WNGrad typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks) diff --git a/include/ensmallen_bits/wn_grad/wn_grad_update.hpp b/include/ensmallen_bits/wn_grad/wn_grad_update.hpp index 502058cce..5b904e03e 100644 --- a/include/ensmallen_bits/wn_grad/wn_grad_update.hpp +++ b/include/ensmallen_bits/wn_grad/wn_grad_update.hpp @@ -83,8 +83,8 @@ class WNGradUpdate const double stepSize, const GradType& gradient) { - parent.b += std::pow(stepSize, 2.0) / parent.b * - std::pow(arma::norm(gradient), 2); + parent.b += pow(stepSize, 2.0) / parent.b * + pow(norm(gradient), 2); iterate -= stepSize * gradient / parent.b; } diff --git a/include/ensmallen_bits/yogi/yogi.hpp b/include/ensmallen_bits/yogi/yogi.hpp index 4529d24cd..030893784 100644 --- a/include/ensmallen_bits/yogi/yogi.hpp +++ b/include/ensmallen_bits/yogi/yogi.hpp @@ -100,15 +100,15 @@ class Yogi typename MatType, typename GradType, typename... CallbackTypes> - typename std::enable_if::value, - typename MatType::elem_type>::type + typename std::enable_if::value || + IsCootType::value, typename MatType::elem_type>::type Optimize(SeparableFunctionType& function, MatType& iterate, CallbackTypes&&... callbacks) { - return optimizer.Optimize(function, iterate, - std::forward(callbacks)...); + return optimizer.template Optimize< + SeparableFunctionType, MatType, GradType, CallbackTypes...>( + function, iterate, std::forward(callbacks)...); } //! Forward the MatType as GradType. diff --git a/include/ensmallen_bits/yogi/yogi_update.hpp b/include/ensmallen_bits/yogi/yogi_update.hpp index cdba28d70..c6495faae 100644 --- a/include/ensmallen_bits/yogi/yogi_update.hpp +++ b/include/ensmallen_bits/yogi/yogi_update.hpp @@ -45,8 +45,6 @@ class YogiUpdate * parameter. * @param beta1 The smoothing parameter. * @param beta2 The second moment coefficient. - * @param v1 The first quasi-hyperbolic term. - * @param v1 The second quasi-hyperbolic term. */ YogiUpdate(const double epsilon = 1e-8, const double beta1 = 0.9, @@ -112,11 +110,11 @@ class YogiUpdate m *= parent.beta1; m += (1 - parent.beta1) * gradient; - const MatType gSquared = arma::square(gradient); - v -= (1 - parent.beta2) * arma::sign(v - gSquared) % gSquared; + const MatType gSquared = square(gradient); + v -= (1 - parent.beta2) * sign(v - gSquared) % gSquared; // Now update the iterate. - iterate -= stepSize * m / (arma::sqrt(v) + parent.epsilon); + iterate -= stepSize * m / (sqrt(v) + parent.epsilon); } private: diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 515247ee0..af4255ee8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,58 +1,59 @@ # The tests that need to be compiled. set(ENSMALLEN_TESTS_SOURCES main.cpp - active_cmaes_test.cpp - ada_belief_test.cpp - ada_bound_test.cpp - ada_delta_test.cpp - ada_grad_test.cpp - ada_sqrt_test.cpp - adam_test.cpp - aug_lagrangian_test.cpp - bigbatch_sgd_test.cpp - callbacks_test.cpp - cd_test.cpp - cmaes_test.cpp - cne_test.cpp - de_test.cpp - demon_adam_test.cpp - demon_sgd_test.cpp - eve_test.cpp - frankwolfe_test.cpp - ftml_test.cpp - function_test.cpp - gradient_descent_test.cpp - grid_search_test.cpp - iqn_test.cpp - indicators_test.cpp - katyusha_test.cpp - lbfgs_test.cpp - line_search_test.cpp - lookahead_test.cpp - lrsdp_test.cpp - moead_test.cpp - agemoea_test.cpp - momentum_sgd_test.cpp - nesterov_momentum_sgd_test.cpp - nsga2_test.cpp - parallel_sgd_test.cpp - proximal_test.cpp - pso_test.cpp - quasi_hyperbolic_momentum_sgd_test.cpp - rmsprop_test.cpp - sa_test.cpp - sarah_test.cpp - sdp_primal_dual_test.cpp - sgdr_test.cpp +# coot_test.cpp +# # active_cmaes_test.cpp +# ada_belief_test.cpp +# ada_bound_test.cpp +# ada_delta_test.cpp +# ada_grad_test.cpp +# ada_sqrt_test.cpp +# adam_test.cpp +# # aug_lagrangian_test.cpp +# bigbatch_sgd_test.cpp +# # callbacks_test.cpp +# # cd_test.cpp +# # cmaes_test.cpp +# cne_test.cpp +# de_test.cpp +# demon_adam_test.cpp +# demon_sgd_test.cpp +# eve_test.cpp +# # frankwolfe_test.cpp +# ftml_test.cpp +# # function_test.cpp +# # gradient_descent_test.cpp +# # grid_search_test.cpp +# # iqn_test.cpp +# # indicators_test.cpp +# katyusha_test.cpp +# # lbfgs_test.cpp +# # line_search_test.cpp +# lookahead_test.cpp +# # lrsdp_test.cpp +# # moead_test.cpp +# # agemoea_test.cpp +# momentum_sgd_test.cpp +# nesterov_momentum_sgd_test.cpp +# # nsga2_test.cpp +# # parallel_sgd_test.cpp +# # proximal_test.cpp +# # pso_test.cpp +# quasi_hyperbolic_momentum_sgd_test.cpp +# rmsprop_test.cpp +# # sa_test.cpp +# sarah_test.cpp +# sdp_primal_dual_test.cpp +# sgdr_test.cpp sgd_test.cpp - smorms3_test.cpp - snapshot_ensembles.cpp - spalera_sgd_test.cpp - spsa_test.cpp - svrg_test.cpp - swats_test.cpp - wn_grad_test.cpp - yogi_test.cpp +# smorms3_test.cpp +# snapshot_ensembles.cpp +# # spalera_sgd_test.cpp +# spsa_test.cpp +# svrg_test.cpp +# swats_test.cpp +# wn_grad_test.cpp +# yogi_test.cpp ) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/tests/ada_belief_test.cpp b/tests/ada_belief_test.cpp index 5190bf712..1048b68ba 100644 --- a/tests/ada_belief_test.cpp +++ b/tests/ada_belief_test.cpp @@ -15,57 +15,23 @@ using namespace ens; using namespace ens::test; -/** - * Test the AdaBelief optimizer on the Sphere function. - */ -TEST_CASE("AdaBeliefSphereFunctionTest", "[AdaBeliefTest]") -{ - AdaBelief optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false); - FunctionTest(optimizer, 0.5, 0.1); -} -/** - * Test the AdaBelief optimizer on the Sphere function with arma::fmat. - */ -TEST_CASE("AdaBeliefSphereFunctionTestFMat", "[AdaBeliefTest]") +TEMPLATE_TEST_CASE("AdaBeliefLogisticRegressionTest", "[AdaBelief]", + arma::mat, arma::fmat) { - AdaBelief optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false); - FunctionTest(optimizer, 0.5, 0.1); + AdaBelief adaBelief; + LogisticRegressionFunctionTest>( + adaBelief, 0.003, 0.006, 1); } -/** - * Test the AdaBelief optimizer on the McCormick function. - */ -TEST_CASE("AdaBeliefMcCormickFunctionTest", "[AdaBeliefTest]") -{ - AdaBelief optimizer(0.5, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false); - FunctionTest(optimizer, 0.5, 0.1); -} +#ifdef USE_COOT -/** - * Run AdaBelief on logistic regression and make sure the results are - * acceptable. - */ -TEST_CASE("AdaBeliefLogisticRegressionTest", "[AdaBeliefTest]") +TEMPLATE_TEST_CASE("AdaBeliefLogisticRegressionTest", "[AdaBelief]", + coot::mat, coot::fmat) { - AdaBelief optimizer; - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); -} - -/** - * Run AdaBelief on logistic regression and make sure the results are - * acceptable, using arma::fmat. - */ -TEST_CASE("AdaBeliefLogisticRegressionFMatTest", "[AdaBeliefTest]") -{ - arma::fmat data, testData, shuffledData; - arma::Row responses, testResponses, shuffledResponses; - - LogisticRegressionTestData(data, testData, shuffledData, - responses, testResponses, shuffledResponses); - LogisticRegression lr(shuffledData, shuffledResponses, 0.5); - - AdaBelief optimizer; - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); + AdaBelief adaBelief; + LogisticRegressionFunctionTest>( + adaBelief, 0.003, 0.006, 1); } +#endif diff --git a/tests/ada_bound_test.cpp b/tests/ada_bound_test.cpp index 11c8ca9c8..be34868b4 100644 --- a/tests/ada_bound_test.cpp +++ b/tests/ada_bound_test.cpp @@ -15,44 +15,22 @@ using namespace ens; using namespace ens::test; -/** - * Test the AdaBound optimizer on the Sphere function. - */ -TEST_CASE("AdaBoundSphereFunctionTest", "[AdaBoundTest]") -{ - AdaBound optimizer(0.001, 2, 0.1, 1e-3, 0.9, 0.999, 1e-8, 500000, - 1e-3, false); - FunctionTest(optimizer, 0.5, 0.1); -} - -/** - * Test the AdaBound optimizer on the Sphere function with arma::fmat. - */ -TEST_CASE("AdaBoundSphereFunctionTestFMat", "[AdaBoundTest]") +TEMPLATE_TEST_CASE("AdaBoundSphereFunctionTest", "[AdaBound]", + arma::mat, arma::fmat) { AdaBound optimizer(0.001, 2, 0.1, 1e-3, 0.9, 0.999, 1e-8, 500000, 1e-3, false); - FunctionTest(optimizer, 0.5, 0.1); + FunctionTest>, TestType>( + optimizer, 0.5, 0.1); } -/** - * Test the AMSBound optimizer on the Sphere function. - */ -TEST_CASE("AMSBoundSphereFunctionTest", "[AdaBoundTest]") -{ - AMSBound optimizer(0.001, 2, 0.1, 1e-3, 0.9, 0.999, 1e-8, 500000, - 1e-3, false); - FunctionTest(optimizer, 0.5, 0.1); -} - -/** - * Test the AMSBound optimizer on the Sphere function with arma::fmat. - */ -TEST_CASE("AMSBoundphereFunctionTestFMat", "[AdaBoundTest]") +TEMPLATE_TEST_CASE("AMSBoundSphereFunctionTest", "[AdaBound]", + arma::mat, arma::fmat) { AMSBound optimizer(0.001, 2, 0.1, 1e-3, 0.9, 0.999, 1e-8, 500000, 1e-3, false); - FunctionTest(optimizer, 0.5, 0.1); + FunctionTest>, TestType>( + optimizer, 0.5, 0.1); } /** @@ -62,43 +40,33 @@ TEST_CASE("AdaBoundSphereFunctionTestSpMat", "[AdaBoundTest]") { AdaBound optimizer(0.001, 2, 0.1, 1e-3, 0.9, 0.999, 1e-8, 500000, 1e-3, false); - FunctionTest(optimizer, 0.5, 0.1); + FunctionTest, arma::sp_mat>(optimizer, 0.5, 0.1); } -/** - * Test the AdaBound optimizer on the Sphere function with arma::sp_mat but a - * dense (arma::mat) gradient. - */ -TEST_CASE("AdaBoundSphereFunctionTestSpMatDenseGradient", "[AdaBoundTest]") +TEST_CASE("AdaBoundSphereFunctionTestSpMatDenseGradient", "[AdaBound]") { - SphereFunction f(2); + SphereFunction<> f(2); AdaBound optimizer(0.001, 2, 0.1, 1e-3, 0.9, 0.999, 1e-8, 500000, 1e-3, false); - arma::sp_mat coordinates = f.GetInitialPoint(); + arma::sp_mat coordinates = arma::conv_to::from( + f.GetInitialPoint()); optimizer.Optimize(f, coordinates); REQUIRE(coordinates(0) == Approx(0.0).margin(0.1)); REQUIRE(coordinates(1) == Approx(0.0).margin(0.1)); } -/** - * Test the AMSBound optimizer on the Sphere function with arma::sp_mat. - */ -TEST_CASE("AMSBoundSphereFunctionTestSpMat", "[AdaBoundTest]") +TEST_CASE("AMSBoundSphereFunctionTestSpMat", "[AdaBound]") { AMSBound optimizer(0.001, 2, 0.1, 1e-3, 0.9, 0.999, 1e-8, 500000, 1e-3, false); - FunctionTest(optimizer, 0.5, 0.1); + FunctionTest, arma::sp_mat>(optimizer, 0.5, 0.1); } -/** - * Test the AMSBound optimizer on the Sphere function with arma::sp_mat but a - * dense (arma::mat) gradient. - */ -TEST_CASE("AMSBoundSphereFunctionTestSpMatDenseGradient", "[AdaBoundTest]") +TEST_CASE("AMSBoundSphereFunctionTestSpMatDenseGradient", "[AdaBound]") { - SphereFunction f(2); + SphereFunction<> f(2); AMSBound optimizer(0.001, 2, 0.1, 1e-3, 0.9, 0.999, 1e-8, 500000, 1e-3, false); @@ -108,3 +76,24 @@ TEST_CASE("AMSBoundSphereFunctionTestSpMatDenseGradient", "[AdaBoundTest]") REQUIRE(coordinates(0) == Approx(0.0).margin(0.1)); REQUIRE(coordinates(1) == Approx(0.0).margin(0.1)); } + +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("AdaBoundSphereFunctionTest", "[AdaBound]", + coot::mat, coot::fmat) +{ + AdaBound optimizer(0.001, 2, 0.1, 1e-3, 0.9, 0.999, 1e-8, 500000, + 1e-3, false); + FunctionTest>, TestType>( + optimizer, 0.5, 0.1); +} + +TEMPLATE_TEST_CASE("AMSBoundSphereFunctionTest", "[AdaBound]", + coot::mat, coot::fmat) +{ + AMSBound optimizer(0.001, 2, 0.1, 1e-3, 0.9, 0.999, 1e-8, 500000, + 1e-3, false); + FunctionTest>, TestType>( + optimizer, 0.5, 0.1); +} +#endif diff --git a/tests/ada_delta_test.cpp b/tests/ada_delta_test.cpp index 8c07cce8d..2ff302e4b 100644 --- a/tests/ada_delta_test.cpp +++ b/tests/ada_delta_test.cpp @@ -18,21 +18,22 @@ using namespace ens; using namespace ens::test; -/** - * Run AdaDelta on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("AdaDeltaLogisticRegressionTest", "[AdaDeltaTest]") +TEMPLATE_TEST_CASE("AdaDeltaLogisticRegressionTest", "[AdaDelta]", + arma::mat, arma::fmat) { AdaDelta adaDelta; - LogisticRegressionFunctionTest(adaDelta, 0.003, 0.006, 1); + LogisticRegressionFunctionTest>( + adaDelta, 0.003, 0.006, 1); } -/** - * Run AdaDelta on logistic regression and make sure the results are acceptable - * with arma::fmat as the type. - */ -TEST_CASE("AdaDeltaLogisticRegressionTestFMat", "[AdaDeltaTest]") +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("AdaDeltaLogisticRegressionTest", "[AdaDelta]", + coot::mat, coot::fmat) { AdaDelta adaDelta; - LogisticRegressionFunctionTest(adaDelta, 0.003, 0.006, 1); + LogisticRegressionFunctionTest>( + adaDelta, 0.003, 0.006, 1); } + +#endif diff --git a/tests/ada_grad_test.cpp b/tests/ada_grad_test.cpp index ec73145dd..11bfed162 100644 --- a/tests/ada_grad_test.cpp +++ b/tests/ada_grad_test.cpp @@ -17,20 +17,22 @@ using namespace ens; using namespace ens::test; -/** - * Run AdaGrad on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("AdaGradLogisticRegressionTest", "[AdaGradTest]") +TEMPLATE_TEST_CASE("AdaGradLogisticRegressionTest", "[AdaGrad]", + arma::mat, arma::fmat) { AdaGrad adagrad(0.99, 32, 1e-8, 5000000, 1e-9, true); - LogisticRegressionFunctionTest(adagrad, 0.003, 0.006); + LogisticRegressionFunctionTest>( + adagrad, 0.003, 0.006); } -/** - * Run AdaGrad on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("AdaGradLogisticRegressionTestFMat", "[AdaGradTest]") +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("AdaGradLogisticRegressionTest", "[AdaGrad]", + coot::mat, coot::fmat) { AdaGrad adagrad(0.99, 32, 1e-8, 5000000, 1e-9, true); - LogisticRegressionFunctionTest(adagrad, 0.003, 0.006); + LogisticRegressionFunctionTest>( + adagrad, 0.003, 0.006); } + +#endif diff --git a/tests/ada_sqrt_test.cpp b/tests/ada_sqrt_test.cpp index 57560a948..75e91b407 100644 --- a/tests/ada_sqrt_test.cpp +++ b/tests/ada_sqrt_test.cpp @@ -15,20 +15,22 @@ using namespace ens; using namespace ens::test; -/** - * Run AdaSqrt on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("AdaSqrtLogisticRegressionTest", "[AdaSqrtTest]") +TEMPLATE_TEST_CASE("AdaSqrtLogisticRegressionTest", "[AdaSqrt]", + arma::mat, arma::fmat) { AdaSqrt optimizer(0.01, 32, 1e-8, 5000000, 1e-9, true); - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); + LogisticRegressionFunctionTest>( + optimizer, 0.003, 0.006, 1); } -/** - * Run AdaSqrt on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("AdaSqrtLogisticRegressionTestFMat", "[AdaSqrtTest]") +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("AdaSqrtLogisticRegressionTest", "[AdaSqrt]", + coot::mat, coot::fmat) { AdaSqrt optimizer(0.01, 32, 1e-8, 5000000, 1e-9, true); - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); + LogisticRegressionFunctionTest>( + optimizer, 0.003, 0.006, 1); } + +#endif diff --git a/tests/adam_test.cpp b/tests/adam_test.cpp index f978fb0c3..94d02d6da 100644 --- a/tests/adam_test.cpp +++ b/tests/adam_test.cpp @@ -20,312 +20,293 @@ using namespace ens; using namespace ens::test; -/** - * Test the Adam optimizer on the Sphere function. - */ -TEST_CASE("AdamSphereFunctionTest", "[AdamTest]") +TEMPLATE_TEST_CASE("AdamSphereFunctionTest", "[Adam]", arma::mat, arma::fmat) { Adam optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false); - FunctionTest(optimizer, 0.5, 0.2); + FunctionTest>, TestType>( + optimizer, 0.5, 0.2); } -/** - * Test the Adam optimizer on the Sphere function with arma::fmat. - */ -TEST_CASE("AdamSphereFunctionTestFMat", "[AdamTest]") +TEMPLATE_TEST_CASE("AdamStyblinskiTangFunctionTest", "[Adam]", arma::mat) { Adam optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false); - FunctionTest(optimizer, 0.5, 0.2); + FunctionTest>, TestType>( + optimizer, 0.5, 0.1); } -/** - * Test the AMSGrad optimizer on the Sphere function with arma::sp_mat. - */ -TEST_CASE("AdamSphereFunctionTestSpMat", "[AdamTest]") +TEMPLATE_TEST_CASE("AdamMcCormickFunctionTest", "[Adam]", arma::mat) { - Adam optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false); - FunctionTest(optimizer, 0.5, 0.2); + Adam optimizer(0.5, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false); + FunctionTest(optimizer, 0.5, 0.1); } -/** - * Test the AMSGrad optimizer on the Sphere function with arma::sp_mat but a - * dense (arma::mat) gradient. - */ -TEST_CASE("AdamSphereFunctionTestSpMatDenseGradient", "[AdamTest]") +TEMPLATE_TEST_CASE("AdamMatyasFunctionTest", "[Adam]", arma::mat) { - SphereFunction f(2); - Adam optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false); - - arma::sp_mat coordinates = f.GetInitialPoint(); - optimizer.Optimize(f, coordinates); + Adam optimizer(0.5, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false); + FunctionTest(optimizer, 0.1, 0.01); +} - REQUIRE(coordinates(0) == Approx(0.0).margin(0.1)); - REQUIRE(coordinates(1) == Approx(0.0).margin(0.1)); +TEMPLATE_TEST_CASE("AdamEasomFunctionTest", "[Adam]", arma::mat) +{ + Adam optimizer(0.2, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false); + FunctionTest(optimizer, 1.5, 0.01); } -/** - * Test the Adam optimizer on the Wood function. - */ -TEST_CASE("AdamStyblinskiTangFunctionTest", "[AdamTest]") +TEMPLATE_TEST_CASE("AdamBoothFunctionTest", "[Adam]", arma::mat) { - Adam optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false); - FunctionTest(optimizer, 0.5, 0.1); + Adam optimizer(1e-1, 1, 0.7, 0.999, 1e-8, 500000, 1e-9, true); + FunctionTest(optimizer); } -/** - * Test the Adam optimizer on the McCormick function. - */ -TEST_CASE("AdamMcCormickFunctionTest", "[AdamTest]") +TEMPLATE_TEST_CASE("AMSGradSphereFunctionTestFMat", "[Adam]", arma::fmat) { - Adam optimizer(0.5, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false); - FunctionTest(optimizer, 0.5, 0.1); + AMSGrad optimizer(1e-3, 1, 0.9, 0.999, 1e-8, 500000, 1e-11, true); + FunctionTest>, TestType>( + optimizer, 0.5, 0.1); } -/** - * Test the Adam optimizer on the Matyas function. - */ -TEST_CASE("AdamMatyasFunctionTest", "[AdamTest]") +TEMPLATE_TEST_CASE("AdamLogisticRegressionTest", "[Adam]", arma::mat) { - Adam optimizer(0.5, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false); - FunctionTest(optimizer, 0.1, 0.01); + Adam adam; + LogisticRegressionFunctionTest(adam, 0.003, 0.006); } -/** - * Test the Adam optimizer on the Easom function. - */ -TEST_CASE("AdamEasomFunctionTest", "[AdamTest]") +TEMPLATE_TEST_CASE("AdaMaxLogisticRegressionTest", "[Adam]", arma::mat) { - Adam optimizer(0.2, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false); - FunctionTest(optimizer, 1.5, 0.01); + AdaMax adamax(1e-3, 1, 0.9, 0.999, 1e-8, 5000000, 1e-9, true); + LogisticRegressionFunctionTest(adamax, 0.003, 0.006); } -/** - * Test the Adam optimizer on the Booth function. - */ -TEST_CASE("AdamBoothFunctionTest", "[AdamTest]") +TEMPLATE_TEST_CASE("AMSGradLogisticRegressionTest", "[Adam]", arma::mat) { - Adam optimizer(1e-1, 1, 0.7, 0.999, 1e-8, 500000, 1e-9, true); - FunctionTest(optimizer); + AMSGrad amsgrad(1e-3, 1, 0.9, 0.999, 1e-8, 500000, 1e-11, true); + LogisticRegressionFunctionTest(amsgrad, 0.003, 0.006); } +TEMPLATE_TEST_CASE("NadamLogisticRegressionTest", "[Adam]", arma::mat) +{ + Nadam nadam; + LogisticRegressionFunctionTest(nadam, 0.003, 0.006); +} -/** - * Test the AMSGrad optimizer on the Sphere function with arma::fmat. - */ -TEST_CASE("AMSGradSphereFunctionTestFMat", "[AdamTest]") +TEMPLATE_TEST_CASE("NadaMaxLogisticRegressionTest", "[Adam]", arma::mat) { - AMSGrad optimizer(1e-3, 1, 0.9, 0.999, 1e-8, 500000, 1e-11, true); - FunctionTest(optimizer, 0.5, 0.1); + NadaMax nadamax(1e-3, 1, 0.9, 0.999, 1e-8, 5000000, 1e-9, true); + LogisticRegressionFunctionTest(nadamax, 0.003, 0.006); } -/** - * Test the AMSGrad optimizer on the Sphere function with arma::sp_mat. - */ -TEST_CASE("AMSGradSphereFunctionTestSpMat", "[AdamTest]") +TEMPLATE_TEST_CASE("OptimisticAdamLogisticRegressionTest", "[Adam]", arma::mat) { - AMSGrad optimizer(1e-3, 1, 0.9, 0.999, 1e-8, 500000, 1e-11, true); - FunctionTest(optimizer, 0.5, 0.1); + OptimisticAdam optimisticAdam; + LogisticRegressionFunctionTest(optimisticAdam, 0.003, 0.006); } -/** - * Test the AMSGrad optimizer on the Sphere function with arma::sp_mat but a - * dense (arma::mat) gradient. - */ -TEST_CASE("AMSGradSphereFunctionTestSpMatDenseGradient", "[AdamTest]") +TEMPLATE_TEST_CASE("PadamLogisticRegressionTest", "[Adam]", arma::mat) { - SphereFunction f(2); - AMSGrad optimizer(1e-3, 1, 0.9, 0.999, 1e-8, 500000, 1e-11, true); + Padam optimizer; + LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); +} - arma::sp_mat coordinates = f.GetInitialPoint(); - optimizer.Optimize(f, coordinates); +TEMPLATE_TEST_CASE("QHAdamLogisticRegressionTest", "[Adam]", + arma::mat, arma::fmat) +{ + QHAdam optimizer; + LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); +} - REQUIRE(coordinates(0) == Approx(0.0).margin(0.1)); - REQUIRE(coordinates(1) == Approx(0.0).margin(0.1)); +TEMPLATE_TEST_CASE("AdamAckleyFunctionTest", "[Adam]", arma::mat) +{ + Adam optimizer(0.001, 2, 0.7, 0.999, 1e-8, 500000, 1e-7, false); + FunctionTest(optimizer); } -/** - * Run Adam on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("AdamLogisticRegressionTest", "[AdamTest]") +TEMPLATE_TEST_CASE("AdamBealeFunctionTest", "[Adam]", arma::mat) { - Adam adam; - LogisticRegressionFunctionTest(adam, 0.003, 0.006); + Adam optimizer(0.001, 2, 0.7, 0.999, 1e-8, 500000, 1e-7, false); + FunctionTest(optimizer, 0.1, 0.01); } -/** - * Run AdaMax on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("AdaMaxLogisticRegressionTest", "[AdamTest]") +TEMPLATE_TEST_CASE("AdamGoldsteinPriceFunctionTest", "[Adam]", arma::mat) { - AdaMax adamax(1e-3, 1, 0.9, 0.999, 1e-8, 5000000, 1e-9, true); - LogisticRegressionFunctionTest(adamax, 0.003, 0.006); + Adam optimizer(0.0001, 2, 0.7, 0.999, 1e-8, 500000, 1e-9, false); + FunctionTest(optimizer, 0.1, 0.01); } -/** - * Run AMSGrad on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("AMSGradLogisticRegressionTest", "[AdamTest]") +TEMPLATE_TEST_CASE("AdamLevyFunctionTest", "[Adam]", arma::mat) { - AMSGrad amsgrad(1e-3, 1, 0.9, 0.999, 1e-8, 500000, 1e-11, true); - LogisticRegressionFunctionTest(amsgrad, 0.003, 0.006); + Adam optimizer(0.001, 2, 0.7, 0.999, 1e-8, 500000, 1e-9, false); + FunctionTest(optimizer, 0.1, 0.01); } -/** - * Run Nadam on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("NadamLogisticRegressionTest", "[AdamTest]") +TEMPLATE_TEST_CASE("AdamHimmelblauFunctionTest", "[Adam]", arma::mat) { - Nadam nadam; - LogisticRegressionFunctionTest(nadam, 0.003, 0.006); + HimmelblauFunction f; + Adam optimizer(0.001, 2, 0.7, 0.999, 1e-8, 500000, 1e-9, false); + + arma::mat coordinates = arma::mat("2.9; 1.9"); + optimizer.Optimize(f, coordinates); + + REQUIRE(coordinates(0) == Approx(3.0).margin(0.05)); + REQUIRE(coordinates(1) == Approx(2.0).margin(0.05)); } -/** - * Run NadaMax on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("NadaMaxLogisticRegressionTest", "[AdamTest]") +TEMPLATE_TEST_CASE("AdamThreeHumpCamelFunctionTest", "[Adam]", arma::mat) { - NadaMax nadamax(1e-3, 1, 0.9, 0.999, 1e-8, 5000000, 1e-9, true); - LogisticRegressionFunctionTest(nadamax, 0.003, 0.006); + Adam optimizer(0.001, 2, 0.7, 0.999, 1e-8, 500000, 1e-9, false); + FunctionTest(optimizer, 0.1, 0.01); } -/** - * Run OptimisticAdam on logistic regression and make sure the results are - * acceptable. - */ -TEST_CASE("OptimisticAdamLogisticRegressionTest", "[AdamTest]") +#if ARMA_VERSION_MAJOR > 9 ||\ + (ARMA_VERSION_MAJOR == 9 && ARMA_VERSION_MINOR >= 400) + +TEMPLATE_TEST_CASE("AdamSphereFunctionTestSpMat", "[Adam]", arma::sp_mat) { - OptimisticAdam optimisticAdam; - LogisticRegressionFunctionTest(optimisticAdam, 0.003, 0.006); + Adam optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false); + FunctionTest>, TestType>( + optimizer, 0.5, 0.2); } -/** - * Run Padam on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("PadamLogisticRegressionTest", "[AdamTest]") +TEST_CASE("AdamSphereFunctionTestSpMatDenseGradient", "[Adam]") { - Padam optimizer; - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); + SphereFunction> f(2); + Adam optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false); + + arma::sp_mat coordinates = f.GetInitialPoint(); + optimizer.Optimize(f, coordinates); + + REQUIRE(coordinates(0) == Approx(0.0).margin(0.1)); + REQUIRE(coordinates(1) == Approx(0.0).margin(0.1)); } -/** - * Run QHAdam on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("QHAdamLogisticRegressionTest", "[AdamTest]") +TEST_CASE("AMSGradSphereFunctionTestSpMat", "[Adam]") { - QHAdam optimizer; - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); + AMSGrad optimizer(1e-3, 1, 0.9, 0.999, 1e-8, 500000, 1e-11, true); + FunctionTest>, + arma::sp_mat>(optimizer, 0.5, 0.1); } -/** - * Run QHAdam on logistic regression and make sure the results are acceptable, - * using arma::fmat. - */ -TEST_CASE("QHAdamLogisticRegressionFMatTest", "[AdamTest]") +TEST_CASE("AMSGradSphereFunctionTestSpMatDenseGradient", "[Adam]") { - QHAdam optimizer; - LogisticRegressionFunctionTest(optimizer, 0.03, 0.06); + SphereFunction> f(2); + AMSGrad optimizer(1e-3, 1, 0.9, 0.999, 1e-8, 500000, 1e-11, true); + + arma::sp_mat coordinates = f.GetInitialPoint(); + optimizer.Optimize(f, coordinates); + + REQUIRE(coordinates(0) == Approx(0.0).margin(0.1)); + REQUIRE(coordinates(1) == Approx(0.0).margin(0.1)); } -/** - * Run QHAdam on logistic regression and make sure the results are acceptable, - * using arma::sp_mat. - */ -TEST_CASE("QHAdamLogisticRegressionSpMatTest", "[AdamTest]") +TEST_CASE("QHAdamLogisticRegressionSpMatTest", "[Adam]") { QHAdam optimizer; LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); } -/** - * Test the Adam optimizer on the Ackley function. - * This is to test the Ackley function and not Adam. - * This test will be removed later. - */ -TEST_CASE("AdamAckleyFunctionTest", "[AdamTest]") +#endif + +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("AdamSphereFunctionTest", "[Adam]", coot::mat, coot::fmat) { - Adam optimizer(0.001, 2, 0.7, 0.999, 1e-8, 500000, 1e-7, false); - FunctionTest(optimizer); + Adam optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false); + FunctionTest>, TestType>( + optimizer, 0.5, 0.2); } -/** - * Test the Adam optimizer on the Beale function. - * This is to test the Beale function and not Adam. - * This test will be removed later. - */ -TEST_CASE("AdamBealeFunctionTest", "[AdamTest]") +TEMPLATE_TEST_CASE("AdamStyblinskiTangFunctionTest", "[Adam]", coot::mat) { - Adam optimizer(0.001, 2, 0.7, 0.999, 1e-8, 500000, 1e-7, false); - FunctionTest(optimizer, 0.1, 0.01); + Adam optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false); + FunctionTest>, TestType>( + optimizer, 0.5, 0.1); } -/** - * Test the Adam optimizer on the Goldstein-Price function. - * This is to test the Goldstein-Price function and not Adam. - * This test will be removed later. - */ -TEST_CASE("AdamGoldsteinPriceFunctionTest", "[AdamTest]") +TEMPLATE_TEST_CASE("AdamMcCormickFunctionTest", "[Adam]", coot::mat) { - Adam optimizer(0.0001, 2, 0.7, 0.999, 1e-8, 500000, 1e-9, false); - FunctionTest(optimizer, 0.1, 0.01); + Adam optimizer(0.5, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false); + FunctionTest(optimizer, 0.5, 0.1); } -/** - * Test the Adam optimizer on the Levi function. - * This is to test the Levi function and not Adam. - * This test will be removed later. - */ -TEST_CASE("AdamLevyFunctionTest", "[AdamTest]") +TEMPLATE_TEST_CASE("AdamMatyasFunctionTest", "[Adam]", coot::mat) { - Adam optimizer(0.001, 2, 0.7, 0.999, 1e-8, 500000, 1e-9, false); - FunctionTest(optimizer, 0.1, 0.01); + Adam optimizer(0.5, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false); + FunctionTest(optimizer, 0.1, 0.01); } -/** - * Test the Adam optimizer on the Himmelblau function. - * This is to test the Himmelblau function and not Adam. - * This test will be removed later. - */ -TEST_CASE("AdamHimmelblauFunctionTest", "[AdamTest]") +TEMPLATE_TEST_CASE("AdamEasomFunctionTest", "[Adam]", coot::mat) { - HimmelblauFunction f; - Adam optimizer(0.001, 2, 0.7, 0.999, 1e-8, 500000, 1e-9, false); + Adam optimizer(0.2, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false); + FunctionTest(optimizer, 1.5, 0.01); +} - arma::mat coordinates = arma::mat("2.9; 1.9"); - optimizer.Optimize(f, coordinates); +TEMPLATE_TEST_CASE("AdamBoothFunctionTest", "[Adam]", coot::mat) +{ + Adam optimizer(1e-1, 1, 0.7, 0.999, 1e-8, 500000, 1e-9, true); + FunctionTest(optimizer); +} - REQUIRE(coordinates(0) == Approx(3.0).margin(0.05)); - REQUIRE(coordinates(1) == Approx(2.0).margin(0.05)); +TEMPLATE_TEST_CASE("AMSGradSphereFunctionTestFMat", "[Adam]", coot::fmat) +{ + AMSGrad optimizer(1e-3, 1, 0.9, 0.999, 1e-8, 500000, 1e-11, true); + FunctionTest>, TestType>( + optimizer, 0.5, 0.1); } -/** - * Test the Adam optimizer on the Three-hump camel function. - * This is to test the Three-hump camel function and not Adam. - * This test will be removed later. - */ -TEST_CASE("AdamThreeHumpCamelFunctionTest", "[AdamTest]") +TEMPLATE_TEST_CASE("AdamLogisticRegressionTest", "[Adam]", coot::mat) { - Adam optimizer(0.001, 2, 0.7, 0.999, 1e-8, 500000, 1e-9, false); - FunctionTest(optimizer, 0.1, 0.01); + Adam adam; + LogisticRegressionFunctionTest>( + adam, 0.003, 0.006); } -/** - * Test that multiple runs of the Adam optimizer result in the exact same - * result. This specifically tests that the update policy is successfully - * reset at the start of each optimization. - */ -TEST_CASE("AdamResetPolicyTest", "[AdamTest]") +TEMPLATE_TEST_CASE("AdaMaxLogisticRegressionTest", "[Adam]", coot::mat) { - Adam optimizer(0.5, 2, 0.7, 0.999, 1e-8, 5, 1e-3, false); - optimizer.ResetPolicy() = true; + AdaMax adamax(1e-3, 1, 0.9, 0.999, 1e-8, 5000000, 1e-9, true); + LogisticRegressionFunctionTest>( + adamax, 0.003, 0.006); +} - SphereFunction f(2); +TEMPLATE_TEST_CASE("AMSGradLogisticRegressionTest", "[Adam]", coot::mat) +{ + AMSGrad amsgrad(1e-3, 1, 0.9, 0.999, 1e-8, 500000, 1e-11, true); + LogisticRegressionFunctionTest>( + amsgrad, 0.003, 0.006); +} - arma::mat coordinatesA = f.GetInitialPoint(); - optimizer.Optimize(f, coordinatesA); +TEMPLATE_TEST_CASE("NadamLogisticRegressionTest", "[Adam]", coot::mat) +{ + Nadam nadam; + LogisticRegressionFunctionTest>( + nadam, 0.003, 0.006); +} - // A second run should produce the exact same results. - arma::mat coordinatesB = f.GetInitialPoint(); - optimizer.Optimize(f, coordinatesB); +TEMPLATE_TEST_CASE("NadaMaxLogisticRegressionTest", "[Adam]", coot::mat) +{ + NadaMax nadamax(1e-3, 1, 0.9, 0.999, 1e-8, 5000000, 1e-9, true); + LogisticRegressionFunctionTest>( + nadamax, 0.003, 0.006); +} - CheckMatrices(coordinatesA, coordinatesB); +TEMPLATE_TEST_CASE("OptimisticAdamLogisticRegressionTest", "[Adam]", coot::mat) +{ + OptimisticAdam optimisticAdam; + LogisticRegressionFunctionTest>( + optimisticAdam, 0.003, 0.006); +} + +TEMPLATE_TEST_CASE("PadamLogisticRegressionTest", "[Adam]", coot::mat) +{ + Padam optimizer; + LogisticRegressionFunctionTest>( + optimizer, 0.003, 0.006); } + +TEMPLATE_TEST_CASE("QHAdamLogisticRegressionTest", "[Adam]", + coot::mat, coot::fmat) +{ + QHAdam optimizer; + LogisticRegressionFunctionTest>( + optimizer, 0.003, 0.006); +} + +#endif \ No newline at end of file diff --git a/tests/bigbatch_sgd_test.cpp b/tests/bigbatch_sgd_test.cpp index f0978af17..4580bbd92 100644 --- a/tests/bigbatch_sgd_test.cpp +++ b/tests/bigbatch_sgd_test.cpp @@ -16,86 +16,53 @@ using namespace ens; using namespace ens::test; -/** - * Run big-batch SGD using BBS_BB on logistic regression and make sure the - * results are acceptable. - */ -TEST_CASE("BBSBBLogisticRegressionTest", "[BigBatchSGDTest]") +TEMPLATE_TEST_CASE("BBSBBLogisticRegressionTest", "[BigBatchSGD]", + arma::mat, arma::fmat) { // Run big-batch SGD with a couple of batch sizes. for (size_t batchSize = 350; batchSize < 360; batchSize += 5) { BBS_BB bbsgd(batchSize, 0.001, 0.1, 10000, 1e-8, true, true); - LogisticRegressionFunctionTest(bbsgd, 0.003, 0.006, 3); + LogisticRegressionFunctionTest>( + bbsgd, 0.003, 0.006); } } -/** - * Run big-batch SGD using BBS_Armijo on logistic regression and make sure the - * results are acceptable. - */ -TEST_CASE("BBSArmijoLogisticRegressionTest", "[BigBatchSGDTest]") +TEMPLATE_TEST_CASE("BBSArmijoLogisticRegressionTest", "[BigBatchSGD]", + arma::mat, arma::fmat) { // Run big-batch SGD with a couple of batch sizes. for (size_t batchSize = 40; batchSize < 50; batchSize += 1) { BBS_Armijo bbsgd(batchSize, 0.005, 0.1, 10000, 1e-6, true, true); - LogisticRegressionFunctionTest(bbsgd, 0.003, 0.006, 3); - } -} - -/** - * Run big-batch SGD using BBS_BB on logistic regression and make sure the - * results are acceptable. Use arma::fmat as the objective type. - */ -TEST_CASE("BBSBBLogisticRegressionFMatTest", "[BigBatchSGDTest]") -{ - // Run big-batch SGD with a couple of batch sizes. - for (size_t batchSize = 350; batchSize < 360; batchSize += 5) - { - BBS_BB bbsgd(batchSize, 0.001, 0.1, 10000, 1e-8, true, true); - LogisticRegressionFunctionTest(bbsgd, 0.003, 0.006, 3); + LogisticRegressionFunctionTest>( + bbsgd, 0.003, 0.006); } } -/** - * Run big-batch SGD using BBS_Armijo on logistic regression and make sure the - * results are acceptable. Use arma::fmat as the objective type. - */ -TEST_CASE("BBSArmijoLogisticRegressionFMatTest", "[BigBatchSGDTest]") -{ - // Run big-batch SGD with a couple of batch sizes. - for (size_t batchSize = 40; batchSize < 50; batchSize += 1) - { - BBS_Armijo bbsgd(batchSize, 0.01, 0.1, 10000, 1e-6, true, true); - LogisticRegressionFunctionTest(bbsgd, 0.003, 0.006, 5); - } -} +#ifdef USE_COOT -/** - * Run big-batch SGD using BBS_BB on logistic regression and make sure the - * results are acceptable. Use arma::sp_mat as the objective type. - */ -TEST_CASE("BBSBBLogisticRegressionSpMatTest", "[BigBatchSGDTest]") +TEMPLATE_TEST_CASE("BBSBBLogisticRegressionTest", "[BigBatchSGD]", + coot::mat, coot::fmat) { // Run big-batch SGD with a couple of batch sizes. for (size_t batchSize = 350; batchSize < 360; batchSize += 5) { - BBS_BB bbsgd(batchSize, 0.005, 0.5, 10000, 1e-8, true, true); - LogisticRegressionFunctionTest(bbsgd, 0.003, 0.006, 3); + BBS_BB bbsgd(batchSize, 0.001, 0.1, 10000, 1e-8, true, true); + LogisticRegressionFunctionTest>( + bbsgd, 0.003, 0.006); } } -/** - * Run big-batch SGD using BBS_Armijo on logistic regression and make sure the - * results are acceptable. Use arma::sp_mat as the objective type. - */ -TEST_CASE("BBSArmijoLogisticRegressionSpMatTest", "[BigBatchSGDTest]") +TEMPLATE_TEST_CASE("BBSArmijoLogisticRegressionTest", "[BigBatchSGD]", + coot::mat, coot::fmat) { // Run big-batch SGD with a couple of batch sizes. for (size_t batchSize = 40; batchSize < 50; batchSize += 1) { - BBS_Armijo bbsgd(batchSize, 0.01, 0.001, 10000, 1e-6, true, true); - LogisticRegressionFunctionTest(bbsgd, 0.003, 0.006, 3); + BBS_Armijo bbsgd(batchSize, 0.005, 0.1, 10000, 1e-6, true, true); + LogisticRegressionFunctionTest>( + bbsgd, 0.003, 0.006); } } +#endif diff --git a/tests/cmaes_test.cpp b/tests/cmaes_test.cpp index 4a608e61e..05eed8e6e 100644 --- a/tests/cmaes_test.cpp +++ b/tests/cmaes_test.cpp @@ -21,7 +21,7 @@ using namespace ens::test; * Run CMA-ES with the full selection policy on logistic regression and * make sure the results are acceptable. */ -TEST_CASE("CMAESLogisticRegressionTest", "[CMAESTest]") +TEMPLATE_TEST_CASE("CMAESLogisticRegressionTest", "[CMAES]", arma::mat) { BoundaryBoxConstraint<> b(-10, 10); CMAES> cmaes(0, b, 32, 500, 1e-3); @@ -56,11 +56,19 @@ TEST_CASE("CMAESLogisticRegressionFMatTest", "[CMAESTest]") * Run CMA-ES with the random selection policy on logistic regression and * make sure the results are acceptable. Use arma::fmat. */ -TEST_CASE("ApproxCMAESLogisticRegressionFMatTest", "[CMAESTest]") +/* TEST_CASE("ApproxCMAESLogisticRegressionFMatTest", "[CMAESTest]") */ +/* { */ +/* ApproxCMAES<> cmaes(0, -1, 1, 32, 200, 1e-3); */ +/* LogisticRegressionFunctionTest(cmaes, 0.01, 0.02, 5); */ +/* } */ + +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("CMAESLogisticRegressionTest", "[CMAES]", coot::fmat) { - BoundaryBoxConstraint b(-10, 10); - ApproxCMAES> cmaes(0, b, 16, 500, 1e-3); - LogisticRegressionFunctionTest(cmaes, 0.01, 0.02, 5); + BoundaryBoxConstraint b(-10, 10); + ApproxCMAES> cmaes(0, b, 16, 500, 1e-3); + LogisticRegressionFunctionTest(cmaes, 0.01, 0.02, 5); } /** @@ -71,7 +79,9 @@ TEST_CASE("ApproxCMAESLogisticRegressionFMatTest", "[CMAESTest]") TEST_CASE("ApproxCMAESEmptyTransformationLogisticRegressionFMatTest", "[CMAESTest]") { - ApproxCMAES> - cmaes(0, EmptyTransformation(), 16, 500, 1e-3); - LogisticRegressionFunctionTest(cmaes, 0.01, 0.02, 5); + ApproxCMAES> + cmaes(0, EmptyTransformation(), 16, 500, 1e-3); + LogisticRegressionFunctionTest(cmaes, 0.01, 0.02, 5); } + +#endif diff --git a/tests/cne_test.cpp b/tests/cne_test.cpp index 2410a80f4..86a6648b7 100644 --- a/tests/cne_test.cpp +++ b/tests/cne_test.cpp @@ -18,29 +18,15 @@ using namespace ens; using namespace ens::test; using namespace std; -/** - * Train and test a logistic regression function using CNE optimizer. - */ -TEST_CASE("CNELogisticRegressionTest", "[CNETest]") -{ - CNE opt(300, 150, 0.2, 0.2, 0.2, -1); - LogisticRegressionFunctionTest(opt, 0.003, 0.006); -} - -/** - * Train and test a logistic regression function using CNE optimizer. Use - * arma::fmat. - */ -TEST_CASE("CNELogisticRegressionFMatTest", "[CNETest]") +TEMPLATE_TEST_CASE("CNELogisticRegressionTest", "[CNE]", + arma::mat, arma::fmat) { CNE opt(300, 150, 0.2, 0.2, 0.2, -1); - LogisticRegressionFunctionTest(opt, 0.003, 0.006); + LogisticRegressionFunctionTest>( + opt, 0.003, 0.006, 1); } -/** - * Test the CNE optimizer on Cross-in-Tray Function. - */ -TEST_CASE("CNECrossInTrayFunctionTest", "[CNETest]") +TEST_CASE("CNECrossInTrayFunctionTest", "[CNE]") { CrossInTrayFunction f; CNE optimizer(450, 1500, 0.3, 0.3, 0.3, -1); @@ -52,46 +38,31 @@ TEST_CASE("CNECrossInTrayFunctionTest", "[CNETest]") REQUIRE(abs(coordinates(1)) == Approx(1.34941).margin(0.1)); } -/** - * Test the CNE optimizer on the Ackley Function. - */ -TEST_CASE("CNEAckleyFunctionTest", "[CNETest]") +TEST_CASE("CNEAckleyFunctionTest", "[CNE]") { CNE optimizer(450, 1500, 0.3, 0.3, 0.3, -1); FunctionTest(optimizer, 0.5, 0.1); } -/** - * Test the CNE optimizer on the Beale Function. - */ -TEST_CASE("CNEBealeFunctionTest", "[CNETest]") +TEST_CASE("CNEBealeFunctionTest", "[CNE]") { CNE optimizer(450, 1500, 0.3, 0.3, 0.3, -1); FunctionTest(optimizer, 0.5, 0.1); } -/** - * Test the CNE optimizer on the Goldstein-Price Function. - */ -TEST_CASE("CNEGoldsteinPriceFunctionTest", "[CNETest]") +TEST_CASE("CNEGoldsteinPriceFunctionTest", "[CNE]") { CNE optimizer(450, 1500, 0.3, 0.3, 0.1, -1); FunctionTest(optimizer, 0.5, 0.1); } -/** - * Test the CNE optimizer on the Levi Function. - */ -TEST_CASE("CNELevyFunctionN13Test", "[CNETest]") +TEST_CASE("CNELevyFunctionN13Test", "[CNE]") { CNE optimizer(450, 1500, 0.3, 0.3, 0.02, -1); FunctionTest(optimizer, 0.5, 0.1); } -/** - * Test the CNE optimizer on the Himmelblau Function. - */ -TEST_CASE("CNEHimmelblauFunctionTest", "[CNETest]") +TEST_CASE("CNEHimmelblauFunctionTest", "[CNE]") { HimmelblauFunction f; CNE optimizer(650, 3000, 0.3, 0.3, 0.3, 1e-7); @@ -112,10 +83,7 @@ TEST_CASE("CNEHimmelblauFunctionTest", "[CNETest]") REQUIRE(coordinates(1) == Approx(2.0).margin(0.2)); } -/** - * Test the CNE optimizer on the Three-hump Camel Function. - */ -TEST_CASE("CNEThreeHumpCamelFunctionTest", "[CNETest]") +TEST_CASE("CNEThreeHumpCamelFunctionTest", "[CNE]") { CNE optimizer(450, 1500, 0.3, 0.3, 0.3, -1); FunctionTest(optimizer, 0.5, 0.1); @@ -127,7 +95,7 @@ TEST_CASE("CNEThreeHumpCamelFunctionTest", "[CNETest]") /** * Test the CNE optimizer on Schaffer function N.4. */ -TEST_CASE("CNESchafferFunctionN4Test", "[CNETest]") +TEST_CASE("CNESchafferFunctionN4Test", "[CNE]") { SchafferFunctionN4 f; CNE optimizer(500, 1600, 0.3, 0.3, 0.3, -1); @@ -154,12 +122,21 @@ TEST_CASE("CNESchafferFunctionN4Test", "[CNETest]") } } -/** - * Test the CNE optimizer on Schaffer Function N.2. - */ -TEST_CASE("CNESchafferFunctionN2Test", "[CNETest]") +TEST_CASE("CNESchafferFunctionN2Test", "[CNE]") { // We allow a few trials in case convergence is not achieved. CNE optimizer(500, 1600, 0.3, 0.3, 0.3, -1); FunctionTest(optimizer, 0.5, 0.1, 7); } + +#ifdef USE_COOT + +// TEMPLATE_TEST_CASE("CNELogisticRegressionTest", "[CNE]", +// coot::mat, coot::fmat) +// { +// CNE opt(300, 150, 0.2, 0.2, 0.2, -1); +// LogisticRegressionFunctionTest>( +// opt, 0.003, 0.006, 1); +// } + +#endif \ No newline at end of file diff --git a/tests/coot_test.cpp b/tests/coot_test.cpp new file mode 100644 index 000000000..9648e344f --- /dev/null +++ b/tests/coot_test.cpp @@ -0,0 +1,98 @@ +/** + * @file coot_test.cpp + * @author Ryan Curtin + * + * Test ensmallen algorithms with bandicoot. + * + * ensmallen 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 ensmallen. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ +#include +#include "catch.hpp" +#include "test_function_tools.hpp" + +using namespace ens; +using namespace ens::test; + +/** + * Run SGD on logistic regression and make sure the results are acceptable. + */ +TEST_CASE("SGDLogisticRegressionTest", "[CootTest]") +{ + coot::mat data, testData, shuffledData; + coot::Row responses, testResponses, shuffledResponses; + + LogisticRegressionTestData(data, testData, shuffledData, + responses, testResponses, shuffledResponses); + std::cout << "rows: " << responses.n_rows << std::endl; + std::cout << "cols: " << responses.n_cols << std::endl; + //std::cout << "----------------------------------------\n"; + //shuffledResponses.print(); + LogisticRegressionFunction> lr(shuffledData, shuffledResponses, 0.5); + + StandardSGD sgd; + coot::mat coordinates = lr.GetInitialPoint(); + sgd.Optimize(lr, coordinates); + + // Ensure that the error is close to zero. + const double acc = lr.ComputeAccuracy(data, responses, coordinates); + REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance. + + const double testAcc = lr.ComputeAccuracy(testData, testResponses, + coordinates); + REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance. +} + +TEST_CASE("SGDLogisticRegressionTestArma", "[ArmaTest]") +{ + arma::mat data, testData, shuffledData; + arma::Row responses, testResponses, shuffledResponses; + + LogisticRegressionTestData(data, testData, shuffledData, + responses, testResponses, shuffledResponses); + std::cout << "rows: " << responses.n_rows << std::endl; + std::cout << "cols: " << responses.n_cols << std::endl; + //std::cout << "----------------------------------------\n"; + //shuffledResponses.print(); + LogisticRegressionFunction> lr(shuffledData, shuffledResponses, 0.5); + + + StandardSGD sgd; + arma::mat coordinates = lr.GetInitialPoint(); + sgd.Optimize(lr, coordinates); + + // Ensure that the error is close to zero. + const double acc = lr.ComputeAccuracy(data, responses, coordinates); + REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance. + + const double testAcc = lr.ComputeAccuracy(testData, testResponses, + coordinates); + REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance. +} +/** + * Run L-BFGS on logistic regression and make sure the results are acceptable. + * +TEST_CASE("LBFGSLogisticRegressionTest", "[CootTest]") +{ + coot::mat data, testData, shuffledData; + coot::Row responses, testResponses, shuffledResponses; + + LogisticRegressionTestData(data, testData, shuffledData, + responses, testResponses, shuffledResponses); + LogisticRegressionFunction> lr(shuffledData, shuffledResponses, 0.5); + + L_BFGS lbfgs; + coot::mat coordinates = lr.GetInitialPoint(); + lbfgs.Optimize(lr, coordinates); + + // Ensure that the error is close to zero. + const double acc = lr.ComputeAccuracy(data, responses, coordinates); + REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance. + + const double testAcc = lr.ComputeAccuracy(testData, testResponses, + coordinates); + REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance. +} +*/ diff --git a/tests/de_test.cpp b/tests/de_test.cpp index a4bb2462e..56f068a4c 100644 --- a/tests/de_test.cpp +++ b/tests/de_test.cpp @@ -1,6 +1,7 @@ /** * @file de_test.cpp * @author Rahul Ganesh Prabhu + * @author Marcus Edel * * ensmallen 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 @@ -8,28 +9,27 @@ * http://www.opensource.org/licenses/BSD-3-Clause for more information. */ -#include "../include/ensmallen.hpp" +#include #include "catch.hpp" #include "test_function_tools.hpp" using namespace ens; using namespace ens::test; -/** - * Train and test a logistic regression function using DE optimizer. - */ -TEST_CASE("DELogisticRegressionTest", "[DETest]") +TEMPLATE_TEST_CASE("DELogisticRegressionTest", "[DE]", arma::mat) { DE opt(200, 1000, 0.6, 0.8, 1e-5); - LogisticRegressionFunctionTest(opt, 0.01, 0.02, 3); + LogisticRegressionFunctionTest>( + opt, 0.01, 0.02, 3); } -/** - * Train and test a logistic regression function using DE optimizer. Use - * arma::fmat. - */ -TEST_CASE("DELogisticRegressionFMatTest", "[DETest]") +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("DELogisticRegressionTest", "[DE]", coot::mat) { DE opt(200, 1000, 0.6, 0.8, 1e-5); - LogisticRegressionFunctionTest(opt, 0.03, 0.06, 3); + LogisticRegressionFunctionTest>( + opt, 0.01, 0.02, 3); } + +#endif diff --git a/tests/demon_adam_test.cpp b/tests/demon_adam_test.cpp index 66115571f..e81435aa2 100644 --- a/tests/demon_adam_test.cpp +++ b/tests/demon_adam_test.cpp @@ -15,61 +15,67 @@ using namespace ens; using namespace ens::test; -/** - * Run DemonAdam on logistic regression and make sure the results are - * acceptable. - */ -TEST_CASE("DemonAdamLogisticRegressionTest", "[DemonAdamTest]") +TEMPLATE_TEST_CASE("DemonAdamLogisticRegressionTest", "[DemonAdam]", arma::mat) { DemonAdam optimizer(0.2, 32, 0.9, 0.9, 0.999, 1e-8, 10000, 1e-9, true, true, true); - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006, 6); + LogisticRegressionFunctionTest(optimizer, 0.003, 0.006, 6); } -/** - * Test the Adam optimizer on the Sphere function. - */ -TEST_CASE("DemonAdamSphereFunctionTest", "[DemonAdamTest]") +TEMPLATE_TEST_CASE("DemonAdaMaxLogisticRegressionTest", "[DemonAdam]", arma::mat) +{ + DemonAdamType optimizer(0.5, 10, 0.9, 0.9, 0.999, 1e-8, + 10000, 1e-9, true, true, true); + LogisticRegressionFunctionTest(optimizer, 0.003, 0.006, 6); +} + +TEMPLATE_TEST_CASE("DemonAdamSphereFunctionTest", "[DemonAdam]", arma::mat, arma::fmat) { - SphereFunction f(2); DemonAdam optimizer(0.5, 2, 0.9); - FunctionTest(optimizer, 1.0, 0.1); + FunctionTest>, TestType>( + optimizer, 1.0, 0.1); } -/** - * Test the DemonAdam optimizer on the Matyas function. - */ -TEST_CASE("DemonAdamMatyasFunctionTest", "[DemonAdamTest]") +TEMPLATE_TEST_CASE("DemonAdamMatyasFunctionTest", "[DemonAdam]", arma::mat, arma::fmat) { DemonAdam optimizer(0.5, 1, 0.9); - FunctionTest(optimizer, 0.1, 0.01); + FunctionTest(optimizer, 0.1, 0.01); } -/** - * Test the Adam optimizer on the Sphere function. - */ -TEST_CASE("DemonAdamSphereFunctionTestFloat", "[DemonAdamTest]") +TEMPLATE_TEST_CASE("DemonAdamSphereFunctionTestSpMat", "[DemonAdam]", arma::sp_mat) { DemonAdam optimizer(0.5, 2, 0.9); - FunctionTest(optimizer, 1.0, 0.1); + FunctionTest>, TestType>( + optimizer, 1.0, 0.1); } -/** - * Test the DemonAdam optimizer on the Matyas function. - */ -TEST_CASE("DemonAdamMatyasFunctionTestFloat", "[DemonAdamTest]") +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("DemonAdamLogisticRegressionTest", "[DemonAdam]", coot::mat) { - DemonAdam optimizer(0.5, 1, 0.9); - FunctionTest(optimizer, 0.1, 0.01); + DemonAdam optimizer(0.2, 32, 0.9, 0.9, 0.999, 1e-8, + 10000, 1e-9, true, true, true); + LogisticRegressionFunctionTest>(optimizer, 0.003, 0.006, 6); } -/** - * Run DemonAdam (AdaMax update) on logistic regression and make sure the - * results are acceptable. - */ -TEST_CASE("DemonAdaMaxLogisticRegressionTest", "[DemonAdamTest]") +TEMPLATE_TEST_CASE("DemonAdaMaxLogisticRegressionTest", "[DemonAdam]", coot::mat) { DemonAdamType optimizer(0.5, 10, 0.9, 0.9, 0.999, 1e-8, 10000, 1e-9, true, true, true); - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006, 3); + LogisticRegressionFunctionTest>(optimizer, 0.003, 0.006, 6); } + +TEMPLATE_TEST_CASE("DemonAdamSphereFunctionTest", "[DemonAdam]", coot::mat, coot::fmat) +{ + DemonAdam optimizer(0.5, 2, 0.9); + FunctionTest>, TestType>( + optimizer, 1.0, 0.1); +} + +TEMPLATE_TEST_CASE("DemonAdamMatyasFunctionTest", "[DemonAdam]", coot::mat, coot::fmat) +{ + DemonAdam optimizer(0.5, 1, 0.9); + FunctionTest(optimizer, 0.1, 0.01); +} + +#endif diff --git a/tests/demon_sgd_test.cpp b/tests/demon_sgd_test.cpp index b8055dcae..95745f563 100644 --- a/tests/demon_sgd_test.cpp +++ b/tests/demon_sgd_test.cpp @@ -15,29 +15,19 @@ using namespace ens; using namespace ens::test; -/** - * Run DemonSGD on logistic regression and make sure the results are - * acceptable. - */ -TEST_CASE("DemonSGDLogisticRegressionTest", "[DemonSGDTest]") +TEMPLATE_TEST_CASE("DemonSGDLogisticRegressionTest", "[DemonSGDTest]", arma::mat, arma::fmat) { DemonSGD optimizer(0.1, 32, 0.9, 1000000, 1e-9, true, true, true); - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006, 6); + LogisticRegressionFunctionTest(optimizer, 0.003, 0.006, 6); } -/** - * Tests the DemonSGD optimizer using a simple test function. - */ -TEST_CASE("DemonSGDSimpleTestFunctionFloat", "[DemonSGDTest]") -{ - SGDTestFunction f; - DemonSGD optimizer(1e-2, 1, 0.9, 400000); +#ifdef USE_COOT - arma::fmat coordinates = f.GetInitialPoint(); - optimizer.Optimize(f, coordinates); - - REQUIRE(coordinates(0) == Approx(0.0).margin(0.1)); - REQUIRE(coordinates(1) == Approx(0.0).margin(0.1)); - REQUIRE(coordinates(2) == Approx(0.0).margin(0.1)); +TEMPLATE_TEST_CASE("DemonSGDLogisticRegressionTest", "[DemonSGDTest]", coot::mat, coot::fmat) +{ + DemonSGD optimizer(0.1, 32, 0.9, 1000000, 1e-9, true, true, true); + LogisticRegressionFunctionTest>(optimizer, 0.003, 0.006, 6); } +#endif + diff --git a/tests/eve_test.cpp b/tests/eve_test.cpp index b357829cd..a27eda7db 100644 --- a/tests/eve_test.cpp +++ b/tests/eve_test.cpp @@ -17,49 +17,64 @@ using namespace ens; using namespace ens::test; -/** - * Run Eve on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("EveLogisticRegressionTest","[EveTest]") +TEMPLATE_TEST_CASE("EveLogisticRegressionTest", "[Eve]", + arma::mat, arma::fmat) { Eve optimizer(1e-3, 1, 0.9, 0.999, 0.999, 1e-8, 10000, 500000, 1e-9, true); - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); + LogisticRegressionFunctionTest>( + optimizer, 0.003, 0.006); } -/** - * Test the Eve optimizer on the Sphere function. - */ -TEST_CASE("EveSphereFunctionTest","[EveTest]") +TEMPLATE_TEST_CASE("EveSphereFunctionTest", "[Eve]", + arma::mat, arma::fmat) { Eve optimizer(1e-3, 2, 0.9, 0.999, 0.999, 1e-8, 10000, 500000, 1e-9, true); - FunctionTest(optimizer, 0.5, 0.1); + FunctionTest>, TestType>( + optimizer, 0.5, 0.1); } -/** - * Test the Eve optimizer on the Styblinski-Tang function. - */ -TEST_CASE("EveStyblinskiTangFunctionTest","[EveTest]") +TEMPLATE_TEST_CASE("EveStyblinskiTangFunctionTest", "[Eve]", + arma::mat, arma::fmat) { Eve optimizer(1e-3, 2, 0.9, 0.999, 0.999, 1e-8, 10000, 500000, 1e-9, true); - FunctionTest(optimizer, 0.5, 0.1); + FunctionTest>, TestType>( + optimizer, 0.5, 0.1); } /** - * Test the Eve optimizer on the Styblinski-Tang function using arma::fmat as + * Test the Eve optimizer on the Styblinski-Tang function, using arma::sp_mat as * the objective type. */ -TEST_CASE("EveStyblinskiTangFunctionFMatTest","[EveTest]") +TEST_CASE("EveStyblinskiTangFunctionSpMatTest","[Eve]") { Eve optimizer(1e-3, 2, 0.9, 0.999, 0.999, 1e-8, 10000, 500000, 1e-9, true); - FunctionTest(optimizer, 0.5, 0.1); + FunctionTest, arma::sp_mat>(optimizer, 0.5, 0.1); } -/** - * Test the Eve optimizer on the Styblinski-Tang function, using arma::sp_mat as - * the objective type. - */ -TEST_CASE("EveStyblinskiTangFunctionSpMatTest","[EveTest]") +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("EveLogisticRegressionTest", "[Eve]", + coot::mat, coot::fmat) +{ + Eve optimizer(1e-3, 1, 0.9, 0.999, 0.999, 1e-8, 10000, 500000, 1e-9, true); + LogisticRegressionFunctionTest>( + optimizer, 0.003, 0.006); +} + +TEMPLATE_TEST_CASE("EveSphereFunctionTest", "[Eve]", + coot::mat, coot::fmat) { Eve optimizer(1e-3, 2, 0.9, 0.999, 0.999, 1e-8, 10000, 500000, 1e-9, true); - FunctionTest(optimizer, 0.5, 0.1); + FunctionTest>, TestType>( + optimizer, 0.5, 0.1); } + +TEMPLATE_TEST_CASE("EveStyblinskiTangFunctionTest", "[Eve]", + coot::mat, coot::fmat) +{ + Eve optimizer(1e-3, 2, 0.9, 0.999, 0.999, 1e-8, 10000, 500000, 1e-9, true); + FunctionTest>, TestType>( + optimizer, 0.5, 0.1); +} + +#endif diff --git a/tests/ftml_test.cpp b/tests/ftml_test.cpp index 1c7fc8ad6..9f489890f 100644 --- a/tests/ftml_test.cpp +++ b/tests/ftml_test.cpp @@ -1,6 +1,7 @@ /** * @file ftml_test.cpp * @author Ryan Curtin + * @author Marcus Edel * * Test file for the FTML optimizer. * @@ -17,42 +18,57 @@ using namespace ens; using namespace ens::test; -/** - * Run FTML on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("FTMLLogisticRegressionTest", "[FTMLTest]") +TEMPLATE_TEST_CASE("FTMLLogisticRegressionTest", "[FTML]", + arma::mat, arma::fmat) { FTML optimizer(0.001, 1, 0.9, 0.999, 1e-8, 100000, 1e-5, true); - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); + LogisticRegressionFunctionTest>( + optimizer, 0.003, 0.006); } -/** - * Test the FTML optimizer on the Sphere function. - */ -TEST_CASE("FTMLSphereFunctionTest", "[FTMLTest]") +TEMPLATE_TEST_CASE("FTMLSphereFunctionTest", "[FTML]", + arma::mat, arma::fmat) { FTML optimizer(0.001, 2, 0.9, 0.999, 1e-8, 500000, 1e-9, true); - FunctionTest(optimizer, 0.5, 0.1); + FunctionTest>, TestType>( + optimizer, 0.5, 0.1); } -/** - * Test the FTML optimizer on the Styblinski-Tang function. - */ -TEST_CASE("FTMLStyblinskiTangFunctionTest", "[FTMLTest]") +TEMPLATE_TEST_CASE("FTMLStyblinskiTangFunctionTest", "[FTML]", + arma::mat, arma::fmat) { FTML optimizer(0.001, 2, 0.9, 0.999, 1e-8, 100000, 1e-5, true); - FunctionTest(optimizer, 0.5, 0.1); + FunctionTest>, TestType>( + optimizer, 0.5, 0.1); } -/** - * Test the FTML optimizer on the Styblinski-Tang function using arma::fmat as - * the objective type. - */ -TEST_CASE("FTMLStyblinskiTangFunctionFMatTest", "[FTMLTest]") +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("FTMLLogisticRegressionTest", "[FTML]", + coot::mat, coot::fmat) +{ + FTML optimizer(0.001, 1, 0.9, 0.999, 1e-8, 100000, 1e-5, true); + LogisticRegressionFunctionTest>( + optimizer, 0.003, 0.006); +} + +TEMPLATE_TEST_CASE("FTMLSphereFunctionTest", "[FTML]", + coot::mat, coot::fmat) +{ + FTML optimizer(0.001, 2, 0.9, 0.999, 1e-8, 500000, 1e-9, true); + FunctionTest>, TestType>( + optimizer, 0.5, 0.1); +} + +TEMPLATE_TEST_CASE("FTMLStyblinskiTangFunctionTest", "[FTML]", + coot::mat, coot::fmat) { FTML optimizer(0.001, 2, 0.9, 0.999, 1e-8, 100000, 1e-5, true); - FunctionTest(optimizer, 0.5, 0.1); + FunctionTest>, TestType>( + optimizer, 0.5, 0.1); } +#endif + // A test with sp_mat is not done, because FTML uses some parts internally that // assume the objective is dense. diff --git a/tests/gradient_descent_test.cpp b/tests/gradient_descent_test.cpp index 86225eb2b..ba07fbb52 100644 --- a/tests/gradient_descent_test.cpp +++ b/tests/gradient_descent_test.cpp @@ -17,20 +17,34 @@ using namespace ens; using namespace ens::test; -TEST_CASE("SimpleGDTestFunction", "[GradientDescentTest]") +TEMPLATE_TEST_CASE("SimpleGDTestFunction", "[GradientDescent]", + arma::mat, arma::fmat) { GradientDescent s(0.01, 5000000, 1e-9); - FunctionTest(s, 0.1, 0.01); + FunctionTest(s, 0.1, 0.01); } -TEST_CASE("GDRosenbrockTest", "[GradientDescentTest]") +TEMPLATE_TEST_CASE("GDRosenbrockTest", "[GradientDescent]", + arma::mat, arma::fmat) { GradientDescent s(0.001, 0, 1e-15); - FunctionTest(s, 0.01, 0.001); + FunctionTest(s, 0.01, 0.001); } -TEST_CASE("GDRosenbrockFMatTest", "[GradientDescentTest]") +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("SimpleGDTestFunction", "[GradientDescent]", + coot::mat, coot::fmat) +{ + GradientDescent s(0.01, 5000000, 1e-9); + FunctionTest(s, 0.1, 0.01); +} + +TEMPLATE_TEST_CASE("GDRosenbrockTest", "[GradientDescent]", + coot::mat, coot::fmat) { GradientDescent s(0.001, 0, 1e-15); - FunctionTest(s, 0.1, 0.01); + FunctionTest(s, 0.01, 0.001); } + +#endif diff --git a/tests/iqn_test.cpp b/tests/iqn_test.cpp index d961b005c..e3e04b65b 100644 --- a/tests/iqn_test.cpp +++ b/tests/iqn_test.cpp @@ -17,29 +17,26 @@ using namespace ens; using namespace ens::test; -/** - * Run IQN on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("IQNLogisticRegressionTest", "[IQNTest]") +TEMPLATE_TEST_CASE("IQNLogisticRegressionTest", "[IQN]", arma::mat, arma::fmat) { // Run on a couple of batch sizes. for (size_t batchSize = 1; batchSize < 9; batchSize += 4) { IQN iqn(0.01, batchSize, 5000, 0.01); - LogisticRegressionFunctionTest(iqn, 0.013, 0.016); + LogisticRegressionFunctionTest(iqn, 0.003, 0.006); } } -/** - * Run IQN on logistic regression and make sure the results are acceptable. Use - * arma::fmat. - */ -TEST_CASE("IQNLogisticRegressionFMatTest", "[IQNTest]") +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("IQNLogisticRegressionTest", "[IQN]", coot::mat, coot::fmat) { // Run on a couple of batch sizes. for (size_t batchSize = 1; batchSize < 9; batchSize += 4) { - IQN iqn(0.001, batchSize, 5000, 0.01); - LogisticRegressionFunctionTest(iqn, 0.013, 0.016); + IQN iqn(0.01, batchSize, 5000, 0.01); + LogisticRegressionFunctionTest>(iqn, 0.003, 0.006); } } + +#endif \ No newline at end of file diff --git a/tests/katyusha_test.cpp b/tests/katyusha_test.cpp index 8ca61ea59..c2408286e 100644 --- a/tests/katyusha_test.cpp +++ b/tests/katyusha_test.cpp @@ -16,85 +16,46 @@ using namespace ens; using namespace ens::test; -/** - * Run Katyusha on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("KatyushaLogisticRegressionTest", "[KatyushaTest]") +TEMPLATE_TEST_CASE("KatyushaLogisticRegressionTest", "[Katyusha]", + arma::mat, arma::fmat) { // Run with a couple of batch sizes. for (size_t batchSize = 30; batchSize < 45; batchSize += 5) { Katyusha optimizer(1.0, 10.0, batchSize, 100, 0, 1e-10, true); - LogisticRegressionFunctionTest(optimizer, 0.015, 0.015); + LogisticRegressionFunctionTest>( + optimizer, 0.015, 0.015); } } -/** - * Run Proximal Katyusha on logistic regression and make sure the results are - * acceptable. - */ -TEST_CASE("KatyushaProximalLogisticRegressionTest", "[KatyushaTest]") +TEMPLATE_TEST_CASE("KatyushaProximalLogisticRegressionTest", "[Katyusha]", + arma::mat, arma::fmat) { // Run with a couple of batch sizes. for (size_t batchSize = 30; batchSize < 45; batchSize += 5) { KatyushaProximal optimizer(1.0, 10.0, batchSize, 100, 0, 1e-10, true); - LogisticRegressionFunctionTest(optimizer, 0.015, 0.015); + LogisticRegressionFunctionTest>( + optimizer, 0.015, 0.015); } } -/** - * Run Katyusha on logistic regression and make sure the results are acceptable. - * Use arma::fmat. - */ -TEST_CASE("KatyushaLogisticRegressionFMatTest", "[KatyushaTest]") -{ - // Run with a couple of batch sizes. - for (size_t batchSize = 30; batchSize < 45; batchSize += 5) - { - Katyusha optimizer(1.0, 10.0, batchSize, 100, 0, 1e-10, true); - LogisticRegressionFunctionTest(optimizer, 0.015, 0.015); - } -} +#ifdef USE_COOT -/** - * Run Proximal Katyusha on logistic regression and make sure the results are - * acceptable. Use arma::fmat. - */ -TEST_CASE("KatyushaProximalLogisticRegressionFMatTest", "[KatyushaTest]") +TEMPLATE_TEST_CASE("KatyushaLogisticRegressionTest", "[Katyusha]", + coot::mat, coot::fmat) { - // Run with a couple of batch sizes. - for (size_t batchSize = 30; batchSize < 45; batchSize += 5) - { - KatyushaProximal optimizer(1.0, 10.0, batchSize, 100, 0, 1e-10, true); - LogisticRegressionFunctionTest(optimizer, 0.015, 0.015); - } + Katyusha optimizer(1.0, 10.0, 10, 100, 0, 1e-10, true); + LogisticRegressionFunctionTest>( + optimizer, 0.015, 0.015); } -/** - * Run Katyusha on logistic regression and make sure the results are acceptable. - * Use arma::sp_mat. - */ -TEST_CASE("KatyushaLogisticRegressionSpMatTest", "[KatyushaTest]") +TEMPLATE_TEST_CASE("KatyushaProximalLogisticRegressionTest", "[Katyusha]", + coot::mat, coot::fmat) { - // Run with a couple of batch sizes. - for (size_t batchSize = 30; batchSize < 45; batchSize += 5) - { - Katyusha optimizer(1.0, 10.0, batchSize, 100, 0, 1e-10, true); - LogisticRegressionFunctionTest(optimizer, 0.015, 0.015); - } + KatyushaProximal optimizer(1.0, 10.0, 30, 100, 0, 1e-10, true); + LogisticRegressionFunctionTest>( + optimizer, 0.015, 0.015); } -/** - * Run Proximal Katyusha on logistic regression and make sure the results are - * acceptable. Use arma::sp_mat. - */ -TEST_CASE("KatyushaProximalLogisticRegressionSpMatTest", "[KatyushaTest]") -{ - // Run with a couple of batch sizes. - for (size_t batchSize = 30; batchSize < 45; batchSize += 5) - { - KatyushaProximal optimizer(1.0, 10.0, batchSize, 100, 0, 1e-10, true); - LogisticRegressionFunctionTest(optimizer, 0.015, 0.015); - } -} +#endif diff --git a/tests/lbfgs_test.cpp b/tests/lbfgs_test.cpp index bcd10e08a..864a27e84 100644 --- a/tests/lbfgs_test.cpp +++ b/tests/lbfgs_test.cpp @@ -17,31 +17,19 @@ using namespace ens; using namespace ens::test; -/** - * Tests the L-BFGS optimizer using the Rosenbrock Function. - */ -TEST_CASE("RosenbrockFunctionTest", "[LBFGSTest]") +TEMPLATE_TEST_CASE("RosenbrockFunctionTest", "[LBFGS]", arma::mat) { L_BFGS lbfgs; lbfgs.MaxIterations() = 10000; - FunctionTest(lbfgs, 0.01, 0.001); -} -/** - * Test the L-BFGS optimizer using an arma::fmat with the Rosenbrock function. - */ -TEST_CASE("RosenbrockFunctionFloatTest", "[LBFGSTest]") -{ - L_BFGS lbfgs; - lbfgs.MaxIterations() = 10000; - FunctionTest(lbfgs, 0.1, 0.01); + FunctionTest(lbfgs, 0.01, 0.001); } /** * Test the L-BFGS optimizer using an arma::mat with the Rosenbrock function and * a sparse gradient. */ -TEST_CASE("RosenbrockFunctionSpGradTest", "[LBFGSTest]") +TEST_CASE("RosenbrockFunctionSpGradTest", "[LBFGS]") { RosenbrockFunction f; L_BFGS lbfgs; @@ -60,31 +48,24 @@ TEST_CASE("RosenbrockFunctionSpGradTest", "[LBFGSTest]") /** * Test the L-BFGS optimizer using an arma::sp_mat with the Rosenbrock function. */ -TEST_CASE("RosenbrockFunctionSpMatTest", "[LBFGSTest]") +TEST_CASE("RosenbrockFunctionSpMatTest", "[LBFGS]") { L_BFGS lbfgs; lbfgs.MaxIterations() = 10000; FunctionTest(lbfgs, 0.01, 0.001); } -/** - * Tests the L-BFGS optimizer using the Colville Function. - */ -TEST_CASE("ColvilleFunctionTest", "[LBFGSTest]") +TEMPLATE_TEST_CASE("ColvilleFunctionTest", "[LBFGS]", arma::mat) { L_BFGS lbfgs; lbfgs.MaxIterations() = 10000; - FunctionTest(lbfgs, 0.01, 0.001); + FunctionTest(lbfgs, 0.01, 0.001); } -/** - * Tests the L-BFGS optimizer using the Wood Function. - */ -TEST_CASE("WoodFunctionTest", "[LBFGSTest]") +TEMPLATE_TEST_CASE("WoodFunctionTest", "[LBFGS]", arma::mat) { L_BFGS lbfgs; - lbfgs.MaxIterations() = 10000; - FunctionTest(lbfgs, 0.01, 0.001); + FunctionTest(lbfgs, 0.01, 0.001); } /** @@ -92,18 +73,19 @@ TEST_CASE("WoodFunctionTest", "[LBFGSTest]") * is actually multiple tests, increasing the dimension by powers of 2, from 4 * dimensions to 1024 dimensions. */ -TEST_CASE("GeneralizedRosenbrockFunctionTest", "[LBFGSTest]") +TEMPLATE_TEST_CASE("GeneralizedRosenbrockFunctionTest", "[LBFGS]", + arma::mat, arma::fmat) { for (int i = 2; i < 10; i++) { // Dimension: powers of 2 int dim = std::pow(2.0, i); - GeneralizedRosenbrockFunction f(dim); + GeneralizedRosenbrockFunction> f(dim); L_BFGS lbfgs(20); lbfgs.MaxIterations() = 10000; - arma::vec coords = f.GetInitialPoint(); + TestType coords = f.GetInitialPoint(); lbfgs.Optimize(f, coords); double finalValue = f.Evaluate(coords); @@ -111,17 +93,74 @@ TEST_CASE("GeneralizedRosenbrockFunctionTest", "[LBFGSTest]") // Test the output to make sure it is correct. REQUIRE(finalValue == Approx(0.0).margin(1e-5)); for (int j = 0; j < dim; j++) - REQUIRE(coords(j) == Approx(1.0).epsilon(1e-7)); + REQUIRE(coords(j) == Approx(1.0).epsilon(1e-3)); } } -/** - * Tests the L-BFGS optimizer using the Rosenbrock-Wood combined function. This - * is a test on optimizing a matrix of coordinates. - */ -TEST_CASE("RosenbrockWoodFunctionTest", "[LBFGSTest]") +TEMPLATE_TEST_CASE("RosenbrockWoodFunctionTest", "[LBFGS]", + arma::mat) { L_BFGS lbfgs; lbfgs.MaxIterations() = 10000; - FunctionTest(lbfgs, 0.01, 0.001); + FunctionTest>, TestType>( + lbfgs, 0.01, 0.001); } + +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("RosenbrockFunctionTest", "[LBFGS]", coot::mat, coot::fmat) +{ + L_BFGS lbfgs; + lbfgs.MaxIterations() = 10000; + + FunctionTest(lbfgs, 0.01, 0.001); +} + +// /** +// * Tests the L-BFGS optimizer using the generalized Rosenbrock function. This +// * is actually multiple tests, increasing the dimension by powers of 2, from 4 +// * dimensions to 1024 dimensions. +// */ +// TEMPLATE_TEST_CASE("GeneralizedRosenbrockFunctionTest", "[LBFGS]", +// coot::mat, coot::fmat) +// { +// typedef typename TestType::elem_type ElemType; + +// for (int i = 2; i < 10; i++) +// { +// // Dimension: powers of 2 +// int dim = std::pow(2.0, i); + +// GeneralizedRosenbrockFunction> f(dim); +// L_BFGS lbfgs(20); +// lbfgs.MaxIterations() = 10000; + +// TestType coords = f.GetInitialPoint(); +// lbfgs.Optimize(f, coords); + +// double finalValue = f.Evaluate(coords); + +// // Test the output to make sure it is correct. +// REQUIRE(finalValue == Approx(0.0).margin(1e-5)); +// for (int j = 0; j < dim; j++) +// REQUIRE(ElemType(coords(j)) == Approx(1.0).epsilon(1e-3)); +// } +// } + +// TEMPLATE_TEST_CASE("WoodFunctionTest", "[LBFGS]", coot::mat) +// { +// L_BFGS lbfgs; +// lbfgs.MaxIterations() = 10000; +// FunctionTest(lbfgs, 0.01, 0.001); +// } + +// TEMPLATE_TEST_CASE("RosenbrockWoodFunctionTest", "[LBFGS]", +// coot::mat) +// { +// L_BFGS lbfgs; +// lbfgs.MaxIterations() = 10000; +// FunctionTest>, TestType>( +// lbfgs, 0.01, 0.001); +// } + +#endif diff --git a/tests/lookahead_test.cpp b/tests/lookahead_test.cpp index e682945e6..e271dfa00 100644 --- a/tests/lookahead_test.cpp +++ b/tests/lookahead_test.cpp @@ -15,10 +15,8 @@ using namespace ens; using namespace ens::test; -/** - * Test the Lookahead - Adam optimizer on the Sphere function. - */ -TEST_CASE("LookaheadAdamSphereFunctionTest", "[LookaheadTest]") +TEMPLATE_TEST_CASE("LookaheadAdamSphereFunctionTest", "[Lookahead]", + arma::mat) { Lookahead<> optimizer(0.5, 5, 100000, 1e-5, NoDecay(), false, true); optimizer.BaseOptimizer().StepSize() = 0.1; @@ -26,39 +24,83 @@ TEST_CASE("LookaheadAdamSphereFunctionTest", "[LookaheadTest]") optimizer.BaseOptimizer().Beta1() = 0.7; optimizer.BaseOptimizer().Tolerance() = 1e-15; // We allow a few trials. - FunctionTest(optimizer, 0.5, 0.2, 3); + FunctionTest>, TestType>( + optimizer, 0.5, 0.2, 3); } -/** - * Test the Lookahead - AdaGrad optimizer on the SphereFunction function. - */ -TEST_CASE("LookaheadAdaGradSphereFunction", "[LookaheadTest]") +TEMPLATE_TEST_CASE("LookaheadAdaGradSphereFunction", "[Lookahead]", + arma::mat) { AdaGrad adagrad(0.99, 1, 1e-8, 5, 1e-15, true); Lookahead optimizer(adagrad, 0.5, 5, 5000000, 1e-15, NoDecay(), false, true); - FunctionTest(optimizer, 0.5, 0.2, 3); + FunctionTest>, TestType>( + optimizer, 0.5, 0.2, 3); } -/** - * Run Lookahead - Adam on logistic regression and make sure the results are - * acceptable. - */ -TEST_CASE("LookaheadAdamLogisticRegressionTest","[LookaheadTest]") +TEMPLATE_TEST_CASE("LookaheadAdamLogisticRegressionTest", "[Lookahead]", + arma::mat) { Adam adam(0.001, 32, 0.9, 0.999, 1e-8, 5, 1e-19); Lookahead optimizer(adam, 0.5, 20, 100000, 1e-15, NoDecay(), false, true); - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); + LogisticRegressionFunctionTest>( + optimizer, 0.003, 0.006); } -/** - * Test the Lookahead - Adam optimizer on the Sphere function (float). - */ -TEST_CASE("LookaheadAdamSimpleSphereFunctionFloat", "[LookaheadTest]") +TEMPLATE_TEST_CASE("LookaheadAdamSimpleSphereFunction", "[Lookahead]", + arma::fmat) { Adam adam(0.001, 1, 0.9, 0.999, 1e-8, 5, 1e-19, false, true); Lookahead optimizer(adam, 0.5, 5, 100000, 1e-15, NoDecay(), false, true); - FunctionTest(optimizer, 0.5, 0.2, 3); + FunctionTest>, TestType>( + optimizer, 0.5, 0.2, 3); } + +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("LookaheadAdamSphereFunctionTest", "[Lookahead]", + coot::mat) +{ + Lookahead<> optimizer(0.5, 5, 100000, 1e-5, NoDecay(), false, true); + optimizer.BaseOptimizer().StepSize() = 0.1; + optimizer.BaseOptimizer().BatchSize() = 2; + optimizer.BaseOptimizer().Beta1() = 0.7; + optimizer.BaseOptimizer().Tolerance() = 1e-15; + // We allow a few trials. + FunctionTest>, TestType>( + optimizer, 0.5, 0.2, 3); +} + +TEMPLATE_TEST_CASE("LookaheadAdaGradSphereFunction", "[Lookahead]", + coot::mat) +{ + AdaGrad adagrad(0.99, 1, 1e-8, 5, 1e-15, true); + Lookahead optimizer(adagrad, 0.5, 5, 5000000, 1e-15, NoDecay(), + false, true); + FunctionTest>, TestType>( + optimizer, 0.5, 0.2, 3); +} + +TEMPLATE_TEST_CASE("LookaheadAdamLogisticRegressionTest", "[Lookahead]", + coot::mat) +{ + Adam adam(0.001, 32, 0.9, 0.999, 1e-8, 5, 1e-19); + Lookahead optimizer(adam, 0.5, 20, 100000, 1e-15, NoDecay(), + false, true); + LogisticRegressionFunctionTest>( + optimizer, 0.003, 0.006); +} + +TEMPLATE_TEST_CASE("LookaheadAdamSimpleSphereFunction", "[Lookahead]", + coot::fmat) +{ + Adam adam(0.001, 1, 0.9, 0.999, 1e-8, 5, 1e-19, false, true); + Lookahead optimizer(adam, 0.5, 5, 100000, 1e-15, NoDecay(), + false, true); + FunctionTest>, TestType>( + optimizer, 0.5, 0.2, 3); +} + +#endif diff --git a/tests/main.cpp b/tests/main.cpp index 4e522661a..18aa8b691 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -9,14 +9,23 @@ */ #include + +#define COOT_DEFAULT_BACKEND CUDA_BACKEND +#define COOT_USE_U64S64 +#define ENS_PRINT_INFO +#define ENS_PRINT_WARN #include -//#define CATCH_CONFIG_MAIN // catch.hpp will define main() -#define CATCH_CONFIG_RUNNER // we will define main() +// We will define main(). +#define CATCH_CONFIG_RUNNER #include "catch.hpp" int main(int argc, char** argv) { + #ifdef USE_COOT + coot::get_rt().init(true); + #endif + Catch::Session session; const int returnCode = session.applyCommandLine(argc, argv); // Check for a command line error. @@ -26,6 +35,10 @@ int main(int argc, char** argv) std::cout << "ensmallen version: " << ens::version::as_string() << std::endl; std::cout << "armadillo version: " << arma::arma_version::as_string() << std::endl; + #ifdef USE_COOT + std::cout << "bandicoot version: " << coot::coot_version::as_string() << std::endl; + #endif + // Use Catch2 command-line to set the random seed. // -rng-seed <'time'|number> // If a number is provided this is used directly as the seed. Alternatively diff --git a/tests/momentum_sgd_test.cpp b/tests/momentum_sgd_test.cpp index 9e333ae41..2e2979b38 100644 --- a/tests/momentum_sgd_test.cpp +++ b/tests/momentum_sgd_test.cpp @@ -16,14 +16,15 @@ using namespace ens; using namespace ens::test; -TEST_CASE("MomentumSGDSpeedUpTestFunction", "[MomentumSGDTest]") +TEMPLATE_TEST_CASE("MomentumSGDSpeedUpTestFunction", "[MomentumSGD]", + arma::mat, arma::fmat) { - SGDTestFunction f; + SGDTestFunction> f; MomentumUpdate momentumUpdate(0.7); MomentumSGD s(0.0003, 1, 2500000, 1e-9, true, momentumUpdate, NoDecay(), true, true); - arma::mat coordinates = f.GetInitialPoint(); + TestType coordinates = f.GetInitialPoint(); double result = s.Optimize(f, coordinates); REQUIRE(result == Approx(-1.0).epsilon(0.0015)); @@ -32,12 +33,12 @@ TEST_CASE("MomentumSGDSpeedUpTestFunction", "[MomentumSGDTest]") REQUIRE(coordinates(2) == Approx(0.0).margin(1e-6)); // Compare with SGD with vanilla update. - SGDTestFunction f1; + SGDTestFunction> f1; VanillaUpdate vanillaUpdate; StandardSGD s1(0.0003, 1, 2500000, 1e-9, true, vanillaUpdate, NoDecay(), true, true); - arma::mat coordinates1 = f1.GetInitialPoint(); + TestType coordinates1 = f1.GetInitialPoint(); double result1 = s1.Optimize(f1, coordinates1); // Result doesn't converge in 2500000 iterations. @@ -49,18 +50,19 @@ TEST_CASE("MomentumSGDSpeedUpTestFunction", "[MomentumSGDTest]") REQUIRE(result < result1); } -TEST_CASE("MomentumSGDGeneralizedRosenbrockTest", "[MomentumSGDTest]") +TEMPLATE_TEST_CASE("MomentumSGDGeneralizedRosenbrockTest", "[MomentumSGD]", + arma::mat) { // Loop over several variants. for (size_t i = 10; i < 50; i += 5) { // Create the generalized Rosenbrock function. - GeneralizedRosenbrockFunction f(i); + GeneralizedRosenbrockFunction> f(i); MomentumUpdate momentumUpdate(0.4); MomentumSGD s(0.0008, 1, 2500000, 1e-15, true, momentumUpdate, NoDecay(), true, true); - arma::mat coordinates = f.GetInitialPoint(); + TestType coordinates = f.GetInitialPoint(); double result = s.Optimize(f, coordinates); REQUIRE(result == Approx(0.0).margin(1e-4)); @@ -69,18 +71,18 @@ TEST_CASE("MomentumSGDGeneralizedRosenbrockTest", "[MomentumSGDTest]") } } -// Use arma::fmat. -TEST_CASE("MomentumSGDGeneralizedRosenbrockFMatTest", "[MomentumSGDTest]") +TEMPLATE_TEST_CASE("MomentumSGDGeneralizedRosenbrockTest", "[MomentumSGD]", + arma::fmat) { // Loop over several variants. for (size_t i = 10; i < 50; i += 5) { // Create the generalized Rosenbrock function. - GeneralizedRosenbrockFunction f(i); + GeneralizedRosenbrockFunction> f(i); MomentumUpdate momentumUpdate(0.1); MomentumSGD s(0.0002, 1, 10000000, 1e-15, true, momentumUpdate); - arma::fmat coordinates = f.GetInitialPoint(); + TestType coordinates = f.GetInitialPoint(); float result = s.Optimize(f, coordinates); REQUIRE(result == Approx(0.0).margin(1e-2)); @@ -89,18 +91,18 @@ TEST_CASE("MomentumSGDGeneralizedRosenbrockFMatTest", "[MomentumSGDTest]") } } -// Use arma::sp_mat. -TEST_CASE("MomentumSGDGeneralizedRosenbrockSpMatTest", "[MomentumSGDTest]") +TEMPLATE_TEST_CASE("MomentumSGDGeneralizedRosenbrockTest", + "[MomentumSGD]", arma::sp_mat) { // Loop over several variants. for (size_t i = 10; i < 50; i += 5) { // Create the generalized Rosenbrock function. - GeneralizedRosenbrockFunction f(i); + GeneralizedRosenbrockFunction> f(i); MomentumUpdate momentumUpdate(0.4); MomentumSGD s(0.0008, 1, 2500000, 1e-15, true, momentumUpdate); - arma::sp_mat coordinates = f.GetInitialPoint(); + TestType coordinates = f.GetInitialPoint(); double result = s.Optimize(f, coordinates); REQUIRE(result == Approx(0.0).margin(1e-4)); @@ -108,3 +110,88 @@ TEST_CASE("MomentumSGDGeneralizedRosenbrockSpMatTest", "[MomentumSGDTest]") REQUIRE(coordinates(j) == Approx(1.0).epsilon(1e-5)); } } + +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("MomentumSGDSpeedUpTestFunction", "[MomentumSGD]", + coot::mat, coot::fmat) +{ + typedef typename TestType::elem_type eT; + + SGDTestFunction> f; + MomentumUpdate momentumUpdate(0.7); + MomentumSGD s(0.0003, 1, 2500000, 1e-9, true, momentumUpdate, NoDecay(), true, + true); + + TestType coordinates = f.GetInitialPoint(); + double result = s.Optimize(f, coordinates); + + REQUIRE(result == Approx(-1.0).epsilon(0.0015)); + REQUIRE(eT(coordinates(0)) == Approx(0.0).margin(0.015)); + REQUIRE(eT(coordinates(1)) == Approx(0.0).margin(1e-6)); + REQUIRE(eT(coordinates(2)) == Approx(0.0).margin(1e-6)); + + // Compare with SGD with vanilla update. + SGDTestFunction> f1; + VanillaUpdate vanillaUpdate; + StandardSGD s1(0.0003, 1, 2500000, 1e-9, true, vanillaUpdate, NoDecay(), true, + true); + + TestType coordinates1 = f1.GetInitialPoint(); + double result1 = s1.Optimize(f1, coordinates1); + + // Result doesn't converge in 2500000 iterations. + REQUIRE((result1 + 1.0) > 0.05); + REQUIRE(eT(coordinates1(0)) >= 0.015); + REQUIRE(eT(coordinates1(1)) == Approx(0.0).margin(1e-6)); + REQUIRE(eT(coordinates1(2)) == Approx(0.0).margin(1e-6)); + + REQUIRE(result < result1); +} + +TEMPLATE_TEST_CASE("MomentumSGDGeneralizedRosenbrockTest", "[MomentumSGD]", + coot::mat) +{ + typedef typename TestType::elem_type eT; + + // Loop over several variants. + for (size_t i = 10; i < 50; i += 5) + { + // Create the generalized Rosenbrock function. + GeneralizedRosenbrockFunction> f(i); + MomentumUpdate momentumUpdate(0.4); + MomentumSGD s(0.0008, 1, 2500000, 1e-15, true, momentumUpdate, NoDecay(), + true, true); + + TestType coordinates = f.GetInitialPoint(); + double result = s.Optimize(f, coordinates); + + REQUIRE(result == Approx(0.0).margin(1e-4)); + for (size_t j = 0; j < i; ++j) + REQUIRE(eT(coordinates(j)) == Approx(1.0).epsilon(1e-5)); + } +} + +TEMPLATE_TEST_CASE("MomentumSGDGeneralizedRosenbrockTest", "[MomentumSGD]", + coot::fmat) +{ + typedef typename TestType::elem_type eT; + + // Loop over several variants. + for (size_t i = 10; i < 50; i += 5) + { + // Create the generalized Rosenbrock function. + GeneralizedRosenbrockFunction> f(i); + MomentumUpdate momentumUpdate(0.1); + MomentumSGD s(0.0002, 1, 10000000, 1e-15, true, momentumUpdate); + + TestType coordinates = f.GetInitialPoint(); + float result = s.Optimize(f, coordinates); + + REQUIRE(result == Approx(0.0).margin(1e-2)); + for (size_t j = 0; j < i; ++j) + REQUIRE(eT(coordinates(j)) == Approx(1.0).epsilon(1e-3)); + } +} + +#endif diff --git a/tests/nesterov_momentum_sgd_test.cpp b/tests/nesterov_momentum_sgd_test.cpp index 9b3b5e428..16d917c6e 100644 --- a/tests/nesterov_momentum_sgd_test.cpp +++ b/tests/nesterov_momentum_sgd_test.cpp @@ -16,17 +16,15 @@ using namespace ens; using namespace ens::test; -/** - * Tests the Nesterov Momentum SGD update policy. - */ -TEST_CASE("NesterovMomentumSGDSpeedUpTestFunction", "[NesterovMomentumSGDTest]") +TEMPLATE_TEST_CASE("NesterovMomentumSGDSpeedUpTestFunction", + "[NesterovMomentumSGD]", arma::mat, arma::fmat) { - SGDTestFunction f; + SGDTestFunction> f; NesterovMomentumUpdate nesterovMomentumUpdate(0.9); NesterovMomentumSGD s(0.0003, 1, 2500000, 1e-9, true, nesterovMomentumUpdate, NoDecay(), true, true); - arma::mat coordinates = f.GetInitialPoint(); + TestType coordinates = f.GetInitialPoint(); double result = s.Optimize(f, coordinates); REQUIRE(result == Approx(-1.0).margin(0.01)); @@ -35,21 +33,19 @@ TEST_CASE("NesterovMomentumSGDSpeedUpTestFunction", "[NesterovMomentumSGDTest]") REQUIRE(coordinates(2) == Approx(0.0).margin(1e-6)); } -/** - * Tests the Nesterov Momentum SGD with Generalized Rosenbrock Test. - */ -TEST_CASE("NesterovMomentumSGDGeneralizedRosenbrockTest", "[NesterovMomentumSGDTest]") +TEMPLATE_TEST_CASE("NesterovMomentumSGDGeneralizedRosenbrockTest", + "[NesterovMomentumSGD]", arma::mat) { // Loop over several variants. for (size_t i = 10; i < 50; i += 5) { // Create the generalized Rosenbrock function. - GeneralizedRosenbrockFunction f(i); + GeneralizedRosenbrockFunction> f(i); NesterovMomentumUpdate nesterovMomentumUpdate(0.9); NesterovMomentumSGD s(0.0001, 1, 0, 1e-15, true, nesterovMomentumUpdate, NoDecay(), true, true); - arma::mat coordinates = f.GetInitialPoint(); + TestType coordinates = f.GetInitialPoint(); double result = s.Optimize(f, coordinates); REQUIRE(result == Approx(0.0).margin(1e-4)); @@ -58,27 +54,23 @@ TEST_CASE("NesterovMomentumSGDGeneralizedRosenbrockTest", "[NesterovMomentumSGDT } } -/** - * Tests the Nesterov Momentum SGD with Generalized Rosenbrock Test. Uses - * arma::fmat. - */ -TEST_CASE("NesterovMomentumSGDGeneralizedRosenbrockFMatTest", - "[NesterovMomentumSGDTest]") +TEMPLATE_TEST_CASE("NesterovMomentumSGDGeneralizedRosenbrockTest", + "[NesterovMomentumSGD]", arma::fmat) { // Loop over several variants. for (size_t i = 10; i < 50; i += 5) { // Create the generalized Rosenbrock function. - GeneralizedRosenbrockFunction f(i); + GeneralizedRosenbrockFunction> f(i); NesterovMomentumUpdate nesterovMomentumUpdate(0.9); NesterovMomentumSGD s(0.00015, 1, 0, 1e-10, true, nesterovMomentumUpdate); size_t trial = 0; float result = std::numeric_limits::max(); - arma::fmat coordinates; + TestType coordinates; while (trial++ < 8 && result > 0.1) { - coordinates = f.GetInitialPoint(); + coordinates = f.GetInitialPoint(); result = s.Optimize(f, coordinates); } @@ -88,22 +80,18 @@ TEST_CASE("NesterovMomentumSGDGeneralizedRosenbrockFMatTest", } } -/** - * Tests the Nesterov Momentum SGD with Generalized Rosenbrock Test. Uses - * arma::sp_mat. - */ -TEST_CASE("NesterovMomentumSGDGeneralizedRosenbrockSpMatTest", - "[NesterovMomentumSGDTest]") +TEMPLATE_TEST_CASE("NesterovMomentumSGDGeneralizedRosenbrockTest", + "[NesterovMomentumSGD]", arma::sp_mat) { // Loop over several variants. for (size_t i = 10; i < 50; i += 5) { // Create the generalized Rosenbrock function. - GeneralizedRosenbrockFunction f(i); + GeneralizedRosenbrockFunction> f(i); NesterovMomentumUpdate nesterovMomentumUpdate(0.9); NesterovMomentumSGD s(0.0001, 1, 0, 1e-15, true, nesterovMomentumUpdate); - arma::sp_mat coordinates = f.GetInitialPoint(); + TestType coordinates = f.GetInitialPoint(); double result = s.Optimize(f, coordinates); REQUIRE(result == Approx(0.0).margin(1e-4)); @@ -111,3 +99,58 @@ TEST_CASE("NesterovMomentumSGDGeneralizedRosenbrockSpMatTest", REQUIRE(coordinates(j) == Approx(1.0).epsilon(0.003)); } } + +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("NesterovMomentumSGDGeneralizedRosenbrockTest", + "[NesterovMomentumSGD]", coot::mat) +{ + typedef typename TestType::elem_type eT; + + // Loop over several variants. + for (size_t i = 10; i < 15; i += 5) + { + // Create the generalized Rosenbrock function. + GeneralizedRosenbrockFunction> f(i); + NesterovMomentumUpdate nesterovMomentumUpdate(0.9); + NesterovMomentumSGD s(0.0001, 1, 0, 1e-15, true, nesterovMomentumUpdate, + NoDecay(), true, true); + + TestType coordinates = f.GetInitialPoint(); + double result = s.Optimize(f, coordinates); + + REQUIRE(result == Approx(0.0).margin(1e-4)); + for (size_t j = 0; j < i; ++j) + REQUIRE(eT(coordinates(j)) == Approx(1.0).epsilon(0.003)); + } +} + +TEMPLATE_TEST_CASE("NesterovMomentumSGDGeneralizedRosenbrockTest", + "[NesterovMomentumSGD]", coot::fmat) +{ + typedef typename TestType::elem_type eT; + + // Loop over several variants. + for (size_t i = 10; i < 15; i += 5) + { + // Create the generalized Rosenbrock function. + GeneralizedRosenbrockFunction> f(i); + NesterovMomentumUpdate nesterovMomentumUpdate(0.9); + NesterovMomentumSGD s(0.00015, 1, 0, 1e-10, true, nesterovMomentumUpdate); + + size_t trial = 0; + float result = std::numeric_limits::max(); + TestType coordinates; + while (trial++ < 8 && result > 0.1) + { + coordinates = f.GetInitialPoint(); + result = s.Optimize(f, coordinates); + } + + REQUIRE(result == Approx(0.0).margin(0.02)); + for (size_t j = 0; j < i; ++j) + REQUIRE(eT(coordinates(j)) == Approx(1.0).margin(0.05)); + } +} + +#endif diff --git a/tests/quasi_hyperbolic_momentum_sgd_test.cpp b/tests/quasi_hyperbolic_momentum_sgd_test.cpp index c1058a67b..6b15bf84c 100644 --- a/tests/quasi_hyperbolic_momentum_sgd_test.cpp +++ b/tests/quasi_hyperbolic_momentum_sgd_test.cpp @@ -1,6 +1,7 @@ /** * @file quasi_hyperbolic_momentum_sgd_test.cpp * @author Niteya Shah + * @author Marcus Edel * * ensmallen 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 @@ -14,50 +15,34 @@ using namespace ens; using namespace ens::test; -/** - * Tests the Quasi Hyperbolic Momentum SGD update policy. - */ -TEST_CASE("QHSphereFunction", "[QHMomentumSGDTest]") +TEMPLATE_TEST_CASE("QHSphereFunction", "[QHMomentumSGD]", + arma::mat, arma::fmat) { QHUpdate update(0.4, 0.9); - QHSGD s(0.0025, 1, 500000, 1e-10, true, update, NoDecay(), true, true); - FunctionTest(s, 0.03, 0.003); + QHSGD s(0.002, 1, 2500000, 1e-9, true, update, NoDecay(), true, true); + FunctionTest>, TestType>( + s, 0.03, 0.003); } -/** - * Tests the Quasi Hyperbolic Momentum SGD update policy using arma::fmat. - */ -TEST_CASE("QHSphereFunctionFMat", "[QHMomentumSGDTest]") -{ - QHUpdate update(0.9, 0.9); - QHSGD s(0.002, 1, 2500000, 1e-9, true, update); - FunctionTest(s, 0.3, 0.03); -} - -/** - * Tests the Quasi Hyperbolic Momentum SGD update policy using arma::sp_mat. - */ -TEST_CASE("QHSpMatTestSphereFunction", "[QHMomentumSGDTest]") +TEST_CASE("QHSpMatTestSphereFunction", "[QHMomentumSGD]") { QHUpdate update(0.9, 0.9); QHSGD s(0.002, 1, 2500000, 1e-15, true, update); s.ExactObjective() = true; - FunctionTest(s, 0.03, 0.003); + FunctionTest, arma::sp_mat>(s, 0.03, 0.003); } -/** - * Tests the Quasi hyperbolic SGD with Generalized Rosenbrock Test. - */ -TEST_CASE("QHSGDSGDGeneralizedRosenbrockTest", "[QHMomentumSGDTest]") -{ // Loop over several variants. +TEMPLATE_TEST_CASE("QHSGDSGDGeneralizedRosenbrockTest", "[QHMomentumSGD]", + arma::mat) +{ for (size_t i = 10; i < 50; i += 5) { // Create the generalized Rosenbrock function. - GeneralizedRosenbrockFunction f(i); + GeneralizedRosenbrockFunction> f(i); QHUpdate update(0.9, 0.99); QHSGD s(0.0005, 1, 2500000, 1e-15, true, update, NoDecay(), true, true); - arma::mat coordinates = f.GetInitialPoint(); + TestType coordinates = f.GetInitialPoint(); double result = s.Optimize(f, coordinates); REQUIRE(result == Approx(0.0).margin(1e-4)); @@ -65,3 +50,37 @@ TEST_CASE("QHSGDSGDGeneralizedRosenbrockTest", "[QHMomentumSGDTest]") REQUIRE(coordinates(j) == Approx(1.0).epsilon(1e-4)); } } + +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("QHSphereFunction", "[QHMomentumSGD]", + coot::mat, coot::fmat) +{ + QHUpdate update(0.4, 0.9); + QHSGD s(0.002, 1, 2500000, 1e-9, true, update, NoDecay(), true, true); + FunctionTest>, TestType>( + s, 0.03, 0.003); +} + +TEMPLATE_TEST_CASE("QHSGDSGDGeneralizedRosenbrockTest", "[QHMomentumSGD]", + coot::mat) +{ + typedef typename TestType::elem_type ElemType; + + for (size_t i = 10; i < 50; i += 5) + { + // Create the generalized Rosenbrock function. + GeneralizedRosenbrockFunction> f(i); + QHUpdate update(0.9, 0.99); + QHSGD s(0.0005, 1, 2500000, 1e-15, true, update, NoDecay(), true, true); + + TestType coordinates = f.GetInitialPoint(); + double result = s.Optimize(f, coordinates); + + REQUIRE(result == Approx(0.0).margin(1e-4)); + for (size_t j = 0; j < i; ++j) + REQUIRE(ElemType(coordinates(j)) == Approx(1.0).epsilon(1e-4)); + } +} + +#endif diff --git a/tests/rmsprop_test.cpp b/tests/rmsprop_test.cpp index 0d1c6dd8e..77950a050 100644 --- a/tests/rmsprop_test.cpp +++ b/tests/rmsprop_test.cpp @@ -16,31 +16,21 @@ using namespace ens; using namespace ens::test; -/** - * Run RMSProp on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("RMSPropLogisticRegressionTest", "[rmsprop]") +TEMPLATE_TEST_CASE("RMSPropLogisticRegressionTest", "[RMSProp]", + arma::mat, arma::fmat, arma::sp_mat) { RMSProp optimizer; - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); + LogisticRegressionFunctionTest>(optimizer, 0.003, 0.006); } -/** - * Run RMSProp on logistic regression and make sure the results are acceptable. - * Use arma::fmat. - */ -TEST_CASE("RMSPropLogisticRegressionFMatTest", "[rmsprop]") -{ - RMSProp optimizer; - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); -} +#ifdef USE_COOT -/** - * Run RMSProp on logistic regression and make sure the results are acceptable. - * Use arma::sp_mat. - */ -TEST_CASE("RMSPropLogisticRegressionSpMatTest", "[rmsprop]") +TEMPLATE_TEST_CASE("RMSPropLogisticRegressionTest", "[RMSProp]", + coot::mat, coot::fmat) { RMSProp optimizer; - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); + LogisticRegressionFunctionTest>(optimizer, 0.003, 0.006); } + +#endif + diff --git a/tests/sarah_test.cpp b/tests/sarah_test.cpp index 3877c27dc..63f0a5306 100644 --- a/tests/sarah_test.cpp +++ b/tests/sarah_test.cpp @@ -16,86 +16,54 @@ using namespace ens; using namespace ens::test; -/** - * Run SARAH on logistic regression and make sure the results are - * acceptable. - */ -TEST_CASE("SARAHLogisticRegressionTest","[SARAHTest]") +TEMPLATE_TEST_CASE("SARAHLogisticRegressionTest", "[SARAH]", + arma::mat, arma::fmat) { // Run SARAH with a couple of batch sizes. for (size_t batchSize = 35; batchSize < 45; batchSize += 5) { SARAH optimizer(0.01, batchSize, 250, 0, 1e-5, true); - LogisticRegressionFunctionTest(optimizer, 0.015, 0.015); + LogisticRegressionFunctionTest>( + optimizer, 0.003, 0.006); } } -/** - * Run SARAH_Plus on logistic regression and make sure the results are - * acceptable. - */ -TEST_CASE("SARAHPlusLogisticRegressionTest","[SARAHTest]") +TEMPLATE_TEST_CASE("SARAHPlusLogisticRegressionTest", "[SARAH]", + arma::mat, arma::fmat) { // Run SARAH_Plus with a couple of batch sizes. for (size_t batchSize = 35; batchSize < 45; batchSize += 5) { SARAH_Plus optimizer(0.01, batchSize, 250, 0, 1e-5, true); - LogisticRegressionFunctionTest(optimizer, 0.015, 0.015); - } -} - -/** - * Run SARAH on logistic regression and make sure the results are - * acceptable. Use arma::fmat. - */ -TEST_CASE("SARAHLogisticRegressionFMatTest","[SARAHTest]") -{ - // Run SARAH with a couple of batch sizes. - for (size_t batchSize = 35; batchSize < 45; batchSize += 5) - { - SARAH optimizer(0.01, batchSize, 250, 0, 1e-5, true); - LogisticRegressionFunctionTest(optimizer, 0.015, 0.015); + LogisticRegressionFunctionTest>( + optimizer, 0.015, 0.015); } } -/** - * Run SARAH_Plus on logistic regression and make sure the results are - * acceptable. Use arma::fmat. - */ -TEST_CASE("SARAHPlusLogisticRegressionFMatTest","[SARAHTest]") -{ - // Run SARAH_Plus with a couple of batch sizes. - for (size_t batchSize = 35; batchSize < 45; batchSize += 5) - { - SARAH_Plus optimizer(0.01, batchSize, 250, 0, 1e-5, true); - LogisticRegressionFunctionTest(optimizer, 0.015, 0.015); - } -} +#ifdef USE_COOT -/** - * Run SARAH on logistic regression and make sure the results are - * acceptable. Use arma::sp_mat. - */ -TEST_CASE("SARAHLogisticRegressionSpMatTest","[SARAHTest]") +TEMPLATE_TEST_CASE("SARAHLogisticRegressionTest", "[SARAH]", + coot::mat, coot::fmat) { // Run SARAH with a couple of batch sizes. for (size_t batchSize = 35; batchSize < 45; batchSize += 5) { SARAH optimizer(0.01, batchSize, 250, 0, 1e-5, true); - LogisticRegressionFunctionTest(optimizer, 0.015, 0.015); + LogisticRegressionFunctionTest>( + optimizer, 0.015, 0.015); } } -/** - * Run SARAH_Plus on logistic regression and make sure the results are - * acceptable. Use arma::sp_mat. - */ -TEST_CASE("SARAHPlusLogisticRegressionSpMatTest","[SARAHTest]") +TEMPLATE_TEST_CASE("SARAHPlusLogisticRegressionTest", "[SARAH]", + coot::mat, coot::fmat) { // Run SARAH_Plus with a couple of batch sizes. for (size_t batchSize = 35; batchSize < 45; batchSize += 5) { SARAH_Plus optimizer(0.01, batchSize, 250, 0, 1e-5, true); - LogisticRegressionFunctionTest(optimizer, 0.015, 0.015); + LogisticRegressionFunctionTest>( + optimizer, 0.015, 0.015); } } + +#endif diff --git a/tests/sgd_test.cpp b/tests/sgd_test.cpp index c413b8e80..f79fc05ef 100644 --- a/tests/sgd_test.cpp +++ b/tests/sgd_test.cpp @@ -14,46 +14,27 @@ #include "catch.hpp" #include "test_function_tools.hpp" -using namespace std; using namespace arma; using namespace ens; using namespace ens::test; -TEST_CASE("GeneralizedRosenbrockTest", "[SGDTest]") +template +void SGDGeneralizedRosenbrockTest() { - // Loop over several variants. - for (size_t i = 10; i < 50; i += 5) - { - // Create the generalized Rosenbrock function. - GeneralizedRosenbrockFunction f(i); - - VanillaUpdate vanillaUpdate; - StandardSGD s(0.001, 1, 0, 1e-15, true, vanillaUpdate, NoDecay(), true, - true); - - arma::mat coordinates = f.GetInitialPoint(); - double result = s.Optimize(f, coordinates); - - REQUIRE(result == Approx(0.0).margin(1e-10)); - for (size_t j = 0; j < i; ++j) - REQUIRE(coordinates(j) == Approx(1.0).epsilon(1e-5)); - } -} + typedef typename MatType::elem_type ElemType; -TEST_CASE("GeneralizedRosenbrockTestFloat", "[SGDTest]") -{ // Loop over several variants. for (size_t i = 10; i < 50; i += 5) { // Create the generalized Rosenbrock function. - GeneralizedRosenbrockFunction f(i); + GeneralizedRosenbrockFunction f(i); // Allow a few trials. for (size_t trial = 0; trial < 5; ++trial) { StandardSGD s(0.001, 1, 0, 1e-15, true); - arma::fmat coordinates = f.GetInitialPoint(); + MatType coordinates = f.GetInitialPoint(); float result = s.Optimize(f, coordinates); if (trial != 4) @@ -62,15 +43,68 @@ TEST_CASE("GeneralizedRosenbrockTestFloat", "[SGDTest]") continue; for (size_t j = 0; j < i; ++j) { - if (coordinates(j) != Approx(1.0).epsilon(1e-3)) + if (ElemType(coordinates(j)) != Approx(1.0).epsilon(1e-3)) continue; } } REQUIRE(result == Approx(0.0).margin(1e-5)); for (size_t j = 0; j < i; ++j) - REQUIRE(coordinates(j) == Approx(1.0).epsilon(1e-3)); + REQUIRE(ElemType(coordinates(j)) == Approx(1.0).epsilon(1e-3)); break; } } } + +template +void SGDLogisticRegressionTest() +{ + MatType data, testData, shuffledData; + LabelsType responses, testResponses, shuffledResponses; + + LogisticRegressionTestData(data, testData, shuffledData, + responses, testResponses, shuffledResponses); + LogisticRegressionFunction lr( + shuffledData, shuffledResponses, 0.5); + + StandardSGD sgd; + MatType coordinates = lr.GetInitialPoint(); + sgd.Optimize(lr, coordinates); + + // Ensure that the error is close to zero. + const double acc = lr.ComputeAccuracy(data, responses, coordinates); + + REQUIRE(acc == Approx(100.0).epsilon(0.003)); // 0.3% error tolerance. + + const double testAcc = lr.ComputeAccuracy(testData, testResponses, + coordinates); + REQUIRE(testAcc == Approx(100.0).epsilon(0.006)); // 0.6% error tolerance. +} + +TEMPLATE_TEST_CASE("SGDGeneralizedRosenbrock", "[SGD]", + arma::mat, arma::fmat) +{ + SGDGeneralizedRosenbrockTest(); +} + +TEMPLATE_TEST_CASE("SGDLogisticRegressionTest", "[SGD]", + arma::mat) +{ + SGDLogisticRegressionTest>(); +} + +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("SGDGeneralizedRosenbrock", "[SGD]", + coot::mat, coot::fmat) +{ + SGDGeneralizedRosenbrockTest(); +} + +TEMPLATE_TEST_CASE("SGDLogisticRegressionTest", "[SGD]", + coot::mat) +{ + SGDLogisticRegressionTest>(); +} + +#endif diff --git a/tests/sgdr_test.cpp b/tests/sgdr_test.cpp index 7284d534b..b1e3f4d5a 100644 --- a/tests/sgdr_test.cpp +++ b/tests/sgdr_test.cpp @@ -16,13 +16,11 @@ using namespace ens; using namespace ens::test; -/* - * Test that the step size resets after a specified number of epochs. - */ -TEST_CASE("SGDRCyclicalResetTest","[SGDRTest]") +TEMPLATE_TEST_CASE("SGDRCyclicalResetTest","[SGDR]", + arma::mat, arma::fmat) { const double stepSize = 0.5; - arma::mat iterate; + TestType iterate; // Now run cyclical decay policy with a couple of multiplicators and initial // restarts. @@ -33,7 +31,7 @@ TEST_CASE("SGDRCyclicalResetTest","[SGDRTest]") double epochStepSize = stepSize; CyclicalDecay cyclicalDecay(restart, double(mult), stepSize); - CyclicalDecay::Policy p(cyclicalDecay); + CyclicalDecay::Policy p(cyclicalDecay); cyclicalDecay.EpochBatches() = (double) 1000 / 10; // Create all restart epochs. @@ -45,7 +43,7 @@ TEST_CASE("SGDRCyclicalResetTest","[SGDRTest]") for (size_t i = 0; i < 1000; ++i) { p.Update(iterate, epochStepSize, iterate); - if (i <= restart || arma::accu(arma::find(nextRestart == i)) > 0) + if (i <= restart || accu(find(nextRestart == i)) > 0) { REQUIRE(epochStepSize == stepSize); } @@ -54,43 +52,30 @@ TEST_CASE("SGDRCyclicalResetTest","[SGDRTest]") } } -/** - * Run SGDR on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("SGDRLogisticRegressionTest","[SGDRTest]") +TEMPLATE_TEST_CASE("SGDRLogisticRegressionTest","[SGDR]", + arma::mat, arma::fmat) { // Run SGDR with a couple of batch sizes. for (size_t batchSize = 5; batchSize < 50; batchSize += 5) { SGDR<> sgdr(50, 2.0, batchSize, 0.01, 10000, 1e-3); - LogisticRegressionFunctionTest(sgdr, 0.003, 0.006); + LogisticRegressionFunctionTest>( + sgdr, 0.003, 0.006); } } -/** - * Run SGDR on logistic regression and make sure the results are acceptable. - * Use arma::fmat. - */ -TEST_CASE("SGDRLogisticRegressionFMatTest","[SGDRTest]") -{ - // Run SGDR with a couple of batch sizes. - for (size_t batchSize = 5; batchSize < 50; batchSize += 5) - { - SGDR<> sgdr(50, 2.0, batchSize, 0.01, 10000, 1e-3); - LogisticRegressionFunctionTest(sgdr, 0.015, 0.03, 3); - } -} +#ifdef USE_COOT -/** - * Run SGDR on logistic regression and make sure the results are acceptable. - * Use arma::sp_mat. - */ -TEST_CASE("SGDRLogisticRegressionSpMatTest","[SGDRTest]") +TEMPLATE_TEST_CASE("SGDRLogisticRegressionTest","[SGDR]", + coot::mat, coot::fmat) { // Run SGDR with a couple of batch sizes. for (size_t batchSize = 5; batchSize < 50; batchSize += 5) { SGDR<> sgdr(50, 2.0, batchSize, 0.01, 10000, 1e-3); - LogisticRegressionFunctionTest(sgdr, 0.003, 0.006); + LogisticRegressionFunctionTest>( + sgdr, 0.003, 0.006); } } + +#endif diff --git a/tests/smorms3_test.cpp b/tests/smorms3_test.cpp index 896c5252c..3d2b48ee7 100644 --- a/tests/smorms3_test.cpp +++ b/tests/smorms3_test.cpp @@ -17,21 +17,21 @@ using namespace ens; using namespace ens::test; -/** - * Run SMORMS3 on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("SMORMS3LogisticRegressionTest","[SMORMS3Test]") +TEMPLATE_TEST_CASE("SMORMS3LogisticRegressionTest", "[SMORMS3]", + arma::mat, arma::fmat) { SMORMS3 smorms3; - LogisticRegressionFunctionTest(smorms3, 0.003, 0.006); + LogisticRegressionFunctionTest(smorms3, 0.003, 0.006); } -/** - * Run SMORMS3 on logistic regression and make sure the results are acceptable. - * Use arma::fmat. - */ -TEST_CASE("SMORMS3LogisticRegressionFMatTest","[SMORMS3Test]") +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("SMORMS3LogisticRegressionTest", "[SMORMS3]", + coot::mat, coot::fmat) { SMORMS3 smorms3; - LogisticRegressionFunctionTest(smorms3, 0.003, 0.006); + LogisticRegressionFunctionTest>( + smorms3, 0.003, 0.006); } + +#endif diff --git a/tests/snapshot_ensembles.cpp b/tests/snapshot_ensembles.cpp index 498d8c06b..eca5ecd96 100644 --- a/tests/snapshot_ensembles.cpp +++ b/tests/snapshot_ensembles.cpp @@ -19,10 +19,11 @@ using namespace ens::test; /* * Test that the step size resets after a specified number of epochs. */ -TEST_CASE("SnapshotEnsemblesResetTest","[SnapshotEnsemblesTest]") +TEMPLATE_TEST_CASE("SnapshotEnsemblesResetTest","[SnapshotEnsembles]", + arma::mat) { const double stepSize = 0.5; - arma::mat iterate; + TestType iterate; // Now run cyclical decay policy with a couple of multiplicators and initial // restarts. @@ -34,7 +35,7 @@ TEST_CASE("SnapshotEnsemblesResetTest","[SnapshotEnsemblesTest]") SnapshotEnsembles snapshotEnsembles(restart, double(mult), stepSize, 1000, 2); - SnapshotEnsembles::Policy p(snapshotEnsembles); + SnapshotEnsembles::Policy p(snapshotEnsembles); snapshotEnsembles.EpochBatches() = 10 / (double)1000; // Create all restart epochs. @@ -57,45 +58,54 @@ TEST_CASE("SnapshotEnsemblesResetTest","[SnapshotEnsemblesTest]") } } -/** - * Run SGDR with snapshot ensembles on logistic regression and make sure the - * results are acceptable. - */ -TEST_CASE("SnapshotEnsemblesLogisticRegressionTest","[SnapshotEnsemblesTest]") +TEMPLATE_TEST_CASE("SnapshotEnsemblesLogisticRegressionTest", + "[SnapshotEnsembles]", arma::mat) { // Run SGDR with snapshot ensembles on a couple of batch sizes. for (size_t batchSize = 5; batchSize < 50; batchSize += 5) { SnapshotSGDR<> sgdr(50, 2.0, batchSize, 0.01, 10000, 1e-3); - LogisticRegressionFunctionTest(sgdr, 0.003, 0.006); + LogisticRegressionFunctionTest>( + sgdr, 0.003, 0.006); } } -/** - * Run SGDR with snapshot ensembles on logistic regression and make sure the - * results are acceptable. Use arma::fmat. - */ -TEST_CASE("SnapshotEnsemblesLogisticRegressionFMatTest","[SnapshotEnsemblesTest]") +TEMPLATE_TEST_CASE("SnapshotEnsemblesLogisticRegressionTest", + "[SnapshotEnsembles]", arma::fmat) { // Run SGDR with snapshot ensembles on a couple of batch sizes. for (size_t batchSize = 5; batchSize < 50; batchSize += 5) { SnapshotSGDR<> sgdr(50, 2.0, batchSize, 0.01, 10000, 1e-3); - LogisticRegressionFunctionTest(sgdr, 0.03, 0.06, 3); + LogisticRegressionFunctionTest>( + sgdr, 0.03, 0.06, 3); } } -/** - * Run SGDR with snapshot ensembles on logistic regression and make sure the - * results are acceptable. Use arma::sp_mat. - */ -TEST_CASE("SnapshotEnsemblesLogisticRegressionSpMatTest", - "[SnapshotEnsemblesTest]") +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("SnapshotEnsemblesLogisticRegressionTest", + "[SnapshotEnsembles]", coot::mat) { // Run SGDR with snapshot ensembles on a couple of batch sizes. - for (size_t batchSize = 5; batchSize < 50; batchSize += 5) + for (size_t batchSize = 25; batchSize < 30; batchSize += 5) { SnapshotSGDR<> sgdr(50, 2.0, batchSize, 0.01, 10000, 1e-3); - LogisticRegressionFunctionTest(sgdr, 0.003, 0.006); + LogisticRegressionFunctionTest>( + sgdr, 0.003, 0.006); } } + +TEMPLATE_TEST_CASE("SnapshotEnsemblesLogisticRegressionTest", + "[SnapshotEnsembles]", coot::fmat) +{ + // Run SGDR with snapshot ensembles on a couple of batch sizes. + for (size_t batchSize = 25; batchSize < 30; batchSize += 5) + { + SnapshotSGDR<> sgdr(50, 2.0, batchSize, 0.01, 10000, 1e-3); + LogisticRegressionFunctionTest>( + sgdr, 0.03, 0.06, 3); + } +} + +#endif diff --git a/tests/spalera_sgd_test.cpp b/tests/spalera_sgd_test.cpp index e9c8358ce..86b9f9432 100644 --- a/tests/spalera_sgd_test.cpp +++ b/tests/spalera_sgd_test.cpp @@ -16,30 +16,30 @@ using namespace ens; using namespace ens::test; -/** - * Run SPALeRA SGD on logistic regression and make sure the results are - * acceptable. - */ -TEST_CASE("LogisticRegressionTest","[SPALeRASGDTest]") +TEMPLATE_TEST_CASE("LogisticRegressionTest","[SPALeRASGD]", + arma::mat, arma::fmat) { // Run SPALeRA SGD with a couple of batch sizes. for (size_t batchSize = 30; batchSize < 50; batchSize += 5) { SPALeRASGD<> optimizer(0.05 / batchSize, batchSize, 10000, 1e-4); - LogisticRegressionFunctionTest(optimizer, 0.015, 0.024, 3); + LogisticRegressionFunctionTest>( + optimizer, 0.015, 0.024, 3); } } -/** - * Run SPALeRA SGD on logistic regression and make sure the results are - * acceptable. Use arma::fmat. - */ -TEST_CASE("LogisticRegressionFMatTest","[SPALeRASGDTest]") +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("LogisticRegressionTest","[SPALeRASGD]", + coot::mat, coot::fmat) { // Run SPALeRA SGD with a couple of batch sizes. for (size_t batchSize = 30; batchSize < 50; batchSize += 5) { SPALeRASGD<> optimizer(0.05 / batchSize, batchSize, 10000, 1e-4); - LogisticRegressionFunctionTest(optimizer, 0.015, 0.024, 3); + LogisticRegressionFunctionTest>( + optimizer, 0.015, 0.024, 3); } } + +#endif diff --git a/tests/spsa_test.cpp b/tests/spsa_test.cpp index 89d1d56af..ba6e1ef9b 100644 --- a/tests/spsa_test.cpp +++ b/tests/spsa_test.cpp @@ -19,49 +19,63 @@ using namespace arma; using namespace ens; using namespace ens::test; -/** - * Test the SPSA optimizer on the Sphere function. - */ -TEST_CASE("SPSASphereFunctionTest", "[SPSATest]") +TEMPLATE_TEST_CASE("SPSASphereFunctionTest", "[SPSA]", arma::mat, arma::fmat) { SPSA optimizer(0.1, 0.102, 0.16, 0.3, 100000, 0); - FunctionTest(optimizer, 1.0, 0.1); + FunctionTest>, TestType>( + optimizer, 1.0, 0.1); } -/** - * Test the SPSA optimizer on the Sphere function using arma::fmat. - */ -TEST_CASE("SPSASphereFunctionFMatTest", "[SPSATest]") +TEMPLATE_TEST_CASE("SPSAMatyasFunctionTest", "[SPSA]", arma::mat, arma::fmat) { SPSA optimizer(0.1, 0.102, 0.16, 0.3, 100000, 0); - FunctionTest(optimizer, 1.0, 0.1); + FunctionTest(optimizer, 0.1, 0.01); } -/** - * Test the SPSA optimizer on the Sphere function using arma::sp_mat. - */ -TEST_CASE("SPSASphereFunctionSpMatTest", "[SPSATest]") +TEMPLATE_TEST_CASE("SPSALogisticRegressionTest", "[SPSA]", + arma::mat) +{ + // We allow 10 trials, because SPSA is definitely not guaranteed to + // converge. + SPSA optimizer(0.5, 0.102, 0.002, 0.3, 5000, 1e-8); + LogisticRegressionFunctionTest>( + optimizer, 0.003, 0.006, 10); +} + +#if ARMA_VERSION_MAJOR > 9 ||\ + (ARMA_VERSION_MAJOR == 9 && ARMA_VERSION_MINOR >= 400) + +TEMPLATE_TEST_CASE("SPSASphereFunctionSpMatTest", "[SPSA]", arma::sp_mat) { SPSA optimizer(0.1, 0.102, 0.16, 0.3, 100000, 0); - FunctionTest(optimizer, 1.0, 0.1); + FunctionTest>, TestType>( + optimizer, 1.0, 0.1); } -/** - * Test the SPSA optimizer on the Matyas function. - */ -TEST_CASE("SPSAMatyasFunctionTest", "[SPSATest]") +#endif + +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("SPSASphereFunctionTest", "[SPSA]", coot::mat, coot::fmat) { SPSA optimizer(0.1, 0.102, 0.16, 0.3, 100000, 0); - FunctionTest(optimizer, 0.1, 0.01); + FunctionTest>, TestType>( + optimizer, 1.0, 0.1); } -/** - * Run SPSA on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("SPSALogisticRegressionTest", "[SPSATest]") +TEMPLATE_TEST_CASE("SPSAMatyasFunctionTest", "[SPSA]", coot::mat, coot::fmat) +{ + SPSA optimizer(0.1, 0.102, 0.16, 0.3, 100000, 0); + FunctionTest(optimizer, 0.1, 0.01); +} + +TEMPLATE_TEST_CASE("SPSALogisticRegressionTest", "[SPSA]", coot::mat) { // We allow 10 trials, because SPSA is definitely not guaranteed to // converge. SPSA optimizer(0.5, 0.102, 0.002, 0.3, 5000, 1e-8); - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006, 10); + LogisticRegressionFunctionTest>( + optimizer, 0.003, 0.006, 10); } + +#endif diff --git a/tests/svrg_test.cpp b/tests/svrg_test.cpp index 4b9f08888..8916a7347 100644 --- a/tests/svrg_test.cpp +++ b/tests/svrg_test.cpp @@ -19,7 +19,7 @@ using namespace ens::test; /** * Run SVRG on logistic regression and make sure the results are acceptable. */ -TEST_CASE("SVRGLogisticRegressionTest", "[SVRGTest]") +TEST_CASE("SVRGLogisticRegressionTest", "[SVRG]") { // Run SVRG with a couple of batch sizes. for (size_t batchSize = 35; batchSize < 50; batchSize += 5) @@ -32,7 +32,7 @@ TEST_CASE("SVRGLogisticRegressionTest", "[SVRGTest]") /** * Run SVRG_BB on logistic regression and make sure the results are acceptable. */ -TEST_CASE("SVRGBBLogisticRegressionTest", "[SVRGTest]") +TEST_CASE("SVRGBBLogisticRegressionTest", "[SVRG]") { // Run SVRG with a couple of batch sizes. for (size_t batchSize = 35; batchSize < 50; batchSize += 5) @@ -47,7 +47,7 @@ TEST_CASE("SVRGBBLogisticRegressionTest", "[SVRGTest]") * Run SVRG on logistic regression and make sure the results are acceptable. * Use arma::fmat. */ -TEST_CASE("SVRGLogisticRegressionFMatTest", "[SVRGTest]") +TEST_CASE("SVRGLogisticRegressionFMatTest", "[SVRG]") { // Run SVRG with a couple of batch sizes. for (size_t batchSize = 35; batchSize < 50; batchSize += 5) @@ -61,7 +61,7 @@ TEST_CASE("SVRGLogisticRegressionFMatTest", "[SVRGTest]") * Run SVRG_BB on logistic regression and make sure the results are acceptable. * Use arma::fmat. */ -TEST_CASE("SVRGBBLogisticRegressionFMatTest", "[SVRGTest]") +TEST_CASE("SVRGBBLogisticRegressionFMatTest", "[SVRG]") { // Run SVRG_BB with a couple of batch sizes. for (size_t batchSize = 35; batchSize < 50; batchSize += 5) @@ -76,7 +76,7 @@ TEST_CASE("SVRGBBLogisticRegressionFMatTest", "[SVRGTest]") * Run SVRG on logistic regression and make sure the results are acceptable. * Use arma::sp_mat. */ -TEST_CASE("SVRGLogisticRegressionSpMatTest", "[SVRGTest]") +TEST_CASE("SVRGLogisticRegressionSpMatTest", "[SVRG]") { // Run SVRG with a couple of batch sizes. for (size_t batchSize = 35; batchSize < 50; batchSize += 5) @@ -90,7 +90,7 @@ TEST_CASE("SVRGLogisticRegressionSpMatTest", "[SVRGTest]") * Run SVRG_BB on logistic regression and make sure the results are acceptable. * Use arma::sp_mat. */ -TEST_CASE("SVRGBBLogisticRegressionSpMatTest", "[SVRGTest]") +TEST_CASE("SVRGBBLogisticRegressionSpMatTest", "[SVRG]") { // Run SVRG with a couple of batch sizes. for (size_t batchSize = 35; batchSize < 50; batchSize += 5) @@ -99,4 +99,4 @@ TEST_CASE("SVRGBBLogisticRegressionSpMatTest", "[SVRGTest]") SVRGUpdate(), BarzilaiBorweinDecay(0.1)); LogisticRegressionFunctionTest(optimizer, 0.015, 0.015); } -} +} \ No newline at end of file diff --git a/tests/swats_test.cpp b/tests/swats_test.cpp index 261bd7243..ca62a1562 100644 --- a/tests/swats_test.cpp +++ b/tests/swats_test.cpp @@ -17,48 +17,64 @@ using namespace ens; using namespace ens::test; -/** - * Run SWATS on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("SWATSLogisticRegressionTestFunction", "[SWATSTest]") +TEMPLATE_TEST_CASE("SWATSLogisticRegressionTestFunction", "[SWATS]", + arma::mat, arma::fmat) { SWATS optimizer(1e-3, 10, 0.9, 0.999, 1e-6, 600000, 1e-9, true); // We allow a few trials in case of poor convergence. - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006, 5); + LogisticRegressionFunctionTest>( + optimizer, 0.003, 0.006, 5); } -/** - * Test the SWATS optimizer on the Sphere function. - */ -TEST_CASE("SWATSSphereFunctionTest", "[SWATSTest]") +TEMPLATE_TEST_CASE("SWATSSphereFunctionTest", "[SWATS]", + arma::mat, arma::fmat) { SWATS optimizer(1e-3, 2, 0.9, 0.999, 1e-6, 500000, 1e-9, true); - FunctionTest(optimizer, 1.0, 0.1); + FunctionTest>, TestType>( + optimizer, 1.0, 0.1); } -/** - * Test the SWATS optimizer on the Styblinski-Tang function. - */ -TEST_CASE("SWATSStyblinskiTangFunctionTest", "[SWATSTest]") +TEMPLATE_TEST_CASE("SWATSStyblinskiTangFunctionFMatTest", "[SWATS]", + arma::mat, arma::fmat) { SWATS optimizer(1e-3, 2, 0.9, 0.999, 1e-6, 500000, 1e-9, true); - FunctionTest(optimizer, 0.3, 0.03); + FunctionTest>, + TestType>(optimizer, 3.0, 0.3); } /** - * Test the SWATS optimizer on the Styblinski-Tang function. Use arma::fmat. + * Test the SWATS optimizer on the Styblinski-Tang function. Use arma::sp_mat. */ -TEST_CASE("SWATSStyblinskiTangFunctionFMatTest", "[SWATSTest]") +TEST_CASE("SWATSStyblinskiTangFunctionSpMatTest", "[SWATSTest]") { SWATS optimizer(1e-3, 2, 0.9, 0.999, 1e-6, 500000, 1e-9, true); - FunctionTest(optimizer, 3.0, 0.3); + FunctionTest, arma::sp_mat>(optimizer, 0.3, 0.03); } -/** - * Test the SWATS optimizer on the Styblinski-Tang function. Use arma::sp_mat. - */ -TEST_CASE("SWATSStyblinskiTangFunctionSpMatTest", "[SWATSTest]") +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("SWATSLogisticRegressionTestFunction", "[SWATS]", + coot::mat, coot::fmat) { - SWATS optimizer(1e-3, 2, 0.9, 0.999, 1e-6, 500000, 1e-9, true); - FunctionTest(optimizer, 0.3, 0.03); + SWATS optimizer(1e-3, 10, 0.9, 0.999, 1e-6, 600000, 1e-9, true); + // We allow a few trials in case of poor convergence. + LogisticRegressionFunctionTest>( + optimizer, 0.003, 0.006, 5); } + +/* TEMPLATE_TEST_CASE("SWATSSphereFunctionTest", "[SWATS]", */ +/* coot::mat, coot::fmat) */ +/* { */ +/* SWATS optimizer(1e-3, 2, 0.9, 0.999, 1e-6, 500000, 1e-9, true); */ +/* FunctionTest, TestType>( */ +/* optimizer, 1.0, 0.1); */ +/* } */ + +/* TEMPLATE_TEST_CASE("SWATSStyblinskiTangFunctionFMatTest", "[SWATS]", */ +/* coot::mat, coot::fmat) */ +/* { */ +/* SWATS optimizer(1e-3, 2, 0.9, 0.999, 1e-6, 500000, 1e-9, true); */ +/* FunctionTest, TestType>(optimizer, 3.0, 0.3); */ +/* } */ + +#endif diff --git a/tests/test_function_tools.hpp b/tests/test_function_tools.hpp index 18c728ff0..29d482541 100644 --- a/tests/test_function_tools.hpp +++ b/tests/test_function_tools.hpp @@ -25,58 +25,67 @@ * @param testResponses Matrix object to store the test responses into. * @param shuffledResponses Matrix object to store the shuffled responses into. */ -template +template inline void LogisticRegressionTestData(MatType& data, MatType& testData, MatType& shuffledData, - arma::Row& responses, - arma::Row& testResponses, - arma::Row& shuffledResponses) + LabelsType& responses, + LabelsType& testResponses, + LabelsType& shuffledResponses) { + typedef typename MatType::elem_type ElemType; + // Generate a two-Gaussian dataset. - data = MatType(3, 1000); - responses = arma::Row(1000); - for (size_t i = 0; i < 500; ++i) + arma::Mat armaData = arma::Mat(3, 100000); + arma::Row armaResponses = arma::Row(100000); + for (size_t i = 0; i < 50000; ++i) { // The first Gaussian is centered at (1, 1, 1) and has covariance I. - data.col(i) = arma::randn>(3) + - arma::Col("1.0 1.0 1.0"); - responses(i) = 0; + armaData.col(i) = arma::randn>(3) + + arma::Col("1.0 1.0 1.0"); + armaResponses(i) = 0; } - for (size_t i = 500; i < 1000; ++i) + for (size_t i = 50000; i < 100000; ++i) { // The second Gaussian is centered at (9, 9, 9) and has covariance I. - data.col(i) = arma::randn>(3) + - arma::Col("9.0 9.0 9.0"); - responses(i) = 1; + armaData.col(i) = arma::randn>(3) + + arma::Col("9.0 9.0 9.0"); + armaResponses(i) = 1; } // Shuffle the dataset. arma::uvec indices = arma::shuffle(arma::linspace(0, - data.n_cols - 1, data.n_cols)); - shuffledData = MatType(3, 1000); - shuffledResponses = arma::Row(1000); - for (size_t i = 0; i < data.n_cols; ++i) + armaData.n_cols - 1, armaData.n_cols)); + arma::Mat armaShuffledData = arma::Mat(3, 100000); + arma::Row armaShuffledResponses = arma::Row(100000); + for (size_t i = 0; i < armaData.n_cols; ++i) { - shuffledData.col(i) = data.col(indices(i)); - shuffledResponses(i) = responses[indices(i)]; + armaShuffledData.col(i) = armaData.col(indices(i)); + armaShuffledResponses(i) = armaResponses[indices(i)]; } // Create a test set. - testData = MatType(3, 1000); - testResponses = arma::Row(1000); - for (size_t i = 0; i < 500; ++i) + arma::Mat armaTestData = arma::Mat(3, 100000); + arma::Row armaTestResponses = arma::Row(100000); + for (size_t i = 0; i < 50000; ++i) { - testData.col(i) = arma::randn>(3) + - arma::Col("1.0 1.0 1.0"); - testResponses(i) = 0; + armaTestData.col(i) = arma::randn>(3) + + arma::Col("1.0 1.0 1.0"); + armaTestResponses(i) = 0; } - for (size_t i = 500; i < 1000; ++i) + for (size_t i = 50000; i < 100000; ++i) { - testData.col(i) = arma::randn>(3) + - arma::Col("9.0 9.0 9.0"); - testResponses(i) = 1; + armaTestData.col(i) = arma::randn>(3) + + arma::Col("9.0 9.0 9.0"); + armaTestResponses(i) = 1; } + + data = MatType(armaData); + testData = MatType(armaTestData); + shuffledData = MatType(armaShuffledData); + responses = LabelsType(armaResponses); + testResponses = LabelsType(armaTestResponses); + shuffledResponses = LabelsType(armaShuffledResponses); } // Check the values of two matrices. @@ -109,12 +118,14 @@ bool TestOptimizer(FunctionType& f, { const double objective = optimizer.Optimize(f, point); + typedef typename PointType::elem_type eT; + if (mustSucceed) { REQUIRE(objective == Approx(expectedObjective).margin(objectiveMargin)); for (size_t i = 0; i < point.n_elem; ++i) { - REQUIRE(point[i] == Approx(expectedResult[i]).margin(coordinateMargin)); + REQUIRE(eT(point[i]) == Approx(expectedResult[i]).margin(coordinateMargin)); } } else @@ -124,7 +135,7 @@ bool TestOptimizer(FunctionType& f, for (size_t i = 0; i < point.n_elem; ++i) { - if (point[i] != Approx(expectedResult[i]).margin(coordinateMargin)) + if (eT(point[i]) != Approx(expectedResult[i]).margin(coordinateMargin)) return false; } } @@ -177,7 +188,8 @@ void FunctionTest(OptimizerType& optimizer, coordinateMargin, f.GetFinalObjective(), objectiveMargin, trials); } -template +template, + typename OptimizerType> void LogisticRegressionFunctionTest(OptimizerType& optimizer, const double trainAccuracyTolerance, const double testAccuracyTolerance, @@ -186,14 +198,14 @@ void LogisticRegressionFunctionTest(OptimizerType& optimizer, // We have to generate new data for each trial, so we can't use // MultipleTrialOptimizerTest(). MatType data, testData, shuffledData; - arma::Row responses, testResponses, shuffledResponses; + LabelsType responses, testResponses, shuffledResponses; for (size_t i = 0; i < trials; ++i) { LogisticRegressionTestData(data, testData, shuffledData, responses, testResponses, shuffledResponses); - ens::test::LogisticRegression lr(shuffledData, shuffledResponses, - 0.5); + ens::test::LogisticRegressionFunction lr( + shuffledData, shuffledResponses, 0.5); MatType coordinates = lr.GetInitialPoint(); diff --git a/tests/wn_grad_test.cpp b/tests/wn_grad_test.cpp index b254e7e2e..6a3f560b5 100644 --- a/tests/wn_grad_test.cpp +++ b/tests/wn_grad_test.cpp @@ -17,47 +17,60 @@ using namespace ens; using namespace ens::test; -/** - * Run WNGrad on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("WNGradLogisticRegressionTest","[WNGradTest]") +TEMPLATE_TEST_CASE("WNGradLogisticRegressionTest", "[WNGrad]", + arma::mat, arma::fmat) { WNGrad optimizer(0.56, 1, 500000, 1e-9, true); - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); + LogisticRegressionFunctionTest>( + optimizer, 0.003, 0.006); } -/** - * Test the WNGrad optimizer on the Sphere function. - */ -TEST_CASE("WNGradSphereFunctionTest","[WNGradTest]") +TEMPLATE_TEST_CASE("WNGradSphereFunctionTest", "[WNGrad]", + arma::mat, arma::fmat) { WNGrad optimizer(0.56, 2, 500000, 1e-9, true); - FunctionTest(optimizer, 1.0, 0.1); + FunctionTest>, TestType>( + optimizer, 1.0, 0.1); } -/** - * Test the WNGrad optimizer on the StyblinskiTangFunction. - */ -TEST_CASE("WNGradStyblinskiTangFunctionTest","[WNGradTest]") +TEMPLATE_TEST_CASE("WNGradStyblinskiTangFunctionTest", "[WNGrad]", + arma::mat, arma::fmat) { WNGrad optimizer(0.56, 2, 500000, 1e-9, true); - FunctionTest(optimizer, 0.3, 0.03); + FunctionTest>, TestType>( + optimizer, 0.3, 0.03); } -/** - * Test the WNGrad optimizer on the StyblinskiTangFunction. Use arma::fmat. - */ -TEST_CASE("WNGradStyblinskiTangFunctionFMatTest", "[WNGradTest]") +TEST_CASE("WNGradStyblinskiTangFunctionSpMatTest", "[WNGrad]") { WNGrad optimizer(0.56, 2, 500000, 1e-9, true); - FunctionTest(optimizer, 3.0, 0.3); + FunctionTest, arma::sp_mat>(optimizer, 0.3, 0.03); } -/** - * Test the WNGrad optimizer on the StyblinskiTangFunction. Use arma::sp_mat. - */ -TEST_CASE("WNGradStyblinskiTangFunctionSpMatTest", "[WNGradTest]") +#ifdef USE_COOT + +TEMPLATE_TEST_CASE("WNGradLogisticRegressionTest", "[WNGrad]", + coot::mat, coot::fmat) +{ + WNGrad optimizer(0.56, 1, 500000, 1e-9, true); + LogisticRegressionFunctionTest>( + optimizer, 0.003, 0.006); +} + +TEMPLATE_TEST_CASE("WNGradSphereFunctionTest", "[WNGrad]", + coot::mat, coot::fmat) { WNGrad optimizer(0.56, 2, 500000, 1e-9, true); - FunctionTest(optimizer, 0.3, 0.03); + FunctionTest>, TestType>( + optimizer, 1.0, 0.1); } + +TEMPLATE_TEST_CASE("WNGradStyblinskiTangFunctionTest", "[WNGrad]", + coot::mat, coot::fmat) +{ + WNGrad optimizer(0.56, 2, 500000, 1e-9, true); + FunctionTest>, TestType>( + optimizer, 0.3, 0.03); +} + +#endif diff --git a/tests/yogi_test.cpp b/tests/yogi_test.cpp index 1fe7a66a9..69b159d8e 100644 --- a/tests/yogi_test.cpp +++ b/tests/yogi_test.cpp @@ -15,60 +15,46 @@ using namespace ens; using namespace ens::test; -/** - * Test the Yogi optimizer on the Sphere function. - */ -TEST_CASE("YogiSphereFunctionTest", "[YogiTest]") +TEMPLATE_TEST_CASE("YogiSphereFunctionTest", "[Yogi]", arma::mat, arma::fmat) { - SphereFunction f(2); Yogi optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false); - arma::mat coordinates = f.GetInitialPoint(); - optimizer.Optimize(f, coordinates); + FunctionTest>, TestType>( + optimizer, 0.5, 0.1); +} - REQUIRE(coordinates(0) == Approx(0.0).margin(0.1)); - REQUIRE(coordinates(1) == Approx(0.0).margin(0.1)); +TEMPLATE_TEST_CASE("YogiMcCormickFunctionTest", "[Yogi]", arma::mat, arma::fmat) +{ + Yogi optimizer(0.5, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false); + FunctionTest(optimizer, 0.5, 0.1); } -/** - * Test the Yogi optimizer on the Sphere function with arma::fmat. - */ -TEST_CASE("YogiSphereFunctionTestFMat", "[YogiTest]") +TEMPLATE_TEST_CASE("YogiLogisticRegressionTest", "[Yogi]", arma::mat, arma::fmat) { - SphereFunction f(2); - Yogi optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false); + Yogi optimizer; + LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); +} + +#ifdef USE_COOT - arma::fmat coordinates = f.GetInitialPoint(); - optimizer.Optimize(f, coordinates); +TEMPLATE_TEST_CASE("YogiSphereFunctionTest", "[Yogi]", coot::mat, coot::fmat) +{ + Yogi optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false); - REQUIRE(coordinates(0) == Approx(0.0).margin(0.1)); - REQUIRE(coordinates(1) == Approx(0.0).margin(0.1)); + FunctionTest>, TestType>( + optimizer, 0.5, 0.1); } -/** - * Test the Yogi optimizer on the McCormick function. - */ -TEST_CASE("YogiMcCormickFunctionTest", "[YogiTest]") +TEMPLATE_TEST_CASE("YogiMcCormickFunctionTest", "[Yogi]", coot::mat) { Yogi optimizer(0.5, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false); - FunctionTest(optimizer, 0.5, 0.1); + FunctionTest(optimizer, 0.5, 0.1); } -/** - * Run Yogi on logistic regression and make sure the results are acceptable. - */ -TEST_CASE("YogiLogisticRegressionTest", "[YogiTest]") +TEMPLATE_TEST_CASE("YogiLogisticRegressionTest", "[Yogi]", coot::mat) { Yogi optimizer; - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); + LogisticRegressionFunctionTest>(optimizer, 0.003, 0.006); } -/** - * Run Yogi on logistic regression and make sure the results are acceptable, - * using arma::fmat. - */ -TEST_CASE("YogiLogisticRegressionFMatTest", "[YogiTest]") -{ - Yogi optimizer; - LogisticRegressionFunctionTest(optimizer, 0.003, 0.006); -} +#endif