diff --git a/OpenFace.sln b/OpenFace.sln index d1fd2932..8e670276 100644 --- a/OpenFace.sln +++ b/OpenFace.sln @@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dlib", "lib\3rdParty\dlib\dlib.vcxproj", "{B47A5F12-2567-44E9-AE49-35763EC82149}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LandmarkDetector", "lib\local\LandmarkDetector\LandmarkDetector.vcxproj", "{BDC1D107-DE17-4705-8E7B-CDDE8BFB2BF8}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FaceAnalyser", "lib\local\FaceAnalyser\FaceAnalyser.vcxproj", "{0E7FC556-0E80-45EA-A876-DDE4C2FEDCD7}" @@ -49,14 +47,6 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B47A5F12-2567-44E9-AE49-35763EC82149}.Debug|Win32.ActiveCfg = Debug|Win32 - {B47A5F12-2567-44E9-AE49-35763EC82149}.Debug|Win32.Build.0 = Debug|Win32 - {B47A5F12-2567-44E9-AE49-35763EC82149}.Debug|x64.ActiveCfg = Debug|x64 - {B47A5F12-2567-44E9-AE49-35763EC82149}.Debug|x64.Build.0 = Debug|x64 - {B47A5F12-2567-44E9-AE49-35763EC82149}.Release|Win32.ActiveCfg = Release|Win32 - {B47A5F12-2567-44E9-AE49-35763EC82149}.Release|Win32.Build.0 = Release|Win32 - {B47A5F12-2567-44E9-AE49-35763EC82149}.Release|x64.ActiveCfg = Release|x64 - {B47A5F12-2567-44E9-AE49-35763EC82149}.Release|x64.Build.0 = Release|x64 {BDC1D107-DE17-4705-8E7B-CDDE8BFB2BF8}.Debug|Win32.ActiveCfg = Debug|Win32 {BDC1D107-DE17-4705-8E7B-CDDE8BFB2BF8}.Debug|Win32.Build.0 = Debug|Win32 {BDC1D107-DE17-4705-8E7B-CDDE8BFB2BF8}.Debug|x64.ActiveCfg = Debug|x64 @@ -174,7 +164,6 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {B47A5F12-2567-44E9-AE49-35763EC82149} = {652CCE53-4997-4B43-9A99-28D075199C99} {BDC1D107-DE17-4705-8E7B-CDDE8BFB2BF8} = {99FEBA13-BDDF-4076-B57E-D8EF4076E20D} {0E7FC556-0E80-45EA-A876-DDE4C2FEDCD7} = {99FEBA13-BDDF-4076-B57E-D8EF4076E20D} {8A23C00D-767D-422D-89A3-CF225E3DAB4B} = {9961DDAC-BE6E-4A6E-8EEF-FFC7D67BD631} diff --git a/lib/3rdParty/dlib/CMakeLists.txt b/lib/3rdParty/dlib/CMakeLists.txt deleted file mode 100644 index 8db4ea91..00000000 --- a/lib/3rdParty/dlib/CMakeLists.txt +++ /dev/null @@ -1,432 +0,0 @@ -# -# This is a CMake makefile. You can find the cmake utility and -# information about it at http://www.cmake.org -# - -# setting this makes CMake allow normal looking if else statements -SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) - -cmake_minimum_required(VERSION 2.4) - -# Suppress cmake warnings about changes in new versions. -if(COMMAND cmake_policy) - cmake_policy(SET CMP0003 NEW) -endif() - -add_definitions(-DDLIB_HAVE_SSE2) -add_definitions(-DDLIB_HAVE_SSE3) -add_definitions(-DDLIB_HAVE_SSE41) - -# make macros that can add #define directives to the entire project. Not just -# to the dlib library itself. I.e. to dlib and to any projects that depend -# on dlib. -macro ( add_global_define def_name ) - if (NOT CMAKE_CXX_FLAGS MATCHES "-D${def_name}") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${def_name}" - CACHE STRING "Flags used by the compiler during all C++ builds." - FORCE) - endif () -endmacro() -macro ( remove_global_define def_name ) - if (CMAKE_CXX_FLAGS MATCHES " -D${def_name}") - string (REGEX REPLACE " -D${def_name}" "" temp_var ${CMAKE_CXX_FLAGS}) - set (CMAKE_CXX_FLAGS "${temp_var}" - CACHE STRING "Flags used by the compiler during all C++ builds." - FORCE) - endif () -endmacro() - - -# Make sure ENABLE_ASSERTS is defined for debug builds -if (NOT CMAKE_CXX_FLAGS_DEBUG MATCHES "-DENABLE_ASSERTS") - set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DENABLE_ASSERTS" - CACHE STRING "Flags used by the compiler during C++ debug builds." - FORCE) -endif () - - -# Don't try to call add_library(dlib) and setup dlib's stuff if it has already -# been done by some other part of the current cmake project. We do this -# because it avoids getting warnings/errors about cmake policy CMP0002. This -# happens when a project tries to call add_subdirectory() on dlib more than -# once. This most often happens when the top level of a project depends on two -# or more other things which both depend on dlib. -if (NOT TARGET dlib) - - set (DLIB_ISO_CPP_ONLY_STR - "Enable this if you don't want to compile any non-ISO C++ code (i.e. you don't use any of the API Wrappers)" ) - set (DLIB_NO_GUI_SUPPORT_STR - "Enable this if you don't want to compile any of the dlib GUI code" ) - set (DLIB_ENABLE_STACK_TRACE_STR - "Enable this if you want to turn on the DLIB_STACK_TRACE macros" ) - set (DLIB_ENABLE_ASSERTS_STR - "Enable this if you want to turn on the DLIB_ASSERT macro" ) - set (DLIB_USE_BLAS_STR - "Disable this if you don't want to use a BLAS library" ) - set (DLIB_USE_LAPACK_STR - "Disable this if you don't want to use a LAPACK library" ) - set (DLIB_LINK_WITH_LIBPNG_STR - "Disable this if you don't want to link against libpng" ) - set (DLIB_LINK_WITH_LIBJPEG_STR - "Disable this if you don't want to link against libjpeg" ) - set (DLIB_LINK_WITH_SQLITE3_STR - "Disable this if you don't want to link against sqlite3" ) - set (DLIB_LINK_WITH_FFTW_STR - "Disable this if you don't want to link against fftw" ) - - option(DLIB_ISO_CPP_ONLY ${DLIB_ISO_CPP_ONLY_STR} OFF) - option(DLIB_NO_GUI_SUPPORT ${DLIB_NO_GUI_SUPPORT_STR} OFF) - option(DLIB_ENABLE_STACK_TRACE ${DLIB_ENABLE_STACK_TRACE_STR} OFF) - option(DLIB_ENABLE_ASSERTS ${DLIB_ENABLE_ASSERTS_STR} OFF) - option(DLIB_USE_BLAS ${DLIB_USE_BLAS_STR} ON) - option(DLIB_USE_LAPACK ${DLIB_USE_LAPACK_STR} ON) - option(DLIB_LINK_WITH_LIBPNG ${DLIB_LINK_WITH_LIBPNG_STR} ON) - option(DLIB_LINK_WITH_LIBJPEG ${DLIB_LINK_WITH_LIBJPEG_STR} ON) - option(DLIB_LINK_WITH_SQLITE3 ${DLIB_LINK_WITH_SQLITE3_STR} ON) - option(DLIB_LINK_WITH_FFTW ${DLIB_LINK_WITH_FFTW_STR} ON) - - set(source_files - include/dlib/base64/base64_kernel_1.cpp - include/dlib/bigint/bigint_kernel_1.cpp - include/dlib/bigint/bigint_kernel_2.cpp - include/dlib/bit_stream/bit_stream_kernel_1.cpp - include/dlib/entropy_decoder/entropy_decoder_kernel_1.cpp - include/dlib/entropy_decoder/entropy_decoder_kernel_2.cpp - include/dlib/entropy_encoder/entropy_encoder_kernel_1.cpp - include/dlib/entropy_encoder/entropy_encoder_kernel_2.cpp - include/dlib/md5/md5_kernel_1.cpp - include/dlib/tokenizer/tokenizer_kernel_1.cpp - include/dlib/unicode/unicode.cpp - include/dlib/data_io/image_dataset_metadata.cpp) - - if (DLIB_ISO_CPP_ONLY) - add_library(dlib STATIC ${source_files} ) - else() - - set(source_files ${source_files} - include/dlib/sockets/sockets_kernel_1.cpp - include/dlib/bsp/bsp.cpp - include/dlib/dir_nav/dir_nav_kernel_1.cpp - include/dlib/dir_nav/dir_nav_kernel_2.cpp - include/dlib/dir_nav/dir_nav_extensions.cpp - include/dlib/linker/linker_kernel_1.cpp - include/dlib/logger/extra_logger_headers.cpp - include/dlib/logger/logger_kernel_1.cpp - include/dlib/logger/logger_config_file.cpp - include/dlib/misc_api/misc_api_kernel_1.cpp - include/dlib/misc_api/misc_api_kernel_2.cpp - include/dlib/sockets/sockets_extensions.cpp - include/dlib/sockets/sockets_kernel_2.cpp - include/dlib/sockstreambuf/sockstreambuf.cpp - include/dlib/sockstreambuf/sockstreambuf_unbuffered.cpp - include/dlib/server/server_kernel.cpp - include/dlib/server/server_iostream.cpp - include/dlib/server/server_http.cpp - include/dlib/threads/multithreaded_object_extension.cpp - include/dlib/threads/threaded_object_extension.cpp - include/dlib/threads/threads_kernel_1.cpp - include/dlib/threads/threads_kernel_2.cpp - include/dlib/threads/threads_kernel_shared.cpp - include/dlib/threads/thread_pool_extension.cpp - include/dlib/timer/timer.cpp - include/dlib/stack_trace.cpp - ) - - # we want to link to the right stuff depending on our platform. - if (WIN32 AND NOT CYGWIN) ############################################################################### - if (DLIB_NO_GUI_SUPPORT) - set (dlib_needed_libraries ws2_32) - else() - set (dlib_needed_libraries ws2_32 comctl32 gdi32 imm32) - endif() - elseif(APPLE) ############################################################################ - find_library(pthreadlib pthread) - set (dlib_needed_libraries ${pthreadlib}) - - if (NOT DLIB_NO_GUI_SUPPORT) - find_library(xlib X11) - # make sure X11 is in the include path - find_path(xlib_path Xlib.h - PATHS - /Developer/SDKs/MacOSX10.4u.sdk/usr/X11R6/include - PATH_SUFFIXES X11 - ) - if (xlib AND xlib_path) - get_filename_component(x11_path ${xlib_path} PATH CACHE) - include_directories(${x11_path}) - set(dlib_needed_libraries ${dlib_needed_libraries} ${xlib} ) - else() - message(" *****************************************************************************") - message(" *** DLIB GUI SUPPORT DISABLED BECAUSE X11 DEVELOPMENT LIBRARIES NOT FOUND ***") - message(" *** Make sure libx11-dev is installed if you want GUI support ***") - message(" *****************************************************************************") - set(DLIB_NO_GUI_SUPPORT ON CACHE STRING ${DLIB_NO_GUI_SUPPORT_STR} FORCE ) - endif() - endif() - - mark_as_advanced(pthreadlib xlib xlib_path x11_path) - else () ################################################################################## - find_library(pthreadlib pthread) - set (dlib_needed_libraries ${pthreadlib}) - - # link to the nsl library if it exists. this is something you need sometimes - find_library(nsllib nsl) - if (nsllib) - set (dlib_needed_libraries ${dlib_needed_libraries} ${nsllib}) - endif () - - # link to the socket library if it exists. this is something you need on solaris - find_library(socketlib socket) - if (socketlib) - set (dlib_needed_libraries ${dlib_needed_libraries} ${socketlib}) - endif () - - if (NOT DLIB_NO_GUI_SUPPORT) - include(FindX11) - if (X11_FOUND) - include_directories(${X11_INCLUDE_DIR}) - set (dlib_needed_libraries ${dlib_needed_libraries} ${X11_LIBRARIES}) - else() - message(" *****************************************************************************") - message(" *** DLIB GUI SUPPORT DISABLED BECAUSE X11 DEVELOPMENT LIBRARIES NOT FOUND ***") - message(" *** Make sure libx11-dev is installed if you want GUI support ***") - message(" *****************************************************************************") - set(DLIB_NO_GUI_SUPPORT ON CACHE STRING ${DLIB_NO_GUI_SUPPORT_STR} FORCE ) - endif() - endif() - - mark_as_advanced(nsllib pthreadlib socketlib) - endif () ################################################################################## - - if (NOT DLIB_NO_GUI_SUPPORT) - set(source_files ${source_files} - include/dlib/gui_widgets/fonts.cpp - include/dlib/gui_widgets/widgets.cpp - include/dlib/gui_widgets/drawable.cpp - include/dlib/gui_widgets/canvas_drawing.cpp - include/dlib/gui_widgets/style.cpp - include/dlib/gui_widgets/base_widgets.cpp - include/dlib/gui_core/gui_core_kernel_1.cpp - include/dlib/gui_core/gui_core_kernel_2.cpp - ) - endif() - - - if (DLIB_LINK_WITH_LIBPNG) - # try to find libpng - set(ZLIB_FIND_QUIETLY ON) - set(PNG_FIND_QUIETLY ON) - include(FindPNG) - if (PNG_FOUND) - include_directories(${PNG_INCLUDE_DIR}) - set (dlib_needed_libraries ${dlib_needed_libraries} ${PNG_LIBRARY}) - else() - # If we can't find libpng then statically compile it in. - include_directories(external/libpng external/zlib) - set(source_files ${source_files} - include/dlib/external/libpng/png.c - include/dlib/external/libpng/pngerror.c - include/dlib/external/libpng/pngget.c - include/dlib/external/libpng/pngmem.c - include/dlib/external/libpng/pngpread.c - include/dlib/external/libpng/pngread.c - include/dlib/external/libpng/pngrio.c - include/dlib/external/libpng/pngrtran.c - include/dlib/external/libpng/pngrutil.c - include/dlib/external/libpng/pngset.c - include/dlib/external/libpng/pngtrans.c - include/dlib/external/libpng/pngwio.c - include/dlib/external/libpng/pngwrite.c - include/dlib/external/libpng/pngwtran.c - include/dlib/external/libpng/pngwutil.c - include/dlib/external/zlib/adler32.c - include/dlib/external/zlib/compress.c - include/dlib/external/zlib/crc32.c - include/dlib/external/zlib/deflate.c - include/dlib/external/zlib/gzclose.c - include/dlib/external/zlib/gzlib.c - include/dlib/external/zlib/gzread.c - include/dlib/external/zlib/gzwrite.c - include/dlib/external/zlib/infback.c - include/dlib/external/zlib/inffast.c - include/dlib/external/zlib/inflate.c - include/dlib/external/zlib/inftrees.c - include/dlib/external/zlib/trees.c - include/dlib/external/zlib/uncompr.c - include/dlib/external/zlib/zutil.c - ) - endif() - set(source_files ${source_files} - include/dlib/image_loader/png_loader.cpp - include/dlib/image_saver/save_png.cpp - ) - endif() - - if (DLIB_LINK_WITH_LIBJPEG) - # try to find libjpeg - include(FindJPEG) - if (JPEG_FOUND) - include_directories(${JPEG_INCLUDE_DIR}) - set (dlib_needed_libraries ${dlib_needed_libraries} ${JPEG_LIBRARY}) - else() - # If we can't find libjpeg then statically compile it in. - include_directories(external/libjpeg) - set(source_files ${source_files} - include/dlib/external/libjpeg/jcomapi.cpp - include/dlib/external/libjpeg/jdapimin.cpp - include/dlib/external/libjpeg/jdapistd.cpp - include/dlib/external/libjpeg/jdatasrc.cpp - include/dlib/external/libjpeg/jdcoefct.cpp - include/dlib/external/libjpeg/jdcolor.cpp - include/dlib/external/libjpeg/jddctmgr.cpp - include/dlib/external/libjpeg/jdhuff.cpp - include/dlib/external/libjpeg/jdinput.cpp - include/dlib/external/libjpeg/jdmainct.cpp - include/dlib/external/libjpeg/jdmarker.cpp - include/dlib/external/libjpeg/jdmaster.cpp - include/dlib/external/libjpeg/jdmerge.cpp - include/dlib/external/libjpeg/jdphuff.cpp - include/dlib/external/libjpeg/jdpostct.cpp - include/dlib/external/libjpeg/jdsample.cpp - include/dlib/external/libjpeg/jerror.cpp - include/dlib/external/libjpeg/jidctflt.cpp - include/dlib/external/libjpeg/jidctfst.cpp - include/dlib/external/libjpeg/jidctint.cpp - include/dlib/external/libjpeg/jidctred.cpp - include/dlib/external/libjpeg/jmemmgr.cpp - include/dlib/external/libjpeg/jmemnobs.cpp - include/dlib/external/libjpeg/jquant1.cpp - include/dlib/external/libjpeg/jquant2.cpp - include/dlib/external/libjpeg/jutils.cpp ) - endif() - set(source_files ${source_files} - include/dlib/image_loader/jpeg_loader.cpp - ) - endif() - - - if (DLIB_USE_BLAS OR DLIB_USE_LAPACK) - # Try to find BLAS and LAPACK - include(cmake_find_blas.txt) - - if (DLIB_USE_BLAS) - if (blas_found) - set (dlib_needed_libraries ${dlib_needed_libraries} ${blas_libraries}) - else() - set(DLIB_USE_BLAS OFF CACHE STRING ${DLIB_USE_BLAS_STR} FORCE ) - endif() - endif() - - if (DLIB_USE_LAPACK) - if (lapack_found) - set (dlib_needed_libraries ${dlib_needed_libraries} ${lapack_libraries}) - else() - set(DLIB_USE_LAPACK OFF CACHE STRING ${DLIB_USE_LAPACK_STR} FORCE ) - endif() - endif() - endif() - - - - if (DLIB_LINK_WITH_SQLITE3) - find_library(sqlite sqlite3) - # make sure sqlite3.h is in the include path - find_path(sqlite_path sqlite3.h) - if (sqlite AND sqlite_path) - get_filename_component(sqlite_path2 ${sqlite_path} PATH CACHE) - include_directories(${sqlite_path2}) - set(dlib_needed_libraries ${dlib_needed_libraries} ${sqlite} ) - else() - set(DLIB_LINK_WITH_SQLITE3 OFF CACHE STRING ${DLIB_LINK_WITH_SQLITE3_STR} FORCE ) - endif() - mark_as_advanced(sqlite sqlite_path sqlite_path2) - endif() - - - - if (DLIB_LINK_WITH_FFTW) - find_library(fftw fftw3) - # make sure fftw3.h is in the include path - find_path(fftw_path fftw3.h) - if (fftw AND fftw_path) - get_filename_component(fftw_path2 ${fftw_path} PATH CACHE) - include_directories(${fftw_path2}) - set(dlib_needed_libraries ${dlib_needed_libraries} ${fftw} ) - else() - set(DLIB_LINK_WITH_FFTW OFF CACHE STRING ${DLIB_LINK_WITH_SQLITE3_STR} FORCE ) - endif() - mark_as_advanced(fftw fftw_path fftw_path2) - endif() - - - add_library(dlib STATIC ${source_files} ) - target_link_libraries(dlib ${dlib_needed_libraries} ) - - endif () ##### end of if NOT DLIB_ISO_CPP_ONLY ########################################################## - - - #test for some things that really should be true about the compiler - include(TestForSTDNamespace) - include(TestForANSIStreamHeaders) - - - if (DLIB_LINK_WITH_LIBPNG AND NOT DLIB_ISO_CPP_ONLY) - add_global_define(DLIB_PNG_SUPPORT) - else() - remove_global_define(DLIB_PNG_SUPPORT) - endif() - - if (DLIB_LINK_WITH_LIBJPEG AND NOT DLIB_ISO_CPP_ONLY) - add_global_define(DLIB_JPEG_SUPPORT) - else() - remove_global_define(DLIB_JPEG_SUPPORT) - endif() - - if (DLIB_LINK_WITH_FFTW AND NOT DLIB_ISO_CPP_ONLY) - add_global_define(DLIB_USE_FFTW) - else() - remove_global_define(DLIB_USE_FFTW) - endif() - - - if (DLIB_USE_BLAS AND blas_found) - add_global_define(DLIB_USE_BLAS) - else() - remove_global_define(DLIB_USE_BLAS) - endif() - - if (DLIB_USE_LAPACK AND lapack_found) - add_global_define(DLIB_USE_LAPACK) - else() - remove_global_define(DLIB_USE_LAPACK) - endif() - - - if (DLIB_ISO_CPP_ONLY) - add_global_define(DLIB_ISO_CPP_ONLY) - else() - remove_global_define(DLIB_ISO_CPP_ONLY) - endif() - - - if (DLIB_NO_GUI_SUPPORT) - add_global_define(DLIB_NO_GUI_SUPPORT) - else() - remove_global_define(DLIB_NO_GUI_SUPPORT) - endif() - - if (DLIB_ENABLE_STACK_TRACE) - add_global_define(DLIB_ENABLE_STACK_TRACE) - else() - remove_global_define(DLIB_ENABLE_STACK_TRACE) - endif() - - - if (DLIB_ENABLE_ASSERTS) - add_global_define(ENABLE_ASSERTS) - else() - remove_global_define(ENABLE_ASSERTS) - endif() - - -endif() \ No newline at end of file diff --git a/lib/3rdParty/dlib/cmake_find_blas.txt b/lib/3rdParty/dlib/cmake_find_blas.txt deleted file mode 100644 index 27e0543a..00000000 --- a/lib/3rdParty/dlib/cmake_find_blas.txt +++ /dev/null @@ -1,227 +0,0 @@ -# -# This is a CMake makefile. You can find the cmake utility and -# information about it at http://www.cmake.org -# -# -# This cmake file tries to find installed BLAS and LAPACK libraries. -# It looks for an installed copy of the Intel MKL library first and then -# attempts to find some other BLAS and LAPACK libraries if you don't have -# the Intel MKL. -# -# blas_found - True if BLAS is available -# lapack_found - True if LAPACK is available -# blas_libraries - link against these to use BLAS library -# lapack_libraries - link against these to use LAPACK library - -# setting this makes CMake allow normal looking if else statements -SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) - -SET(blas_found 0) -SET(lapack_found 0) - - -if (UNIX) - message(STATUS "Searching for BLAS and LAPACK") - - include(CheckTypeSize) - check_type_size( "void*" SIZE_OF_VOID_PTR) - - if (SIZE_OF_VOID_PTR EQUAL 8) - set( mkl_search_path - /opt/intel/mkl/*/lib/em64t - /opt/intel/mkl/lib/intel64 - /opt/intel/lib/intel64 - ) - - find_library(mkl_intel mkl_intel_lp64 ${mkl_search_path}) - else() - set( mkl_search_path - /opt/intel/mkl/*/lib/32 - /opt/intel/mkl/lib/ia32 - /opt/intel/lib/ia32 - ) - - find_library(mkl_intel mkl_intel ${mkl_search_path}) - endif() - - include(CheckLibraryExists) - - - # Search for the needed libraries from the MKL. We will try to link against the mkl_rt - # file first since this way avoids linking bugs in some cases. - find_library(mkl_rt mkl_rt ${mkl_search_path}) - mark_as_advanced( mkl_rt ) - # if we found the MKL - if ( mkl_rt) - set(blas_libraries ${mkl_rt} ) - set(lapack_libraries ${mkl_rt} ) - set(blas_found 1) - set(lapack_found 1) - set(found_intel_mkl 1) - message(STATUS "Found Intel MKL BLAS/LAPACK library") - endif() - - - - if (NOT found_intel_mkl) - # Search for the needed libraries from the MKL. This time try looking for a different - # set of MKL files and try to link against those. - find_library(mkl_core mkl_core ${mkl_search_path}) - find_library(mkl_thread mkl_intel_thread ${mkl_search_path}) - find_library(mkl_iomp iomp5 ${mkl_search_path}) - find_library(mkl_pthread pthread ${mkl_search_path}) - - mark_as_advanced( mkl_intel mkl_core mkl_thread mkl_iomp mkl_pthread) - # If we found the MKL - if (mkl_intel AND mkl_core AND mkl_thread AND mkl_iomp AND mkl_pthread) - set(blas_libraries ${mkl_intel} ${mkl_core} ${mkl_thread} ${mkl_iomp} ${mkl_pthread}) - set(lapack_libraries ${mkl_intel} ${mkl_core} ${mkl_thread} ${mkl_iomp} ${mkl_pthread}) - set(blas_found 1) - set(lapack_found 1) - set(found_intel_mkl 1) - message(STATUS "Found Intel MKL BLAS/LAPACK library") - endif() - endif() - - - # try to find some other LAPACK libraries if we didn't find the MKL - set(extra_paths - /usr/lib64 - /usr/lib64/atlas-sse3 - /usr/lib64/atlas-sse2 - /usr/lib64/atlas - /usr/lib - /usr/lib/atlas-sse3 - /usr/lib/atlas-sse2 - /usr/lib/atlas) - - - if (NOT lapack_found) - find_library(lapack_lib NAMES lapack lapack-3 PATHS ${extra_paths}) - if (lapack_lib) - set(lapack_libraries ${lapack_lib}) - set(lapack_found 1) - message(STATUS "Found LAPACK library") - endif() - mark_as_advanced( lapack_lib) - endif() - - - # try to find some other BLAS libraries if we didn't find the MKL - - if (NOT blas_found) - find_library(atlas_lib atlas PATHS ${extra_paths}) - find_library(cblas_lib cblas PATHS ${extra_paths}) - if (atlas_lib AND cblas_lib) - set(blas_libraries ${atlas_lib} ${cblas_lib}) - set(blas_found 1) - message(STATUS "Found ATLAS BLAS library") - endif() - mark_as_advanced( atlas_lib cblas_lib) - endif() - - - if (NOT blas_found) - find_library(cblas_lib cblas PATHS ${extra_paths}) - if (cblas_lib) - set(blas_libraries ${cblas_lib}) - set(blas_found 1) - message(STATUS "Found CBLAS library") - endif() - mark_as_advanced( cblas_lib) - endif() - - - if (NOT blas_found) - find_library(generic_blas blas PATHS ${extra_paths}) - if (generic_blas) - set(blas_libraries ${generic_blas}) - set(blas_found 1) - message(STATUS "Found BLAS library") - endif() - mark_as_advanced( generic_blas) - endif() - - - - - # Make sure we really found a CBLAS library. That is, it needs to expose - # the proper cblas link symbols. So here we test if one of them is present - # and assume everything is good if it is. Note that we don't do this check if - # we found the Intel MKL since for some reason CHECK_FUNCTION_EXISTS doesn't work - # with it. But it's fine since the MKL should always have cblas. - if (blas_found AND NOT found_intel_mkl) - INCLUDE (CheckFunctionExists) - set(CMAKE_REQUIRED_LIBRARIES ${blas_libraries}) - CHECK_FUNCTION_EXISTS(cblas_ddot HAVE_CBLAS) - if (NOT HAVE_CBLAS) - message(STATUS "BLAS library does not have cblas symbols, so dlib will not use BLAS or LAPACK") - set(blas_found 0) - set(lapack_found 0) - endif() - endif() - - - if (NOT blas_found) - message(" *****************************************************************************") - message(" *** No BLAS library found so using dlib's built in BLAS. However, if you ***") - message(" *** install an optimized BLAS such as openblas or the Intel MKL your code ***") - message(" *** will run faster. On Ubuntu you can install openblas by executing: ***") - message(" *** sudo apt-get install libopenblas-dev liblapack-dev ***") - message(" *****************************************************************************") - endif() - -elseif(WIN32 AND NOT MINGW) - message(STATUS "Searching for BLAS and LAPACK") - - include(CheckTypeSize) - check_type_size( "void*" SIZE_OF_VOID_PTR) - if (SIZE_OF_VOID_PTR EQUAL 8) - set( mkl_search_path - "C:/Program Files (x86)/Intel/Composer XE/mkl/lib/intel64" - "C:/Program Files (x86)/Intel/Composer XE/compiler/lib/intel64" - "C:/Program Files/Intel/Composer XE/mkl/lib/intel64" - "C:/Program Files/Intel/Composer XE/compiler/lib/intel64" - ) - find_library(mkl_intel mkl_intel_lp64 ${mkl_search_path}) - else() - set( mkl_search_path - "C:/Program Files (x86)/Intel/Composer XE/mkl/lib/ia32" - "C:/Program Files (x86)/Intel/Composer XE/compiler/lib/ia32" - "C:/Program Files/Intel/Composer XE/mkl/lib/ia32" - "C:/Program Files/Intel/Composer XE/compiler/lib/ia32" - ) - find_library(mkl_intel mkl_intel_c ${mkl_search_path}) - endif() - - - # Search for the needed libraries from the MKL. - find_library(mkl_core mkl_core ${mkl_search_path}) - find_library(mkl_thread mkl_intel_thread ${mkl_search_path}) - find_library(mkl_iomp libiomp5md ${mkl_search_path}) - - mark_as_advanced( mkl_intel mkl_core mkl_thread mkl_iomp) - # If we found the MKL - if (mkl_intel AND mkl_core AND mkl_thread AND mkl_iomp ) - set(blas_libraries ${mkl_intel} ${mkl_core} ${mkl_thread} ${mkl_iomp} ) - set(lapack_libraries ${mkl_intel} ${mkl_core} ${mkl_thread} ${mkl_iomp} ) - set(blas_found 1) - set(lapack_found 1) - message(STATUS "Found Intel MKL BLAS/LAPACK library") - - if (MSVC) - # need to set /bigobj when statically linking with the MKL on - # visual studio or it doesn't work right. - if (NOT CMAKE_CXX_FLAGS MATCHES "/bigobj") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj" - CACHE STRING "Flags used by the compiler during all C++ builds." - FORCE) - endif () - endif() - endif() - - -endif() - - - diff --git a/lib/3rdParty/dlib/dlib.props b/lib/3rdParty/dlib/dlib.props index c0323b9a..47dffa57 100644 --- a/lib/3rdParty/dlib/dlib.props +++ b/lib/3rdParty/dlib/dlib.props @@ -4,5 +4,9 @@ $(SolutionDir)lib\3rdParty\dlib\include\dlib\..;%(AdditionalIncludeDirectories) + + $(SolutionDir)lib\3rdParty\dlib\lib\$(PlatformTarget)\$(PlatformToolset)\$(Configuration);%(AdditionalLibraryDirectories) + dlib.lib;%(AdditionalDependencies) + \ No newline at end of file diff --git a/lib/3rdParty/dlib/dlib.vcxproj b/lib/3rdParty/dlib/dlib.vcxproj deleted file mode 100644 index 0f263123..00000000 --- a/lib/3rdParty/dlib/dlib.vcxproj +++ /dev/null @@ -1,217 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - - - - {B47A5F12-2567-44E9-AE49-35763EC82149} - Win32Proj - Win32 - dlib - 8.1 - - - - StaticLibrary - false - Unicode - v140 - - - StaticLibrary - false - Unicode - v140 - - - StaticLibrary - false - Unicode - v140 - true - - - StaticLibrary - false - Unicode - v140 - true - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.20506.1 - $(SolutionDir)$(Configuration)\ - $(ProjectDir)$(Configuration)\ - dlib - dlib - .lib - .lib - $(SolutionDir)$(Configuration)\ - $(ProjectDir)$(Configuration)\ - $(ProjectName) - $(ProjectName) - .lib - .lib - - - - $(SolutionDir)dlib/include/dlib/..;%(AdditionalIncludeDirectories) - EnableFastChecks - CompileAsCpp - ProgramDatabase - StreamingSIMDExtensions2 - Sync - Disabled - Disabled - NotUsing - MultiThreadedDebugDLL - true - Level3 - DLIB_NO_GUI_SUPPORT;WIN32;_WINDOWS;_DEBUG;ENABLE_ASSERTS;DLIB_HAVE_SSE2;DLIB_HAVE_SSE3;DLIB_HAVE_SSE41;CMAKE_INTDIR="Debug";%(PreprocessorDefinitions) - Debug - $(IntDir) - $(IntDir)vc$(PlatformToolsetVersion).pdb - true - - - true - - - - - $(SolutionDir)dlib/include/dlib/..;%(AdditionalIncludeDirectories) - EnableFastChecks - CompileAsCpp - ProgramDatabase - AdvancedVectorExtensions - Sync - Disabled - Disabled - NotUsing - MultiThreadedDebugDLL - true - Level3 - DLIB_NO_GUI_SUPPORT;WIN64;_WINDOWS;_DEBUG;ENABLE_ASSERTS;DLIB_HAVE_SSE2;DLIB_HAVE_SSE3;DLIB_HAVE_SSE41;CMAKE_INTDIR="Debug";%(PreprocessorDefinitions) - Debug - $(IntDir) - $(IntDir)vc$(PlatformToolsetVersion).pdb - true - - - true - - - - - $(SolutionDir)dlib/include/dlib/..;%(AdditionalIncludeDirectories) - CompileAsCpp - AdvancedVectorExtensions - Sync - AnySuitable - Full - NotUsing - MultiThreadedDLL - true - Level3 - - - DLIB_NO_GUI_SUPPORT;WIN32;_WINDOWS;NDEBUG;DLIB_HAVE_SSE2;DLIB_HAVE_SSE3;DLIB_HAVE_SSE41;%(PreprocessorDefinitions) - $(IntDir) - $(IntDir) - $(IntDir)vc$(PlatformToolsetVersion).pdb - Speed - true - - - WIN32;_WINDOWS;DLIB_PNG_SUPPORT;DLIB_JPEG_SUPPORT;NDEBUG;DLIB_HAVE_SSE2;DLIB_HAVE_SSE3;DLIB_HAVE_SSE41;CMAKE_INTDIR=\"Release\";%(PreprocessorDefinitions) - $(SolutionDir)/dlib/..;$(SolutionDir)/dlib/external/libpng;$(SolutionDir)/dlib/external/zlib;$(SolutionDir)/dlib/external/libjpeg;%(AdditionalIncludeDirectories) - - - $(SolutionDir)/dlib/..;$(SolutionDir)/dlib/external/libpng;$(SolutionDir)/dlib/external/zlib;$(SolutionDir)/dlib/external/libjpeg;%(AdditionalIncludeDirectories) - $(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - true - - - - - $(SolutionDir)dlib/include/dlib/..;%(AdditionalIncludeDirectories) - CompileAsCpp - AdvancedVectorExtensions - Sync - AnySuitable - Full - NotUsing - MultiThreadedDLL - true - Level3 - - - DLIB_NO_GUI_SUPPORT;WIN64;_WINDOWS;NDEBUG;DLIB_HAVE_SSE2;DLIB_HAVE_SSE3;DLIB_HAVE_SSE41;%(PreprocessorDefinitions) - $(IntDir) - $(IntDir) - $(IntDir)vc$(PlatformToolsetVersion).pdb - Speed - true - - - WIN32;_WINDOWS;DLIB_PNG_SUPPORT;DLIB_JPEG_SUPPORT;NDEBUG;DLIB_HAVE_SSE2;DLIB_HAVE_SSE3;DLIB_HAVE_SSE41;CMAKE_INTDIR=\"Release\";%(PreprocessorDefinitions) - $(SolutionDir)/dlib/..;$(SolutionDir)/dlib/external/libpng;$(SolutionDir)/dlib/external/zlib;$(SolutionDir)/dlib/external/libjpeg;%(AdditionalIncludeDirectories) - - - $(SolutionDir)/dlib/..;$(SolutionDir)/dlib/external/libpng;$(SolutionDir)/dlib/external/zlib;$(SolutionDir)/dlib/external/libjpeg;%(AdditionalIncludeDirectories) - $(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - true - - - - - - \ No newline at end of file diff --git a/lib/3rdParty/dlib/include/dlib/add_python_module b/lib/3rdParty/dlib/include/dlib/add_python_module deleted file mode 100644 index 2e5c2f3b..00000000 --- a/lib/3rdParty/dlib/include/dlib/add_python_module +++ /dev/null @@ -1,111 +0,0 @@ -# This is a CMake file that sets up the add_python_module() macro. This macro -# lets you easily make python modules that use dlib. -# -# The macro takes the module name as its first argument and then a list of -# source files to compile into the module. See ../tools/python/CMakeLists.txt -# for an example. -# -# It also sets up a macro called install_${module_name}_to() where -# ${module_name} is whatever you named your module. This install_*_to() macro -# takes a folder name and creates an install target that will copy the compiled -# python module to that folder when you run "make install". Note that the path -# given to install_*_to() is relative to your CMakeLists.txt file. - - - -# A list of various paths you need to search on windows since people install -# boost in a bunch of different places. -set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} - "C:/local/boost_1_*" - "C:/Program Files (x86)/boost/boost_1_*" - "C:/Program Files/boost/boost_1_*") -set(BOOST_LIBRARYDIR "C:/local/boost_1_*/lib32-msvc-*") - - - -#SET(Boost_USE_STATIC_LIBS OFF) -#SET(Boost_USE_MULTITHREADED ON) -#SET(Boost_USE_STATIC_RUNTIME OFF) -set(Boost_NO_BOOST_CMAKE ON) - -FIND_PACKAGE(Boost 1.41.0 COMPONENTS python REQUIRED) -FIND_PACKAGE(PythonLibs 2.6 REQUIRED) - -if (WIN32 AND NOT Boost_LIBRARIES) - message(FATAL_ERROR "We couldn't find the right version of boost python. If you installed boost and you are still " - "getting this error then you might have installed a version of boost that was compiled with a different " - "version of visual studio than the one you are using. So you have to make sure that the version of " - "visual studio is the same version that was used to compile the copy of boost you are using.") -endif() - - -INCLUDE_DIRECTORIES("${Boost_INCLUDE_DIRS}") -if (PYTHON_INCLUDE_PATH) - INCLUDE_DIRECTORIES("${PYTHON_INCLUDE_PATH}" ) -else() - INCLUDE_DIRECTORIES("${PYTHON_INCLUDE_DIRS}" ) -endif() - -if (CMAKE_COMPILER_IS_GNUCXX) - add_definitions("-fPIC") -endif() - -# include dlib so we can link against it -string(REGEX REPLACE "add_python_module$" "" dlib_path ${CMAKE_CURRENT_LIST_FILE}) -include(${dlib_path}/cmake) - -# We put the extra _ on the end of the name just so it's possible to -# have a module name of dlib and not get a conflict with the target named -# dlib in ../dlib/cmake. We use the target OUPUT_NAME property to ensure the -# output name is set to what the user asked for (i.e. no _). -macro(add_python_module module_name module_sources ) - ADD_LIBRARY(${module_name}_ SHARED ${module_sources} ${ARGN} ) - TARGET_LINK_LIBRARIES(${module_name}_ ${Boost_LIBRARIES} ${PYTHON_LIBRARIES} dlib) - if(WIN32 AND NOT CYGWIN) - SET_TARGET_PROPERTIES( ${module_name}_ - PROPERTIES - PREFIX "" - SUFFIX ".pyd" - OUTPUT_NAME ${module_name} - ) - elseif(CYGWIN) - SET_TARGET_PROPERTIES( ${module_name}_ - PROPERTIES - PREFIX "" - SUFFIX ".dll" - OUTPUT_NAME ${module_name} - ) - else() - SET_TARGET_PROPERTIES( ${module_name}_ - PROPERTIES - PREFIX "" - SUFFIX ".so" - OUTPUT_NAME ${module_name} - ) - endif() - - macro(install_${module_name}_to path) - # Determine the path to our CMakeLists.txt file. - string(REGEX REPLACE "CMakeLists.txt$" "" base_path ${CMAKE_CURRENT_LIST_FILE}) - INSTALL(TARGETS ${module_name}_ - DESTINATION "${base_path}/${path}" - ) - - # On windows we will usually need to have the boost-python .dll files in the same folder or - # you will get an error about how they can't be found. So copy the boost .dll files along with - # your module to the install folder to avoid this. - if (WIN32) - list(GET Boost_LIBRARIES 1 boostlibs1) - list(GET Boost_LIBRARIES 3 boostlibs2) - string(REGEX REPLACE ".lib$" ".dll" boostdlls1 ${boostlibs1}) - string(REGEX REPLACE ".lib$" ".dll" boostdlls2 ${boostlibs2}) - INSTALL(FILES ${boostdlls1} ${boostdlls2} - DESTINATION "${base_path}/${path}" - ) - endif() - endmacro() - -endmacro() - - - diff --git a/lib/3rdParty/dlib/include/dlib/algs.h b/lib/3rdParty/dlib/include/dlib/algs.h index 640a62f4..9a2e0d22 100644 --- a/lib/3rdParty/dlib/include/dlib/algs.h +++ b/lib/3rdParty/dlib/include/dlib/algs.h @@ -1,12 +1,37 @@ // Copyright (C) 2003 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. + +#ifdef DLIB_ALL_SOURCE_END +#include "dlib_basic_cpp_build_tutorial.txt" +#endif + #ifndef DLIB_ALGs_ #define DLIB_ALGs_ // this file contains miscellaneous stuff +// Give people who forget the -std=c++11 option a reminder +#if (defined(__GNUC__) && ((__GNUC__ >= 4 && __GNUC_MINOR__ >= 8) || (__GNUC__ > 4))) || \ + (defined(__clang__) && ((__clang_major__ >= 3 && __clang_minor__ >= 4) || (__clang_major__ >= 3))) + #if __cplusplus < 201103 + #error "Dlib requires C++11 support. Give your compiler the -std=c++11 option to enable it." + #endif +#endif + +#if defined __NVCC__ + // Disable the "statement is unreachable" message since it will go off on code that is + // actually reachable but just happens to not be reachable sometimes during certain + // template instantiations. + #pragma diag_suppress code_is_unreachable +#endif + #ifdef _MSC_VER + +#if _MSC_VER < 1900 +#error "dlib versions newer than v19.1 use C++11 and therefore require Visual Studio 2015 or newer." +#endif + // Disable the following warnings for Visual Studio // this is to disable the "'this' : used in base member initializer list" @@ -43,6 +68,16 @@ // This warning happens often in generic code that works with functions and isn't useful. #pragma warning(disable : 4180) +// Disable "warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)" +#pragma warning(disable : 4290) + + +// DNN module uses template-based network declaration that leads to very long +// type names. Visual Studio will produce Warning C4503 in such cases. https://msdn.microsoft.com/en-us/library/074af4b6.aspx says +// that correct binaries are still produced even when this warning happens, but linker errors from visual studio, if they occurr could be confusing. +#pragma warning( disable: 4503 ) + + #endif #ifdef __BORLANDC__ @@ -71,6 +106,7 @@ namespace std #include // for std::swap #include // for std::bad_alloc #include +#include #include // for std::numeric_limits for is_finite() #include "assert.h" #include "error.h" @@ -275,7 +311,7 @@ namespace dlib typename A, typename B > - bool operator> ( + constexpr bool operator> ( const A& a, const B& b ) { return b < a; } @@ -286,7 +322,7 @@ namespace dlib typename A, typename B > - bool operator!= ( + constexpr bool operator!= ( const A& a, const B& b ) { return !(a == b); } @@ -297,7 +333,7 @@ namespace dlib typename A, typename B > - bool operator<= ( + constexpr bool operator<= ( const A& a, const B& b ) { return !(b < a); } @@ -308,7 +344,7 @@ namespace dlib typename A, typename B > - bool operator>= ( + constexpr bool operator>= ( const A& a, const B& b ) { return !(a < b); } @@ -480,6 +516,13 @@ namespace dlib // ---------------------------------------------------------------------------------------- + struct general_ {}; + struct special_ : general_ {}; + template struct int_ { typedef int type; }; + +// ---------------------------------------------------------------------------------------- + + /*!A is_same_object This is a templated function which checks if both of its arguments are actually @@ -759,10 +802,10 @@ namespace dlib abs<4>::value == 4 !*/ - template - struct tabs { const static long value = x; }; - template - struct tabs::type> { const static long value = -x; }; + template + struct tabs { const static long value = x; }; + template + struct tabs::type> { const static long value = -x; }; // ---------------------------------------------------------------------------------------- @@ -774,10 +817,10 @@ namespace dlib abs<4,7>::value == 7 !*/ - template - struct tmax { const static long value = x; }; - template - struct tmax x)>::type> { const static long value = y; }; + template + struct tmax { const static long value = x; }; + template + struct tmax x)>::type> { const static long value = y; }; // ---------------------------------------------------------------------------------------- @@ -789,12 +832,12 @@ namespace dlib abs<4,7>::value == 4 !*/ - template - struct tmin { const static long value = x; }; - template - struct tmin::type> { const static long value = y; }; + template + struct tmin { const static long value = x; }; + template + struct tmin::type> { const static long value = y; }; - // ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- #define DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(testname, returnT, funct_name, args) \ struct _two_bytes_##testname { char a[2]; }; \ @@ -1025,6 +1068,88 @@ namespace dlib void* const data; }; +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename F + > + auto max_scoring_element( + const T& container, + F score_func + ) -> decltype(std::make_pair(*container.begin(), 0.0)) + /*! + requires + - container has .begin() and .end(), allowing it to be enumerated. + - score_func() is a function that takes an element of the container and returns a double. + ensures + - This function finds the element of container that has the largest score, + according to score_func(), and returns a std::pair containing that maximal + element along with the score. + - If the container is empty then make_pair(a default initialized object, -infinity) is returned. + !*/ + { + double best_score = -std::numeric_limits::infinity(); + auto best_i = container.begin(); + for (auto i = container.begin(); i != container.end(); ++i) + { + auto score = score_func(*i); + if (score > best_score) + { + best_score = score; + best_i = i; + } + } + + using item_type = typename std::remove_reference::type; + + if (best_i == container.end()) + return std::make_pair(item_type(), best_score); + else + return std::make_pair(*best_i, best_score); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename F + > + auto min_scoring_element( + const T& container, + F score_func + ) -> decltype(std::make_pair(*container.begin(), 0.0)) + /*! + requires + - container has .begin() and .end(), allowing it to be enumerated. + - score_func() is a function that takes an element of the container and returns a double. + ensures + - This function finds the element of container that has the smallest score, + according to score_func(), and returns a std::pair containing that minimal + element along with the score. + - If the container is empty then make_pair(a default initialized object, infinity) is returned. + !*/ + { + double best_score = std::numeric_limits::infinity(); + auto best_i = container.begin(); + for (auto i = container.begin(); i != container.end(); ++i) + { + auto score = score_func(*i); + if (score < best_score) + { + best_score = score; + best_i = i; + } + } + + using item_type = typename std::remove_reference::type; + + if (best_i == container.end()) + return std::make_pair(item_type(), best_score); + else + return std::make_pair(*best_i, best_score); + } + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/all/source.cpp b/lib/3rdParty/dlib/include/dlib/all/source.cpp deleted file mode 100644 index 1177de59..00000000 --- a/lib/3rdParty/dlib/include/dlib/all/source.cpp +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_ALL_SOURCe_ -#define DLIB_ALL_SOURCe_ - -// ISO C++ code -#include "../base64/base64_kernel_1.cpp" -//#include "../bigint/bigint_kernel_1.cpp" -//#include "../bigint/bigint_kernel_2.cpp" -#include "../bit_stream/bit_stream_kernel_1.cpp" -#include "../entropy_decoder/entropy_decoder_kernel_1.cpp" -#include "../entropy_decoder/entropy_decoder_kernel_2.cpp" -#include "../entropy_encoder/entropy_encoder_kernel_1.cpp" -#include "../entropy_encoder/entropy_encoder_kernel_2.cpp" -//#include "../md5/md5_kernel_1.cpp" -#include "../tokenizer/tokenizer_kernel_1.cpp" -//#include "../unicode/unicode.cpp" -//#include "../data_io/image_dataset_metadata.cpp" - -#ifndef DLIB_ISO_CPP_ONLY -// Code that depends on OS specific APIs - -// include this first so that it can disable the older version -// of the winsock API when compiled in windows. -#include "../sockets/sockets_kernel_1.cpp" -//#include "../bsp/bsp.cpp" - -//#include "../dir_nav/dir_nav_kernel_1.cpp" -//#include "../dir_nav/dir_nav_kernel_2.cpp" -//#include "../dir_nav/dir_nav_extensions.cpp" -//#include "../linker/linker_kernel_1.cpp" -//#include "../logger/extra_logger_headers.cpp" -//#include "../logger/logger_kernel_1.cpp" -//#include "../logger/logger_config_file.cpp" -#include "../misc_api/misc_api_kernel_1.cpp" -#include "../misc_api/misc_api_kernel_2.cpp" -#include "../sockets/sockets_extensions.cpp" -#include "../sockets/sockets_kernel_2.cpp" -#include "../sockstreambuf/sockstreambuf.cpp" -#include "../sockstreambuf/sockstreambuf_unbuffered.cpp" -//#include "../server/server_kernel.cpp" -//#include "../server/server_iostream.cpp" -//#include "../server/server_http.cpp" -//#include "../threads/multithreaded_object_extension.cpp" -#include "../threads/threaded_object_extension.cpp" -#include "../threads/threads_kernel_1.cpp" -#include "../threads/threads_kernel_2.cpp" -#include "../threads/threads_kernel_shared.cpp" -//#include "../threads/thread_pool_extension.cpp" -#include "../timer/timer.cpp" -//#include "../stack_trace.cpp" - -#ifdef DLIB_PNG_SUPPORT -#include "../image_loader/png_loader.cpp" -#include "../image_saver/save_png.cpp" -#endif - -#ifdef DLIB_JPEG_SUPPORT -#include "../image_loader/jpeg_loader.cpp" -#endif - -#ifndef DLIB_NO_GUI_SUPPORT -#include "../gui_widgets/fonts.cpp" -#include "../gui_widgets/widgets.cpp" -#include "../gui_widgets/drawable.cpp" -#include "../gui_widgets/canvas_drawing.cpp" -#include "../gui_widgets/style.cpp" -#include "../gui_widgets/base_widgets.cpp" -#include "../gui_core/gui_core_kernel_1.cpp" -#include "../gui_core/gui_core_kernel_2.cpp" -#endif // DLIB_NO_GUI_SUPPORT - -#endif // DLIB_ISO_CPP_ONLY - -#endif // DLIB_ALL_SOURCe_ - diff --git a/lib/3rdParty/dlib/include/dlib/all_console.cpp b/lib/3rdParty/dlib/include/dlib/all_console.cpp deleted file mode 100644 index 556983be..00000000 --- a/lib/3rdParty/dlib/include/dlib/all_console.cpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_ALL_CONSOLe_ -#define DLIB_ALL_CONSOLe_ - -#error "This file has been replaced. Instead you should add dlib/all/source.cpp to your project" - -#endif // DLIB_ALL_CONSOLe_ - diff --git a/lib/3rdParty/dlib/include/dlib/all_gui.cpp b/lib/3rdParty/dlib/include/dlib/all_gui.cpp deleted file mode 100644 index cd397dbf..00000000 --- a/lib/3rdParty/dlib/include/dlib/all_gui.cpp +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_ALL_GUi_ -#define DLIB_ALL_GUi_ - -#error "This file has been replaced. Instead you should add dlib/all/source.cpp to your project" - -#endif // DLIB_ALL_GUi_ - diff --git a/lib/3rdParty/dlib/include/dlib/any/any.h b/lib/3rdParty/dlib/include/dlib/any/any.h index 6d9938d6..b5ef1bc8 100644 --- a/lib/3rdParty/dlib/include/dlib/any/any.h +++ b/lib/3rdParty/dlib/include/dlib/any/any.h @@ -4,7 +4,9 @@ #define DLIB_AnY_H_ #include "any_abstract.h" -#include "../smart_pointers.h" +#include "../algs.h" + +#include #include namespace dlib @@ -136,7 +138,7 @@ namespace dlib virtual ~base() {} virtual void copy_to ( - scoped_ptr& dest + std::unique_ptr& dest ) const = 0; }; @@ -148,14 +150,14 @@ namespace dlib derived(const T& val) : item(val) {} virtual void copy_to ( - scoped_ptr& dest + std::unique_ptr& dest ) const { dest.reset(new derived(item)); } }; - scoped_ptr data; + std::unique_ptr data; }; // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/any/any_decision_function.h b/lib/3rdParty/dlib/include/dlib/any/any_decision_function.h index d165fcca..771e9302 100644 --- a/lib/3rdParty/dlib/include/dlib/any/any_decision_function.h +++ b/lib/3rdParty/dlib/include/dlib/any/any_decision_function.h @@ -4,7 +4,6 @@ #define DLIB_AnY_DECISION_FUNCTION_Hh_ #include "any.h" -#include "../smart_pointers.h" #include "any_decision_function_abstract.h" @@ -148,7 +147,7 @@ namespace dlib virtual ~base() {} virtual void copy_to ( - scoped_ptr& dest + std::unique_ptr& dest ) const = 0; virtual result_type evaluate ( @@ -164,7 +163,7 @@ namespace dlib derived(const T& val) : item(val) {} virtual void copy_to ( - scoped_ptr& dest + std::unique_ptr& dest ) const { dest.reset(new derived(item)); @@ -178,7 +177,7 @@ namespace dlib } }; - scoped_ptr data; + std::unique_ptr data; }; // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/any/any_function.h b/lib/3rdParty/dlib/include/dlib/any/any_function.h index d9aa4931..f186b4d3 100644 --- a/lib/3rdParty/dlib/include/dlib/any/any_function.h +++ b/lib/3rdParty/dlib/include/dlib/any/any_function.h @@ -4,7 +4,6 @@ #define DLIB_AnY_FUNCTION_Hh_ #include "any.h" -#include "../smart_pointers.h" #include "any_function_abstract.h" @@ -32,6 +31,16 @@ namespace dlib typedef void arg8_type; typedef void arg9_type; typedef void arg10_type; + typedef void arg11_type; + typedef void arg12_type; + typedef void arg13_type; + typedef void arg14_type; + typedef void arg15_type; + typedef void arg16_type; + typedef void arg17_type; + typedef void arg18_type; + typedef void arg19_type; + typedef void arg20_type; const static unsigned long num_args = 0; }; @@ -53,6 +62,16 @@ namespace dlib typedef void arg8_type; typedef void arg9_type; typedef void arg10_type; + typedef void arg11_type; + typedef void arg12_type; + typedef void arg13_type; + typedef void arg14_type; + typedef void arg15_type; + typedef void arg16_type; + typedef void arg17_type; + typedef void arg18_type; + typedef void arg19_type; + typedef void arg20_type; const static unsigned long num_args = 1; }; @@ -74,6 +93,16 @@ namespace dlib typedef void arg8_type; typedef void arg9_type; typedef void arg10_type; + typedef void arg11_type; + typedef void arg12_type; + typedef void arg13_type; + typedef void arg14_type; + typedef void arg15_type; + typedef void arg16_type; + typedef void arg17_type; + typedef void arg18_type; + typedef void arg19_type; + typedef void arg20_type; const static unsigned long num_args = 2; }; @@ -95,6 +124,16 @@ namespace dlib typedef void arg8_type; typedef void arg9_type; typedef void arg10_type; + typedef void arg11_type; + typedef void arg12_type; + typedef void arg13_type; + typedef void arg14_type; + typedef void arg15_type; + typedef void arg16_type; + typedef void arg17_type; + typedef void arg18_type; + typedef void arg19_type; + typedef void arg20_type; const static unsigned long num_args = 3; }; @@ -117,6 +156,16 @@ namespace dlib typedef void arg8_type; typedef void arg9_type; typedef void arg10_type; + typedef void arg11_type; + typedef void arg12_type; + typedef void arg13_type; + typedef void arg14_type; + typedef void arg15_type; + typedef void arg16_type; + typedef void arg17_type; + typedef void arg18_type; + typedef void arg19_type; + typedef void arg20_type; const static unsigned long num_args = 4; }; @@ -139,6 +188,16 @@ namespace dlib typedef void arg8_type; typedef void arg9_type; typedef void arg10_type; + typedef void arg11_type; + typedef void arg12_type; + typedef void arg13_type; + typedef void arg14_type; + typedef void arg15_type; + typedef void arg16_type; + typedef void arg17_type; + typedef void arg18_type; + typedef void arg19_type; + typedef void arg20_type; const static unsigned long num_args = 5; }; @@ -161,6 +220,16 @@ namespace dlib typedef void arg8_type; typedef void arg9_type; typedef void arg10_type; + typedef void arg11_type; + typedef void arg12_type; + typedef void arg13_type; + typedef void arg14_type; + typedef void arg15_type; + typedef void arg16_type; + typedef void arg17_type; + typedef void arg18_type; + typedef void arg19_type; + typedef void arg20_type; const static unsigned long num_args = 6; }; @@ -184,6 +253,16 @@ namespace dlib typedef void arg8_type; typedef void arg9_type; typedef void arg10_type; + typedef void arg11_type; + typedef void arg12_type; + typedef void arg13_type; + typedef void arg14_type; + typedef void arg15_type; + typedef void arg16_type; + typedef void arg17_type; + typedef void arg18_type; + typedef void arg19_type; + typedef void arg20_type; const static unsigned long num_args = 7; }; @@ -207,6 +286,16 @@ namespace dlib typedef A8 arg8_type; typedef void arg9_type; typedef void arg10_type; + typedef void arg11_type; + typedef void arg12_type; + typedef void arg13_type; + typedef void arg14_type; + typedef void arg15_type; + typedef void arg16_type; + typedef void arg17_type; + typedef void arg18_type; + typedef void arg19_type; + typedef void arg20_type; const static unsigned long num_args = 8; }; @@ -230,6 +319,16 @@ namespace dlib typedef A8 arg8_type; typedef A9 arg9_type; typedef void arg10_type; + typedef void arg11_type; + typedef void arg12_type; + typedef void arg13_type; + typedef void arg14_type; + typedef void arg15_type; + typedef void arg16_type; + typedef void arg17_type; + typedef void arg18_type; + typedef void arg19_type; + typedef void arg20_type; const static unsigned long num_args = 9; }; @@ -254,10 +353,415 @@ namespace dlib typedef A8 arg8_type; typedef A9 arg9_type; typedef A10 arg10_type; + typedef void arg11_type; + typedef void arg12_type; + typedef void arg13_type; + typedef void arg14_type; + typedef void arg15_type; + typedef void arg16_type; + typedef void arg17_type; + typedef void arg18_type; + typedef void arg19_type; + typedef void arg20_type; const static unsigned long num_args = 10; }; + template < + typename T, + typename A1, typename A2, typename A3, + typename A4, typename A5, typename A6, + typename A7, typename A8, typename A9, + typename A10, + typename A11 + > + struct sig_traits + { + typedef T result_type; + typedef A1 arg1_type; + typedef A2 arg2_type; + typedef A3 arg3_type; + typedef A4 arg4_type; + typedef A5 arg5_type; + typedef A6 arg6_type; + typedef A7 arg7_type; + typedef A8 arg8_type; + typedef A9 arg9_type; + typedef A10 arg10_type; + typedef A11 arg11_type; + typedef void arg12_type; + typedef void arg13_type; + typedef void arg14_type; + typedef void arg15_type; + typedef void arg16_type; + typedef void arg17_type; + typedef void arg18_type; + typedef void arg19_type; + typedef void arg20_type; + + const static unsigned long num_args = 11; + }; + + template < + typename T, + typename A1, typename A2, typename A3, + typename A4, typename A5, typename A6, + typename A7, typename A8, typename A9, + typename A10, + typename A11, + typename A12 + > + struct sig_traits + { + typedef T result_type; + typedef A1 arg1_type; + typedef A2 arg2_type; + typedef A3 arg3_type; + typedef A4 arg4_type; + typedef A5 arg5_type; + typedef A6 arg6_type; + typedef A7 arg7_type; + typedef A8 arg8_type; + typedef A9 arg9_type; + typedef A10 arg10_type; + typedef A11 arg11_type; + typedef A12 arg12_type; + typedef void arg13_type; + typedef void arg14_type; + typedef void arg15_type; + typedef void arg16_type; + typedef void arg17_type; + typedef void arg18_type; + typedef void arg19_type; + typedef void arg20_type; + + const static unsigned long num_args = 12; + }; + + template < + typename T, + typename A1, typename A2, typename A3, + typename A4, typename A5, typename A6, + typename A7, typename A8, typename A9, + typename A10, + typename A11, + typename A12, + typename A13 + > + struct sig_traits + { + typedef T result_type; + typedef A1 arg1_type; + typedef A2 arg2_type; + typedef A3 arg3_type; + typedef A4 arg4_type; + typedef A5 arg5_type; + typedef A6 arg6_type; + typedef A7 arg7_type; + typedef A8 arg8_type; + typedef A9 arg9_type; + typedef A10 arg10_type; + typedef A11 arg11_type; + typedef A12 arg12_type; + typedef A13 arg13_type; + typedef void arg14_type; + typedef void arg15_type; + typedef void arg16_type; + typedef void arg17_type; + typedef void arg18_type; + typedef void arg19_type; + typedef void arg20_type; + + const static unsigned long num_args = 13; + }; + + template < + typename T, + typename A1, typename A2, typename A3, + typename A4, typename A5, typename A6, + typename A7, typename A8, typename A9, + typename A10, + typename A11, + typename A12, + typename A13, + typename A14 + > + struct sig_traits + { + typedef T result_type; + typedef A1 arg1_type; + typedef A2 arg2_type; + typedef A3 arg3_type; + typedef A4 arg4_type; + typedef A5 arg5_type; + typedef A6 arg6_type; + typedef A7 arg7_type; + typedef A8 arg8_type; + typedef A9 arg9_type; + typedef A10 arg10_type; + typedef A11 arg11_type; + typedef A12 arg12_type; + typedef A13 arg13_type; + typedef A14 arg14_type; + typedef void arg15_type; + typedef void arg16_type; + typedef void arg17_type; + typedef void arg18_type; + typedef void arg19_type; + typedef void arg20_type; + + const static unsigned long num_args = 14; + }; + + template < + typename T, + typename A1, typename A2, typename A3, + typename A4, typename A5, typename A6, + typename A7, typename A8, typename A9, + typename A10, + typename A11, + typename A12, + typename A13, + typename A14, + typename A15 + > + struct sig_traits + { + typedef T result_type; + typedef A1 arg1_type; + typedef A2 arg2_type; + typedef A3 arg3_type; + typedef A4 arg4_type; + typedef A5 arg5_type; + typedef A6 arg6_type; + typedef A7 arg7_type; + typedef A8 arg8_type; + typedef A9 arg9_type; + typedef A10 arg10_type; + typedef A11 arg11_type; + typedef A12 arg12_type; + typedef A13 arg13_type; + typedef A14 arg14_type; + typedef A15 arg15_type; + typedef void arg16_type; + typedef void arg17_type; + typedef void arg18_type; + typedef void arg19_type; + typedef void arg20_type; + + const static unsigned long num_args = 15; + }; + + template < + typename T, + typename A1, typename A2, typename A3, + typename A4, typename A5, typename A6, + typename A7, typename A8, typename A9, + typename A10, + typename A11, + typename A12, + typename A13, + typename A14, + typename A15, + typename A16 + > + struct sig_traits + { + typedef T result_type; + typedef A1 arg1_type; + typedef A2 arg2_type; + typedef A3 arg3_type; + typedef A4 arg4_type; + typedef A5 arg5_type; + typedef A6 arg6_type; + typedef A7 arg7_type; + typedef A8 arg8_type; + typedef A9 arg9_type; + typedef A10 arg10_type; + typedef A11 arg11_type; + typedef A12 arg12_type; + typedef A13 arg13_type; + typedef A14 arg14_type; + typedef A15 arg15_type; + typedef A16 arg16_type; + typedef void arg17_type; + typedef void arg18_type; + typedef void arg19_type; + typedef void arg20_type; + + const static unsigned long num_args = 16; + }; + + template < + typename T, + typename A1, typename A2, typename A3, + typename A4, typename A5, typename A6, + typename A7, typename A8, typename A9, + typename A10, + typename A11, + typename A12, + typename A13, + typename A14, + typename A15, + typename A16, + typename A17 + > + struct sig_traits + { + typedef T result_type; + typedef A1 arg1_type; + typedef A2 arg2_type; + typedef A3 arg3_type; + typedef A4 arg4_type; + typedef A5 arg5_type; + typedef A6 arg6_type; + typedef A7 arg7_type; + typedef A8 arg8_type; + typedef A9 arg9_type; + typedef A10 arg10_type; + typedef A11 arg11_type; + typedef A12 arg12_type; + typedef A13 arg13_type; + typedef A14 arg14_type; + typedef A15 arg15_type; + typedef A16 arg16_type; + typedef A17 arg17_type; + typedef void arg18_type; + typedef void arg19_type; + typedef void arg20_type; + + const static unsigned long num_args = 17; + }; + + template < + typename T, + typename A1, typename A2, typename A3, + typename A4, typename A5, typename A6, + typename A7, typename A8, typename A9, + typename A10, + typename A11, + typename A12, + typename A13, + typename A14, + typename A15, + typename A16, + typename A17, + typename A18 + > + struct sig_traits + { + typedef T result_type; + typedef A1 arg1_type; + typedef A2 arg2_type; + typedef A3 arg3_type; + typedef A4 arg4_type; + typedef A5 arg5_type; + typedef A6 arg6_type; + typedef A7 arg7_type; + typedef A8 arg8_type; + typedef A9 arg9_type; + typedef A10 arg10_type; + typedef A11 arg11_type; + typedef A12 arg12_type; + typedef A13 arg13_type; + typedef A14 arg14_type; + typedef A15 arg15_type; + typedef A16 arg16_type; + typedef A17 arg17_type; + typedef A18 arg18_type; + typedef void arg19_type; + typedef void arg20_type; + + const static unsigned long num_args = 18; + }; + + template < + typename T, + typename A1, typename A2, typename A3, + typename A4, typename A5, typename A6, + typename A7, typename A8, typename A9, + typename A10, + typename A11, + typename A12, + typename A13, + typename A14, + typename A15, + typename A16, + typename A17, + typename A18, + typename A19 + > + struct sig_traits + { + typedef T result_type; + typedef A1 arg1_type; + typedef A2 arg2_type; + typedef A3 arg3_type; + typedef A4 arg4_type; + typedef A5 arg5_type; + typedef A6 arg6_type; + typedef A7 arg7_type; + typedef A8 arg8_type; + typedef A9 arg9_type; + typedef A10 arg10_type; + typedef A11 arg11_type; + typedef A12 arg12_type; + typedef A13 arg13_type; + typedef A14 arg14_type; + typedef A15 arg15_type; + typedef A16 arg16_type; + typedef A17 arg17_type; + typedef A18 arg18_type; + typedef A19 arg19_type; + typedef void arg20_type; + + const static unsigned long num_args = 19; + }; + + template < + typename T, + typename A1, typename A2, typename A3, + typename A4, typename A5, typename A6, + typename A7, typename A8, typename A9, + typename A10, + typename A11, + typename A12, + typename A13, + typename A14, + typename A15, + typename A16, + typename A17, + typename A18, + typename A19, + typename A20 + > + struct sig_traits + { + typedef T result_type; + typedef A1 arg1_type; + typedef A2 arg2_type; + typedef A3 arg3_type; + typedef A4 arg4_type; + typedef A5 arg5_type; + typedef A6 arg6_type; + typedef A7 arg7_type; + typedef A8 arg8_type; + typedef A9 arg9_type; + typedef A10 arg10_type; + typedef A11 arg11_type; + typedef A12 arg12_type; + typedef A13 arg13_type; + typedef A14 arg14_type; + typedef A15 arg15_type; + typedef A16 arg16_type; + typedef A17 arg17_type; + typedef A18 arg18_type; + typedef A19 arg19_type; + typedef A20 arg20_type; + + const static unsigned long num_args = 20; + }; + // ---------------------------------------------------------------------------------------- template < diff --git a/lib/3rdParty/dlib/include/dlib/any/any_function_impl.h b/lib/3rdParty/dlib/include/dlib/any/any_function_impl.h index efd4b2b1..f9a45683 100644 --- a/lib/3rdParty/dlib/include/dlib/any/any_function_impl.h +++ b/lib/3rdParty/dlib/include/dlib/any/any_function_impl.h @@ -166,7 +166,7 @@ struct Tbase { virtual ~Tbase() {} virtual result_type evaluate () const = 0; - virtual void copy_to ( scoped_ptr& dest) const = 0; + virtual void copy_to ( std::unique_ptr& dest) const = 0; }; template < @@ -177,7 +177,7 @@ struct Tbase { virtual ~Tbase() {} virtual T evaluate ( A1) const = 0; - virtual void copy_to ( scoped_ptr& dest) const = 0; + virtual void copy_to ( std::unique_ptr& dest) const = 0; }; template < @@ -188,7 +188,7 @@ struct Tbase { virtual ~Tbase() {} virtual T evaluate (A1,A2) const = 0; - virtual void copy_to ( scoped_ptr& dest) const = 0; + virtual void copy_to ( std::unique_ptr& dest) const = 0; }; template < @@ -199,7 +199,7 @@ struct Tbase { virtual ~Tbase() {} virtual T evaluate (A1,A2,A3) const = 0; - virtual void copy_to ( scoped_ptr& dest) const = 0; + virtual void copy_to ( std::unique_ptr& dest) const = 0; }; template < @@ -211,7 +211,7 @@ struct Tbase { virtual ~Tbase() {} virtual T evaluate (A1,A2,A3,A4) const = 0; - virtual void copy_to ( scoped_ptr& dest) const = 0; + virtual void copy_to ( std::unique_ptr& dest) const = 0; }; template < @@ -223,7 +223,7 @@ struct Tbase { virtual ~Tbase() {} virtual T evaluate (A1,A2,A3,A4,A5) const = 0; - virtual void copy_to ( scoped_ptr& dest) const = 0; + virtual void copy_to ( std::unique_ptr& dest) const = 0; }; template < @@ -235,7 +235,7 @@ struct Tbase { virtual ~Tbase() {} virtual T evaluate (A1,A2,A3,A4,A5,A6) const = 0; - virtual void copy_to ( scoped_ptr& dest) const = 0; + virtual void copy_to ( std::unique_ptr& dest) const = 0; }; template < @@ -248,7 +248,7 @@ struct Tbase { virtual ~Tbase() {} virtual T evaluate (A1,A2,A3,A4,A5,A6,A7) const = 0; - virtual void copy_to ( scoped_ptr& dest) const = 0; + virtual void copy_to ( std::unique_ptr& dest) const = 0; }; template < @@ -261,7 +261,7 @@ struct Tbase { virtual ~Tbase() {} virtual T evaluate (A1,A2,A3,A4,A5,A6,A7,A8) const = 0; - virtual void copy_to ( scoped_ptr& dest) const = 0; + virtual void copy_to ( std::unique_ptr& dest) const = 0; }; template < @@ -274,7 +274,7 @@ struct Tbase { virtual ~Tbase() {} virtual T evaluate (A1,A2,A3,A4,A5,A6,A7,A8,A9) const = 0; - virtual void copy_to ( scoped_ptr& dest) const = 0; + virtual void copy_to ( std::unique_ptr& dest) const = 0; }; template < @@ -288,7 +288,7 @@ struct Tbase { virtual ~Tbase() {} virtual T evaluate (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10) const = 0; - virtual void copy_to ( scoped_ptr& dest) const = 0; + virtual void copy_to ( std::unique_ptr& dest) const = 0; }; typedef Tbase base; @@ -318,7 +318,7 @@ static typename disable_if,const T&>::type deref (const U& item) typename funct_type::type item; \ derived() {} \ derived(const T& val) : item(copy(val)) {} \ - virtual void copy_to ( scoped_ptr& dest) const \ + virtual void copy_to ( std::unique_ptr& dest) const \ { dest.reset(new derived(deref(item))); } template @@ -508,7 +508,7 @@ struct derived : public base !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ }; -scoped_ptr data; +std::unique_ptr data; #undef DLIB_ANY_FUNCTION_DERIVED_BOILERPLATE diff --git a/lib/3rdParty/dlib/include/dlib/any/any_trainer.h b/lib/3rdParty/dlib/include/dlib/any/any_trainer.h index 2346ca4f..4df10a14 100644 --- a/lib/3rdParty/dlib/include/dlib/any/any_trainer.h +++ b/lib/3rdParty/dlib/include/dlib/any/any_trainer.h @@ -4,7 +4,6 @@ #define DLIB_AnY_TRAINER_H_ #include "any.h" -#include "../smart_pointers.h" #include "any_decision_function.h" @@ -157,7 +156,7 @@ namespace dlib ) const = 0; virtual void copy_to ( - scoped_ptr& dest + std::unique_ptr& dest ) const = 0; }; @@ -169,7 +168,7 @@ namespace dlib derived(const T& val) : item(val) {} virtual void copy_to ( - scoped_ptr& dest + std::unique_ptr& dest ) const { dest.reset(new derived(item)); @@ -184,7 +183,7 @@ namespace dlib } }; - scoped_ptr data; + std::unique_ptr data; }; // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/array/array_kernel.h b/lib/3rdParty/dlib/include/dlib/array/array_kernel.h index ca1c23b4..02858ba4 100644 --- a/lib/3rdParty/dlib/include/dlib/array/array_kernel.h +++ b/lib/3rdParty/dlib/include/dlib/array/array_kernel.h @@ -90,8 +90,26 @@ namespace dlib _at_start(true) {} + array(const array&) = delete; + array& operator=(array&) = delete; + + array( + array&& item + ) : array() + { + swap(item); + } + + array& operator=( + array&& item + ) + { + swap(item); + return *this; + } + explicit array ( - unsigned long new_size + size_t new_size ) : array_size(0), max_array_size(0), @@ -110,22 +128,22 @@ namespace dlib ); inline const T& operator[] ( - unsigned long pos + size_t pos ) const; inline T& operator[] ( - unsigned long pos + size_t pos ); void set_size ( - unsigned long size + size_t size ); - inline unsigned long max_size( + inline size_t max_size( ) const; void set_max_size( - unsigned long max + size_t max ); void swap ( @@ -133,7 +151,7 @@ namespace dlib ); // functions from the enumerable interface - inline unsigned long size ( + inline size_t size ( ) const; inline bool at_start ( @@ -158,7 +176,7 @@ namespace dlib ); void resize ( - unsigned long new_size + size_t new_size ); const T& back ( @@ -178,6 +196,10 @@ namespace dlib T& item ); + void push_back ( + T&& item + ); + typedef T* iterator; typedef const T* const_iterator; iterator begin() { return array_elements; } @@ -190,18 +212,14 @@ namespace dlib typename mem_manager::template rebind::other pool; // data members - unsigned long array_size; - unsigned long max_array_size; + size_t array_size; + size_t max_array_size; T* array_elements; mutable T* pos; T* last_pos; mutable bool _at_start; - // restricted functions - array(array&); // copy constructor - array& operator=(array&); // assignment operator - }; template < @@ -229,7 +247,7 @@ namespace dlib serialize(item.max_size(),out); serialize(item.size(),out); - for (unsigned long i = 0; i < item.size(); ++i) + for (size_t i = 0; i < item.size(); ++i) serialize(item[i],out); } catch (serialization_error e) @@ -249,12 +267,12 @@ namespace dlib { try { - unsigned long max_size, size; + size_t max_size, size; deserialize(max_size,in); deserialize(size,in); item.set_max_size(max_size); item.set_size(size); - for (unsigned long i = 0; i < size; ++i) + for (size_t i = 0; i < size; ++i) deserialize(item[i],in); } catch (serialization_error e) @@ -314,7 +332,7 @@ namespace dlib > const T& array:: operator[] ( - unsigned long pos + size_t pos ) const { // make sure requires clause is not broken @@ -337,7 +355,7 @@ namespace dlib > T& array:: operator[] ( - unsigned long pos + size_t pos ) { // make sure requires clause is not broken @@ -360,7 +378,7 @@ namespace dlib > void array:: set_size ( - unsigned long size + size_t size ) { // make sure requires clause is not broken @@ -386,7 +404,7 @@ namespace dlib typename T, typename mem_manager > - unsigned long array:: + size_t array:: size ( ) const { @@ -401,7 +419,7 @@ namespace dlib > void array:: set_max_size( - unsigned long max + size_t max ) { reset(); @@ -439,7 +457,7 @@ namespace dlib typename T, typename mem_manager > - unsigned long array:: + size_t array:: max_size ( ) const { @@ -457,8 +475,8 @@ namespace dlib array& item ) { - unsigned long array_size_temp = item.array_size; - unsigned long max_array_size_temp = item.max_array_size; + auto array_size_temp = item.array_size; + auto max_array_size_temp = item.max_array_size; T* array_elements_temp = item.array_elements; item.array_size = array_size; @@ -627,7 +645,7 @@ namespace dlib > void array:: resize ( - unsigned long new_size + size_t new_size ) { if (this->max_size() < new_size) @@ -635,7 +653,7 @@ namespace dlib array temp; temp.set_max_size(new_size); temp.set_size(new_size); - for (unsigned long i = 0; i < this->size(); ++i) + for (size_t i = 0; i < this->size(); ++i) { exchange((*this)[i],temp[i]); } @@ -750,7 +768,7 @@ namespace dlib array temp; temp.set_max_size(this->size()*2 + 1); temp.set_size(this->size()+1); - for (unsigned long i = 0; i < this->size(); ++i) + for (size_t i = 0; i < this->size(); ++i) { exchange((*this)[i],temp[i]); } @@ -764,6 +782,17 @@ namespace dlib } } +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void array:: + push_back ( + T&& item + ) { push_back(item); } + // ---------------------------------------------------------------------------------------- template diff --git a/lib/3rdParty/dlib/include/dlib/array/array_kernel_abstract.h b/lib/3rdParty/dlib/include/dlib/array/array_kernel_abstract.h index 1d714979..5cfdd483 100644 --- a/lib/3rdParty/dlib/include/dlib/array/array_kernel_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/array/array_kernel_abstract.h @@ -66,7 +66,7 @@ namespace dlib !*/ explicit array ( - unsigned long new_size + size_t new_size ); /*! ensures @@ -85,6 +85,25 @@ namespace dlib - all memory associated with *this has been released !*/ + array( + array&& item + ); + /*! + ensures + - move constructs *this from item. Therefore, the state of item is + moved into *this and #item has a valid but unspecified state. + !*/ + + array& operator=( + array&& item + ); + /*! + ensures + - move assigns *this from item. Therefore, the state of item is + moved into *this and #item has a valid but unspecified state. + - returns a reference to #*this + !*/ + void clear ( ); /*! @@ -97,7 +116,7 @@ namespace dlib !*/ const T& operator[] ( - unsigned long pos + size_t pos ) const; /*! requires @@ -107,7 +126,7 @@ namespace dlib !*/ T& operator[] ( - unsigned long pos + size_t pos ); /*! requires @@ -117,7 +136,7 @@ namespace dlib !*/ void set_size ( - unsigned long size + size_t size ); /*! requires @@ -136,7 +155,7 @@ namespace dlib if it does throw then the call to set_size() has no effect !*/ - unsigned long max_size( + size_t max_size( ) const; /*! ensures @@ -144,7 +163,7 @@ namespace dlib !*/ void set_max_size( - unsigned long max + size_t max ); /*! ensures @@ -179,7 +198,7 @@ namespace dlib !*/ void resize ( - unsigned long new_size + size_t new_size ); /*! ensures @@ -255,6 +274,11 @@ namespace dlib If an exception is thrown then it has no effect on *this. !*/ + void push_back (T&& item) { push_back(item); } + /*! + enable push_back from rvalues + !*/ + typedef T* iterator; typedef const T* const_iterator; diff --git a/lib/3rdParty/dlib/include/dlib/array2d/array2d_generic_image.h b/lib/3rdParty/dlib/include/dlib/array2d/array2d_generic_image.h index 13323376..a96f5e3c 100644 --- a/lib/3rdParty/dlib/include/dlib/array2d/array2d_generic_image.h +++ b/lib/3rdParty/dlib/include/dlib/array2d/array2d_generic_image.h @@ -13,6 +13,11 @@ namespace dlib { typedef T pixel_type; }; + template + struct image_traits > + { + typedef T pixel_type; + }; template inline long num_rows( const array2d& img) { return img.nr(); } diff --git a/lib/3rdParty/dlib/include/dlib/array2d/array2d_kernel.h b/lib/3rdParty/dlib/include/dlib/array2d/array2d_kernel.h index c4429824..c3cd9584 100644 --- a/lib/3rdParty/dlib/include/dlib/array2d/array2d_kernel.h +++ b/lib/3rdParty/dlib/include/dlib/array2d/array2d_kernel.h @@ -60,6 +60,9 @@ namespace dlib typedef T type; typedef mem_manager mem_manager_type; + typedef T* iterator; + typedef const T* const_iterator; + // ----------------------------------- @@ -72,7 +75,7 @@ namespace dlib - (*this)[x] == data[x] !*/ - friend class array2d; + friend class array2d; friend class row_helper; public: @@ -160,6 +163,24 @@ namespace dlib set_size(rows,cols); } + array2d(const array2d&) = delete; // copy constructor + array2d& operator=(const array2d&) = delete; // assignment operator + +#ifdef DLIB_HAS_RVALUE_REFERENCES + array2d(array2d&& item) : array2d() + { + swap(item); + } + + array2d& operator= ( + array2d&& rhs + ) + { + swap(rhs); + return *this; + } +#endif + virtual ~array2d ( ) { clear(); } @@ -294,8 +315,8 @@ namespace dlib } } - unsigned long size ( - ) const { return static_cast(nc_ * nr_); } + size_t size ( + ) const { return static_cast(nc_) * static_cast(nr_); } long width_step ( ) const @@ -303,6 +324,27 @@ namespace dlib return nc_*sizeof(T); } + iterator begin() + { + return data; + } + + iterator end() + { + return data+size(); + } + + const_iterator begin() const + { + return data; + } + + const_iterator end() const + { + return data+size(); + } + + private: @@ -315,10 +357,6 @@ namespace dlib T* last; mutable bool at_start_; - // restricted functions - array2d(array2d&); // copy constructor - array2d& operator=(array2d&); // assignment operator - }; // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/array2d/array2d_kernel_abstract.h b/lib/3rdParty/dlib/include/dlib/array2d/array2d_kernel_abstract.h index f037522b..daccfc60 100644 --- a/lib/3rdParty/dlib/include/dlib/array2d/array2d_kernel_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/array2d/array2d_kernel_abstract.h @@ -64,6 +64,8 @@ namespace dlib typedef T type; typedef mem_manager mem_manager_type; + typedef T* iterator; + typedef const T* const_iterator; // ---------------------------------------- @@ -122,6 +124,18 @@ namespace dlib - std::bad_alloc !*/ + array2d(const array2d&) = delete; // copy constructor + array2d& operator=(const array2d&) = delete; // assignment operator + + array2d( + array2d&& item + ); + /*! + ensures + - Moves the state of item into *this. + - #item is in a valid but unspecified state. + !*/ + array2d ( long rows, long cols @@ -218,6 +232,16 @@ namespace dlib - swaps *this and item !*/ + array2d& operator= ( + array2d&& rhs + ); + /*! + ensures + - Moves the state of item into *this. + - #item is in a valid but unspecified state. + - returns #*this + !*/ + long width_step ( ) const; /*! @@ -233,11 +257,41 @@ namespace dlib An example of such an object is the dlib::cv_image. !*/ - private: + iterator begin( + ); + /*! + ensures + - returns a random access iterator pointing to the first element in this + object. + - The iterator will iterate over the elements of the object in row major + order. + !*/ - // restricted functions - array2d(array2d&); // copy constructor - array2d& operator=(array2d&); // assignment operator + iterator end( + ); + /*! + ensures + - returns a random access iterator pointing to one past the end of the last + element in this object. + !*/ + + const_iterator begin( + ) const; + /*! + ensures + - returns a random access iterator pointing to the first element in this + object. + - The iterator will iterate over the elements of the object in row major + order. + !*/ + + const_iterator end( + ) const; + /*! + ensures + - returns a random access iterator pointing to one past the end of the last + element in this object. + !*/ }; diff --git a/lib/3rdParty/dlib/include/dlib/assert.h b/lib/3rdParty/dlib/include/dlib/assert.h index cce9645a..370f9c07 100644 --- a/lib/3rdParty/dlib/include/dlib/assert.h +++ b/lib/3rdParty/dlib/include/dlib/assert.h @@ -20,12 +20,53 @@ // (C) Copyright Gennaro Prota 2003. // (C) Copyright Eric Friedman 2003. // License: Boost Software License See LICENSE.txt for the full license. -#ifndef BOOST_JOIN -#define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y ) -#define BOOST_DO_JOIN( X, Y ) BOOST_DO_JOIN2(X,Y) -#define BOOST_DO_JOIN2( X, Y ) X##Y +// +#ifndef DLIB_BOOST_JOIN +#define DLIB_BOOST_JOIN( X, Y ) DLIB_BOOST_DO_JOIN( X, Y ) +#define DLIB_BOOST_DO_JOIN( X, Y ) DLIB_BOOST_DO_JOIN2(X,Y) +#define DLIB_BOOST_DO_JOIN2( X, Y ) X##Y #endif +// figure out if the compiler has rvalue references. +#if defined(__clang__) +# if __has_feature(cxx_rvalue_references) +# define DLIB_HAS_RVALUE_REFERENCES +# endif +# if __has_feature(cxx_generalized_initializers) +# define DLIB_HAS_INITIALIZER_LISTS +# endif +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && defined(__GXX_EXPERIMENTAL_CXX0X__) +# define DLIB_HAS_RVALUE_REFERENCES +# define DLIB_HAS_INITIALIZER_LISTS +#elif defined(_MSC_VER) && _MSC_VER >= 1800 +# define DLIB_HAS_INITIALIZER_LISTS +# define DLIB_HAS_RVALUE_REFERENCES +#elif defined(_MSC_VER) && _MSC_VER >= 1600 +# define DLIB_HAS_RVALUE_REFERENCES +#elif defined(__INTEL_COMPILER) && defined(BOOST_INTEL_STDCXX0X) +# define DLIB_HAS_RVALUE_REFERENCES +# define DLIB_HAS_INITIALIZER_LISTS +#endif + +#if defined(__APPLE__) && defined(__GNUC_LIBSTD__) && ((__GNUC_LIBSTD__-0) * 100 + __GNUC_LIBSTD_MINOR__-0 <= 402) + // Apple has not updated libstdc++ in some time and anything under 4.02 does not have for sure. +# undef DLIB_HAS_INITIALIZER_LISTS +#endif + +// figure out if the compiler has static_assert. +#if defined(__clang__) +# if __has_feature(cxx_static_assert) +# define DLIB_HAS_STATIC_ASSERT +# endif +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && defined(__GXX_EXPERIMENTAL_CXX0X__) +# define DLIB_HAS_STATIC_ASSERT +#elif defined(_MSC_VER) && _MSC_VER >= 1600 +# define DLIB_HAS_STATIC_ASSERT +#elif defined(__INTEL_COMPILER) && defined(BOOST_INTEL_STDCXX0X) +# define DLIB_HAS_STATIC_ASSERT +#endif + + // ----------------------------- namespace dlib @@ -37,6 +78,9 @@ namespace dlib template struct assert_are_same_type {enum{value=1};}; template struct assert_are_not_same_type {enum{value=1}; }; template struct assert_are_not_same_type {}; + + template struct assert_types_match {enum{value=0};}; + template struct assert_types_match {enum{value=1};}; } @@ -48,14 +92,22 @@ namespace dlib #define DLIB_NO_WARN_UNUSED #endif -#define COMPILE_TIME_ASSERT(expression) \ - DLIB_NO_WARN_UNUSED typedef char BOOST_JOIN(DLIB_CTA, __LINE__)[::dlib::compile_time_assert<(bool)(expression)>::value] +// Use the newer static_assert if it's available since it produces much more readable error +// messages. +#ifdef DLIB_HAS_STATIC_ASSERT + #define COMPILE_TIME_ASSERT(expression) static_assert(expression, "Failed assertion") + #define ASSERT_ARE_SAME_TYPE(type1, type2) static_assert(::dlib::assert_types_match::value, "These types should be the same but aren't.") + #define ASSERT_ARE_NOT_SAME_TYPE(type1, type2) static_assert(!::dlib::assert_types_match::value, "These types should NOT be the same.") +#else + #define COMPILE_TIME_ASSERT(expression) \ + DLIB_NO_WARN_UNUSED typedef char DLIB_BOOST_JOIN(DLIB_CTA, __LINE__)[::dlib::compile_time_assert<(bool)(expression)>::value] -#define ASSERT_ARE_SAME_TYPE(type1, type2) \ - DLIB_NO_WARN_UNUSED typedef char BOOST_JOIN(DLIB_AAST, __LINE__)[::dlib::assert_are_same_type::value] + #define ASSERT_ARE_SAME_TYPE(type1, type2) \ + DLIB_NO_WARN_UNUSED typedef char DLIB_BOOST_JOIN(DLIB_AAST, __LINE__)[::dlib::assert_are_same_type::value] -#define ASSERT_ARE_NOT_SAME_TYPE(type1, type2) \ - DLIB_NO_WARN_UNUSED typedef char BOOST_JOIN(DLIB_AANST, __LINE__)[::dlib::assert_are_not_same_type::value] + #define ASSERT_ARE_NOT_SAME_TYPE(type1, type2) \ + DLIB_NO_WARN_UNUSED typedef char DLIB_BOOST_JOIN(DLIB_AANST, __LINE__)[::dlib::assert_are_not_same_type::value] +#endif // ----------------------------- @@ -88,7 +140,7 @@ namespace dlib #define DLIB_FUNCTION_NAME "unknown function" #endif -#define DLIB_CASSERT(_exp,_message) \ +#define DLIBM_CASSERT(_exp,_message) \ {if ( !(_exp) ) \ { \ dlib_assert_breakpoint(); \ @@ -101,12 +153,22 @@ namespace dlib throw dlib::fatal_error(dlib::EBROKEN_ASSERT,dlib_o_out.str()); \ }} +// This macro is not needed if you have a real C++ compiler. It's here to work around bugs in Visual Studio's preprocessor. +#define DLIB_WORKAROUND_VISUAL_STUDIO_BUGS(x) x +// Make it so the 2nd argument of DLIB_CASSERT is optional. That is, you can call it like +// DLIB_CASSERT(exp) or DLIB_CASSERT(exp,message). +#define DLIBM_CASSERT_1_ARGS(exp) DLIBM_CASSERT(exp,"") +#define DLIBM_CASSERT_2_ARGS(exp,message) DLIBM_CASSERT(exp,message) +#define DLIBM_GET_3TH_ARG(arg1, arg2, arg3, ...) arg3 +#define DLIBM_CASSERT_CHOOSER(...) DLIB_WORKAROUND_VISUAL_STUDIO_BUGS(DLIBM_GET_3TH_ARG(__VA_ARGS__, DLIBM_CASSERT_2_ARGS, DLIBM_CASSERT_1_ARGS)) +#define DLIB_CASSERT(...) DLIB_WORKAROUND_VISUAL_STUDIO_BUGS(DLIBM_CASSERT_CHOOSER(__VA_ARGS__)(__VA_ARGS__)) + #ifdef ENABLE_ASSERTS - #define DLIB_ASSERT(_exp,_message) DLIB_CASSERT(_exp,_message) + #define DLIB_ASSERT(...) DLIB_CASSERT(__VA_ARGS__) #define DLIB_IF_ASSERT(exp) exp #else - #define DLIB_ASSERT(_exp,_message) + #define DLIB_ASSERT(...) {} #define DLIB_IF_ASSERT(exp) #endif @@ -126,8 +188,8 @@ namespace dlib !*/ // Use the fact that in C++03 you can't put non-PODs into a union. #define DLIB_ASSERT_HAS_STANDARD_LAYOUT(type) \ - union BOOST_JOIN(DAHSL_,__LINE__) { type TYPE_NOT_STANDARD_LAYOUT; }; \ - DLIB_NO_WARN_UNUSED typedef char BOOST_JOIN(DAHSL2_,__LINE__)[sizeof(BOOST_JOIN(DAHSL_,__LINE__))]; + union DLIB_BOOST_JOIN(DAHSL_,__LINE__) { type TYPE_NOT_STANDARD_LAYOUT; }; \ + DLIB_NO_WARN_UNUSED typedef char DLIB_BOOST_JOIN(DAHSL2_,__LINE__)[sizeof(DLIB_BOOST_JOIN(DAHSL_,__LINE__))]; // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/base64/base64_kernel_1.cpp b/lib/3rdParty/dlib/include/dlib/base64/base64_kernel_1.cpp deleted file mode 100644 index 06cae3d9..00000000 --- a/lib/3rdParty/dlib/include/dlib/base64/base64_kernel_1.cpp +++ /dev/null @@ -1,403 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_BASE64_KERNEL_1_CPp_ -#define DLIB_BASE64_KERNEL_1_CPp_ - -#include "base64_kernel_1.h" -#include -#include -#include - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - base64::line_ending_type base64:: - line_ending ( - ) const - { - return eol_style; - } - -// ---------------------------------------------------------------------------------------- - - void base64:: - set_line_ending ( - line_ending_type eol_style_ - ) - { - eol_style = eol_style_; - } - -// ---------------------------------------------------------------------------------------- - - base64:: - base64 ( - ) : - encode_table(0), - decode_table(0), - bad_value(100), - eol_style(LF) - { - try - { - encode_table = new char[64]; - decode_table = new unsigned char[UCHAR_MAX]; - } - catch (...) - { - if (encode_table) delete [] encode_table; - if (decode_table) delete [] decode_table; - throw; - } - - // now set up the tables with the right stuff - encode_table[0] = 'A'; - encode_table[17] = 'R'; - encode_table[34] = 'i'; - encode_table[51] = 'z'; - - encode_table[1] = 'B'; - encode_table[18] = 'S'; - encode_table[35] = 'j'; - encode_table[52] = '0'; - - encode_table[2] = 'C'; - encode_table[19] = 'T'; - encode_table[36] = 'k'; - encode_table[53] = '1'; - - encode_table[3] = 'D'; - encode_table[20] = 'U'; - encode_table[37] = 'l'; - encode_table[54] = '2'; - - encode_table[4] = 'E'; - encode_table[21] = 'V'; - encode_table[38] = 'm'; - encode_table[55] = '3'; - - encode_table[5] = 'F'; - encode_table[22] = 'W'; - encode_table[39] = 'n'; - encode_table[56] = '4'; - - encode_table[6] = 'G'; - encode_table[23] = 'X'; - encode_table[40] = 'o'; - encode_table[57] = '5'; - - encode_table[7] = 'H'; - encode_table[24] = 'Y'; - encode_table[41] = 'p'; - encode_table[58] = '6'; - - encode_table[8] = 'I'; - encode_table[25] = 'Z'; - encode_table[42] = 'q'; - encode_table[59] = '7'; - - encode_table[9] = 'J'; - encode_table[26] = 'a'; - encode_table[43] = 'r'; - encode_table[60] = '8'; - - encode_table[10] = 'K'; - encode_table[27] = 'b'; - encode_table[44] = 's'; - encode_table[61] = '9'; - - encode_table[11] = 'L'; - encode_table[28] = 'c'; - encode_table[45] = 't'; - encode_table[62] = '+'; - - encode_table[12] = 'M'; - encode_table[29] = 'd'; - encode_table[46] = 'u'; - encode_table[63] = '/'; - - encode_table[13] = 'N'; - encode_table[30] = 'e'; - encode_table[47] = 'v'; - - encode_table[14] = 'O'; - encode_table[31] = 'f'; - encode_table[48] = 'w'; - - encode_table[15] = 'P'; - encode_table[32] = 'g'; - encode_table[49] = 'x'; - - encode_table[16] = 'Q'; - encode_table[33] = 'h'; - encode_table[50] = 'y'; - - - - // we can now fill out the decode_table by using the encode_table - for (int i = 0; i < UCHAR_MAX; ++i) - { - decode_table[i] = bad_value; - } - for (unsigned char i = 0; i < 64; ++i) - { - decode_table[(unsigned char)encode_table[i]] = i; - } - } - -// ---------------------------------------------------------------------------------------- - - base64:: - ~base64 ( - ) - { - delete [] encode_table; - delete [] decode_table; - } - -// ---------------------------------------------------------------------------------------- - - void base64:: - encode ( - std::istream& in_, - std::ostream& out_ - ) const - { - using namespace std; - streambuf& in = *in_.rdbuf(); - streambuf& out = *out_.rdbuf(); - - unsigned char inbuf[3]; - unsigned char outbuf[4]; - streamsize status = in.sgetn(reinterpret_cast(&inbuf),3); - - unsigned char c1, c2, c3, c4, c5, c6; - - int counter = 19; - - // while we haven't hit the end of the input stream - while (status != 0) - { - if (counter == 0) - { - counter = 19; - // write a newline - char ch; - switch (eol_style) - { - case CR: - ch = '\r'; - if (out.sputn(&ch,1)!=1) - throw std::ios_base::failure("error occured in the base64 object"); - break; - case LF: - ch = '\n'; - if (out.sputn(&ch,1)!=1) - throw std::ios_base::failure("error occured in the base64 object"); - break; - case CRLF: - ch = '\r'; - if (out.sputn(&ch,1)!=1) - throw std::ios_base::failure("error occured in the base64 object"); - ch = '\n'; - if (out.sputn(&ch,1)!=1) - throw std::ios_base::failure("error occured in the base64 object"); - break; - default: - DLIB_CASSERT(false,"this should never happen"); - } - } - --counter; - - if (status == 3) - { - // encode the bytes in inbuf to base64 and write them to the output stream - c1 = inbuf[0]&0xfc; - c2 = inbuf[0]&0x03; - c3 = inbuf[1]&0xf0; - c4 = inbuf[1]&0x0f; - c5 = inbuf[2]&0xc0; - c6 = inbuf[2]&0x3f; - - outbuf[0] = c1>>2; - outbuf[1] = (c2<<4)|(c3>>4); - outbuf[2] = (c4<<2)|(c5>>6); - outbuf[3] = c6; - - - outbuf[0] = encode_table[outbuf[0]]; - outbuf[1] = encode_table[outbuf[1]]; - outbuf[2] = encode_table[outbuf[2]]; - outbuf[3] = encode_table[outbuf[3]]; - - // write the encoded bytes to the output stream - if (out.sputn(reinterpret_cast(&outbuf),4)!=4) - { - throw std::ios_base::failure("error occured in the base64 object"); - } - - // get 3 more input bytes - status = in.sgetn(reinterpret_cast(&inbuf),3); - continue; - } - else if (status == 2) - { - // we are at the end of the input stream and need to add some padding - - // encode the bytes in inbuf to base64 and write them to the output stream - c1 = inbuf[0]&0xfc; - c2 = inbuf[0]&0x03; - c3 = inbuf[1]&0xf0; - c4 = inbuf[1]&0x0f; - c5 = 0; - - outbuf[0] = c1>>2; - outbuf[1] = (c2<<4)|(c3>>4); - outbuf[2] = (c4<<2)|(c5>>6); - outbuf[3] = '='; - - outbuf[0] = encode_table[outbuf[0]]; - outbuf[1] = encode_table[outbuf[1]]; - outbuf[2] = encode_table[outbuf[2]]; - - // write the encoded bytes to the output stream - if (out.sputn(reinterpret_cast(&outbuf),4)!=4) - { - throw std::ios_base::failure("error occured in the base64 object"); - } - - - break; - } - else // in this case status must be 1 - { - // we are at the end of the input stream and need to add some padding - - // encode the bytes in inbuf to base64 and write them to the output stream - c1 = inbuf[0]&0xfc; - c2 = inbuf[0]&0x03; - c3 = 0; - - outbuf[0] = c1>>2; - outbuf[1] = (c2<<4)|(c3>>4); - outbuf[2] = '='; - outbuf[3] = '='; - - outbuf[0] = encode_table[outbuf[0]]; - outbuf[1] = encode_table[outbuf[1]]; - - - // write the encoded bytes to the output stream - if (out.sputn(reinterpret_cast(&outbuf),4)!=4) - { - throw std::ios_base::failure("error occured in the base64 object"); - } - - break; - } - } // while (status != 0) - - - // make sure the stream buffer flushes to its I/O channel - out.pubsync(); - } - -// ---------------------------------------------------------------------------------------- - - void base64:: - decode ( - std::istream& in_, - std::ostream& out_ - ) const - { - using namespace std; - streambuf& in = *in_.rdbuf(); - streambuf& out = *out_.rdbuf(); - - unsigned char inbuf[4]; - unsigned char outbuf[3]; - int inbuf_pos = 0; - streamsize status = in.sgetn(reinterpret_cast(inbuf),1); - - // only count this character if it isn't some kind of filler - if (status == 1 && decode_table[inbuf[0]] != bad_value ) - ++inbuf_pos; - - unsigned char c1, c2, c3, c4, c5, c6; - streamsize outsize; - - // while we haven't hit the end of the input stream - while (status != 0) - { - // if we have 4 valid characters - if (inbuf_pos == 4) - { - inbuf_pos = 0; - - // this might be the end of the encoded data so we need to figure out if - // there was any padding applied. - outsize = 3; - if (inbuf[3] == '=') - { - if (inbuf[2] == '=') - outsize = 1; - else - outsize = 2; - } - - // decode the incoming characters - inbuf[0] = decode_table[inbuf[0]]; - inbuf[1] = decode_table[inbuf[1]]; - inbuf[2] = decode_table[inbuf[2]]; - inbuf[3] = decode_table[inbuf[3]]; - - - // now pack these guys into bytes rather than 6 bit chunks - c1 = inbuf[0]<<2; - c2 = inbuf[1]>>4; - c3 = inbuf[1]<<4; - c4 = inbuf[2]>>2; - c5 = inbuf[2]<<6; - c6 = inbuf[3]; - - outbuf[0] = c1|c2; - outbuf[1] = c3|c4; - outbuf[2] = c5|c6; - - - // write the encoded bytes to the output stream - if (out.sputn(reinterpret_cast(&outbuf),outsize)!=outsize) - { - throw std::ios_base::failure("error occured in the base64 object"); - } - } - - // get more input characters - status = in.sgetn(reinterpret_cast(inbuf + inbuf_pos),1); - // only count this character if it isn't some kind of filler - if ((decode_table[inbuf[inbuf_pos]] != bad_value || inbuf[inbuf_pos] == '=') && - status != 0) - ++inbuf_pos; - } // while (status != 0) - - if (inbuf_pos != 0) - { - ostringstream sout; - sout << inbuf_pos << " extra characters were found at the end of the encoded data." - << " This may indicate that the data stream has been truncated."; - // this happens if we hit EOF in the middle of decoding a 24bit block. - throw decode_error(sout.str()); - } - - // make sure the stream buffer flushes to its I/O channel - out.pubsync(); - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_BASE64_KERNEL_1_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/base64/base64_kernel_abstract.h b/lib/3rdParty/dlib/include/dlib/base64/base64_kernel_abstract.h index 7bd85e13..0a63d3b8 100644 --- a/lib/3rdParty/dlib/include/dlib/base64/base64_kernel_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/base64/base64_kernel_abstract.h @@ -93,7 +93,7 @@ namespace dlib ) const; /*! ensures - - reads data from in (until EOF is reached) and decodees it + - reads data from in (until EOF is reached), decodes it, and writes it to out. throws - std::ios_base::failure diff --git a/lib/3rdParty/dlib/include/dlib/bayes_utils/bayes_utils.h b/lib/3rdParty/dlib/include/dlib/bayes_utils/bayes_utils.h index 72d84729..04b3d118 100644 --- a/lib/3rdParty/dlib/include/dlib/bayes_utils/bayes_utils.h +++ b/lib/3rdParty/dlib/include/dlib/bayes_utils/bayes_utils.h @@ -5,6 +5,11 @@ #include "bayes_utils_abstract.h" +#include +#include +#include +#include + #include "../string.h" #include "../map.h" #include "../matrix.h" @@ -13,11 +18,7 @@ #include "../set.h" #include "../algs.h" #include "../noncopyable.h" -#include "../smart_pointers.h" #include "../graph.h" -#include -#include -#include namespace dlib { @@ -355,7 +356,7 @@ namespace dlib table.clear(); } - unsigned long size () const { return table.size(); } + size_t size () const { return table.size(); } bool move_next() const { return table.move_next(); } void reset() const { table.reset(); } map_pair& element() @@ -1659,7 +1660,7 @@ namespace dlib private: - scoped_ptr impl; + std::unique_ptr impl; unsigned long num_nodes; }; diff --git a/lib/3rdParty/dlib/include/dlib/bayes_utils/bayes_utils_abstract.h b/lib/3rdParty/dlib/include/dlib/bayes_utils/bayes_utils_abstract.h index f2ac8643..b19e6e1d 100644 --- a/lib/3rdParty/dlib/include/dlib/bayes_utils/bayes_utils_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/bayes_utils/bayes_utils_abstract.h @@ -367,7 +367,7 @@ namespace dlib std::ostream& out ); /*! - provides deserialization support + provides serialization support !*/ void deserialize ( @@ -499,7 +499,7 @@ namespace dlib std::ostream& out ); /*! - provides deserialization support + provides serialization support !*/ void deserialize ( @@ -615,7 +615,7 @@ namespace dlib std::ostream& out ); /*! - provides deserialization support + provides serialization support !*/ void deserialize ( diff --git a/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_1.cpp b/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_1.cpp deleted file mode 100644 index feef761c..00000000 --- a/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_1.cpp +++ /dev/null @@ -1,1720 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_BIGINT_KERNEL_1_CPp_ -#define DLIB_BIGINT_KERNEL_1_CPp_ -#include "bigint_kernel_1.h" - -#include - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // member/friend function definitions -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - bigint_kernel_1:: - bigint_kernel_1 ( - ) : - slack(25), - data(new data_record(slack)) - {} - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_1:: - bigint_kernel_1 ( - uint32 value - ) : - slack(25), - data(new data_record(slack)) - { - *(data->number) = static_cast(value&0xFFFF); - *(data->number+1) = static_cast((value>>16)&0xFFFF); - if (*(data->number+1) != 0) - data->digits_used = 2; - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_1:: - bigint_kernel_1 ( - const bigint_kernel_1& item - ) : - slack(25), - data(item.data) - { - data->references += 1; - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_1:: - ~bigint_kernel_1 ( - ) - { - if (data->references == 1) - { - delete data; - } - else - { - data->references -= 1; - } - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_1 bigint_kernel_1:: - operator+ ( - const bigint_kernel_1& rhs - ) const - { - data_record* temp = new data_record ( - std::max(rhs.data->digits_used,data->digits_used) + slack - ); - long_add(data,rhs.data,temp); - return bigint_kernel_1(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_1& bigint_kernel_1:: - operator+= ( - const bigint_kernel_1& rhs - ) - { - // if there are other references to our data - if (data->references != 1) - { - data_record* temp = new data_record(std::max(data->digits_used,rhs.data->digits_used)+slack); - data->references -= 1; - long_add(data,rhs.data,temp); - data = temp; - } - // if data is not big enough for the result - else if (data->size <= std::max(data->digits_used,rhs.data->digits_used)) - { - data_record* temp = new data_record(std::max(data->digits_used,rhs.data->digits_used)+slack); - long_add(data,rhs.data,temp); - delete data; - data = temp; - } - // there is enough size and no references - else - { - long_add(data,rhs.data,data); - } - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_1 bigint_kernel_1:: - operator- ( - const bigint_kernel_1& rhs - ) const - { - data_record* temp = new data_record ( - data->digits_used + slack - ); - long_sub(data,rhs.data,temp); - return bigint_kernel_1(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_1& bigint_kernel_1:: - operator-= ( - const bigint_kernel_1& rhs - ) - { - // if there are other references to this data - if (data->references != 1) - { - data_record* temp = new data_record(data->digits_used+slack); - data->references -= 1; - long_sub(data,rhs.data,temp); - data = temp; - } - else - { - long_sub(data,rhs.data,data); - } - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_1 bigint_kernel_1:: - operator* ( - const bigint_kernel_1& rhs - ) const - { - data_record* temp = new data_record ( - data->digits_used + rhs.data->digits_used + slack - ); - long_mul(data,rhs.data,temp); - return bigint_kernel_1(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_1& bigint_kernel_1:: - operator*= ( - const bigint_kernel_1& rhs - ) - { - // create a data_record to store the result of the multiplication in - data_record* temp = new data_record(rhs.data->digits_used+data->digits_used+slack); - long_mul(data,rhs.data,temp); - - // if there are other references to data - if (data->references != 1) - { - data->references -= 1; - } - else - { - delete data; - } - data = temp; - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_1 bigint_kernel_1:: - operator/ ( - const bigint_kernel_1& rhs - ) const - { - data_record* temp = new data_record(data->digits_used+slack); - data_record* remainder; - try { - remainder = new data_record(data->digits_used+slack); - } catch (...) { delete temp; throw; } - - long_div(data,rhs.data,temp,remainder); - delete remainder; - - - return bigint_kernel_1(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_1& bigint_kernel_1:: - operator/= ( - const bigint_kernel_1& rhs - ) - { - - data_record* temp = new data_record(data->digits_used+slack); - data_record* remainder; - try { - remainder = new data_record(data->digits_used+slack); - } catch (...) { delete temp; throw; } - - long_div(data,rhs.data,temp,remainder); - - // check if there are other references to data - if (data->references != 1) - { - data->references -= 1; - } - // if there are no references to data then it must be deleted - else - { - delete data; - } - data = temp; - delete remainder; - - - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_1 bigint_kernel_1:: - operator% ( - const bigint_kernel_1& rhs - ) const - { - data_record* temp = new data_record(data->digits_used+slack); - data_record* remainder; - try { - remainder = new data_record(data->digits_used+slack); - } catch (...) { delete temp; throw; } - - long_div(data,rhs.data,temp,remainder); - delete temp; - return bigint_kernel_1(remainder,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_1& bigint_kernel_1:: - operator%= ( - const bigint_kernel_1& rhs - ) - { - data_record* temp = new data_record(data->digits_used+slack); - data_record* remainder; - try { - remainder = new data_record(data->digits_used+slack); - } catch (...) { delete temp; throw; } - - long_div(data,rhs.data,temp,remainder); - - // check if there are other references to data - if (data->references != 1) - { - data->references -= 1; - } - // if there are no references to data then it must be deleted - else - { - delete data; - } - data = remainder; - delete temp; - return *this; - } - -// ---------------------------------------------------------------------------------------- - - bool bigint_kernel_1:: - operator < ( - const bigint_kernel_1& rhs - ) const - { - return is_less_than(data,rhs.data); - } - -// ---------------------------------------------------------------------------------------- - - bool bigint_kernel_1:: - operator == ( - const bigint_kernel_1& rhs - ) const - { - return is_equal_to(data,rhs.data); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_1& bigint_kernel_1:: - operator= ( - const bigint_kernel_1& rhs - ) - { - if (this == &rhs) - return *this; - - // if we have the only reference to our data then delete it - if (data->references == 1) - { - delete data; - data = rhs.data; - data->references += 1; - } - else - { - data->references -= 1; - data = rhs.data; - data->references += 1; - } - - return *this; - } - -// ---------------------------------------------------------------------------------------- - - std::ostream& operator<< ( - std::ostream& out_, - const bigint_kernel_1& rhs - ) - { - std::ostream out(out_.rdbuf()); - - typedef bigint_kernel_1 bigint; - - bigint::data_record* temp = new bigint::data_record(*rhs.data,0); - - - - // get a char array big enough to hold the number in ascii format - char* str; - try { - str = new char[(rhs.data->digits_used)*5+10]; - } catch (...) { delete temp; throw; } - - char* str_start = str; - str += (rhs.data->digits_used)*5+9; - *str = 0; --str; - - - uint16 remainder; - rhs.short_div(temp,10000,temp,remainder); - - // pull the digits out of remainder - char a = remainder % 10 + '0'; - remainder /= 10; - char b = remainder % 10 + '0'; - remainder /= 10; - char c = remainder % 10 + '0'; - remainder /= 10; - char d = remainder % 10 + '0'; - remainder /= 10; - - - *str = a; --str; - *str = b; --str; - *str = c; --str; - *str = d; --str; - - - // keep looping until temp represents zero - while (temp->digits_used != 1 || *(temp->number) != 0) - { - rhs.short_div(temp,10000,temp,remainder); - - // pull the digits out of remainder - char a = remainder % 10 + '0'; - remainder /= 10; - char b = remainder % 10 + '0'; - remainder /= 10; - char c = remainder % 10 + '0'; - remainder /= 10; - char d = remainder % 10 + '0'; - remainder /= 10; - - *str = a; --str; - *str = b; --str; - *str = c; --str; - *str = d; --str; - } - - // throw away and extra leading zeros - ++str; - if (*str == '0') - ++str; - if (*str == '0') - ++str; - if (*str == '0') - ++str; - - - - - out << str; - delete [] str_start; - delete temp; - return out_; - - } - -// ---------------------------------------------------------------------------------------- - - std::istream& operator>> ( - std::istream& in_, - bigint_kernel_1& rhs - ) - { - std::istream in(in_.rdbuf()); - - // ignore any leading whitespaces - while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\n') - { - in.get(); - } - - // if the first digit is not an integer then this is an error - if ( !(in.peek() >= '0' && in.peek() <= '9')) - { - in_.clear(std::ios::failbit); - return in_; - } - - int num_read; - bigint_kernel_1 temp; - do - { - - // try to get 4 chars from in - num_read = 1; - char a = 0; - char b = 0; - char c = 0; - char d = 0; - - if (in.peek() >= '0' && in.peek() <= '9') - { - num_read *= 10; - a = in.get(); - } - if (in.peek() >= '0' && in.peek() <= '9') - { - num_read *= 10; - b = in.get(); - } - if (in.peek() >= '0' && in.peek() <= '9') - { - num_read *= 10; - c = in.get(); - } - if (in.peek() >= '0' && in.peek() <= '9') - { - num_read *= 10; - d = in.get(); - } - - // merge the for digits into an uint16 - uint16 num = 0; - if (a != 0) - { - num = a - '0'; - } - if (b != 0) - { - num *= 10; - num += b - '0'; - } - if (c != 0) - { - num *= 10; - num += c - '0'; - } - if (d != 0) - { - num *= 10; - num += d - '0'; - } - - - if (num_read != 1) - { - // shift the digits in temp left by the number of new digits we just read - temp *= num_read; - // add in new digits - temp += num; - } - - } while (num_read == 10000); - - - rhs = temp; - return in_; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_1 operator+ ( - uint16 lhs, - const bigint_kernel_1& rhs - ) - { - typedef bigint_kernel_1 bigint; - bigint::data_record* temp = new bigint::data_record - (rhs.data->digits_used+rhs.slack); - - rhs.short_add(rhs.data,lhs,temp); - return bigint_kernel_1(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_1 operator+ ( - const bigint_kernel_1& lhs, - uint16 rhs - ) - { - typedef bigint_kernel_1 bigint; - bigint::data_record* temp = new bigint::data_record - (lhs.data->digits_used+lhs.slack); - - lhs.short_add(lhs.data,rhs,temp); - return bigint_kernel_1(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_1& bigint_kernel_1:: - operator+= ( - uint16 rhs - ) - { - // if there are other references to this data - if (data->references != 1) - { - data_record* temp = new data_record(data->digits_used+slack); - data->references -= 1; - short_add(data,rhs,temp); - data = temp; - } - // or if we need to enlarge data then do so - else if (data->digits_used == data->size) - { - data_record* temp = new data_record(data->digits_used+slack); - short_add(data,rhs,temp); - delete data; - data = temp; - } - // or if there is plenty of space and no references - else - { - short_add(data,rhs,data); - } - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_1 operator- ( - uint16 lhs, - const bigint_kernel_1& rhs - ) - { - typedef bigint_kernel_1 bigint; - bigint::data_record* temp = new bigint::data_record(rhs.slack); - - *(temp->number) = lhs - *(rhs.data->number); - - return bigint_kernel_1(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_1 operator- ( - const bigint_kernel_1& lhs, - uint16 rhs - ) - { - typedef bigint_kernel_1 bigint; - bigint::data_record* temp = new bigint::data_record - (lhs.data->digits_used+lhs.slack); - - lhs.short_sub(lhs.data,rhs,temp); - return bigint_kernel_1(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_1& bigint_kernel_1:: - operator-= ( - uint16 rhs - ) - { - // if there are other references to this data - if (data->references != 1) - { - data_record* temp = new data_record(data->digits_used+slack); - data->references -= 1; - short_sub(data,rhs,temp); - data = temp; - } - else - { - short_sub(data,rhs,data); - } - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_1 operator* ( - uint16 lhs, - const bigint_kernel_1& rhs - ) - { - typedef bigint_kernel_1 bigint; - bigint::data_record* temp = new bigint::data_record - (rhs.data->digits_used+rhs.slack); - - rhs.short_mul(rhs.data,lhs,temp); - return bigint_kernel_1(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_1 operator* ( - const bigint_kernel_1& lhs, - uint16 rhs - ) - { - typedef bigint_kernel_1 bigint; - bigint::data_record* temp = new bigint::data_record - (lhs.data->digits_used+lhs.slack); - - lhs.short_mul(lhs.data,rhs,temp); - return bigint_kernel_1(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_1& bigint_kernel_1:: - operator*= ( - uint16 rhs - ) - { - // if there are other references to this data - if (data->references != 1) - { - data_record* temp = new data_record(data->digits_used+slack); - data->references -= 1; - short_mul(data,rhs,temp); - data = temp; - } - // or if we need to enlarge data - else if (data->digits_used == data->size) - { - data_record* temp = new data_record(data->digits_used+slack); - short_mul(data,rhs,temp); - delete data; - data = temp; - } - else - { - short_mul(data,rhs,data); - } - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_1 operator/ ( - uint16 lhs, - const bigint_kernel_1& rhs - ) - { - typedef bigint_kernel_1 bigint; - bigint::data_record* temp = new bigint::data_record(rhs.slack); - - // if rhs might not be bigger than lhs - if (rhs.data->digits_used == 1) - { - *(temp->number) = lhs/ *(rhs.data->number); - } - - return bigint_kernel_1(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_1 operator/ ( - const bigint_kernel_1& lhs, - uint16 rhs - ) - { - typedef bigint_kernel_1 bigint; - bigint::data_record* temp = new bigint::data_record - (lhs.data->digits_used+lhs.slack); - - uint16 remainder; - lhs.short_div(lhs.data,rhs,temp,remainder); - return bigint_kernel_1(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_1& bigint_kernel_1:: - operator/= ( - uint16 rhs - ) - { - uint16 remainder; - // if there are other references to this data - if (data->references != 1) - { - data_record* temp = new data_record(data->digits_used+slack); - data->references -= 1; - short_div(data,rhs,temp,remainder); - data = temp; - } - else - { - short_div(data,rhs,data,remainder); - } - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_1 operator% ( - uint16 lhs, - const bigint_kernel_1& rhs - ) - { - typedef bigint_kernel_1 bigint; - // temp is zero by default - bigint::data_record* temp = new bigint::data_record(rhs.slack); - - if (rhs.data->digits_used == 1) - { - // if rhs is just an uint16 inside then perform the modulus - *(temp->number) = lhs % *(rhs.data->number); - } - else - { - // if rhs is bigger than lhs then the answer is lhs - *(temp->number) = lhs; - } - - return bigint_kernel_1(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_1 operator% ( - const bigint_kernel_1& lhs, - uint16 rhs - ) - { - typedef bigint_kernel_1 bigint; - bigint::data_record* temp = new bigint::data_record(lhs.data->digits_used+lhs.slack); - - uint16 remainder; - - lhs.short_div(lhs.data,rhs,temp,remainder); - temp->digits_used = 1; - *(temp->number) = remainder; - return bigint_kernel_1(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_1& bigint_kernel_1:: - operator%= ( - uint16 rhs - ) - { - uint16 remainder; - // if there are other references to this data - if (data->references != 1) - { - data_record* temp = new data_record(data->digits_used+slack); - data->references -= 1; - short_div(data,rhs,temp,remainder); - data = temp; - } - else - { - short_div(data,rhs,data,remainder); - } - - data->digits_used = 1; - *(data->number) = remainder; - return *this; - } - -// ---------------------------------------------------------------------------------------- - - bool operator < ( - uint16 lhs, - const bigint_kernel_1& rhs - ) - { - return (rhs.data->digits_used > 1 || lhs < *(rhs.data->number) ); - } - -// ---------------------------------------------------------------------------------------- - - bool operator < ( - const bigint_kernel_1& lhs, - uint16 rhs - ) - { - return (lhs.data->digits_used == 1 && *(lhs.data->number) < rhs); - } - -// ---------------------------------------------------------------------------------------- - - bool operator == ( - const bigint_kernel_1& lhs, - uint16 rhs - ) - { - return (lhs.data->digits_used == 1 && *(lhs.data->number) == rhs); - } - -// ---------------------------------------------------------------------------------------- - - bool operator == ( - uint16 lhs, - const bigint_kernel_1& rhs - ) - { - return (rhs.data->digits_used == 1 && *(rhs.data->number) == lhs); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_1& bigint_kernel_1:: - operator= ( - uint16 rhs - ) - { - // check if there are other references to our data - if (data->references != 1) - { - data->references -= 1; - try { - data = new data_record(slack); - } catch (...) { data->references += 1; throw; } - } - else - { - data->digits_used = 1; - } - - *(data->number) = rhs; - - return *this; - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_1& bigint_kernel_1:: - operator++ ( - ) - { - // if there are other references to this data then make a copy of it - if (data->references != 1) - { - data_record* temp = new data_record(data->digits_used+slack); - data->references -= 1; - increment(data,temp); - data = temp; - } - // or if we need to enlarge data then do so - else if (data->digits_used == data->size) - { - data_record* temp = new data_record(data->digits_used+slack); - increment(data,temp); - delete data; - data = temp; - } - else - { - increment(data,data); - } - - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_1 bigint_kernel_1:: - operator++ ( - int - ) - { - data_record* temp; // this is the copy of temp we will return in the end - - data_record* temp2 = new data_record(data->digits_used+slack); - increment(data,temp2); - - temp = data; - data = temp2; - - return bigint_kernel_1(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_1& bigint_kernel_1:: - operator-- ( - ) - { - // if there are other references to this data - if (data->references != 1) - { - data_record* temp = new data_record(data->digits_used+slack); - data->references -= 1; - decrement(data,temp); - data = temp; - } - else - { - decrement(data,data); - } - - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_1 bigint_kernel_1:: - operator-- ( - int - ) - { - data_record* temp; // this is the copy of temp we will return in the end - - data_record* temp2 = new data_record(data->digits_used+slack); - decrement(data,temp2); - - temp = data; - data = temp2; - - return bigint_kernel_1(temp,0); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // private member function definitions -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_1:: - short_add ( - const data_record* data, - uint16 value, - data_record* result - ) const - { - // put value into the carry part of temp - uint32 temp = value; - temp <<= 16; - - - const uint16* number = data->number; - const uint16* end = number + data->digits_used; // one past the end of number - uint16* r = result->number; - - while (number != end) - { - // add *number and the current carry - temp = *number + (temp>>16); - // put the low word of temp into *r - *r = static_cast(temp & 0xFFFF); - - ++number; - ++r; - } - - // if there is a final carry - if ((temp>>16) != 0) - { - result->digits_used = data->digits_used + 1; - // store the carry in the most significant digit of the result - *r = static_cast(temp>>16); - } - else - { - result->digits_used = data->digits_used; - } - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_1:: - short_sub ( - const data_record* data, - uint16 value, - data_record* result - ) const - { - - - const uint16* number = data->number; - const uint16* end = number + data->digits_used - 1; - uint16* r = result->number; - - uint32 temp = *number - value; - - // put the low word of temp into *data - *r = static_cast(temp & 0xFFFF); - - - while (number != end) - { - ++number; - ++r; - - // subtract the carry from *number - temp = *number - (temp>>31); - - // put the low word of temp into *r - *r = static_cast(temp & 0xFFFF); - } - - // if we lost a digit in the subtraction - if (*r == 0) - { - if (data->digits_used == 1) - result->digits_used = 1; - else - result->digits_used = data->digits_used - 1; - } - else - { - result->digits_used = data->digits_used; - } - - - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_1:: - short_mul ( - const data_record* data, - uint16 value, - data_record* result - ) const - { - - uint32 temp = 0; - - - const uint16* number = data->number; - uint16* r = result->number; - const uint16* end = r + data->digits_used; - - - - while ( r != end) - { - - // multiply *data and value and add in the carry - temp = *number*(uint32)value + (temp>>16); - - // put the low word of temp into *data - *r = static_cast(temp & 0xFFFF); - - ++number; - ++r; - } - - // if there is a final carry - if ((temp>>16) != 0) - { - result->digits_used = data->digits_used + 1; - // put the final carry into the most significant digit of the result - *r = static_cast(temp>>16); - } - else - { - result->digits_used = data->digits_used; - } - - - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_1:: - short_div ( - const data_record* data, - uint16 value, - data_record* result, - uint16& rem - ) const - { - - uint16 remainder = 0; - uint32 temp; - - - - const uint16* number = data->number + data->digits_used - 1; - const uint16* end = number - data->digits_used; - uint16* r = result->number + data->digits_used - 1; - - - // if we are losing a digit in this division - if (*number < value) - { - if (data->digits_used == 1) - result->digits_used = 1; - else - result->digits_used = data->digits_used - 1; - } - else - { - result->digits_used = data->digits_used; - } - - - // perform the actual division - while (number != end) - { - - temp = *number + (((uint32)remainder)<<16); - - *r = static_cast(temp/value); - remainder = static_cast(temp%value); - - --number; - --r; - } - - rem = remainder; - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_1:: - long_add ( - const data_record* lhs, - const data_record* rhs, - data_record* result - ) const - { - // put value into the carry part of temp - uint32 temp=0; - - uint16* min_num; // the number with the least digits used - uint16* max_num; // the number with the most digits used - uint16* min_end; // one past the end of min_num - uint16* max_end; // one past the end of max_num - uint16* r = result->number; - - uint32 max_digits_used; - if (lhs->digits_used < rhs->digits_used) - { - max_digits_used = rhs->digits_used; - min_num = lhs->number; - max_num = rhs->number; - min_end = min_num + lhs->digits_used; - max_end = max_num + rhs->digits_used; - } - else - { - max_digits_used = lhs->digits_used; - min_num = rhs->number; - max_num = lhs->number; - min_end = min_num + rhs->digits_used; - max_end = max_num + lhs->digits_used; - } - - - - - while (min_num != min_end) - { - // add *min_num, *max_num and the current carry - temp = *min_num + *max_num + (temp>>16); - // put the low word of temp into *r - *r = static_cast(temp & 0xFFFF); - - ++min_num; - ++max_num; - ++r; - } - - - while (max_num != max_end) - { - // add *max_num and the current carry - temp = *max_num + (temp>>16); - // put the low word of temp into *r - *r = static_cast(temp & 0xFFFF); - - ++max_num; - ++r; - } - - // check if there was a final carry - if ((temp>>16) != 0) - { - result->digits_used = max_digits_used + 1; - // put the carry into the most significant digit in the result - *r = static_cast(temp>>16); - } - else - { - result->digits_used = max_digits_used; - } - - - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_1:: - long_sub ( - const data_record* lhs, - const data_record* rhs, - data_record* result - ) const - { - - - const uint16* number1 = lhs->number; - const uint16* number2 = rhs->number; - const uint16* end = number2 + rhs->digits_used; - uint16* r = result->number; - - - - uint32 temp =0; - - - while (number2 != end) - { - - // subtract *number2 from *number1 and then subtract any carry - temp = *number1 - *number2 - (temp>>31); - - // put the low word of temp into *r - *r = static_cast(temp & 0xFFFF); - - ++number1; - ++number2; - ++r; - } - - end = lhs->number + lhs->digits_used; - while (number1 != end) - { - - // subtract the carry from *number1 - temp = *number1 - (temp>>31); - - // put the low word of temp into *r - *r = static_cast(temp & 0xFFFF); - - ++number1; - ++r; - } - - result->digits_used = lhs->digits_used; - // adjust the number of digits used appropriately - --r; - while (*r == 0 && result->digits_used > 1) - { - --r; - --result->digits_used; - } - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_1:: - long_div ( - const data_record* lhs, - const data_record* rhs, - data_record* result, - data_record* remainder - ) const - { - // zero result - result->digits_used = 1; - *(result->number) = 0; - - uint16* a; - uint16* b; - uint16* end; - - // copy lhs into remainder - remainder->digits_used = lhs->digits_used; - a = remainder->number; - end = a + remainder->digits_used; - b = lhs->number; - while (a != end) - { - *a = *b; - ++a; - ++b; - } - - - // if rhs is bigger than lhs then result == 0 and remainder == lhs - // so then we can quit right now - if (is_less_than(lhs,rhs)) - { - return; - } - - - // make a temporary number - data_record temp(lhs->digits_used + slack); - - - // shift rhs left until it is one shift away from being larger than lhs and - // put the number of left shifts necessary into shifts - uint32 shifts; - shifts = (lhs->digits_used - rhs->digits_used) * 16; - - shift_left(rhs,&temp,shifts); - - - // while (lhs > temp) - while (is_less_than(&temp,lhs)) - { - shift_left(&temp,&temp,1); - ++shifts; - } - // make sure lhs isn't smaller than temp - while (is_less_than(lhs,&temp)) - { - shift_right(&temp,&temp); - --shifts; - } - - - - // we want to execute the loop shifts +1 times - ++shifts; - while (shifts != 0) - { - shift_left(result,result,1); - // if (temp <= remainder) - if (!is_less_than(remainder,&temp)) - { - long_sub(remainder,&temp,remainder); - - // increment result - uint16* r = result->number; - uint16* end = r + result->digits_used; - while (true) - { - ++(*r); - // if there was no carry then we are done - if (*r != 0) - break; - - ++r; - - // if we hit the end of r and there is still a carry then - // the next digit of r is 1 and there is one more digit used - if (r == end) - { - *r = 1; - ++(result->digits_used); - break; - } - } - } - shift_right(&temp,&temp); - --shifts; - } - - - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_1:: - long_mul ( - const data_record* lhs, - const data_record* rhs, - data_record* result - ) const - { - // make result be zero - result->digits_used = 1; - *(result->number) = 0; - - - const data_record* aa; - const data_record* bb; - - if (lhs->digits_used < rhs->digits_used) - { - // make copies of lhs and rhs and give them an appropriate amount of - // extra memory so there won't be any overflows - aa = lhs; - bb = rhs; - } - else - { - // make copies of lhs and rhs and give them an appropriate amount of - // extra memory so there won't be any overflows - aa = rhs; - bb = lhs; - } - // this is where we actually copy lhs and rhs - data_record b(*bb,aa->digits_used+slack); // the larger(approximately) of lhs and rhs - - - uint32 shift_value = 0; - uint16* anum = aa->number; - uint16* end = anum + aa->digits_used; - while (anum != end ) - { - uint16 bit = 0x0001; - - for (int i = 0; i < 16; ++i) - { - // if the specified bit of a is 1 - if ((*anum & bit) != 0) - { - shift_left(&b,&b,shift_value); - shift_value = 0; - long_add(&b,result,result); - } - ++shift_value; - bit <<= 1; - } - - ++anum; - } - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_1:: - shift_left ( - const data_record* data, - data_record* result, - uint32 shift_amount - ) const - { - uint32 offset = shift_amount/16; - shift_amount &= 0xf; // same as shift_amount %= 16; - - uint16* r = result->number + data->digits_used + offset; // result - uint16* end = data->number; - uint16* s = end + data->digits_used; // source - const uint32 temp = 16 - shift_amount; - - *r = (*(--s) >> temp); - // set the number of digits used in the result - // if the upper bits from *s were zero then don't count this first word - if (*r == 0) - { - result->digits_used = data->digits_used + offset; - } - else - { - result->digits_used = data->digits_used + offset + 1; - } - --r; - - while (s != end) - { - *r = ((*s << shift_amount) | ( *(s-1) >> temp)); - --r; - --s; - } - *r = *s << shift_amount; - - // now zero the rest of the result - end = result->number; - while (r != end) - *(--r) = 0; - - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_1:: - shift_right ( - const data_record* data, - data_record* result - ) const - { - - uint16* r = result->number; // result - uint16* s = data->number; // source - uint16* end = s + data->digits_used - 1; - - while (s != end) - { - *r = (*s >> 1) | (*(s+1) << 15); - ++r; - ++s; - } - *r = *s >> 1; - - - // calculate the new number for digits_used - if (*r == 0) - { - if (data->digits_used != 1) - result->digits_used = data->digits_used - 1; - else - result->digits_used = 1; - } - else - { - result->digits_used = data->digits_used; - } - - - } - -// ---------------------------------------------------------------------------------------- - - bool bigint_kernel_1:: - is_less_than ( - const data_record* lhs, - const data_record* rhs - ) const - { - uint32 lhs_digits_used = lhs->digits_used; - uint32 rhs_digits_used = rhs->digits_used; - - // if lhs is definitely less than rhs - if (lhs_digits_used < rhs_digits_used ) - return true; - // if lhs is definitely greater than rhs - else if (lhs_digits_used > rhs_digits_used) - return false; - else - { - uint16* end = lhs->number; - uint16* l = end + lhs_digits_used; - uint16* r = rhs->number + rhs_digits_used; - - while (l != end) - { - --l; - --r; - if (*l < *r) - return true; - else if (*l > *r) - return false; - } - - // at this point we know that they are equal - return false; - } - - } - -// ---------------------------------------------------------------------------------------- - - bool bigint_kernel_1:: - is_equal_to ( - const data_record* lhs, - const data_record* rhs - ) const - { - // if lhs and rhs are definitely not equal - if (lhs->digits_used != rhs->digits_used ) - { - return false; - } - else - { - uint16* l = lhs->number; - uint16* r = rhs->number; - uint16* end = l + lhs->digits_used; - - while (l != end) - { - if (*l != *r) - return false; - ++l; - ++r; - } - - // at this point we know that they are equal - return true; - } - - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_1:: - increment ( - const data_record* source, - data_record* dest - ) const - { - uint16* s = source->number; - uint16* d = dest->number; - uint16* end = s + source->digits_used; - while (true) - { - *d = *s + 1; - - // if there was no carry then break out of the loop - if (*d != 0) - { - dest->digits_used = source->digits_used; - - // copy the rest of the digits over to d - ++d; ++s; - while (s != end) - { - *d = *s; - ++d; - ++s; - } - - break; - } - - - ++s; - - // if we have hit the end of s and there was a carry up to this point - // then just make the next digit 1 and add one to the digits used - if (s == end) - { - ++d; - dest->digits_used = source->digits_used + 1; - *d = 1; - break; - } - - ++d; - } - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_1:: - decrement ( - const data_record* source, - data_record* dest - ) const - { - uint16* s = source->number; - uint16* d = dest->number; - uint16* end = s + source->digits_used; - while (true) - { - *d = *s - 1; - - // if there was no carry then break out of the loop - if (*d != 0xFFFF) - { - // if we lost a digit in the subtraction - if (*d == 0 && s+1 == end) - { - if (source->digits_used == 1) - dest->digits_used = 1; - else - dest->digits_used = source->digits_used - 1; - } - else - { - dest->digits_used = source->digits_used; - } - break; - } - else - { - ++d; - ++s; - } - - } - - // copy the rest of the digits over to d - ++d; - ++s; - while (s != end) - { - *d = *s; - ++d; - ++s; - } - } - -// ---------------------------------------------------------------------------------------- - -} -#endif // DLIB_BIGINT_KERNEL_1_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_1.h b/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_1.h index 12a51d0f..3e7f3d85 100644 --- a/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_1.h @@ -12,7 +12,6 @@ namespace dlib { - using namespace dlib::relational_operators; // defined in algs.h class bigint_kernel_1 { @@ -531,6 +530,10 @@ namespace dlib } } + inline bool operator> (const bigint_kernel_1& a, const bigint_kernel_1& b) { return b < a; } + inline bool operator!= (const bigint_kernel_1& a, const bigint_kernel_1& b) { return !(a == b); } + inline bool operator<= (const bigint_kernel_1& a, const bigint_kernel_1& b) { return !(b < a); } + inline bool operator>= (const bigint_kernel_1& a, const bigint_kernel_1& b) { return !(a < b); } } #ifdef NO_MAKEFILE diff --git a/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_2.cpp b/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_2.cpp deleted file mode 100644 index 005e080a..00000000 --- a/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_2.cpp +++ /dev/null @@ -1,1945 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_BIGINT_KERNEL_2_CPp_ -#define DLIB_BIGINT_KERNEL_2_CPp_ -#include "bigint_kernel_2.h" - -#include -#include - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // member/friend function definitions -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - bigint_kernel_2:: - bigint_kernel_2 ( - ) : - slack(25), - data(new data_record(slack)) - {} - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_2:: - bigint_kernel_2 ( - uint32 value - ) : - slack(25), - data(new data_record(slack)) - { - *(data->number) = static_cast(value&0xFFFF); - *(data->number+1) = static_cast((value>>16)&0xFFFF); - if (*(data->number+1) != 0) - data->digits_used = 2; - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_2:: - bigint_kernel_2 ( - const bigint_kernel_2& item - ) : - slack(25), - data(item.data) - { - data->references += 1; - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_2:: - ~bigint_kernel_2 ( - ) - { - if (data->references == 1) - { - delete data; - } - else - { - data->references -= 1; - } - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_2 bigint_kernel_2:: - operator+ ( - const bigint_kernel_2& rhs - ) const - { - data_record* temp = new data_record ( - std::max(rhs.data->digits_used,data->digits_used) + slack - ); - long_add(data,rhs.data,temp); - return bigint_kernel_2(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_2& bigint_kernel_2:: - operator+= ( - const bigint_kernel_2& rhs - ) - { - // if there are other references to our data - if (data->references != 1) - { - data_record* temp = new data_record(std::max(data->digits_used,rhs.data->digits_used)+slack); - data->references -= 1; - long_add(data,rhs.data,temp); - data = temp; - } - // if data is not big enough for the result - else if (data->size <= std::max(data->digits_used,rhs.data->digits_used)) - { - data_record* temp = new data_record(std::max(data->digits_used,rhs.data->digits_used)+slack); - long_add(data,rhs.data,temp); - delete data; - data = temp; - } - // there is enough size and no references - else - { - long_add(data,rhs.data,data); - } - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_2 bigint_kernel_2:: - operator- ( - const bigint_kernel_2& rhs - ) const - { - data_record* temp = new data_record ( - data->digits_used + slack - ); - long_sub(data,rhs.data,temp); - return bigint_kernel_2(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_2& bigint_kernel_2:: - operator-= ( - const bigint_kernel_2& rhs - ) - { - // if there are other references to this data - if (data->references != 1) - { - data_record* temp = new data_record(data->digits_used+slack); - data->references -= 1; - long_sub(data,rhs.data,temp); - data = temp; - } - else - { - long_sub(data,rhs.data,data); - } - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_2 bigint_kernel_2:: - operator* ( - const bigint_kernel_2& rhs - ) const - { - data_record* temp = new data_record ( - data->digits_used + rhs.data->digits_used + slack - ); - long_mul(data,rhs.data,temp); - return bigint_kernel_2(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_2& bigint_kernel_2:: - operator*= ( - const bigint_kernel_2& rhs - ) - { - // create a data_record to store the result of the multiplication in - data_record* temp = new data_record(rhs.data->digits_used+data->digits_used+slack); - long_mul(data,rhs.data,temp); - - // if there are other references to data - if (data->references != 1) - { - data->references -= 1; - } - else - { - delete data; - } - data = temp; - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_2 bigint_kernel_2:: - operator/ ( - const bigint_kernel_2& rhs - ) const - { - data_record* temp = new data_record(data->digits_used+slack); - data_record* remainder; - try { - remainder = new data_record(data->digits_used+slack); - } catch (...) { delete temp; throw; } - - long_div(data,rhs.data,temp,remainder); - delete remainder; - - - return bigint_kernel_2(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_2& bigint_kernel_2:: - operator/= ( - const bigint_kernel_2& rhs - ) - { - - data_record* temp = new data_record(data->digits_used+slack); - data_record* remainder; - try { - remainder = new data_record(data->digits_used+slack); - } catch (...) { delete temp; throw; } - - long_div(data,rhs.data,temp,remainder); - - // check if there are other references to data - if (data->references != 1) - { - data->references -= 1; - } - // if there are no references to data then it must be deleted - else - { - delete data; - } - data = temp; - delete remainder; - - - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_2 bigint_kernel_2:: - operator% ( - const bigint_kernel_2& rhs - ) const - { - data_record* temp = new data_record(data->digits_used+slack); - data_record* remainder; - try { - remainder = new data_record(data->digits_used+slack); - } catch (...) { delete temp; throw; } - - long_div(data,rhs.data,temp,remainder); - delete temp; - return bigint_kernel_2(remainder,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_2& bigint_kernel_2:: - operator%= ( - const bigint_kernel_2& rhs - ) - { - data_record* temp = new data_record(data->digits_used+slack); - data_record* remainder; - try { - remainder = new data_record(data->digits_used+slack); - } catch (...) { delete temp; throw; } - - long_div(data,rhs.data,temp,remainder); - - // check if there are other references to data - if (data->references != 1) - { - data->references -= 1; - } - // if there are no references to data then it must be deleted - else - { - delete data; - } - data = remainder; - delete temp; - return *this; - } - -// ---------------------------------------------------------------------------------------- - - bool bigint_kernel_2:: - operator < ( - const bigint_kernel_2& rhs - ) const - { - return is_less_than(data,rhs.data); - } - -// ---------------------------------------------------------------------------------------- - - bool bigint_kernel_2:: - operator == ( - const bigint_kernel_2& rhs - ) const - { - return is_equal_to(data,rhs.data); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_2& bigint_kernel_2:: - operator= ( - const bigint_kernel_2& rhs - ) - { - if (this == &rhs) - return *this; - - // if we have the only reference to our data then delete it - if (data->references == 1) - { - delete data; - data = rhs.data; - data->references += 1; - } - else - { - data->references -= 1; - data = rhs.data; - data->references += 1; - } - - return *this; - } - -// ---------------------------------------------------------------------------------------- - - std::ostream& operator<< ( - std::ostream& out_, - const bigint_kernel_2& rhs - ) - { - std::ostream out(out_.rdbuf()); - - typedef bigint_kernel_2 bigint; - - bigint::data_record* temp = new bigint::data_record(*rhs.data,0); - - - - // get a char array big enough to hold the number in ascii format - char* str; - try { - str = new char[(rhs.data->digits_used)*5+10]; - } catch (...) { delete temp; throw; } - - char* str_start = str; - str += (rhs.data->digits_used)*5+9; - *str = 0; --str; - - - uint16 remainder; - rhs.short_div(temp,10000,temp,remainder); - - // pull the digits out of remainder - char a = remainder % 10 + '0'; - remainder /= 10; - char b = remainder % 10 + '0'; - remainder /= 10; - char c = remainder % 10 + '0'; - remainder /= 10; - char d = remainder % 10 + '0'; - remainder /= 10; - - - *str = a; --str; - *str = b; --str; - *str = c; --str; - *str = d; --str; - - - // keep looping until temp represents zero - while (temp->digits_used != 1 || *(temp->number) != 0) - { - rhs.short_div(temp,10000,temp,remainder); - - // pull the digits out of remainder - char a = remainder % 10 + '0'; - remainder /= 10; - char b = remainder % 10 + '0'; - remainder /= 10; - char c = remainder % 10 + '0'; - remainder /= 10; - char d = remainder % 10 + '0'; - remainder /= 10; - - *str = a; --str; - *str = b; --str; - *str = c; --str; - *str = d; --str; - } - - // throw away and extra leading zeros - ++str; - if (*str == '0') - ++str; - if (*str == '0') - ++str; - if (*str == '0') - ++str; - - - - - out << str; - delete [] str_start; - delete temp; - return out_; - - } - -// ---------------------------------------------------------------------------------------- - - std::istream& operator>> ( - std::istream& in_, - bigint_kernel_2& rhs - ) - { - std::istream in(in_.rdbuf()); - - // ignore any leading whitespaces - while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\n') - { - in.get(); - } - - // if the first digit is not an integer then this is an error - if ( !(in.peek() >= '0' && in.peek() <= '9')) - { - in_.clear(std::ios::failbit); - return in_; - } - - int num_read; - bigint_kernel_2 temp; - do - { - - // try to get 4 chars from in - num_read = 1; - char a = 0; - char b = 0; - char c = 0; - char d = 0; - - if (in.peek() >= '0' && in.peek() <= '9') - { - num_read *= 10; - a = in.get(); - } - if (in.peek() >= '0' && in.peek() <= '9') - { - num_read *= 10; - b = in.get(); - } - if (in.peek() >= '0' && in.peek() <= '9') - { - num_read *= 10; - c = in.get(); - } - if (in.peek() >= '0' && in.peek() <= '9') - { - num_read *= 10; - d = in.get(); - } - - // merge the for digits into an uint16 - uint16 num = 0; - if (a != 0) - { - num = a - '0'; - } - if (b != 0) - { - num *= 10; - num += b - '0'; - } - if (c != 0) - { - num *= 10; - num += c - '0'; - } - if (d != 0) - { - num *= 10; - num += d - '0'; - } - - - if (num_read != 1) - { - // shift the digits in temp left by the number of new digits we just read - temp *= num_read; - // add in new digits - temp += num; - } - - } while (num_read == 10000); - - - rhs = temp; - return in_; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_2 operator+ ( - uint16 lhs, - const bigint_kernel_2& rhs - ) - { - typedef bigint_kernel_2 bigint; - bigint::data_record* temp = new bigint::data_record - (rhs.data->digits_used+rhs.slack); - - rhs.short_add(rhs.data,lhs,temp); - return bigint_kernel_2(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_2 operator+ ( - const bigint_kernel_2& lhs, - uint16 rhs - ) - { - typedef bigint_kernel_2 bigint; - bigint::data_record* temp = new bigint::data_record - (lhs.data->digits_used+lhs.slack); - - lhs.short_add(lhs.data,rhs,temp); - return bigint_kernel_2(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_2& bigint_kernel_2:: - operator+= ( - uint16 rhs - ) - { - // if there are other references to this data - if (data->references != 1) - { - data_record* temp = new data_record(data->digits_used+slack); - data->references -= 1; - short_add(data,rhs,temp); - data = temp; - } - // or if we need to enlarge data then do so - else if (data->digits_used == data->size) - { - data_record* temp = new data_record(data->digits_used+slack); - short_add(data,rhs,temp); - delete data; - data = temp; - } - // or if there is plenty of space and no references - else - { - short_add(data,rhs,data); - } - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_2 operator- ( - uint16 lhs, - const bigint_kernel_2& rhs - ) - { - typedef bigint_kernel_2 bigint; - bigint::data_record* temp = new bigint::data_record(rhs.slack); - - *(temp->number) = lhs - *(rhs.data->number); - - return bigint_kernel_2(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_2 operator- ( - const bigint_kernel_2& lhs, - uint16 rhs - ) - { - typedef bigint_kernel_2 bigint; - bigint::data_record* temp = new bigint::data_record - (lhs.data->digits_used+lhs.slack); - - lhs.short_sub(lhs.data,rhs,temp); - return bigint_kernel_2(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_2& bigint_kernel_2:: - operator-= ( - uint16 rhs - ) - { - // if there are other references to this data - if (data->references != 1) - { - data_record* temp = new data_record(data->digits_used+slack); - data->references -= 1; - short_sub(data,rhs,temp); - data = temp; - } - else - { - short_sub(data,rhs,data); - } - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_2 operator* ( - uint16 lhs, - const bigint_kernel_2& rhs - ) - { - typedef bigint_kernel_2 bigint; - bigint::data_record* temp = new bigint::data_record - (rhs.data->digits_used+rhs.slack); - - rhs.short_mul(rhs.data,lhs,temp); - return bigint_kernel_2(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_2 operator* ( - const bigint_kernel_2& lhs, - uint16 rhs - ) - { - typedef bigint_kernel_2 bigint; - bigint::data_record* temp = new bigint::data_record - (lhs.data->digits_used+lhs.slack); - - lhs.short_mul(lhs.data,rhs,temp); - return bigint_kernel_2(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_2& bigint_kernel_2:: - operator*= ( - uint16 rhs - ) - { - // if there are other references to this data - if (data->references != 1) - { - data_record* temp = new data_record(data->digits_used+slack); - data->references -= 1; - short_mul(data,rhs,temp); - data = temp; - } - // or if we need to enlarge data - else if (data->digits_used == data->size) - { - data_record* temp = new data_record(data->digits_used+slack); - short_mul(data,rhs,temp); - delete data; - data = temp; - } - else - { - short_mul(data,rhs,data); - } - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_2 operator/ ( - uint16 lhs, - const bigint_kernel_2& rhs - ) - { - typedef bigint_kernel_2 bigint; - bigint::data_record* temp = new bigint::data_record(rhs.slack); - - // if rhs might not be bigger than lhs - if (rhs.data->digits_used == 1) - { - *(temp->number) = lhs/ *(rhs.data->number); - } - - return bigint_kernel_2(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_2 operator/ ( - const bigint_kernel_2& lhs, - uint16 rhs - ) - { - typedef bigint_kernel_2 bigint; - bigint::data_record* temp = new bigint::data_record - (lhs.data->digits_used+lhs.slack); - - uint16 remainder; - lhs.short_div(lhs.data,rhs,temp,remainder); - return bigint_kernel_2(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_2& bigint_kernel_2:: - operator/= ( - uint16 rhs - ) - { - uint16 remainder; - // if there are other references to this data - if (data->references != 1) - { - data_record* temp = new data_record(data->digits_used+slack); - data->references -= 1; - short_div(data,rhs,temp,remainder); - data = temp; - } - else - { - short_div(data,rhs,data,remainder); - } - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_2 operator% ( - uint16 lhs, - const bigint_kernel_2& rhs - ) - { - typedef bigint_kernel_2 bigint; - // temp is zero by default - bigint::data_record* temp = new bigint::data_record(rhs.slack); - - if (rhs.data->digits_used == 1) - { - // if rhs is just an uint16 inside then perform the modulus - *(temp->number) = lhs % *(rhs.data->number); - } - else - { - // if rhs is bigger than lhs then the answer is lhs - *(temp->number) = lhs; - } - - return bigint_kernel_2(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_2 operator% ( - const bigint_kernel_2& lhs, - uint16 rhs - ) - { - typedef bigint_kernel_2 bigint; - bigint::data_record* temp = new bigint::data_record(lhs.data->digits_used+lhs.slack); - - uint16 remainder; - - lhs.short_div(lhs.data,rhs,temp,remainder); - temp->digits_used = 1; - *(temp->number) = remainder; - return bigint_kernel_2(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_2& bigint_kernel_2:: - operator%= ( - uint16 rhs - ) - { - uint16 remainder; - // if there are other references to this data - if (data->references != 1) - { - data_record* temp = new data_record(data->digits_used+slack); - data->references -= 1; - short_div(data,rhs,temp,remainder); - data = temp; - } - else - { - short_div(data,rhs,data,remainder); - } - - data->digits_used = 1; - *(data->number) = remainder; - return *this; - } - -// ---------------------------------------------------------------------------------------- - - bool operator < ( - uint16 lhs, - const bigint_kernel_2& rhs - ) - { - return (rhs.data->digits_used > 1 || lhs < *(rhs.data->number) ); - } - -// ---------------------------------------------------------------------------------------- - - bool operator < ( - const bigint_kernel_2& lhs, - uint16 rhs - ) - { - return (lhs.data->digits_used == 1 && *(lhs.data->number) < rhs); - } - -// ---------------------------------------------------------------------------------------- - - bool operator == ( - const bigint_kernel_2& lhs, - uint16 rhs - ) - { - return (lhs.data->digits_used == 1 && *(lhs.data->number) == rhs); - } - -// ---------------------------------------------------------------------------------------- - - bool operator == ( - uint16 lhs, - const bigint_kernel_2& rhs - ) - { - return (rhs.data->digits_used == 1 && *(rhs.data->number) == lhs); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_2& bigint_kernel_2:: - operator= ( - uint16 rhs - ) - { - // check if there are other references to our data - if (data->references != 1) - { - data->references -= 1; - try { - data = new data_record(slack); - } catch (...) { data->references += 1; throw; } - } - else - { - data->digits_used = 1; - } - - *(data->number) = rhs; - - return *this; - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_2& bigint_kernel_2:: - operator++ ( - ) - { - // if there are other references to this data then make a copy of it - if (data->references != 1) - { - data_record* temp = new data_record(data->digits_used+slack); - data->references -= 1; - increment(data,temp); - data = temp; - } - // or if we need to enlarge data then do so - else if (data->digits_used == data->size) - { - data_record* temp = new data_record(data->digits_used+slack); - increment(data,temp); - delete data; - data = temp; - } - else - { - increment(data,data); - } - - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_2 bigint_kernel_2:: - operator++ ( - int - ) - { - data_record* temp; // this is the copy of temp we will return in the end - - data_record* temp2 = new data_record(data->digits_used+slack); - increment(data,temp2); - - temp = data; - data = temp2; - - return bigint_kernel_2(temp,0); - } - -// ---------------------------------------------------------------------------------------- - - bigint_kernel_2& bigint_kernel_2:: - operator-- ( - ) - { - // if there are other references to this data - if (data->references != 1) - { - data_record* temp = new data_record(data->digits_used+slack); - data->references -= 1; - decrement(data,temp); - data = temp; - } - else - { - decrement(data,data); - } - - return *this; - } - -// ---------------------------------------------------------------------------------------- - - const bigint_kernel_2 bigint_kernel_2:: - operator-- ( - int - ) - { - data_record* temp; // this is the copy of temp we will return in the end - - data_record* temp2 = new data_record(data->digits_used+slack); - decrement(data,temp2); - - temp = data; - data = temp2; - - return bigint_kernel_2(temp,0); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // private member function definitions -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_2:: - short_add ( - const data_record* data, - uint16 value, - data_record* result - ) const - { - // put value into the carry part of temp - uint32 temp = value; - temp <<= 16; - - - const uint16* number = data->number; - const uint16* end = number + data->digits_used; // one past the end of number - uint16* r = result->number; - - while (number != end) - { - // add *number and the current carry - temp = *number + (temp>>16); - // put the low word of temp into *r - *r = static_cast(temp & 0xFFFF); - - ++number; - ++r; - } - - // if there is a final carry - if ((temp>>16) != 0) - { - result->digits_used = data->digits_used + 1; - // store the carry in the most significant digit of the result - *r = static_cast(temp>>16); - } - else - { - result->digits_used = data->digits_used; - } - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_2:: - short_sub ( - const data_record* data, - uint16 value, - data_record* result - ) const - { - - - const uint16* number = data->number; - const uint16* end = number + data->digits_used - 1; - uint16* r = result->number; - - uint32 temp = *number - value; - - // put the low word of temp into *data - *r = static_cast(temp & 0xFFFF); - - - while (number != end) - { - ++number; - ++r; - - // subtract the carry from *number - temp = *number - (temp>>31); - - // put the low word of temp into *r - *r = static_cast(temp & 0xFFFF); - } - - // if we lost a digit in the subtraction - if (*r == 0) - { - if (data->digits_used == 1) - result->digits_used = 1; - else - result->digits_used = data->digits_used - 1; - } - else - { - result->digits_used = data->digits_used; - } - - - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_2:: - short_mul ( - const data_record* data, - uint16 value, - data_record* result - ) const - { - - uint32 temp = 0; - - - const uint16* number = data->number; - uint16* r = result->number; - const uint16* end = r + data->digits_used; - - - - while ( r != end) - { - - // multiply *data and value and add in the carry - temp = *number*(uint32)value + (temp>>16); - - // put the low word of temp into *data - *r = static_cast(temp & 0xFFFF); - - ++number; - ++r; - } - - // if there is a final carry - if ((temp>>16) != 0) - { - result->digits_used = data->digits_used + 1; - // put the final carry into the most significant digit of the result - *r = static_cast(temp>>16); - } - else - { - result->digits_used = data->digits_used; - } - - - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_2:: - short_div ( - const data_record* data, - uint16 value, - data_record* result, - uint16& rem - ) const - { - - uint16 remainder = 0; - uint32 temp; - - - - const uint16* number = data->number + data->digits_used - 1; - const uint16* end = number - data->digits_used; - uint16* r = result->number + data->digits_used - 1; - - - // if we are losing a digit in this division - if (*number < value) - { - if (data->digits_used == 1) - result->digits_used = 1; - else - result->digits_used = data->digits_used - 1; - } - else - { - result->digits_used = data->digits_used; - } - - - // perform the actual division - while (number != end) - { - - temp = *number + (((uint32)remainder)<<16); - - *r = static_cast(temp/value); - remainder = static_cast(temp%value); - - --number; - --r; - } - - rem = remainder; - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_2:: - long_add ( - const data_record* lhs, - const data_record* rhs, - data_record* result - ) const - { - // put value into the carry part of temp - uint32 temp=0; - - uint16* min_num; // the number with the least digits used - uint16* max_num; // the number with the most digits used - uint16* min_end; // one past the end of min_num - uint16* max_end; // one past the end of max_num - uint16* r = result->number; - - uint32 max_digits_used; - if (lhs->digits_used < rhs->digits_used) - { - max_digits_used = rhs->digits_used; - min_num = lhs->number; - max_num = rhs->number; - min_end = min_num + lhs->digits_used; - max_end = max_num + rhs->digits_used; - } - else - { - max_digits_used = lhs->digits_used; - min_num = rhs->number; - max_num = lhs->number; - min_end = min_num + rhs->digits_used; - max_end = max_num + lhs->digits_used; - } - - - - - while (min_num != min_end) - { - // add *min_num, *max_num and the current carry - temp = *min_num + *max_num + (temp>>16); - // put the low word of temp into *r - *r = static_cast(temp & 0xFFFF); - - ++min_num; - ++max_num; - ++r; - } - - - while (max_num != max_end) - { - // add *max_num and the current carry - temp = *max_num + (temp>>16); - // put the low word of temp into *r - *r = static_cast(temp & 0xFFFF); - - ++max_num; - ++r; - } - - // check if there was a final carry - if ((temp>>16) != 0) - { - result->digits_used = max_digits_used + 1; - // put the carry into the most significant digit in the result - *r = static_cast(temp>>16); - } - else - { - result->digits_used = max_digits_used; - } - - - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_2:: - long_sub ( - const data_record* lhs, - const data_record* rhs, - data_record* result - ) const - { - - - const uint16* number1 = lhs->number; - const uint16* number2 = rhs->number; - const uint16* end = number2 + rhs->digits_used; - uint16* r = result->number; - - - - uint32 temp =0; - - - while (number2 != end) - { - - // subtract *number2 from *number1 and then subtract any carry - temp = *number1 - *number2 - (temp>>31); - - // put the low word of temp into *r - *r = static_cast(temp & 0xFFFF); - - ++number1; - ++number2; - ++r; - } - - end = lhs->number + lhs->digits_used; - while (number1 != end) - { - - // subtract the carry from *number1 - temp = *number1 - (temp>>31); - - // put the low word of temp into *r - *r = static_cast(temp & 0xFFFF); - - ++number1; - ++r; - } - - result->digits_used = lhs->digits_used; - // adjust the number of digits used appropriately - --r; - while (*r == 0 && result->digits_used > 1) - { - --r; - --result->digits_used; - } - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_2:: - long_div ( - const data_record* lhs, - const data_record* rhs, - data_record* result, - data_record* remainder - ) const - { - // zero result - result->digits_used = 1; - *(result->number) = 0; - - uint16* a; - uint16* b; - uint16* end; - - // copy lhs into remainder - remainder->digits_used = lhs->digits_used; - a = remainder->number; - end = a + remainder->digits_used; - b = lhs->number; - while (a != end) - { - *a = *b; - ++a; - ++b; - } - - - // if rhs is bigger than lhs then result == 0 and remainder == lhs - // so then we can quit right now - if (is_less_than(lhs,rhs)) - { - return; - } - - - // make a temporary number - data_record temp(lhs->digits_used + slack); - - - // shift rhs left until it is one shift away from being larger than lhs and - // put the number of left shifts necessary into shifts - uint32 shifts; - shifts = (lhs->digits_used - rhs->digits_used) * 16; - - shift_left(rhs,&temp,shifts); - - - // while (lhs > temp) - while (is_less_than(&temp,lhs)) - { - shift_left(&temp,&temp,1); - ++shifts; - } - // make sure lhs isn't smaller than temp - while (is_less_than(lhs,&temp)) - { - shift_right(&temp,&temp); - --shifts; - } - - - - // we want to execute the loop shifts +1 times - ++shifts; - while (shifts != 0) - { - shift_left(result,result,1); - // if (temp <= remainder) - if (!is_less_than(remainder,&temp)) - { - long_sub(remainder,&temp,remainder); - - // increment result - uint16* r = result->number; - uint16* end = r + result->digits_used; - while (true) - { - ++(*r); - // if there was no carry then we are done - if (*r != 0) - break; - - ++r; - - // if we hit the end of r and there is still a carry then - // the next digit of r is 1 and there is one more digit used - if (r == end) - { - *r = 1; - ++(result->digits_used); - break; - } - } - } - shift_right(&temp,&temp); - --shifts; - } - - - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_2:: - long_mul ( - const data_record* lhs, - const data_record* rhs, - data_record* result - ) const - { - // if one of the numbers is small then use this simple but O(n^2) algorithm - if (std::min(lhs->digits_used, rhs->digits_used) < 10) - { - // make result be zero - result->digits_used = 1; - *(result->number) = 0; - - - const data_record* aa; - const data_record* bb; - - if (lhs->digits_used < rhs->digits_used) - { - // make copies of lhs and rhs and give them an appropriate amount of - // extra memory so there won't be any overflows - aa = lhs; - bb = rhs; - } - else - { - // make copies of lhs and rhs and give them an appropriate amount of - // extra memory so there won't be any overflows - aa = rhs; - bb = lhs; - } - - // copy the larger(approximately) of lhs and rhs into b - data_record b(*bb,aa->digits_used+slack); - - - uint32 shift_value = 0; - uint16* anum = aa->number; - uint16* end = anum + aa->digits_used; - while (anum != end ) - { - uint16 bit = 0x0001; - - for (int i = 0; i < 16; ++i) - { - // if the specified bit of a is 1 - if ((*anum & bit) != 0) - { - shift_left(&b,&b,shift_value); - shift_value = 0; - long_add(&b,result,result); - } - ++shift_value; - bit <<= 1; - } - - ++anum; - } - } - else // else if both lhs and rhs are large then use the more complex - // O(n*logn) algorithm - { - uint32 size = 1; - // make size a power of 2 - while (size < (lhs->digits_used + rhs->digits_used)*2) - { - size *= 2; - } - - // allocate some temporary space so we can do the FFT - ct* a = new ct[size]; - ct* b; try {b = new ct[size]; } catch (...) { delete [] a; throw; } - - // load lhs into the a array. We are breaking the input number into - // 8bit chunks for the purpose of using this fft algorithm. The reason - // for this is so that we have smaller numbers coming out of the final - // ifft. This helps avoid overflow. - for (uint32 i = 0; i < lhs->digits_used; ++i) - { - a[i*2] = ct((t)(lhs->number[i]&0xFF),0); - a[i*2+1] = ct((t)(lhs->number[i]>>8),0); - } - for (uint32 i = lhs->digits_used*2; i < size; ++i) - { - a[i] = 0; - } - - // load rhs into the b array - for (uint32 i = 0; i < rhs->digits_used; ++i) - { - b[i*2] = ct((t)(rhs->number[i]&0xFF),0); - b[i*2+1] = ct((t)(rhs->number[i]>>8),0); - } - for (uint32 i = rhs->digits_used*2; i < size; ++i) - { - b[i] = 0; - } - - // perform the forward fft of a and b - fft(a,size); - fft(b,size); - - const double l = 1.0/size; - - // do the pointwise multiply of a and b and also apply the scale - // factor in this loop too. - for (unsigned long i = 0; i < size; ++i) - { - a[i] = l*a[i]*b[i]; - } - - // Now compute the inverse fft of the pointwise multiplication of a and b. - // This is basically the result. We just have to take care of any carries - // that should happen. - ifft(a,size); - - // loop over the result and propagate any carries that need to take place. - // We will also be moving the resulting numbers into result->number at - // the same time. - uint64 carry = 0; - result->digits_used = 0; - int zeros = 0; - const uint32 len = lhs->digits_used + rhs->digits_used; - for (unsigned long i = 0; i < len; ++i) - { - uint64 num1 = static_cast(std::floor(a[i*2].real()+0.5)); - num1 += carry; - carry = 0; - if (num1 > 255) - { - carry = num1 >> 8; - num1 = (num1&0xFF); - } - - uint64 num2 = static_cast(std::floor(a[i*2+1].real()+0.5)); - num2 += carry; - carry = 0; - if (num2 > 255) - { - carry = num2 >> 8; - num2 = (num2&0xFF); - } - - // put the new number into its final place - num1 = (num2<<8) | num1; - result->number[i] = static_cast(num1); - - // keep track of the number of leading zeros - if (num1 == 0) - ++zeros; - else - zeros = 0; - ++(result->digits_used); - } - - // adjust digits_used so that it reflects the actual number - // of non-zero digits in our representation. - result->digits_used -= zeros; - - // if the result was zero then adjust the result accordingly - if (result->digits_used == 0) - { - // make result be zero - result->digits_used = 1; - *(result->number) = 0; - } - - // free all the temporary buffers - delete [] a; - delete [] b; - } - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_2:: - shift_left ( - const data_record* data, - data_record* result, - uint32 shift_amount - ) const - { - uint32 offset = shift_amount/16; - shift_amount &= 0xf; // same as shift_amount %= 16; - - uint16* r = result->number + data->digits_used + offset; // result - uint16* end = data->number; - uint16* s = end + data->digits_used; // source - const uint32 temp = 16 - shift_amount; - - *r = (*(--s) >> temp); - // set the number of digits used in the result - // if the upper bits from *s were zero then don't count this first word - if (*r == 0) - { - result->digits_used = data->digits_used + offset; - } - else - { - result->digits_used = data->digits_used + offset + 1; - } - --r; - - while (s != end) - { - *r = ((*s << shift_amount) | ( *(s-1) >> temp)); - --r; - --s; - } - *r = *s << shift_amount; - - // now zero the rest of the result - end = result->number; - while (r != end) - *(--r) = 0; - - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_2:: - shift_right ( - const data_record* data, - data_record* result - ) const - { - - uint16* r = result->number; // result - uint16* s = data->number; // source - uint16* end = s + data->digits_used - 1; - - while (s != end) - { - *r = (*s >> 1) | (*(s+1) << 15); - ++r; - ++s; - } - *r = *s >> 1; - - - // calculate the new number for digits_used - if (*r == 0) - { - if (data->digits_used != 1) - result->digits_used = data->digits_used - 1; - else - result->digits_used = 1; - } - else - { - result->digits_used = data->digits_used; - } - - - } - -// ---------------------------------------------------------------------------------------- - - bool bigint_kernel_2:: - is_less_than ( - const data_record* lhs, - const data_record* rhs - ) const - { - uint32 lhs_digits_used = lhs->digits_used; - uint32 rhs_digits_used = rhs->digits_used; - - // if lhs is definitely less than rhs - if (lhs_digits_used < rhs_digits_used ) - return true; - // if lhs is definitely greater than rhs - else if (lhs_digits_used > rhs_digits_used) - return false; - else - { - uint16* end = lhs->number; - uint16* l = end + lhs_digits_used; - uint16* r = rhs->number + rhs_digits_used; - - while (l != end) - { - --l; - --r; - if (*l < *r) - return true; - else if (*l > *r) - return false; - } - - // at this point we know that they are equal - return false; - } - - } - -// ---------------------------------------------------------------------------------------- - - bool bigint_kernel_2:: - is_equal_to ( - const data_record* lhs, - const data_record* rhs - ) const - { - // if lhs and rhs are definitely not equal - if (lhs->digits_used != rhs->digits_used ) - { - return false; - } - else - { - uint16* l = lhs->number; - uint16* r = rhs->number; - uint16* end = l + lhs->digits_used; - - while (l != end) - { - if (*l != *r) - return false; - ++l; - ++r; - } - - // at this point we know that they are equal - return true; - } - - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_2:: - increment ( - const data_record* source, - data_record* dest - ) const - { - uint16* s = source->number; - uint16* d = dest->number; - uint16* end = s + source->digits_used; - while (true) - { - *d = *s + 1; - - // if there was no carry then break out of the loop - if (*d != 0) - { - dest->digits_used = source->digits_used; - - // copy the rest of the digits over to d - ++d; ++s; - while (s != end) - { - *d = *s; - ++d; - ++s; - } - - break; - } - - - ++s; - - // if we have hit the end of s and there was a carry up to this point - // then just make the next digit 1 and add one to the digits used - if (s == end) - { - ++d; - dest->digits_used = source->digits_used + 1; - *d = 1; - break; - } - - ++d; - } - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_2:: - decrement ( - const data_record* source, - data_record* dest - ) const - { - uint16* s = source->number; - uint16* d = dest->number; - uint16* end = s + source->digits_used; - while (true) - { - *d = *s - 1; - - // if there was no carry then break out of the loop - if (*d != 0xFFFF) - { - // if we lost a digit in the subtraction - if (*d == 0 && s+1 == end) - { - if (source->digits_used == 1) - dest->digits_used = 1; - else - dest->digits_used = source->digits_used - 1; - } - else - { - dest->digits_used = source->digits_used; - } - break; - } - else - { - ++d; - ++s; - } - - } - - // copy the rest of the digits over to d - ++d; - ++s; - while (s != end) - { - *d = *s; - ++d; - ++s; - } - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_2:: - fft ( - ct* data, - unsigned long len - ) const - { - const t pi2 = -2.0*3.1415926535897932384626433832795028841971693993751; - - const unsigned long half = len/2; - - std::vector twiddle_factors; - twiddle_factors.resize(half); - - // compute the complex root of unity w - const t temp = pi2/len; - ct w = ct(std::cos(temp),std::sin(temp)); - - ct w_pow = 1; - - // compute the twiddle factors - for (std::vector::size_type j = 0; j < twiddle_factors.size(); ++j) - { - twiddle_factors[j] = w_pow; - w_pow *= w; - } - - ct a, b; - - // now compute the decimation in frequency. This first - // outer loop loops log2(len) number of times - unsigned long skip = 1; - for (unsigned long step = half; step != 0; step >>= 1) - { - // do blocks of butterflies in this loop - for (unsigned long j = 0; j < len; j += step*2) - { - // do step butterflies - for (unsigned long k = 0; k < step; ++k) - { - const unsigned long a_idx = j+k; - const unsigned long b_idx = j+k+step; - a = data[a_idx] + data[b_idx]; - b = (data[a_idx] - data[b_idx])*twiddle_factors[k*skip]; - data[a_idx] = a; - data[b_idx] = b; - } - } - skip *= 2; - } - } - -// ---------------------------------------------------------------------------------------- - - void bigint_kernel_2:: - ifft( - ct* data, - unsigned long len - ) const - { - const t pi2 = 2.0*3.1415926535897932384626433832795028841971693993751; - - const unsigned long half = len/2; - - std::vector twiddle_factors; - twiddle_factors.resize(half); - - // compute the complex root of unity w - const t temp = pi2/len; - ct w = ct(std::cos(temp),std::sin(temp)); - - ct w_pow = 1; - - // compute the twiddle factors - for (std::vector::size_type j = 0; j < twiddle_factors.size(); ++j) - { - twiddle_factors[j] = w_pow; - w_pow *= w; - } - - ct a, b; - - // now compute the inverse decimation in frequency. This first - // outer loop loops log2(len) number of times - unsigned long skip = half; - for (unsigned long step = 1; step <= half; step <<= 1) - { - // do blocks of butterflies in this loop - for (unsigned long j = 0; j < len; j += step*2) - { - // do step butterflies - for (unsigned long k = 0; k < step; ++k) - { - const unsigned long a_idx = j+k; - const unsigned long b_idx = j+k+step; - data[b_idx] *= twiddle_factors[k*skip]; - a = data[a_idx] + data[b_idx]; - b = data[a_idx] - data[b_idx]; - data[a_idx] = a; - data[b_idx] = b; - } - } - skip /= 2; - } - } - -// ---------------------------------------------------------------------------------------- - -} -#endif // DLIB_BIGINT_KERNEL_2_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_2.h b/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_2.h index 9950d4e9..cbd8f895 100644 --- a/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_2.h +++ b/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_2.h @@ -15,8 +15,6 @@ namespace dlib { - using namespace dlib::relational_operators; // defined in algs.h - class bigint_kernel_2 { /*! @@ -557,6 +555,11 @@ namespace dlib } } + inline bool operator> (const bigint_kernel_2& a, const bigint_kernel_2& b) { return b < a; } + inline bool operator!= (const bigint_kernel_2& a, const bigint_kernel_2& b) { return !(a == b); } + inline bool operator<= (const bigint_kernel_2& a, const bigint_kernel_2& b) { return !(b < a); } + inline bool operator>= (const bigint_kernel_2& a, const bigint_kernel_2& b) { return !(a < b); } + } #ifdef NO_MAKEFILE diff --git a/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_abstract.h b/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_abstract.h index ef9eb9ec..99a54520 100644 --- a/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_abstract.h @@ -10,7 +10,6 @@ namespace dlib { - using namespace dlib::relational_operators; // defined in algs.h class bigint { @@ -661,6 +660,10 @@ namespace dlib provides deserialization support !*/ + inline bool operator> (const bigint& a, const bigint& b) { return b < a; } + inline bool operator!= (const bigint& a, const bigint& b) { return !(a == b); } + inline bool operator<= (const bigint& a, const bigint& b) { return !(b < a); } + inline bool operator>= (const bigint& a, const bigint& b) { return !(a < b); } } #endif // DLIB_BIGINT_KERNEl_ABSTRACT_ diff --git a/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_c.h b/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_c.h index da25b03d..954869a3 100644 --- a/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_c.h +++ b/lib/3rdParty/dlib/include/dlib/bigint/bigint_kernel_c.h @@ -1122,6 +1122,17 @@ namespace dlib return *this; } +// ---------------------------------------------------------------------------------------- + + template < typename bigint_base > + inline bool operator> (const bigint_kernel_c& a, const bigint_kernel_c& b) { return b < a; } + template < typename bigint_base > + inline bool operator!= (const bigint_kernel_c& a, const bigint_kernel_c& b) { return !(a == b); } + template < typename bigint_base > + inline bool operator<= (const bigint_kernel_c& a, const bigint_kernel_c& b) { return !(b < a); } + template < typename bigint_base > + inline bool operator>= (const bigint_kernel_c& a, const bigint_kernel_c& b) { return !(a < b); } + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/binary_search_tree/binary_search_tree_kernel_1.h b/lib/3rdParty/dlib/include/dlib/binary_search_tree/binary_search_tree_kernel_1.h index 5db58c42..418eb07d 100644 --- a/lib/3rdParty/dlib/include/dlib/binary_search_tree/binary_search_tree_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/binary_search_tree/binary_search_tree_kernel_1.h @@ -168,7 +168,7 @@ namespace dlib ); // functions from the enumerable interface - inline unsigned long size ( + inline size_t size ( ) const; bool at_start ( @@ -597,7 +597,7 @@ namespace dlib typename mem_manager, typename compare > - unsigned long binary_search_tree_kernel_1:: + size_t binary_search_tree_kernel_1:: size ( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/binary_search_tree/binary_search_tree_kernel_2.h b/lib/3rdParty/dlib/include/dlib/binary_search_tree/binary_search_tree_kernel_2.h index 7ca78c91..098d38c2 100644 --- a/lib/3rdParty/dlib/include/dlib/binary_search_tree/binary_search_tree_kernel_2.h +++ b/lib/3rdParty/dlib/include/dlib/binary_search_tree/binary_search_tree_kernel_2.h @@ -169,7 +169,7 @@ namespace dlib ); // functions from the enumerable interface - inline unsigned long size ( + inline size_t size ( ) const; bool at_start ( @@ -543,7 +543,7 @@ namespace dlib typename mem_manager, typename compare > - unsigned long binary_search_tree_kernel_2:: + size_t binary_search_tree_kernel_2:: size ( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/bit_stream/bit_stream_kernel_1.cpp b/lib/3rdParty/dlib/include/dlib/bit_stream/bit_stream_kernel_1.cpp deleted file mode 100644 index ad3d63ef..00000000 --- a/lib/3rdParty/dlib/include/dlib/bit_stream/bit_stream_kernel_1.cpp +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_BIT_STREAM_KERNEL_1_CPp_ -#define DLIB_BIT_STREAM_KERNEL_1_CPp_ - - -#include "bit_stream_kernel_1.h" -#include "../algs.h" - -#include - -namespace dlib -{ - - inline void swap ( - bit_stream_kernel_1& a, - bit_stream_kernel_1& b - ) { a.swap(b); } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // member function definitions -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void bit_stream_kernel_1:: - clear ( - ) - { - if (write_mode) - { - write_mode = false; - - // flush output buffer - if (buffer_size > 0) - { - buffer <<= 8 - buffer_size; - osp->write(reinterpret_cast(&buffer),1); - } - } - else - read_mode = false; - - } - -// ---------------------------------------------------------------------------------------- - - void bit_stream_kernel_1:: - set_input_stream ( - std::istream& is - ) - { - isp = &is; - read_mode = true; - - buffer_size = 0; - } - -// ---------------------------------------------------------------------------------------- - - void bit_stream_kernel_1:: - set_output_stream ( - std::ostream& os - ) - { - osp = &os; - write_mode = true; - - buffer_size = 0; - } - -// ---------------------------------------------------------------------------------------- - - void bit_stream_kernel_1:: - close ( - ) - { - if (write_mode) - { - write_mode = false; - - // flush output buffer - if (buffer_size > 0) - { - buffer <<= 8 - buffer_size; - osp->write(reinterpret_cast(&buffer),1); - } - } - else - read_mode = false; - } - -// ---------------------------------------------------------------------------------------- - - bool bit_stream_kernel_1:: - is_in_write_mode ( - ) const - { - return write_mode; - } - -// ---------------------------------------------------------------------------------------- - - bool bit_stream_kernel_1:: - is_in_read_mode ( - ) const - { - return read_mode; - } - -// ---------------------------------------------------------------------------------------- - - void bit_stream_kernel_1:: - write ( - int bit - ) - { - // flush buffer if necessary - if (buffer_size == 8) - { - buffer <<= 8 - buffer_size; - if (osp->rdbuf()->sputn(reinterpret_cast(&buffer),1) == 0) - { - throw std::ios_base::failure("error occured in the bit_stream object"); - } - - buffer_size = 0; - } - - ++buffer_size; - buffer <<= 1; - buffer += static_cast(bit); - } - -// ---------------------------------------------------------------------------------------- - - bool bit_stream_kernel_1:: - read ( - int& bit - ) - { - // get new byte if necessary - if (buffer_size == 0) - { - if (isp->rdbuf()->sgetn(reinterpret_cast(&buffer), 1) == 0) - { - // if we didn't read anything then return false - return false; - } - - buffer_size = 8; - } - - // put the most significant bit from buffer into bit - bit = static_cast(buffer >> 7); - - // shift out the bit that was just read - buffer <<= 1; - --buffer_size; - - return true; - } - -// ---------------------------------------------------------------------------------------- - - void bit_stream_kernel_1:: - swap ( - bit_stream_kernel_1& item - ) - { - - std::istream* isp_temp = item.isp; - std::ostream* osp_temp = item.osp; - bool write_mode_temp = item.write_mode; - bool read_mode_temp = item.read_mode; - unsigned char buffer_temp = item.buffer; - unsigned short buffer_size_temp = item.buffer_size; - - item.isp = isp; - item.osp = osp; - item.write_mode = write_mode; - item.read_mode = read_mode; - item.buffer = buffer; - item.buffer_size = buffer_size; - - - isp = isp_temp; - osp = osp_temp; - write_mode = write_mode_temp; - read_mode = read_mode_temp; - buffer = buffer_temp; - buffer_size = buffer_size_temp; - - } - -// ---------------------------------------------------------------------------------------- - -} -#endif // DLIB_BIT_STREAM_KERNEL_1_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/string/cassert b/lib/3rdParty/dlib/include/dlib/bits/c++config.h similarity index 100% rename from lib/3rdParty/dlib/include/dlib/string/cassert rename to lib/3rdParty/dlib/include/dlib/bits/c++config.h diff --git a/lib/3rdParty/dlib/include/dlib/bridge.h b/lib/3rdParty/dlib/include/dlib/bridge.h index 79f89559..4b633c40 100644 --- a/lib/3rdParty/dlib/include/dlib/bridge.h +++ b/lib/3rdParty/dlib/include/dlib/bridge.h @@ -1,5 +1,11 @@ // Copyright (C) 2011 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. + +#ifdef DLIB_ALL_SOURCE_END +#include "dlib_basic_cpp_build_tutorial.txt" +#endif + + #ifndef DLIB_BRIdGE_ #define DLIB_BRIdGE_ diff --git a/lib/3rdParty/dlib/include/dlib/bridge/bridge.h b/lib/3rdParty/dlib/include/dlib/bridge/bridge.h index 3160102d..da4e0bd7 100644 --- a/lib/3rdParty/dlib/include/dlib/bridge/bridge.h +++ b/lib/3rdParty/dlib/include/dlib/bridge/bridge.h @@ -3,17 +3,19 @@ #ifndef DLIB_BRIDGe_Hh_ #define DLIB_BRIDGe_Hh_ -#include "bridge_abstract.h" +#include +#include #include + +#include "bridge_abstract.h" #include "../pipe.h" #include "../threads.h" -#include "../smart_pointers.h" #include "../serialize.h" #include "../sockets.h" #include "../sockstreambuf.h" #include "../logger.h" #include "../algs.h" -#include + namespace dlib { @@ -141,7 +143,7 @@ namespace dlib // ---------------------------------------------------------------------------------------- - namespace impl + namespace impl_brns { class impl_bridge_base { @@ -545,8 +547,8 @@ namespace dlib signaler s; bool receive_thread_active; bool transmit_thread_active; - scoped_ptr con; - scoped_ptr list; + std::unique_ptr con; + std::unique_ptr list; const unsigned short port; const std::string ip; transmit_pipe_type* const transmit_pipe; @@ -594,26 +596,26 @@ namespace dlib listen_on_port network_parameters, bridge_transmit_decoration transmit_pipe, bridge_receive_decoration receive_pipe - ) { pimpl.reset(); pimpl.reset(new impl::impl_bridge(network_parameters.port, &transmit_pipe.p, &receive_pipe.p)); } + ) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge(network_parameters.port, &transmit_pipe.p, &receive_pipe.p)); } template < typename T, typename R > void reconfigure ( listen_on_port network_parameters, bridge_receive_decoration receive_pipe, bridge_transmit_decoration transmit_pipe - ) { pimpl.reset(); pimpl.reset(new impl::impl_bridge(network_parameters.port, &transmit_pipe.p, &receive_pipe.p)); } + ) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge(network_parameters.port, &transmit_pipe.p, &receive_pipe.p)); } template < typename T > void reconfigure ( listen_on_port network_parameters, bridge_transmit_decoration transmit_pipe - ) { pimpl.reset(); pimpl.reset(new impl::impl_bridge(network_parameters.port, &transmit_pipe.p, 0)); } + ) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge(network_parameters.port, &transmit_pipe.p, 0)); } template < typename R > void reconfigure ( listen_on_port network_parameters, bridge_receive_decoration receive_pipe - ) { pimpl.reset(); pimpl.reset(new impl::impl_bridge(network_parameters.port, 0, &receive_pipe.p)); } + ) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge(network_parameters.port, 0, &receive_pipe.p)); } @@ -623,26 +625,26 @@ namespace dlib connect_to_ip_and_port network_parameters, bridge_transmit_decoration transmit_pipe, bridge_receive_decoration receive_pipe - ) { pimpl.reset(); pimpl.reset(new impl::impl_bridge(network_parameters.ip, network_parameters.port, &transmit_pipe.p, &receive_pipe.p)); } + ) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge(network_parameters.ip, network_parameters.port, &transmit_pipe.p, &receive_pipe.p)); } template < typename T, typename R > void reconfigure ( connect_to_ip_and_port network_parameters, bridge_receive_decoration receive_pipe, bridge_transmit_decoration transmit_pipe - ) { pimpl.reset(); pimpl.reset(new impl::impl_bridge(network_parameters.ip, network_parameters.port, &transmit_pipe.p, &receive_pipe.p)); } + ) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge(network_parameters.ip, network_parameters.port, &transmit_pipe.p, &receive_pipe.p)); } template < typename R > void reconfigure ( connect_to_ip_and_port network_parameters, bridge_receive_decoration receive_pipe - ) { pimpl.reset(); pimpl.reset(new impl::impl_bridge(network_parameters.ip, network_parameters.port, 0, &receive_pipe.p)); } + ) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge(network_parameters.ip, network_parameters.port, 0, &receive_pipe.p)); } template < typename T > void reconfigure ( connect_to_ip_and_port network_parameters, bridge_transmit_decoration transmit_pipe - ) { pimpl.reset(); pimpl.reset(new impl::impl_bridge(network_parameters.ip, network_parameters.port, &transmit_pipe.p, 0)); } + ) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge(network_parameters.ip, network_parameters.port, &transmit_pipe.p, 0)); } bridge_status get_bridge_status ( @@ -656,7 +658,7 @@ namespace dlib private: - scoped_ptr pimpl; + std::unique_ptr pimpl; }; // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/bsp/bsp.cpp b/lib/3rdParty/dlib/include/dlib/bsp/bsp.cpp deleted file mode 100644 index f1367cf5..00000000 --- a/lib/3rdParty/dlib/include/dlib/bsp/bsp.cpp +++ /dev/null @@ -1,495 +0,0 @@ -// Copyright (C) 2012 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_BSP_CPph_ -#define DLIB_BSP_CPph_ - -#include "bsp.h" -#include - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - -namespace dlib -{ - - namespace impl1 - { - - void connect_all ( - map_id_to_con& cons, - const std::vector& hosts, - unsigned long node_id - ) - { - cons.clear(); - for (unsigned long i = 0; i < hosts.size(); ++i) - { - scoped_ptr con(new bsp_con(hosts[i])); - dlib::serialize(node_id, con->stream); // tell the other end our node_id - unsigned long id = i+1; - cons.add(id, con); - } - } - - void connect_all_hostinfo ( - map_id_to_con& cons, - const std::vector& hosts, - unsigned long node_id, - std::string& error_string - ) - { - cons.clear(); - for (unsigned long i = 0; i < hosts.size(); ++i) - { - try - { - scoped_ptr con(new bsp_con(hosts[i].addr)); - dlib::serialize(node_id, con->stream); // tell the other end our node_id - con->stream.flush(); - unsigned long id = hosts[i].node_id; - cons.add(id, con); - } - catch (std::exception&) - { - std::ostringstream sout; - sout << "Could not connect to " << hosts[i].addr; - error_string = sout.str(); - break; - } - } - } - - - void send_out_connection_orders ( - map_id_to_con& cons, - const std::vector& hosts - ) - { - // tell everyone their node ids - cons.reset(); - while (cons.move_next()) - { - dlib::serialize(cons.element().key(), cons.element().value()->stream); - } - - // now tell them who to connect to - std::vector targets; - for (unsigned long i = 0; i < hosts.size(); ++i) - { - hostinfo info(hosts[i], i+1); - - dlib::serialize(targets, cons[info.node_id]->stream); - targets.push_back(info); - - // let the other host know how many incoming connections to expect - const unsigned long num = hosts.size()-targets.size(); - dlib::serialize(num, cons[info.node_id]->stream); - cons[info.node_id]->stream.flush(); - } - } - - // ------------------------------------------------------------------------------------ - - - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - namespace impl2 - { - // These control bytes are sent before each message between nodes. Note that many - // of these are only sent between the control node (node 0) and the other nodes. - // This is because the controller node is responsible for handling the - // synchronization that needs to happen when all nodes block on calls to - // receive_data() - // at the same time. - - // denotes a normal content message. - const static char MESSAGE_HEADER = 0; - - // sent to the controller node when someone receives a message via receive_data(). - const static char GOT_MESSAGE = 1; - - // sent to the controller node when someone sends a message via send(). - const static char SENT_MESSAGE = 2; - - // sent to the controller node when someone enters a call to receive_data() - const static char IN_WAITING_STATE = 3; - - // broadcast when a node terminates itself. - const static char NODE_TERMINATE = 5; - - // broadcast by the controller node when it determines that all nodes are blocked - // on calls to receive_data() and there aren't any messages in flight. This is also - // what makes us go to the next epoch. - const static char SEE_ALL_IN_WAITING_STATE = 6; - - // This isn't ever transmitted between nodes. It is used internally to indicate - // that an error occurred. - const static char READ_ERROR = 7; - - // ------------------------------------------------------------------------------------ - - void read_thread ( - impl1::bsp_con* con, - unsigned long node_id, - unsigned long sender_id, - impl1::thread_safe_message_queue& msg_buffer - ) - { - try - { - while(true) - { - impl1::msg_data msg; - deserialize(msg.msg_type, con->stream); - msg.sender_id = sender_id; - - if (msg.msg_type == MESSAGE_HEADER) - { - msg.data.reset(new std::vector); - deserialize(msg.epoch, con->stream); - deserialize(*msg.data, con->stream); - } - - msg_buffer.push_and_consume(msg); - - if (msg.msg_type == NODE_TERMINATE) - break; - } - } - catch (std::exception& e) - { - impl1::msg_data msg; - msg.data.reset(new std::vector); - vectorstream sout(*msg.data); - sout << "An exception was thrown while attempting to receive a message from processing node " << sender_id << ".\n"; - sout << " Sending processing node address: " << con->con->get_foreign_ip() << ":" << con->con->get_foreign_port() << std::endl; - sout << " Receiving processing node address: " << con->con->get_local_ip() << ":" << con->con->get_local_port() << std::endl; - sout << " Receiving processing node id: " << node_id << std::endl; - sout << " Error message in the exception: " << e.what() << std::endl; - - msg.sender_id = sender_id; - msg.msg_type = READ_ERROR; - - msg_buffer.push_and_consume(msg); - } - catch (...) - { - impl1::msg_data msg; - msg.data.reset(new std::vector); - vectorstream sout(*msg.data); - sout << "An exception was thrown while attempting to receive a message from processing node " << sender_id << ".\n"; - sout << " Sending processing node address: " << con->con->get_foreign_ip() << ":" << con->con->get_foreign_port() << std::endl; - sout << " Receiving processing node address: " << con->con->get_local_ip() << ":" << con->con->get_local_port() << std::endl; - sout << " Receiving processing node id: " << node_id << std::endl; - - msg.sender_id = sender_id; - msg.msg_type = READ_ERROR; - - msg_buffer.push_and_consume(msg); - } - } - - // ------------------------------------------------------------------------------------ - - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// IMPLEMENTATION OF bsp_context OBJECT MEMBERS -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void bsp_context:: - close_all_connections_gracefully( - ) - { - if (node_id() != 0) - { - _cons.reset(); - while (_cons.move_next()) - { - // tell the other end that we are intentionally dropping the connection - serialize(impl2::NODE_TERMINATE,_cons.element().value()->stream); - _cons.element().value()->stream.flush(); - } - } - - impl1::msg_data msg; - // now wait for all the other nodes to terminate - while (num_terminated_nodes < _cons.size() ) - { - if (node_id() == 0 && num_waiting_nodes + num_terminated_nodes == _cons.size() && outstanding_messages == 0) - { - num_waiting_nodes = 0; - broadcast_byte(impl2::SEE_ALL_IN_WAITING_STATE); - ++current_epoch; - } - - if (!msg_buffer.pop(msg)) - throw dlib::socket_error("Error reading from msg_buffer in dlib::bsp_context."); - - if (msg.msg_type == impl2::NODE_TERMINATE) - { - ++num_terminated_nodes; - _cons[msg.sender_id]->terminated = true; - } - else if (msg.msg_type == impl2::READ_ERROR) - { - throw dlib::socket_error(msg.data_to_string()); - } - else if (msg.msg_type == impl2::MESSAGE_HEADER) - { - throw dlib::socket_error("A BSP node received a message after it has terminated."); - } - else if (msg.msg_type == impl2::GOT_MESSAGE) - { - --num_waiting_nodes; - --outstanding_messages; - } - else if (msg.msg_type == impl2::SENT_MESSAGE) - { - ++outstanding_messages; - } - else if (msg.msg_type == impl2::IN_WAITING_STATE) - { - ++num_waiting_nodes; - } - } - - if (node_id() == 0) - { - _cons.reset(); - while (_cons.move_next()) - { - // tell the other end that we are intentionally dropping the connection - serialize(impl2::NODE_TERMINATE,_cons.element().value()->stream); - _cons.element().value()->stream.flush(); - } - - if (outstanding_messages != 0) - { - std::ostringstream sout; - sout << "A BSP job was allowed to terminate before all sent messages have been received.\n"; - sout << "There are at least " << outstanding_messages << " messages still in flight. Make sure all sent messages\n"; - sout << "have a corresponding call to receive()."; - throw dlib::socket_error(sout.str()); - } - } - } - -// ---------------------------------------------------------------------------------------- - - bsp_context:: - ~bsp_context() - { - _cons.reset(); - while (_cons.move_next()) - { - _cons.element().value()->con->shutdown(); - } - - msg_buffer.disable(); - - // this will wait for all the threads to terminate - threads.clear(); - } - -// ---------------------------------------------------------------------------------------- - - bsp_context:: - bsp_context( - unsigned long node_id_, - impl1::map_id_to_con& cons_ - ) : - outstanding_messages(0), - num_waiting_nodes(0), - num_terminated_nodes(0), - current_epoch(1), - _cons(cons_), - _node_id(node_id_) - { - // spawn a bunch of read threads, one for each connection - _cons.reset(); - while (_cons.move_next()) - { - scoped_ptr ptr(new thread_function(&impl2::read_thread, - _cons.element().value().get(), - _node_id, - _cons.element().key(), - ref(msg_buffer))); - threads.push_back(ptr); - } - - } - -// ---------------------------------------------------------------------------------------- - - bool bsp_context:: - receive_data ( - shared_ptr >& item, - unsigned long& sending_node_id - ) - { - notify_control_node(impl2::IN_WAITING_STATE); - - while (true) - { - // If there aren't any nodes left to give us messages then return right now. - // We need to check the msg_buffer size to make sure there aren't any - // unprocessed message there. Recall that this can happen because status - // messages always jump to the front of the message buffer. So we might have - // learned about the node terminations before processing their messages for us. - if (num_terminated_nodes == _cons.size() && msg_buffer.size() == 0) - { - return false; - } - - // if all running nodes are currently blocking forever on receive_data() - if (node_id() == 0 && outstanding_messages == 0 && num_terminated_nodes + num_waiting_nodes == _cons.size()) - { - num_waiting_nodes = 0; - broadcast_byte(impl2::SEE_ALL_IN_WAITING_STATE); - - // Note that the reason we have this epoch counter is so we can tell if a - // sent message is from before or after one of these "all nodes waiting" - // synchronization events. If we didn't have the epoch count we would have - // a race condition where one node gets the SEE_ALL_IN_WAITING_STATE - // message before others and then sends out a message to another node - // before that node got the SEE_ALL_IN_WAITING_STATE message. Then that - // node would think the normal message came before SEE_ALL_IN_WAITING_STATE - // which would be bad. - ++current_epoch; - return false; - } - - impl1::msg_data data; - if (!msg_buffer.pop(data, current_epoch)) - throw dlib::socket_error("Error reading from msg_buffer in dlib::bsp_context."); - - - switch(data.msg_type) - { - case impl2::MESSAGE_HEADER: { - item = data.data; - sending_node_id = data.sender_id; - notify_control_node(impl2::GOT_MESSAGE); - return true; - } break; - - case impl2::IN_WAITING_STATE: { - ++num_waiting_nodes; - } break; - - case impl2::GOT_MESSAGE: { - --outstanding_messages; - --num_waiting_nodes; - } break; - - case impl2::SENT_MESSAGE: { - ++outstanding_messages; - } break; - - case impl2::NODE_TERMINATE: { - ++num_terminated_nodes; - _cons[data.sender_id]->terminated = true; - } break; - - case impl2::SEE_ALL_IN_WAITING_STATE: { - ++current_epoch; - return false; - } break; - - case impl2::READ_ERROR: { - throw dlib::socket_error(data.data_to_string()); - } break; - - default: { - throw dlib::socket_error("Unknown message received by dlib::bsp_context"); - } break; - } // end switch() - } // end while (true) - } - -// ---------------------------------------------------------------------------------------- - - void bsp_context:: - notify_control_node ( - char val - ) - { - if (node_id() == 0) - { - using namespace impl2; - switch(val) - { - case SENT_MESSAGE: { - ++outstanding_messages; - } break; - - case GOT_MESSAGE: { - --outstanding_messages; - } break; - - case IN_WAITING_STATE: { - // nothing to do in this case - } break; - - default: - DLIB_CASSERT(false,"This should never happen"); - } - } - else - { - serialize(val, _cons[0]->stream); - _cons[0]->stream.flush(); - } - } - -// ---------------------------------------------------------------------------------------- - - void bsp_context:: - broadcast_byte ( - char val - ) - { - for (unsigned long i = 0; i < number_of_nodes(); ++i) - { - // don't send to yourself or to terminated nodes - if (i == node_id() || _cons[i]->terminated) - continue; - - serialize(val, _cons[i]->stream); - _cons[i]->stream.flush(); - } - } - -// ---------------------------------------------------------------------------------------- - - void bsp_context:: - send_data( - const std::vector& item, - unsigned long target_node_id - ) - { - using namespace impl2; - if (_cons[target_node_id]->terminated) - throw socket_error("Attempt to send a message to a node that has terminated."); - - serialize(MESSAGE_HEADER, _cons[target_node_id]->stream); - serialize(current_epoch, _cons[target_node_id]->stream); - serialize(item, _cons[target_node_id]->stream); - _cons[target_node_id]->stream.flush(); - - notify_control_node(SENT_MESSAGE); - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_BSP_CPph_ - diff --git a/lib/3rdParty/dlib/include/dlib/bsp/bsp.h b/lib/3rdParty/dlib/include/dlib/bsp/bsp.h index 59485a01..f0732c15 100644 --- a/lib/3rdParty/dlib/include/dlib/bsp/bsp.h +++ b/lib/3rdParty/dlib/include/dlib/bsp/bsp.h @@ -4,17 +4,19 @@ #define DLIB_BsP_Hh_ #include "bsp_abstract.h" + +#include +#include +#include + #include "../sockets.h" #include "../array.h" -#include "../smart_pointers.h" #include "../sockstreambuf.h" #include "../string.h" #include "../serialize.h" #include "../map.h" #include "../ref.h" #include "../vectorstream.h" -#include -#include namespace dlib { @@ -41,7 +43,7 @@ namespace dlib } bsp_con( - scoped_ptr& conptr + std::unique_ptr& conptr ) : buf(conptr), stream(&buf), @@ -53,13 +55,13 @@ namespace dlib con->disable_nagle(); } - scoped_ptr con; + std::unique_ptr con; sockstreambuf buf; std::iostream stream; bool terminated; }; - typedef dlib::map >::kernel_1a_c map_id_to_con; + typedef dlib::map >::kernel_1a_c map_id_to_con; void connect_all ( map_id_to_con& cons, @@ -134,7 +136,7 @@ namespace dlib ) { cons.clear(); - scoped_ptr list; + std::unique_ptr list; const int status = create_listener(list, port); if (status == PORTINUSE) { @@ -148,13 +150,13 @@ namespace dlib port_notify_function(list->get_listening_port()); - scoped_ptr con; + std::unique_ptr con; if (list->accept(con)) { throw socket_error("Error occurred while accepting new connection"); } - scoped_ptr temp(new bsp_con(con)); + std::unique_ptr temp(new bsp_con(con)); unsigned long remote_node_id; dlib::deserialize(remote_node_id, temp->stream); @@ -197,7 +199,7 @@ namespace dlib while (cons2.size() > 0) { unsigned long id; - scoped_ptr temp; + std::unique_ptr temp; cons2.remove_any(id,temp); cons.add(id,temp); } @@ -207,7 +209,7 @@ namespace dlib struct msg_data { - shared_ptr > data; + std::shared_ptr > data; unsigned long sender_id; char msg_type; dlib::uint64 epoch; @@ -420,7 +422,7 @@ namespace dlib ) { unsigned long id; - shared_ptr > temp; + std::shared_ptr > temp; if (receive_data(temp,id)) throw dlib::socket_error("Call to bsp_context::receive() got an unexpected message."); } @@ -459,7 +461,7 @@ namespace dlib unsigned long& sending_node_id ) { - shared_ptr > temp; + std::shared_ptr > temp; if (receive_data(temp, sending_node_id)) { vectorstream sin(*temp); @@ -496,7 +498,7 @@ namespace dlib !*/ bool receive_data ( - shared_ptr >& item, + std::shared_ptr >& item, unsigned long& sending_node_id ); @@ -533,7 +535,7 @@ namespace dlib impl1::map_id_to_con& _cons; const unsigned long _node_id; - array > threads; + array > threads; // ----------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/cassert b/lib/3rdParty/dlib/include/dlib/cassert deleted file mode 100644 index eb0e59e4..00000000 --- a/lib/3rdParty/dlib/include/dlib/cassert +++ /dev/null @@ -1 +0,0 @@ -#include "dlib_include_path_tutorial.txt" diff --git a/lib/3rdParty/dlib/include/dlib/clustering.h b/lib/3rdParty/dlib/include/dlib/clustering.h index 67a42737..3cbd6cfd 100644 --- a/lib/3rdParty/dlib/include/dlib/clustering.h +++ b/lib/3rdParty/dlib/include/dlib/clustering.h @@ -5,6 +5,8 @@ #include "clustering/modularity_clustering.h" #include "clustering/chinese_whispers.h" +#include "clustering/spectral_cluster.h" +#include "clustering/bottom_up_cluster.h" #include "svm/kkmeans.h" #endif // DLIB_CLuSTERING_ diff --git a/lib/3rdParty/dlib/include/dlib/clustering/bottom_up_cluster.h b/lib/3rdParty/dlib/include/dlib/clustering/bottom_up_cluster.h new file mode 100644 index 00000000..f80b6510 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/clustering/bottom_up_cluster.h @@ -0,0 +1,253 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BOTTOM_uP_CLUSTER_Hh_ +#define DLIB_BOTTOM_uP_CLUSTER_Hh_ + +#include +#include + +#include "bottom_up_cluster_abstract.h" +#include "../algs.h" +#include "../matrix.h" +#include "../disjoint_subsets.h" +#include "../graph_utils.h" + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + namespace buc_impl + { + inline void merge_sets ( + matrix& dists, + unsigned long dest, + unsigned long src + ) + { + for (long r = 0; r < dists.nr(); ++r) + dists(dest,r) = dists(r,dest) = std::max(dists(r,dest), dists(r,src)); + } + + struct compare_dist + { + bool operator() ( + const sample_pair& a, + const sample_pair& b + ) const + { + return a.distance() > b.distance(); + } + }; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + unsigned long bottom_up_cluster ( + const matrix_exp& dists_, + std::vector& labels, + unsigned long min_num_clusters, + double max_dist = std::numeric_limits::infinity() + ) + { + matrix dists = matrix_cast(dists_); + // make sure requires clause is not broken + DLIB_CASSERT(dists.nr() == dists.nc() && min_num_clusters > 0, + "\t unsigned long bottom_up_cluster()" + << "\n\t Invalid inputs were given to this function." + << "\n\t dists.nr(): " << dists.nr() + << "\n\t dists.nc(): " << dists.nc() + << "\n\t min_num_clusters: " << min_num_clusters + ); + + using namespace buc_impl; + + labels.resize(dists.nr()); + disjoint_subsets sets; + sets.set_size(dists.nr()); + if (labels.size() == 0) + return 0; + + // push all the edges in the graph into a priority queue so the best edges to merge + // come first. + std::priority_queue, compare_dist> que; + for (long r = 0; r < dists.nr(); ++r) + for (long c = r+1; c < dists.nc(); ++c) + que.push(sample_pair(r,c,dists(r,c))); + + // Now start merging nodes. + for (unsigned long iter = min_num_clusters; iter < sets.size(); ++iter) + { + // find the next best thing to merge. + double best_dist = que.top().distance(); + unsigned long a = sets.find_set(que.top().index1()); + unsigned long b = sets.find_set(que.top().index2()); + que.pop(); + // we have been merging and modifying the distances, so make sure this distance + // is still valid and these guys haven't been merged already. + while(a == b || best_dist < dists(a,b)) + { + // Haven't merged it yet, so put it back in with updated distance for + // reconsideration later. + if (a != b) + que.push(sample_pair(a, b, dists(a, b))); + + best_dist = que.top().distance(); + a = sets.find_set(que.top().index1()); + b = sets.find_set(que.top().index2()); + que.pop(); + } + + + // now merge these sets if the best distance is small enough + if (best_dist > max_dist) + break; + unsigned long news = sets.merge_sets(a,b); + unsigned long olds = (news==a)?b:a; + merge_sets(dists, news, olds); + } + + // figure out which cluster each element is in. Also make sure the labels are + // contiguous. + std::map relabel; + for (unsigned long r = 0; r < labels.size(); ++r) + { + unsigned long l = sets.find_set(r); + // relabel to make contiguous + if (relabel.count(l) == 0) + { + unsigned long next = relabel.size(); + relabel[l] = next; + } + labels[r] = relabel[l]; + } + + + return relabel.size(); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + struct snl_range + { + snl_range() = default; + snl_range(double val) : lower(val), upper(val) {} + snl_range(double l, double u) : lower(l), upper(u) { DLIB_ASSERT(lower <= upper)} + + double lower = 0; + double upper = 0; + + double width() const { return upper-lower; } + bool operator<(const snl_range& item) const { return lower < item.lower; } + }; + + inline snl_range merge(const snl_range& a, const snl_range& b) + { + return snl_range(std::min(a.lower, b.lower), std::max(a.upper, b.upper)); + } + + inline double distance (const snl_range& a, const snl_range& b) + { + return std::max(a.lower,b.lower) - std::min(a.upper,b.upper); + } + + inline std::ostream& operator<< (std::ostream& out, const snl_range& item ) + { + out << "["< segment_number_line ( + const std::vector& x, + const double max_range_width + ) + { + DLIB_CASSERT(max_range_width >= 0); + + // create initial ranges, one for each value in x. So initially, all the ranges have + // width of 0. + std::vector ranges; + for (auto v : x) + ranges.push_back(v); + std::sort(ranges.begin(), ranges.end()); + + std::vector greedy_final_ranges; + if (ranges.size() == 0) + return greedy_final_ranges; + // We will try two different clustering strategies. One that does a simple greedy left + // to right sweep and another that does a bottom up agglomerative clustering. This + // first loop runs the greedy left to right sweep. Then at the end of this routine we + // will return the results that produced the tightest clustering. + greedy_final_ranges.push_back(ranges[0]); + for (size_t i = 1; i < ranges.size(); ++i) + { + auto m = merge(greedy_final_ranges.back(), ranges[i]); + if (m.width() <= max_range_width) + greedy_final_ranges.back() = m; + else + greedy_final_ranges.push_back(ranges[i]); + } + + + // Here we do the bottom up clustering. So compute the edges connecting our ranges. + // We will simply say there are edges between ranges if and only if they are + // immediately adjacent on the number line. + std::vector edges; + for (size_t i = 1; i < ranges.size(); ++i) + edges.push_back(sample_pair(i-1,i, distance(ranges[i-1],ranges[i]))); + std::sort(edges.begin(), edges.end(), order_by_distance); + + disjoint_subsets sets; + sets.set_size(ranges.size()); + + // Now start merging nodes. + for (auto edge : edges) + { + // find the next best thing to merge. + unsigned long a = sets.find_set(edge.index1()); + unsigned long b = sets.find_set(edge.index2()); + + // merge it if it doesn't result in an interval that's too big. + auto m = merge(ranges[a], ranges[b]); + if (m.width() <= max_range_width) + { + unsigned long news = sets.merge_sets(a,b); + ranges[news] = m; + } + } + + // Now create a list of the final ranges. We will do this by keeping track of which + // range we already added to final_ranges. + std::vector final_ranges; + std::vector already_output(ranges.size(), false); + for (unsigned long i = 0; i < sets.size(); ++i) + { + auto s = sets.find_set(i); + if (!already_output[s]) + { + final_ranges.push_back(ranges[s]); + already_output[s] = true; + } + } + + // only use the greedy clusters if they found a clustering with fewer clusters. + // Otherwise, the bottom up clustering probably produced a more sensible clustering. + if (final_ranges.size() <= greedy_final_ranges.size()) + return final_ranges; + else + return greedy_final_ranges; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_BOTTOM_uP_CLUSTER_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/clustering/bottom_up_cluster_abstract.h b/lib/3rdParty/dlib/include/dlib/clustering/bottom_up_cluster_abstract.h new file mode 100644 index 00000000..72d362c1 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/clustering/bottom_up_cluster_abstract.h @@ -0,0 +1,136 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_BOTTOM_uP_CLUSTER_ABSTRACT_Hh_ +#ifdef DLIB_BOTTOM_uP_CLUSTER_ABSTRACT_Hh_ + +#include "../matrix.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + unsigned long bottom_up_cluster ( + const matrix_exp& dists, + std::vector& labels, + unsigned long min_num_clusters, + double max_dist = std::numeric_limits::infinity() + ); + /*! + requires + - dists.nr() == dists.nc() + - min_num_clusters > 0 + - dists == trans(dists) + (l.e. dists should be symmetric) + ensures + - Runs a bottom up agglomerative clustering algorithm. + - Interprets dists as a matrix that gives the distances between dists.nr() + items. In particular, we take dists(i,j) to be the distance between the ith + and jth element of some set. This function clusters the elements of this set + into at least min_num_clusters (or dists.nr() if there aren't enough + elements). Additionally, within each cluster, the maximum pairwise distance + between any two cluster elements is <= max_dist. + - returns the number of clusters found. + - #labels.size() == dists.nr() + - for all valid i: + - #labels[i] == the cluster ID of the node with index i (i.e. the node + corresponding to the distances dists(i,*)). + - 0 <= #labels[i] < the number of clusters found + (i.e. cluster IDs are assigned contiguously and start at 0) + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + struct snl_range + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents an interval on the real number line. It is used + to store the outputs of the segment_number_line() routine defined below. + !*/ + + snl_range( + ); + /*! + ensures + - #lower == 0 + - #upper == 0 + !*/ + + snl_range( + double val + ); + /*! + ensures + - #lower == val + - #upper == val + !*/ + + snl_range( + double l, + double u + ); + /*! + requires + - l <= u + ensures + - #lower == l + - #upper == u + !*/ + + double lower; + double upper; + + double width( + ) const { return upper-lower; } + /*! + ensures + - returns the width of this interval on the number line. + !*/ + + bool operator<(const snl_range& item) const { return lower < item.lower; } + /*! + ensures + - provides a total ordering of snl_range objects assuming they are + non-overlapping. + !*/ + }; + + std::ostream& operator<< (std::ostream& out, const snl_range& item ); + /*! + ensures + - prints item to out in the form [lower,upper]. + !*/ + +// ---------------------------------------------------------------------------------------- + + std::vector segment_number_line ( + const std::vector& x, + const double max_range_width + ); + /*! + requires + - max_range_width >= 0 + ensures + - Finds a clustering of the values in x and returns the ranges that define the + clustering. This routine uses a combination of bottom up clustering and a + simple greedy scan to try and find the most compact set of ranges that + contain all the values in x. + - This routine has approximately linear runtime. + - Every value in x will be contained inside one of the returned snl_range + objects; + - All returned snl_range object's will have a width() <= max_range_width and + will also be non-overlapping. + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_BOTTOM_uP_CLUSTER_ABSTRACT_Hh_ + + diff --git a/lib/3rdParty/dlib/include/dlib/clustering/spectral_cluster.h b/lib/3rdParty/dlib/include/dlib/clustering/spectral_cluster.h new file mode 100644 index 00000000..2cac9870 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/clustering/spectral_cluster.h @@ -0,0 +1,80 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SPECTRAL_CLUSTEr_H_ +#define DLIB_SPECTRAL_CLUSTEr_H_ + +#include "spectral_cluster_abstract.h" +#include +#include "../matrix.h" +#include "../svm/kkmeans.h" + +namespace dlib +{ + template < + typename kernel_type, + typename vector_type + > + std::vector spectral_cluster ( + const kernel_type& k, + const vector_type& samples, + const unsigned long num_clusters + ) + { + DLIB_CASSERT(num_clusters > 0, + "\t std::vector spectral_cluster(k,samples,num_clusters)" + << "\n\t num_clusters can't be 0." + ); + + if (num_clusters == 1) + { + // nothing to do, just assign everything to the 0 cluster. + return std::vector(samples.size(), 0); + } + + // compute the similarity matrix. + matrix K(samples.size(), samples.size()); + for (long r = 0; r < K.nr(); ++r) + for (long c = r+1; c < K.nc(); ++c) + K(r,c) = K(c,r) = (double)k(samples[r], samples[c]); + for (long r = 0; r < K.nr(); ++r) + K(r,r) = 0; + + matrix D(K.nr()); + for (long r = 0; r < K.nr(); ++r) + D(r) = sum(rowm(K,r)); + D = sqrt(reciprocal(D)); + K = diagm(D)*K*diagm(D); + matrix u,w,v; + // Use the normal SVD routine unless the matrix is really big, then use the fast + // approximate version. + if (K.nr() < 1000) + svd3(K,u,w,v); + else + svd_fast(K,u,w,v, num_clusters+100, 5); + // Pick out the eigenvectors associated with the largest eigenvalues. + rsort_columns(v,w); + v = colm(v, range(0,num_clusters-1)); + // Now build the normalized spectral vectors, one for each input vector. + std::vector > spec_samps, centers; + for (long r = 0; r < v.nr(); ++r) + { + spec_samps.push_back(trans(rowm(v,r))); + const double len = length(spec_samps.back()); + if (len != 0) + spec_samps.back() /= len; + } + // Finally do the K-means clustering + pick_initial_centers(num_clusters, centers, spec_samps); + find_clusters_using_kmeans(spec_samps, centers); + // And then compute the cluster assignments based on the output of K-means. + std::vector assignments; + for (unsigned long i = 0; i < spec_samps.size(); ++i) + assignments.push_back(nearest_center(centers, spec_samps[i])); + + return assignments; + } + +} + +#endif // DLIB_SPECTRAL_CLUSTEr_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/clustering/spectral_cluster_abstract.h b/lib/3rdParty/dlib/include/dlib/clustering/spectral_cluster_abstract.h new file mode 100644 index 00000000..880ad80a --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/clustering/spectral_cluster_abstract.h @@ -0,0 +1,43 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SPECTRAL_CLUSTEr_ABSTRACT_H_ +#ifdef DLIB_SPECTRAL_CLUSTEr_ABSTRACT_H_ + +#include + +namespace dlib +{ + template < + typename kernel_type, + typename vector_type + > + std::vector spectral_cluster ( + const kernel_type& k, + const vector_type& samples, + const unsigned long num_clusters + ); + /*! + requires + - samples must be something with an interface compatible with std::vector. + - The following expression must evaluate to a double or float: + k(samples[i], samples[j]) + - num_clusters > 0 + ensures + - Performs the spectral clustering algorithm described in the paper: + On spectral clustering: Analysis and an algorithm by Ng, Jordan, and Weiss. + and returns the results. + - This function clusters the input data samples into num_clusters clusters and + returns a vector that indicates which cluster each sample falls into. In + particular, we return an array A such that: + - A.size() == samples.size() + - A[i] == the cluster assignment of samples[i]. + - for all valid i: 0 <= A[i] < num_clusters + - The "similarity" of samples[i] with samples[j] is given by + k(samples[i],samples[j]). This means that k() should output a number >= 0 + and the number should be larger for samples that are more similar. + !*/ +} + +#endif // DLIB_SPECTRAL_CLUSTEr_ABSTRACT_H_ + + diff --git a/lib/3rdParty/dlib/include/dlib/cmake b/lib/3rdParty/dlib/include/dlib/cmake deleted file mode 100644 index d14af7f8..00000000 --- a/lib/3rdParty/dlib/include/dlib/cmake +++ /dev/null @@ -1,73 +0,0 @@ - -# Don't add dlib if it's already been added to the cmake project -if (NOT TARGET dlib) - - # Determine the path to dlib. - string(REGEX REPLACE "cmake$" "" dlib_path ${CMAKE_CURRENT_LIST_FILE}) - - if (CMAKE_COMPILER_IS_GNUCXX) - # By default, g++ won't warn or error if you forget to return a value in a - # function which requires you to do so. This option makes it give a warning - # for doing this. - add_definitions("-Wreturn-type") - endif() - - # Setup some options to allow a user to enable SSE and AVX instruction use. - if (CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" - OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" - OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") - option(USE_SSE2_INSTRUCTIONS "Compile your program with SSE2 instructions" OFF) - option(USE_SSE4_INSTRUCTIONS "Compile your program with SSE4 instructions" OFF) - option(USE_AVX_INSTRUCTIONS "Compile your program with AVX instructions" OFF) - if(USE_AVX_INSTRUCTIONS) - add_definitions(-mavx) - elseif (USE_SSE4_INSTRUCTIONS) - add_definitions(-msse4) - elseif(USE_SSE2_INSTRUCTIONS) - add_definitions(-msse2) - endif() - elseif (MSVC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # else if using Visual Studio - # Use SSE2 by default when using Visual Studio. - option(USE_SSE2_INSTRUCTIONS "Compile your program with SSE2 instructions" ON) - # Visual Studio 2005 didn't support SSE4 - if (NOT MSVC80) - option(USE_SSE4_INSTRUCTIONS "Compile your program with SSE4 instructions" OFF) - endif() - # Visual Studio 2005 and 2008 didn't support AVX - if (NOT MSVC80 AND NOT MSVC90) - option(USE_AVX_INSTRUCTIONS "Compile your program with AVX instructions" OFF) - endif() - include(CheckTypeSize) - check_type_size( "void*" SIZE_OF_VOID_PTR) - if(USE_AVX_INSTRUCTIONS) - add_definitions(/arch:AVX) - elseif (USE_SSE4_INSTRUCTIONS) - # Visual studio doesn't have an /arch:SSE2 flag when building in 64 bit modes. - # So only give it when we are doing a 32 bit build. - if (SIZE_OF_VOID_PTR EQUAL 4) - add_definitions(/arch:SSE2) - endif() - add_definitions(-DDLIB_HAVE_SSE2) - add_definitions(-DDLIB_HAVE_SSE3) - add_definitions(-DDLIB_HAVE_SSE41) - elseif(USE_SSE2_INSTRUCTIONS) - # Visual studio doesn't have an /arch:SSE2 flag when building in 64 bit modes. - # So only give it when we are doing a 32 bit build. - if (SIZE_OF_VOID_PTR EQUAL 4) - add_definitions(/arch:SSE2) - endif() - add_definitions(-DDLIB_HAVE_SSE2) - endif() - endif() - - - # Add folder containing dlib to the include search path. - INCLUDE_DIRECTORIES(${dlib_path}/..) - - # This is really optional, but nice. It will make sure the build mode - # created by cmake is always release by default. - include(${dlib_path}/release_build_by_default) - - add_subdirectory(${dlib_path} dlib_build) -endif() - diff --git a/lib/3rdParty/dlib/include/dlib/cmake_utils/add_global_compiler_switch.cmake b/lib/3rdParty/dlib/include/dlib/cmake_utils/add_global_compiler_switch.cmake new file mode 100644 index 00000000..5f3d83ce --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cmake_utils/add_global_compiler_switch.cmake @@ -0,0 +1,35 @@ + + +cmake_minimum_required(VERSION 2.8.12) + +message(WARNING "add_global_compiler_switch() is deprecated. Use target_compile_options() instead") + +# Make macros that can add compiler switches to the entire project. Not just +# to the current cmake folder being built. +macro ( add_global_compiler_switch switch_name ) + # If removing the switch would change the flags then it's already present + # and we don't need to do anything. + string(REPLACE "${switch_name}" "" tempstr "${CMAKE_CXX_FLAGS}") + if ("${CMAKE_CXX_FLAGS}" STREQUAL "${tempstr}" ) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${switch_name}" + CACHE STRING "Flags used by the compiler during all C++ builds." + FORCE) + endif () +endmacro() + +macro ( remove_global_compiler_switch switch_name ) + string(REPLACE "${switch_name}" "" tempstr "${CMAKE_CXX_FLAGS}") + if (NOT "${CMAKE_CXX_FLAGS}" STREQUAL "${tempstr}" ) + set (CMAKE_CXX_FLAGS "${tempstr}" + CACHE STRING "Flags used by the compiler during all C++ builds." + FORCE) + endif () +endmacro() + +macro (add_global_define def_name) + add_global_compiler_switch(-D${def_name}) +endmacro() + +macro (remove_global_define def_name) + remove_global_compiler_switch(-D${def_name}) +endmacro() diff --git a/lib/3rdParty/dlib/include/dlib/cmake_utils/check_if_avx_instructions_executable_on_host.cmake b/lib/3rdParty/dlib/include/dlib/cmake_utils/check_if_avx_instructions_executable_on_host.cmake new file mode 100644 index 00000000..a5d7320f --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cmake_utils/check_if_avx_instructions_executable_on_host.cmake @@ -0,0 +1,19 @@ +# This script checks if your compiler and host processor can generate and then run programs with AVX instructions. + +cmake_minimum_required(VERSION 2.8.12) + +# Don't rerun this script if its already been executed. +if (DEFINED AVX_IS_AVAILABLE_ON_HOST) + return() +endif() + +# Set to false unless we find out otherwise in the code below. +set(AVX_IS_AVAILABLE_ON_HOST 0) + +try_compile(test_for_avx_worked ${PROJECT_BINARY_DIR}/avx_test_build ${CMAKE_CURRENT_LIST_DIR}/test_for_avx + avx_test) + +if(test_for_avx_worked) + message (STATUS "AVX instructions can be executed by the host processor.") + set(AVX_IS_AVAILABLE_ON_HOST 1) +endif() diff --git a/lib/3rdParty/dlib/include/dlib/cmake_utils/check_if_neon_available.cmake b/lib/3rdParty/dlib/include/dlib/cmake_utils/check_if_neon_available.cmake new file mode 100644 index 00000000..0510707d --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cmake_utils/check_if_neon_available.cmake @@ -0,0 +1,20 @@ +# This script checks if __ARM_NEON__ is defined for your compiler + +cmake_minimum_required(VERSION 2.8.12) + +# Don't rerun this script if its already been executed. +if (DEFINED ARM_NEON_IS_AVAILABLE) + return() +endif() + +# Set to false unless we find out otherwise in the code below. +set(ARM_NEON_IS_AVAILABLE 0) + +# test if __ARM_NEON__ is defined +try_compile(test_for_neon_worked ${PROJECT_BINARY_DIR}/neon_test_build ${CMAKE_CURRENT_LIST_DIR}/test_for_neon + neon_test) + +if(test_for_neon_worked) + message (STATUS "__ARM_NEON__ defined.") + set(ARM_NEON_IS_AVAILABLE 1) +endif() diff --git a/lib/3rdParty/dlib/include/dlib/cmake_utils/find_blas.cmake b/lib/3rdParty/dlib/include/dlib/cmake_utils/find_blas.cmake new file mode 100644 index 00000000..24fca712 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cmake_utils/find_blas.cmake @@ -0,0 +1,385 @@ +# +# This is a CMake makefile. You can find the cmake utility and +# information about it at http://www.cmake.org +# +# +# This cmake file tries to find installed BLAS and LAPACK libraries. +# It looks for an installed copy of the Intel MKL library first and then +# attempts to find some other BLAS and LAPACK libraries if you don't have +# the Intel MKL. +# +# blas_found - True if BLAS is available +# lapack_found - True if LAPACK is available +# found_intel_mkl - True if the Intel MKL library is available +# found_intel_mkl_headers - True if Intel MKL headers are available +# blas_libraries - link against these to use BLAS library +# lapack_libraries - link against these to use LAPACK library +# mkl_libraries - link against these to use the MKL library +# mkl_include_dir - add to the include path to use the MKL library +# openmp_libraries - Set to Intel's OpenMP library if and only if we +# find the MKL. + +# setting this makes CMake allow normal looking if else statements +SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) + +SET(blas_found 0) +SET(lapack_found 0) +SET(found_intel_mkl 0) +SET(found_intel_mkl_headers 0) +SET(lapack_with_underscore 0) +SET(lapack_without_underscore 0) + +message(STATUS "Searching for BLAS and LAPACK") + +if (UNIX OR MINGW) + message(STATUS "Searching for BLAS and LAPACK") + + if (BUILDING_MATLAB_MEX_FILE) + # # This commented out stuff would link directly to MATLAB's built in + # BLAS and LAPACK. But it's better to not link to anything and do a + #find_library(MATLAB_BLAS_LIBRARY mwblas PATHS ${MATLAB_LIB_FOLDERS} ) + #find_library(MATLAB_LAPACK_LIBRARY mwlapack PATHS ${MATLAB_LIB_FOLDERS} ) + #if (MATLAB_BLAS_LIBRARY AND MATLAB_LAPACK_LIBRARY) + # add_subdirectory(external/cblas) + # set(blas_libraries ${MATLAB_BLAS_LIBRARY} cblas ) + # set(lapack_libraries ${MATLAB_LAPACK_LIBRARY} ) + # set(blas_found 1) + # set(lapack_found 1) + # message(STATUS "Found MATLAB's BLAS and LAPACK libraries") + #endif() + + # We need cblas since MATLAB doesn't provide cblas symbols. + add_subdirectory(external/cblas) + set(blas_libraries cblas ) + set(blas_found 1) + set(lapack_found 1) + message(STATUS "Will link with MATLAB's BLAS and LAPACK at runtime (hopefully!)") + + + ## Don't try to link to anything other than MATLAB's own internal blas + ## and lapack libraries because doing so generally upsets MATLAB. So + ## we just end here no matter what. + return() + endif() + + # First, search for libraries via pkg-config, which is the cleanest path + find_package(PkgConfig) + pkg_check_modules(BLAS_REFERENCE cblas) + pkg_check_modules(LAPACK_REFERENCE lapack) + if (BLAS_REFERENCE_FOUND AND LAPACK_REFERENCE_FOUND) + set(blas_libraries "${BLAS_REFERENCE_LDFLAGS}") + set(lapack_libraries "${LAPACK_REFERENCE_LDFLAGS}") + set(blas_found 1) + set(lapack_found 1) + set(REQUIRES_LIBS "${REQUIRES_LIBS} cblas lapack") + message(STATUS "Found BLAS and LAPACK via pkg-config") + return() + endif() + + include(CheckTypeSize) + check_type_size( "void*" SIZE_OF_VOID_PTR) + + if (SIZE_OF_VOID_PTR EQUAL 8) + set( mkl_search_path + /opt/intel/mkl/*/lib/em64t + /opt/intel/mkl/lib/intel64 + /opt/intel/lib/intel64 + /opt/intel/mkl/lib + ) + + find_library(mkl_intel mkl_intel_lp64 ${mkl_search_path}) + mark_as_advanced(mkl_intel) + else() + set( mkl_search_path + /opt/intel/mkl/*/lib/32 + /opt/intel/mkl/lib/ia32 + /opt/intel/lib/ia32 + ) + + find_library(mkl_intel mkl_intel ${mkl_search_path}) + mark_as_advanced(mkl_intel) + endif() + + include(CheckLibraryExists) + + # Get mkl_include_dir + set(mkl_include_search_path + /opt/intel/mkl/include + /opt/intel/include + ) + find_path(mkl_include_dir mkl_version.h ${mkl_include_search_path}) + mark_as_advanced(mkl_include_dir) + + # Search for the needed libraries from the MKL. We will try to link against the mkl_rt + # file first since this way avoids linking bugs in some cases. + find_library(mkl_rt mkl_rt ${mkl_search_path}) + find_library(openmp_libraries iomp5 ${mkl_search_path}) + mark_as_advanced( mkl_rt openmp_libraries ) + # if we found the MKL + if ( mkl_rt) + set(mkl_libraries ${mkl_rt} ) + set(blas_libraries ${mkl_rt} ) + set(lapack_libraries ${mkl_rt} ) + set(blas_found 1) + set(lapack_found 1) + set(found_intel_mkl 1) + message(STATUS "Found Intel MKL BLAS/LAPACK library") + endif() + + if (NOT found_intel_mkl) + # Search for the needed libraries from the MKL. This time try looking for a different + # set of MKL files and try to link against those. + find_library(mkl_core mkl_core ${mkl_search_path}) + find_library(mkl_thread mkl_intel_thread ${mkl_search_path}) + find_library(mkl_iomp iomp5 ${mkl_search_path}) + find_library(mkl_pthread pthread ${mkl_search_path}) + + mark_as_advanced( mkl_intel mkl_core mkl_thread mkl_iomp mkl_pthread) + # If we found the MKL + if (mkl_intel AND mkl_core AND mkl_thread AND mkl_iomp AND mkl_pthread) + set(mkl_libraries ${mkl_intel} ${mkl_core} ${mkl_thread} ${mkl_iomp} ${mkl_pthread}) + set(blas_libraries ${mkl_intel} ${mkl_core} ${mkl_thread} ${mkl_iomp} ${mkl_pthread}) + set(lapack_libraries ${mkl_intel} ${mkl_core} ${mkl_thread} ${mkl_iomp} ${mkl_pthread}) + set(blas_found 1) + set(lapack_found 1) + set(found_intel_mkl 1) + message(STATUS "Found Intel MKL BLAS/LAPACK library") + endif() + endif() + + if (found_intel_mkl AND mkl_include_dir) + set(found_intel_mkl_headers 1) + endif() + + # try to find some other LAPACK libraries if we didn't find the MKL + set(extra_paths + /usr/lib64 + /usr/lib64/atlas-sse3 + /usr/lib64/atlas-sse2 + /usr/lib64/atlas + /usr/lib + /usr/lib/atlas-sse3 + /usr/lib/atlas-sse2 + /usr/lib/atlas + /usr/lib/openblas-base + /opt/OpenBLAS/lib + $ENV{OPENBLAS_HOME}/lib + ) + + INCLUDE (CheckFunctionExists) + + if (NOT blas_found) + find_library(cblas_lib openblas PATHS ${extra_paths}) + if (cblas_lib) + set(blas_libraries ${cblas_lib}) + set(blas_found 1) + message(STATUS "Found OpenBLAS library") + set(CMAKE_REQUIRED_LIBRARIES ${blas_libraries}) + # If you compiled OpenBLAS with LAPACK in it then it should have the + # sgetrf_single function in it. So if we find that function in + # OpenBLAS then just use OpenBLAS's LAPACK. + CHECK_FUNCTION_EXISTS(sgetrf_single OPENBLAS_HAS_LAPACK) + if (OPENBLAS_HAS_LAPACK) + message(STATUS "Using OpenBLAS's built in LAPACK") + # set(lapack_libraries gfortran) + set(lapack_found 1) + endif() + endif() + mark_as_advanced( cblas_lib) + endif() + + + if (NOT lapack_found) + find_library(lapack_lib NAMES lapack lapack-3 PATHS ${extra_paths}) + if (lapack_lib) + set(lapack_libraries ${lapack_lib}) + set(lapack_found 1) + message(STATUS "Found LAPACK library") + endif() + mark_as_advanced( lapack_lib) + endif() + + + # try to find some other BLAS libraries if we didn't find the MKL + + if (NOT blas_found) + find_library(atlas_lib atlas PATHS ${extra_paths}) + find_library(cblas_lib cblas PATHS ${extra_paths}) + if (atlas_lib AND cblas_lib) + set(blas_libraries ${atlas_lib} ${cblas_lib}) + set(blas_found 1) + message(STATUS "Found ATLAS BLAS library") + endif() + mark_as_advanced( atlas_lib cblas_lib) + endif() + + # CentOS 7 atlas + if (NOT blas_found) + find_library(tatlas_lib tatlas PATHS ${extra_paths}) + find_library(satlas_lib satlas PATHS ${extra_paths}) + if (tatlas_lib AND satlas_lib ) + set(blas_libraries ${tatlas_lib} ${satlas_lib}) + set(blas_found 1) + message(STATUS "Found ATLAS BLAS library") + endif() + mark_as_advanced( tatlas_lib satlas_lib) + endif() + + + if (NOT blas_found) + find_library(cblas_lib cblas PATHS ${extra_paths}) + if (cblas_lib) + set(blas_libraries ${cblas_lib}) + set(blas_found 1) + message(STATUS "Found CBLAS library") + endif() + mark_as_advanced( cblas_lib) + endif() + + + if (NOT blas_found) + find_library(generic_blas blas PATHS ${extra_paths}) + if (generic_blas) + set(blas_libraries ${generic_blas}) + set(blas_found 1) + message(STATUS "Found BLAS library") + endif() + mark_as_advanced( generic_blas) + endif() + + + + + # Make sure we really found a CBLAS library. That is, it needs to expose + # the proper cblas link symbols. So here we test if one of them is present + # and assume everything is good if it is. Note that we don't do this check if + # we found the Intel MKL since for some reason CHECK_FUNCTION_EXISTS doesn't work + # with it. But it's fine since the MKL should always have cblas. + if (blas_found AND NOT found_intel_mkl) + set(CMAKE_REQUIRED_LIBRARIES ${blas_libraries}) + CHECK_FUNCTION_EXISTS(cblas_ddot HAVE_CBLAS) + if (NOT HAVE_CBLAS) + message(STATUS "BLAS library does not have cblas symbols, so dlib will not use BLAS or LAPACK") + set(blas_found 0) + set(lapack_found 0) + endif() + endif() + + + +elseif(WIN32 AND NOT MINGW) + message(STATUS "Searching for BLAS and LAPACK") + + include(CheckTypeSize) + check_type_size( "void*" SIZE_OF_VOID_PTR) + if (SIZE_OF_VOID_PTR EQUAL 8) + set( mkl_search_path + "C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_*/windows/mkl/lib/intel64" + "C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_*/windows/compiler/lib/intel64" + "C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/compiler/lib/intel64" + "C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/mkl/lib/intel64" + "C:/Program Files (x86)/Intel/Composer XE/mkl/lib/intel64" + "C:/Program Files (x86)/Intel/Composer XE/compiler/lib/intel64" + "C:/Program Files/Intel/Composer XE/mkl/lib/intel64" + "C:/Program Files/Intel/Composer XE/compiler/lib/intel64" + ) + find_library(mkl_intel mkl_intel_lp64 ${mkl_search_path}) + else() + set( mkl_search_path + "C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_*/windows/mkl/lib/ia32" + "C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_*/windows/compiler/lib/ia32" + "C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/mkl/lib/ia32" + "C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/compiler/lib/ia32" + "C:/Program Files (x86)/Intel/Composer XE/mkl/lib/ia32" + "C:/Program Files (x86)/Intel/Composer XE/compiler/lib/ia32" + "C:/Program Files/Intel/Composer XE/mkl/lib/ia32" + "C:/Program Files/Intel/Composer XE/compiler/lib/ia32" + ) + find_library(mkl_intel mkl_intel_c ${mkl_search_path}) + endif() + + INCLUDE (CheckFunctionExists) + + # Search for the needed libraries from the MKL. + find_library(mkl_core mkl_core ${mkl_search_path}) + find_library(mkl_thread mkl_intel_thread ${mkl_search_path}) + find_library(mkl_iomp libiomp5md ${mkl_search_path}) + + mark_as_advanced( mkl_intel mkl_core mkl_thread mkl_iomp) + # If we found the MKL + if (mkl_intel AND mkl_core AND mkl_thread AND mkl_iomp ) + set(blas_libraries ${mkl_intel} ${mkl_core} ${mkl_thread} ${mkl_iomp} ) + set(lapack_libraries ${mkl_intel} ${mkl_core} ${mkl_thread} ${mkl_iomp} ) + set(blas_found 1) + set(lapack_found 1) + message(STATUS "Found Intel MKL BLAS/LAPACK library") + + # Make sure the version of the Intel MKL we found is compatible with + # the compiler we are using. One way to do this check is to see if we can + # link to it right now. + set(CMAKE_REQUIRED_LIBRARIES ${blas_libraries}) + CHECK_FUNCTION_EXISTS(cblas_ddot HAVE_CBLAS) + if (NOT HAVE_CBLAS) + message("BLAS library does not have cblas symbols, so dlib will not use BLAS or LAPACK") + set(blas_found 0) + set(lapack_found 0) + endif() + + endif() + + +endif() + + +# When all else fails use CMake's built in functions to find BLAS and LAPACK +if (NOT blas_found) + find_package(BLAS QUIET) + if (${BLAS_FOUND}) + set(blas_libraries ${BLAS_LIBRARIES}) + set(blas_found 1) + if (NOT lapack_found) + find_package(LAPACK QUIET) + if (${LAPACK_FOUND}) + set(lapack_libraries ${LAPACK_LIBRARIES}) + set(lapack_found 1) + endif() + endif() + endif() +endif() + + +# If using lapack, determine whether to mangle functions +if (lapack_found) + include(CheckFunctionExists) + include(CheckFortranFunctionExists) + set(CMAKE_REQUIRED_LIBRARIES ${lapack_libraries}) + + check_function_exists("sgesv" LAPACK_FOUND_C_UNMANGLED) + check_function_exists("sgesv_" LAPACK_FOUND_C_MANGLED) + if (CMAKE_Fortran_COMPILER_LOADED) + check_fortran_function_exists("sgesv" LAPACK_FOUND_FORTRAN_UNMANGLED) + check_fortran_function_exists("sgesv_" LAPACK_FOUND_FORTRAN_MANGLED) + endif () + if (LAPACK_FOUND_C_MANGLED OR LAPACK_FOUND_FORTRAN_MANGLED) + set(lapack_with_underscore 1) + elseif (LAPACK_FOUND_C_UNMANGLED OR LAPACK_FOUND_FORTRAN_UNMANGLED) + set(lapack_without_underscore 1) + endif () +endif() + + +if (UNIX OR MINGW) + if (NOT blas_found) + message(" *****************************************************************************") + message(" *** No BLAS library found so using dlib's built in BLAS. However, if you ***") + message(" *** install an optimized BLAS such as OpenBLAS or the Intel MKL your code ***") + message(" *** will run faster. On Ubuntu you can install OpenBLAS by executing: ***") + message(" *** sudo apt-get install libopenblas-dev liblapack-dev ***") + message(" *** Or you can easily install OpenBLAS from source by downloading the ***") + message(" *** source tar file from http://www.openblas.net, extracting it, and ***") + message(" *** running: ***") + message(" *** make; sudo make install ***") + message(" *****************************************************************************") + endif() +endif() + diff --git a/lib/3rdParty/dlib/include/dlib/cmake_utils/set_compiler_specific_options.cmake b/lib/3rdParty/dlib/include/dlib/cmake_utils/set_compiler_specific_options.cmake new file mode 100644 index 00000000..94ae00e1 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cmake_utils/set_compiler_specific_options.cmake @@ -0,0 +1,150 @@ + +cmake_minimum_required(VERSION 2.8.12) + +if (POLICY CMP0054) + cmake_policy(SET CMP0054 NEW) +endif() + + + +# Check if we are being built as part of a pybind11 module. +if (COMMAND pybind11_add_module) + # For python users, assume they have SSE4 at least and then if the host machine has AVX use that too. + set(USE_SSE4_INSTRUCTIONS ON CACHE BOOL "Use SSE4 instructions") + include(${CMAKE_CURRENT_LIST_DIR}/check_if_avx_instructions_executable_on_host.cmake) + if (AVX_IS_AVAILABLE_ON_HOST) + set(USE_AVX_INSTRUCTIONS ON CACHE BOOL "Use AVX instructions") + endif() +endif() + + + +set(USING_OLD_VISUAL_STUDIO_COMPILER 0) +if(MSVC AND MSVC_VERSION VERSION_LESS 1900) + message(FATAL_ERROR "C++11 is required to use dlib, but the version of Visual Studio you are using is too old and doesn't support C++11. You need Visual Studio 2015 or newer. ") +elseif(MSVC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0.24210.0 ) + message(STATUS "NOTE: Visual Studio didn't have good enough C++11 support until Visual Studio 2015 update 3 (v19.0.24210.0)") + message(STATUS "So we aren't enabling things that require full C++11 support (e.g. the deep learning tools).") + message(STATUS "Also, be aware that Visual Studio's version naming is confusing, in particular, there are multiple versions of 'update 3'") + message(STATUS "So if you are getting this message you need to update to the newer version of Visual Studio to use full C++11.") + set(USING_OLD_VISUAL_STUDIO_COMPILER 1) +elseif(MSVC AND (MSVC_VERSION EQUAL 1911 OR MSVC_VERSION EQUAL 1910)) + message(STATUS "******************************************************************************************") + message(STATUS "Your version of Visual Studio has incomplete C++11 support and is unable to compile the ") + message(STATUS "DNN examples. So we are disabling the deep learning tools. If you want to use the DNN ") + message(STATUS "tools in dlib then update your copy of Visual Studio.") + message(STATUS "******************************************************************************************") + set(USING_OLD_VISUAL_STUDIO_COMPILER 1) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX) + execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) + if (GCC_VERSION VERSION_LESS 4.8) + message(FATAL_ERROR "C++11 is required to use dlib, but the version of GCC you are using is too old and doesn't support C++11. You need GCC 4.8 or newer. ") + endif() +endif() + + +# push USING_OLD_VISUAL_STUDIO_COMPILER to the parent so we can use it in the +# examples CMakeLists.txt file. +get_directory_property(has_parent PARENT_DIRECTORY) +if(has_parent) + set(USING_OLD_VISUAL_STUDIO_COMPILER ${USING_OLD_VISUAL_STUDIO_COMPILER} PARENT_SCOPE) +endif() + + + +set(gcc_like_compilers GNU Clang Intel) +set(intel_archs x86_64 i386 i686 AMD64 amd64 x86) + + +# Setup some options to allow a user to enable SSE and AVX instruction use. +if ((";${gcc_like_compilers};" MATCHES ";${CMAKE_CXX_COMPILER_ID};") AND + (";${intel_archs};" MATCHES ";${CMAKE_SYSTEM_PROCESSOR};") AND NOT USE_AUTO_VECTOR) + option(USE_SSE2_INSTRUCTIONS "Compile your program with SSE2 instructions" OFF) + option(USE_SSE4_INSTRUCTIONS "Compile your program with SSE4 instructions" OFF) + option(USE_AVX_INSTRUCTIONS "Compile your program with AVX instructions" OFF) + if(USE_AVX_INSTRUCTIONS) + list(APPEND active_compile_opts -mavx) + message(STATUS "Enabling AVX instructions") + elseif (USE_SSE4_INSTRUCTIONS) + list(APPEND active_compile_opts -msse4) + message(STATUS "Enabling SSE4 instructions") + elseif(USE_SSE2_INSTRUCTIONS) + list(APPEND active_compile_opts -msse2) + message(STATUS "Enabling SSE2 instructions") + endif() +elseif (MSVC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # else if using Visual Studio + # Use SSE2 by default when using Visual Studio. + option(USE_SSE2_INSTRUCTIONS "Compile your program with SSE2 instructions" ON) + option(USE_SSE4_INSTRUCTIONS "Compile your program with SSE4 instructions" OFF) + option(USE_AVX_INSTRUCTIONS "Compile your program with AVX instructions" OFF) + + include(CheckTypeSize) + check_type_size( "void*" SIZE_OF_VOID_PTR) + if(USE_AVX_INSTRUCTIONS) + list(APPEND active_compile_opts /arch:AVX) + message(STATUS "Enabling AVX instructions") + elseif (USE_SSE4_INSTRUCTIONS) + # Visual studio doesn't have an /arch:SSE2 flag when building in 64 bit modes. + # So only give it when we are doing a 32 bit build. + if (SIZE_OF_VOID_PTR EQUAL 4) + list(APPEND active_compile_opts /arch:SSE2) + endif() + message(STATUS "Enabling SSE4 instructions") + list(APPEND active_preprocessor_switches "-DDLIB_HAVE_SSE2") + list(APPEND active_preprocessor_switches "-DDLIB_HAVE_SSE3") + list(APPEND active_preprocessor_switches "-DDLIB_HAVE_SSE41") + elseif(USE_SSE2_INSTRUCTIONS) + # Visual studio doesn't have an /arch:SSE2 flag when building in 64 bit modes. + # So only give it when we are doing a 32 bit build. + if (SIZE_OF_VOID_PTR EQUAL 4) + list(APPEND active_compile_opts /arch:SSE2) + endif() + message(STATUS "Enabling SSE2 instructions") + list(APPEND active_preprocessor_switches "-DDLIB_HAVE_SSE2") + endif() + +elseif((";${gcc_like_compilers};" MATCHES ";${CMAKE_CXX_COMPILER_ID};") AND + ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "^arm")) + option(USE_NEON_INSTRUCTIONS "Compile your program with ARM-NEON instructions" OFF) + if(USE_NEON_INSTRUCTIONS) + list(APPEND active_compile_opts -mfpu=neon) + message(STATUS "Enabling ARM-NEON instructions") + endif() +endif() + + + + +if (CMAKE_COMPILER_IS_GNUCXX) + # By default, g++ won't warn or error if you forget to return a value in a + # function which requires you to do so. This option makes it give a warning + # for doing this. + list(APPEND active_compile_opts "-Wreturn-type") +endif() + +if ("Clang" MATCHES ${CMAKE_CXX_COMPILER_ID}) + # Increase clang's default tempalte recurision depth so the dnn examples don't error out. + list(APPEND active_compile_opts "-ftemplate-depth=500") +endif() + +if (MSVC) + # By default Visual Studio does not support .obj files with more than 65k sections. + # However, code generated by file_to_code_ex and code using DNN module can have + # them. So this flag enables > 65k sections, but produces .obj files + # that will not be readable by VS 2005. + list(APPEND active_compile_opts "/bigobj") + + # Build dlib with all cores. Don't propagate the setting to client programs + # though since they might compile large translation units that use too much + # RAM. + list(APPEND active_compile_opts_private "/MP") + + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3.3) + # Clang can compile all Dlib's code at Windows platform. Tested with Clang 5 + list(APPEND active_compile_opts "-Xclang -fcxx-exceptions") + endif() +endif() + + diff --git a/lib/3rdParty/dlib/include/dlib/cmake_utils/tell_visual_studio_to_use_static_runtime.cmake b/lib/3rdParty/dlib/include/dlib/cmake_utils/tell_visual_studio_to_use_static_runtime.cmake new file mode 100644 index 00000000..8cab322e --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cmake_utils/tell_visual_studio_to_use_static_runtime.cmake @@ -0,0 +1,19 @@ + +# Including this cmake script into your cmake project will cause visual studio +# to build your project against the static C runtime. + +cmake_minimum_required(VERSION 2.8.12) +if (POLICY CMP0054) + cmake_policy(SET CMP0054 NEW) +endif() + +if (MSVC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + foreach(flag_var + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if(${flag_var} MATCHES "/MD") + string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") + endif() + endforeach(flag_var) +endif() + diff --git a/lib/3rdParty/dlib/include/dlib/cmake_utils/use_cpp_11.cmake b/lib/3rdParty/dlib/include/dlib/cmake_utils/use_cpp_11.cmake new file mode 100644 index 00000000..e49e30f2 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cmake_utils/use_cpp_11.cmake @@ -0,0 +1,113 @@ +# This script creates a function, enable_cpp11_for_target(), which checks if your +# compiler has C++11 support and enables it if it does. + + +cmake_minimum_required(VERSION 2.8.12) + +if (POLICY CMP0054) + cmake_policy(SET CMP0054 NEW) +endif() + + +set(_where_is_cmake_utils_dir ${CMAKE_CURRENT_LIST_DIR}) + +function(enable_cpp11_for_target target_name) + + +# Set to false unless we find out otherwise in the code below. +set(COMPILER_CAN_DO_CPP_11 0) + + + +macro(test_compiler_for_cpp11) + message(STATUS "Building a C++11 test project to see if your compiler supports C++11") + try_compile(test_for_cpp11_worked ${PROJECT_BINARY_DIR}/cpp11_test_build + ${_where_is_cmake_utils_dir}/test_for_cpp11 cpp11_test) + if (test_for_cpp11_worked) + message(STATUS "C++11 activated.") + set(COMPILER_CAN_DO_CPP_11 1) + else() + set(COMPILER_CAN_DO_CPP_11 0) + message(STATUS "********** Your compiler failed to build a C++11 project. C++11 is required to use all parts of dlib! **********") + endif() +endmacro() + +# Now turn on the appropriate compiler switch to enable C++11 if you have a +# C++11 compiler. In CMake 3.1 there is a simple flag you can set, but earlier +# verions of CMake are not so convenient. +if (CMAKE_VERSION VERSION_LESS "3.1.2") + if(CMAKE_COMPILER_IS_GNUCXX) + execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) + if (GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8) + message(STATUS "C++11 activated.") + target_compile_options(${target_name} PUBLIC "-std=gnu++11") + set(COMPILER_CAN_DO_CPP_11 1) + endif() + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + execute_process( COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE clang_full_version_string ) + string (REGEX REPLACE ".*clang version ([0-9]+\\.[0-9]+).*" "\\1" CLANG_VERSION ${clang_full_version_string}) + if (CLANG_VERSION VERSION_GREATER 3.3) + message(STATUS "C++11 activated.") + target_compile_options(${target_name} PUBLIC "-std=c++11") + set(COMPILER_CAN_DO_CPP_11 1) + endif() + else() + # Since we don't know what compiler this is just try to build a c++11 project and see if it compiles. + test_compiler_for_cpp11() + endif() +else() + + # Set a flag if the compiler you are using is capable of providing C++11 features. + get_property(cxx_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES) + if (";${cxx_features};" MATCHES ";cxx_rvalue_references;" AND + ";${cxx_features};" MATCHES ";cxx_variadic_templates;" AND + ";${cxx_features};" MATCHES ";cxx_lambdas;" AND + ";${cxx_features};" MATCHES ";cxx_defaulted_move_initializers;" AND + ";${cxx_features};" MATCHES ";cxx_delegating_constructors;" AND + ";${cxx_features};" MATCHES ";cxx_thread_local;" AND + ";${cxx_features};" MATCHES ";cxx_constexpr;" AND + ";${cxx_features};" MATCHES ";cxx_decltype_incomplete_return_types;" AND + ";${cxx_features};" MATCHES ";cxx_auto_type;") + + set(COMPILER_CAN_DO_CPP_11 1) + # Tell cmake that we need C++11 for dlib + target_compile_features(${target_name} + PUBLIC + cxx_rvalue_references + cxx_variadic_templates + cxx_lambdas + cxx_defaulted_move_initializers + cxx_delegating_constructors + cxx_thread_local + cxx_constexpr + # cxx_decltype_incomplete_return_types # purposfully commented out because cmake errors out on this when using visual studio and cmake 3.8.0 + cxx_auto_type + ) + + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + # Sometimes clang will lie and report that it supports C++11 when + # really it doesn't support thread_local. So check for that. + test_compiler_for_cpp11() + else() + message(STATUS "C++11 activated.") + endif() + endif() +endif() + +# Always enable whatever partial C++11 support we have, even if it isn't full +# support, and just hope for the best. +if (NOT COMPILER_CAN_DO_CPP_11) + include(CheckCXXCompilerFlag) + CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) + CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) + if(COMPILER_SUPPORTS_CXX11) + message(STATUS "C++11 activated (compiler doesn't have full C++11 support).") + target_compile_options(${target_name} PUBLIC "-std=c++11") + elseif(COMPILER_SUPPORTS_CXX0X) + message(STATUS "C++0x activated (compiler doesn't have full C++11 support).") + target_compile_options(${target_name} PUBLIC "-std=c++0x") + endif() +endif() + +endfunction() + diff --git a/lib/3rdParty/dlib/include/dlib/cmd_line_parser/cmd_line_parser_kernel_1.h b/lib/3rdParty/dlib/include/dlib/cmd_line_parser/cmd_line_parser_kernel_1.h index b821b48f..68ea5a13 100644 --- a/lib/3rdParty/dlib/include/dlib/cmd_line_parser/cmd_line_parser_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/cmd_line_parser/cmd_line_parser_kernel_1.h @@ -305,7 +305,7 @@ namespace dlib bool move_next ( ) const { return options.move_next(); } - unsigned long size ( + size_t size ( ) const { return options.size(); } private: diff --git a/lib/3rdParty/dlib/include/dlib/cmd_line_parser/cmd_line_parser_print_1.h b/lib/3rdParty/dlib/include/dlib/cmd_line_parser/cmd_line_parser_print_1.h index 3ff30b0d..3f52c842 100644 --- a/lib/3rdParty/dlib/include/dlib/cmd_line_parser/cmd_line_parser_print_1.h +++ b/lib/3rdParty/dlib/include/dlib/cmd_line_parser/cmd_line_parser_print_1.h @@ -10,7 +10,7 @@ #include #include #include -#include "../smart_pointers.h" +#include namespace dlib { @@ -105,7 +105,7 @@ namespace dlib // Make a separate ostringstream for each option group. We are going to write // the output for each group to a separate ostringstream so that we can keep // them grouped together in the final output. - std::map > groups; + std::map > groups; this->reset(); while(this->move_next()) { @@ -173,7 +173,7 @@ namespace dlib out << _dT(ct,"Options:"); // Now print everything out - typename std::map >::iterator i; + typename std::map >::iterator i; for (i = groups.begin(); i != groups.end(); ++i) { // print the group name if we have one diff --git a/lib/3rdParty/dlib/include/dlib/config.h b/lib/3rdParty/dlib/include/dlib/config.h index a5ebee56..11c4d63b 100644 --- a/lib/3rdParty/dlib/include/dlib/config.h +++ b/lib/3rdParty/dlib/include/dlib/config.h @@ -7,15 +7,28 @@ // always off. If you don't define one of these two macros then DLIB_ASSERT will toggle // automatically depending on the state of certain other macros, which is not what you want // when creating a shared library. -//#define ENABLE_ASSERTS // asserts always enabled -//#define DLIB_DISABLE_ASSERTS // asserts always disabled +/* #undef ENABLE_ASSERTS */ +#define DLIB_DISABLE_ASSERTS // asserts always disabled +/* #undef DLIB_ISO_CPP_ONLY */ +#define DLIB_NO_GUI_SUPPORT +/* #undef DLIB_ENABLE_STACK_TRACE */ +/* #undef LAPACK_FORCE_UNDERSCORE */ +/* #undef LAPACK_FORCE_NOUNDERSCORE */ + +// You should also consider telling dlib to link against libjpeg, libpng, libgif, fftw, CUDA, +// and a BLAS and LAPACK library. To do this you need to uncomment the following #defines. +/* #undef DLIB_JPEG_SUPPORT */ +/* #undef DLIB_PNG_SUPPORT */ +/* #undef DLIB_GIF_SUPPORT */ +/* #undef DLIB_USE_FFTW */ +/* #undef DLIB_USE_BLAS */ +/* #undef DLIB_USE_LAPACK */ +/* #undef DLIB_USE_CUDA */ +/* #undef DLIB_USE_MKL_FFT */ + +// This variable allows dlib/test_for_odr_violations.h to catch people who mistakenly use +// headers from one version of dlib with a compiled dlib binary from a different dlib version. +#define DLIB_CHECK_FOR_VERSION_MISMATCH DLIB_VERSION_MISMATCH_CHECK__EXPECTED_VERSION_19_13_0 -// You should also consider telling dlib to link against libjpeg, libpng, fftw, and a BLAS -// and LAPACK library. To do this you need to uncomment the following #defines. -// #define DLIB_JPEG_SUPPORT -// #define DLIB_PNG_SUPPORT -// #define DLIB_USE_FFTW -// #define DLIB_USE_BLAS -// #define DLIB_USE_LAPACK diff --git a/lib/3rdParty/dlib/include/dlib/console_progress_indicator.h b/lib/3rdParty/dlib/include/dlib/console_progress_indicator.h index aaf27dfc..8f04aa53 100644 --- a/lib/3rdParty/dlib/include/dlib/console_progress_indicator.h +++ b/lib/3rdParty/dlib/include/dlib/console_progress_indicator.h @@ -65,7 +65,8 @@ namespace dlib !*/ inline bool print_status ( - double cur + double cur, + bool always_print = false ); /*! ensures @@ -74,10 +75,13 @@ namespace dlib remaining until cur becomes equal to target(). - prints a status message to the screen which indicates how much more time is left until cur is equal to target() - - This function throttles the printing so that at most 1 message is printed - each second. Note that it won't print anything to the screen until about - one second has elapsed. This means that the first call to print_status() - never prints to the screen. + - if (always_print) then + - This function prints to the screen each time it is called. + - else + - This function throttles the printing so that at most 1 message is + printed each second. Note that it won't print anything to the screen + until about one second has elapsed. This means that the first call + to print_status() never prints to the screen. - This function returns true if it prints to the screen and false otherwise. !*/ @@ -115,7 +119,8 @@ namespace dlib bool console_progress_indicator:: print_status ( - double cur + double cur, + bool always_print ) { const time_t cur_time = std::time(0); @@ -132,7 +137,7 @@ namespace dlib return false; } - if (cur_time != last_time) + if (cur_time != last_time || always_print) { last_time = cur_time; double delta_t = static_cast(cur_time - start_time); @@ -152,17 +157,17 @@ namespace dlib if (seconds < 60) { ss = std::cout.precision(0); - std::cout << "Time remaining: " << seconds << " seconds. \r" << std::flush; + std::cout << "Time remaining: " << seconds << " seconds. \r" << std::flush; } else if (seconds < 60*60) { ss = std::cout.precision(2); - std::cout << "Time remaining: " << seconds/60 << " minutes. \r" << std::flush; + std::cout << "Time remaining: " << seconds/60 << " minutes. \r" << std::flush; } else { ss = std::cout.precision(2); - std::cout << "Time remaining: " << seconds/60/60 << " hours. \r" << std::flush; + std::cout << "Time remaining: " << seconds/60/60 << " hours. \r" << std::flush; } // restore previous output flags and precision settings diff --git a/lib/3rdParty/dlib/include/dlib/control.h b/lib/3rdParty/dlib/include/dlib/control.h new file mode 100644 index 00000000..85d00817 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/control.h @@ -0,0 +1,11 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CONTRoL_ +#define DLIB_CONTRoL_ + +#include "control/lspi.h" +#include "control/mpc.h" + +#endif // DLIB_CONTRoL_ + + diff --git a/lib/3rdParty/dlib/include/dlib/control/approximate_linear_models.h b/lib/3rdParty/dlib/include/dlib/control/approximate_linear_models.h new file mode 100644 index 00000000..9732d71e --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/control/approximate_linear_models.h @@ -0,0 +1,128 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_APPROXIMATE_LINEAR_MODELS_Hh_ +#define DLIB_APPROXIMATE_LINEAR_MODELS_Hh_ + +#include "approximate_linear_models_abstract.h" +#include "../matrix.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename feature_extractor + > + struct process_sample + { + typedef feature_extractor feature_extractor_type; + typedef typename feature_extractor::state_type state_type; + typedef typename feature_extractor::action_type action_type; + + process_sample(){} + + process_sample( + const state_type& s, + const action_type& a, + const state_type& n, + const double& r + ) : state(s), action(a), next_state(n), reward(r) {} + + state_type state; + action_type action; + state_type next_state; + double reward; + }; + + template < typename feature_extractor > + void serialize (const process_sample& item, std::ostream& out) + { + serialize(item.state, out); + serialize(item.action, out); + serialize(item.next_state, out); + serialize(item.reward, out); + } + + template < typename feature_extractor > + void deserialize (process_sample& item, std::istream& in) + { + deserialize(item.state, in); + deserialize(item.action, in); + deserialize(item.next_state, in); + deserialize(item.reward, in); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename feature_extractor + > + class policy + { + public: + + typedef feature_extractor feature_extractor_type; + typedef typename feature_extractor::state_type state_type; + typedef typename feature_extractor::action_type action_type; + + + policy ( + ) + { + w.set_size(fe.num_features()); + w = 0; + } + + policy ( + const matrix& weights_, + const feature_extractor& fe_ + ) : w(weights_), fe(fe_) {} + + action_type operator() ( + const state_type& state + ) const + { + return fe.find_best_action(state,w); + } + + const feature_extractor& get_feature_extractor ( + ) const { return fe; } + + const matrix& get_weights ( + ) const { return w; } + + + private: + matrix w; + feature_extractor fe; + }; + + template < typename feature_extractor > + inline void serialize(const policy& item, std::ostream& out) + { + int version = 1; + serialize(version, out); + serialize(item.get_feature_extractor(), out); + serialize(item.get_weights(), out); + } + template < typename feature_extractor > + inline void deserialize(policy& item, std::istream& in) + { + int version = 0; + deserialize(version, in); + if (version != 1) + throw serialization_error("Unexpected version found while deserializing dlib::policy object."); + feature_extractor fe; + matrix w; + deserialize(fe, in); + deserialize(w, in); + item = policy(w,fe); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_APPROXIMATE_LINEAR_MODELS_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/control/approximate_linear_models_abstract.h b/lib/3rdParty/dlib/include/dlib/control/approximate_linear_models_abstract.h new file mode 100644 index 00000000..59dac427 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/control/approximate_linear_models_abstract.h @@ -0,0 +1,213 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_APPROXIMATE_LINEAR_MODELS_ABSTRACT_Hh_ +#ifdef DLIB_APPROXIMATE_LINEAR_MODELS_ABSTRACT_Hh_ + +#include "../matrix.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + struct example_feature_extractor + { + /*! + WHAT THIS OBJECT REPRESENTS + This object defines the interface a feature extractor must implement if it + is to be used with the process_sample and policy objects defined at the + bottom of this file. Moreover, it is meant to represent the core part + of a model used in a reinforcement learning algorithm. + + In particular, this object models a Q(state,action) function where + Q(state,action) == dot(w, PSI(state,action)) + where PSI(state,action) is a feature vector and w is a parameter + vector. + + Therefore, a feature extractor defines how the PSI(x,y) feature vector is + calculated. It also defines the types used to represent the state and + action objects. + + + THREAD SAFETY + Instances of this object are required to be threadsafe, that is, it should + be safe for multiple threads to make concurrent calls to the member + functions of this object. + !*/ + + // The state and actions can be any types so long as you provide typedefs for them. + typedef T state_type; + typedef U action_type; + // We can also say that the last element in the weight vector w must be 1. This + // can be useful for including a prior into your model. + const static bool force_last_weight_to_1 = false; + + example_feature_extractor( + ); + /*! + ensures + - this object is properly initialized. + !*/ + + unsigned long num_features( + ) const; + /*! + ensures + - returns the dimensionality of the PSI() feature vector. + !*/ + + action_type find_best_action ( + const state_type& state, + const matrix& w + ) const; + /*! + ensures + - returns the action A that maximizes Q(state,A) = dot(w,PSI(state,A)). + That is, this function finds the best action to take in the given state + when our model is parameterized by the given weight vector w. + !*/ + + void get_features ( + const state_type& state, + const action_type& action, + matrix& feats + ) const; + /*! + ensures + - #feats.size() == num_features() + - #feats == PSI(state,action) + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename feature_extractor + > + struct process_sample + { + /*! + REQUIREMENTS ON feature_extractor + feature_extractor should implement the example_feature_extractor interface + defined at the top of this file. + + WHAT THIS OBJECT REPRESENTS + This object holds a training sample for a reinforcement learning algorithm. + In particular, it should be a sample from some process where the process + was in state this->state, then took this->action action which resulted in + receiving this->reward and ending up in the state this->next_state. + !*/ + + typedef feature_extractor feature_extractor_type; + typedef typename feature_extractor::state_type state_type; + typedef typename feature_extractor::action_type action_type; + + process_sample(){} + + process_sample( + const state_type& s, + const action_type& a, + const state_type& n, + const double& r + ) : state(s), action(a), next_state(n), reward(r) {} + + state_type state; + action_type action; + state_type next_state; + double reward; + }; + + template < typename feature_extractor > + void serialize (const process_sample& item, std::ostream& out); + template < typename feature_extractor > + void deserialize (process_sample& item, std::istream& in); + /*! + provides serialization support. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename feature_extractor + > + class policy + { + /*! + REQUIREMENTS ON feature_extractor + feature_extractor should implement the example_feature_extractor interface + defined at the top of this file. + + WHAT THIS OBJECT REPRESENTS + This is a policy based on the supplied feature_extractor model. In + particular, it maps from feature_extractor::state_type to the best action + to take in that state. + !*/ + + public: + + typedef feature_extractor feature_extractor_type; + typedef typename feature_extractor::state_type state_type; + typedef typename feature_extractor::action_type action_type; + + + policy ( + ); + /*! + ensures + - #get_feature_extractor() == feature_extractor() + (i.e. it will have its default value) + - #get_weights().size() == #get_feature_extractor().num_features() + - #get_weights() == 0 + !*/ + + policy ( + const matrix& weights, + const feature_extractor& fe + ); + /*! + requires + - fe.num_features() == weights.size() + ensures + - #get_feature_extractor() == fe + - #get_weights() == weights + !*/ + + action_type operator() ( + const state_type& state + ) const; + /*! + ensures + - returns get_feature_extractor().find_best_action(state,w); + !*/ + + const feature_extractor& get_feature_extractor ( + ) const; + /*! + ensures + - returns the feature extractor used by this object + !*/ + + const matrix& get_weights ( + ) const; + /*! + ensures + - returns the parameter vector (w) associated with this object. The length + of the vector is get_feature_extractor().num_features(). + !*/ + + }; + + template < typename feature_extractor > + void serialize(const policy& item, std::ostream& out); + template < typename feature_extractor > + void deserialize(policy& item, std::istream& in); + /*! + provides serialization support. + !*/ + +// ---------------------------------------------------------------------------------------- + + +#endif // DLIB_APPROXIMATE_LINEAR_MODELS_ABSTRACT_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/control/lspi.h b/lib/3rdParty/dlib/include/dlib/control/lspi.h new file mode 100644 index 00000000..b21a501d --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/control/lspi.h @@ -0,0 +1,188 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LSPI_Hh_ +#define DLIB_LSPI_Hh_ + +#include "lspi_abstract.h" +#include "approximate_linear_models.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename feature_extractor + > + class lspi + { + public: + typedef feature_extractor feature_extractor_type; + typedef typename feature_extractor::state_type state_type; + typedef typename feature_extractor::action_type action_type; + + explicit lspi( + const feature_extractor& fe_ + ) : fe(fe_) + { + init(); + } + + lspi( + ) + { + init(); + } + + double get_discount ( + ) const { return discount; } + + void set_discount ( + double value + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(0 < value && value <= 1, + "\t void lspi::set_discount(value)" + << "\n\t invalid inputs were given to this function" + << "\n\t value: " << value + ); + discount = value; + } + + const feature_extractor& get_feature_extractor ( + ) const { return fe; } + + void be_verbose ( + ) + { + verbose = true; + } + + void be_quiet ( + ) + { + verbose = false; + } + + void set_epsilon ( + double eps_ + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(eps_ > 0, + "\t void lspi::set_epsilon(eps_)" + << "\n\t invalid inputs were given to this function" + << "\n\t eps_: " << eps_ + ); + eps = eps_; + } + + double get_epsilon ( + ) const + { + return eps; + } + + void set_lambda ( + double lambda_ + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(lambda_ >= 0, + "\t void lspi::set_lambda(lambda_)" + << "\n\t invalid inputs were given to this function" + << "\n\t lambda_: " << lambda_ + ); + lambda = lambda_; + } + + double get_lambda ( + ) const + { + return lambda; + } + + void set_max_iterations ( + unsigned long max_iter + ) { max_iterations = max_iter; } + + unsigned long get_max_iterations ( + ) { return max_iterations; } + + template + policy train ( + const vector_type& samples + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT(samples.size() > 0, + "\t policy lspi::train(samples)" + << "\n\t invalid inputs were given to this function" + ); + + matrix w(fe.num_features()); + w = 0; + matrix prev_w, b, f1, f2; + + matrix A; + + double change; + unsigned long iter = 0; + do + { + A = identity_matrix(fe.num_features())*lambda; + b = 0; + for (unsigned long i = 0; i < samples.size(); ++i) + { + fe.get_features(samples[i].state, samples[i].action, f1); + fe.get_features(samples[i].next_state, + fe.find_best_action(samples[i].next_state,w), + f2); + A += f1*trans(f1 - discount*f2); + b += f1*samples[i].reward; + } + + prev_w = w; + if (feature_extractor::force_last_weight_to_1) + w = join_cols(pinv(colm(A,range(0,A.nc()-2)))*(b-colm(A,A.nc()-1)),mat(1.0)); + else + w = pinv(A)*b; + + change = length(w-prev_w); + ++iter; + + if (verbose) + std::cout << "iteration: " << iter << "\tchange: " << change << std::endl; + + } while(change > eps && iter < max_iterations); + + return policy(w,fe); + } + + + private: + + void init() + { + lambda = 0.01; + discount = 0.8; + eps = 0.01; + verbose = false; + max_iterations = 100; + } + + double lambda; + double discount; + double eps; + bool verbose; + unsigned long max_iterations; + feature_extractor fe; + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_LSPI_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/control/lspi_abstract.h b/lib/3rdParty/dlib/include/dlib/control/lspi_abstract.h new file mode 100644 index 00000000..f262d16f --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/control/lspi_abstract.h @@ -0,0 +1,193 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_LSPI_ABSTRACT_Hh_ +#ifdef DLIB_LSPI_ABSTRACT_Hh_ + +#include "approximate_linear_models_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename feature_extractor + > + class lspi + { + /*! + REQUIREMENTS ON feature_extractor + feature_extractor should implement the example_feature_extractor interface + defined at the top of dlib/control/approximate_linear_models_abstract.h + + WHAT THIS OBJECT REPRESENTS + This object is an implementation of the reinforcement learning algorithm + described in the following paper: + Lagoudakis, Michail G., and Ronald Parr. "Least-squares policy + iteration." The Journal of Machine Learning Research 4 (2003): + 1107-1149. + + This means that it takes a bunch of training data in the form of + process_samples and outputs a policy that hopefully performs well when run + on the process that generated those samples. + !*/ + + public: + typedef feature_extractor feature_extractor_type; + typedef typename feature_extractor::state_type state_type; + typedef typename feature_extractor::action_type action_type; + + explicit lspi( + const feature_extractor& fe_ + ); + /*! + ensures + - #get_feature_extractor() == fe_ + - #get_lambda() == 0.01 + - #get_discount == 0.8 + - #get_epsilon() == 0.01 + - is not verbose + - #get_max_iterations() == 100 + !*/ + + lspi( + ); + /*! + ensures + - #get_feature_extractor() == feature_extractor() + (i.e. it will have its default value) + - #get_lambda() == 0.01 + - #get_discount == 0.8 + - #get_epsilon() == 0.01 + - is not verbose + - #get_max_iterations() == 100 + !*/ + + double get_discount ( + ) const; + /*! + ensures + - returns the discount applied to the sum of rewards in the Bellman + equation. + !*/ + + void set_discount ( + double value + ); + /*! + requires + - 0 < value <= 1 + ensures + - #get_discount() == value + !*/ + + const feature_extractor& get_feature_extractor ( + ) const; + /*! + ensures + - returns the feature extractor used by this object + !*/ + + void be_verbose ( + ); + /*! + ensures + - This object will print status messages to standard out so that a + user can observe the progress of the algorithm. + !*/ + + void be_quiet ( + ); + /*! + ensures + - this object will not print anything to standard out + !*/ + + void set_epsilon ( + double eps + ); + /*! + requires + - eps > 0 + ensures + - #get_epsilon() == eps + !*/ + + double get_epsilon ( + ) const; + /*! + ensures + - returns the error epsilon that determines when training should stop. + Smaller values may result in a more accurate solution but take longer to + train. + !*/ + + void set_lambda ( + double lambda_ + ); + /*! + requires + - lambda >= 0 + ensures + - #get_lambda() == lambda + !*/ + + double get_lambda ( + ) const; + /*! + ensures + - returns the regularization parameter. It is the parameter that + determines the trade off between trying to fit the training data + exactly or allowing more errors but hopefully improving the + generalization ability of the resulting function. Smaller values + encourage exact fitting while larger values of lambda may encourage + better generalization. + !*/ + + void set_max_iterations ( + unsigned long max_iter + ); + /*! + ensures + - #get_max_iterations() == max_iter + !*/ + + unsigned long get_max_iterations ( + ); + /*! + ensures + - returns the maximum number of iterations the SVM optimizer is allowed to + run before it is required to stop and return a result. + !*/ + + template < + typename vector_type + > + policy train ( + const vector_type& samples + ) const; + /*! + requires + - samples.size() > 0 + - samples is something with an interface that looks like + std::vector>. That is, it should + be some kind of array of process_sample objects. + ensures + - Trains a policy based on the given data and returns the results. The + idea is to find a policy that will obtain the largest possible reward + when run on the process that generated the samples. In particular, + if the returned policy is P then: + - P(S) == the best action to take when in state S. + - if (feature_extractor::force_last_weight_to_1) then + - The last element of P.get_weights() is 1. + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_LSPI_ABSTRACT_Hh_ + + diff --git a/lib/3rdParty/dlib/include/dlib/control/mpc.h b/lib/3rdParty/dlib/include/dlib/control/mpc.h new file mode 100644 index 00000000..48ef2b72 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/control/mpc.h @@ -0,0 +1,370 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MPC_Hh_ +#define DLIB_MPC_Hh_ + +#include "mpc_abstract.h" +#include "../matrix.h" +#include "../algs.h" + + +namespace dlib +{ + template < + long S_, + long I_, + unsigned long horizon_ + > + class mpc + { + + public: + + const static long S = S_; + const static long I = I_; + const static unsigned long horizon = horizon_; + + mpc( + ) + { + A = 0; + B = 0; + C = 0; + Q = 0; + R = 0; + lower = 0; + upper = 0; + + max_iterations = 0; + eps = 0.01; + for (unsigned long i = 0; i < horizon; ++i) + { + target[i].set_size(A.nr()); + target[i] = 0; + + controls[i].set_size(B.nc()); + controls[i] = 0; + } + lambda = 0; + } + + mpc ( + const matrix& A_, + const matrix& B_, + const matrix& C_, + const matrix& Q_, + const matrix& R_, + const matrix& lower_, + const matrix& upper_ + ) : A(A_), B(B_), C(C_), Q(Q_), R(R_), lower(lower_), upper(upper_) + { + // make sure requires clause is not broken + DLIB_ASSERT(A.nr() > 0 && B.nc() > 0, + "\t mpc::mpc()" + << "\n\t invalid inputs were given to this function" + << "\n\t A.nr(): " << A.nr() + << "\n\t B.nc(): " << B.nc() + ); + + DLIB_ASSERT(A.nr() == A.nc() && + A.nr() == B.nr() && + A.nr() == C.nr() && + A.nr() == Q.nr(), + "\t mpc::mpc()" + << "\n\t invalid inputs were given to this function" + << "\n\t A.nr(): " << A.nr() + << "\n\t A.nc(): " << A.nc() + << "\n\t B.nr(): " << B.nr() + << "\n\t C.nr(): " << C.nr() + << "\n\t Q.nr(): " << Q.nr() + ); + DLIB_ASSERT( + B.nc() == R.nr() && + B.nc() == lower.nr() && + B.nc() == upper.nr() , + "\t mpc::mpc()" + << "\n\t invalid inputs were given to this function" + << "\n\t B.nr(): " << B.nr() + << "\n\t B.nc(): " << B.nc() + << "\n\t lower.nr(): " << lower.nr() + << "\n\t upper.nr(): " << upper.nr() + ); + DLIB_ASSERT(min(Q) >= 0 && + min(R) > 0 && + min(upper-lower) >= 0, + "\t mpc::mpc()" + << "\n\t invalid inputs were given to this function" + << "\n\t min(Q): " << min(Q) + << "\n\t min(R): " << min(R) + << "\n\t min(upper-lower): " << min(upper-lower) + ); + + + max_iterations = 10000; + eps = 0.01; + for (unsigned long i = 0; i < horizon; ++i) + { + target[i].set_size(A.nr()); + target[i] = 0; + + controls[i].set_size(B.nc()); + controls[i] = 0; + } + + // Bound the maximum eigenvalue of the hessian by computing the trace of the + // hessian matrix. + lambda = sum(R)*horizon; + matrix temp = diagm(Q); + for (unsigned long c = 0; c < horizon; ++c) + { + lambda += trace(trans(B)*temp*B); + Q_diag[horizon-c-1] = diag(trans(B)*temp*B); + temp = trans(A)*temp*A + diagm(Q); + } + + } + + const matrix& get_A ( + ) const { return A; } + const matrix& get_B ( + ) const { return B; } + const matrix& get_C ( + ) const { return C; } + const matrix& get_Q ( + ) const { return Q; } + const matrix& get_R ( + ) const { return R; } + const matrix& get_lower_constraints ( + ) const { return lower; } + const matrix& get_upper_constraints ( + ) const { return upper; } + + void set_target ( + const matrix& val, + const unsigned long time + ) + { + DLIB_ASSERT(time < horizon, + "\t void mpc::set_target(eps_)" + << "\n\t invalid inputs were given to this function" + << "\n\t time: " << time + << "\n\t horizon: " << horizon + ); + + target[time] = val; + } + + void set_target ( + const matrix& val + ) + { + for (unsigned long i = 0; i < horizon; ++i) + target[i] = val; + } + + void set_last_target ( + const matrix& val + ) + { + set_target(val, horizon-1); + } + + const matrix& get_target ( + const unsigned long time + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT(time < horizon, + "\t matrix mpc::get_target(eps_)" + << "\n\t invalid inputs were given to this function" + << "\n\t time: " << time + << "\n\t horizon: " << horizon + ); + + return target[time]; + } + + unsigned long get_max_iterations ( + ) const { return max_iterations; } + + void set_max_iterations ( + unsigned long max_iter + ) + { + max_iterations = max_iter; + } + + void set_epsilon ( + double eps_ + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(eps_ > 0, + "\t void mpc::set_epsilon(eps_)" + << "\n\t invalid inputs were given to this function" + << "\n\t eps_: " << eps_ + ); + eps = eps_; + } + + double get_epsilon ( + ) const + { + return eps; + } + + matrix operator() ( + const matrix& current_state + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(min(R) > 0 && A.nr() == current_state.size(), + "\t matrix mpc::operator(current_state)" + << "\n\t invalid inputs were given to this function" + << "\n\t min(R): " << min(R) + << "\n\t A.nr(): " << A.nr() + << "\n\t current_state.size(): " << current_state.size() + ); + + // Shift the inputs over by one time step so we can use them to warm start the + // optimizer. + for (unsigned long i = 1; i < horizon; ++i) + controls[i-1] = controls[i]; + + solve_linear_mpc(current_state); + + for (unsigned long i = 1; i < horizon; ++i) + target[i-1] = target[i]; + + return controls[0]; + } + + private: + + + // These temporary variables here just to avoid reallocating them on each call to + // operator(). + matrix M[horizon]; + matrix MM[horizon]; + matrix df[horizon]; + matrix v[horizon]; + matrix v_old[horizon]; + + void solve_linear_mpc ( + const matrix& initial_state + ) + { + // make it so MM == trans(K)*Q*(M-target) + M[0] = A*initial_state + C; + for (unsigned long i = 1; i < horizon; ++i) + M[i] = A*M[i-1] + C; + for (unsigned long i = 0; i < horizon; ++i) + M[i] = diagm(Q)*(M[i]-target[i]); + for (long i = (long)horizon-2; i >= 0; --i) + M[i] += trans(A)*M[i+1]; + for (unsigned long i = 0; i < horizon; ++i) + MM[i] = trans(B)*M[i]; + + + + unsigned long iter = 0; + for (; iter < max_iterations; ++iter) + { + // compute current gradient and put it into df. + // df == H*controls + MM; + M[0] = B*controls[0]; + for (unsigned long i = 1; i < horizon; ++i) + M[i] = A*M[i-1] + B*controls[i]; + for (unsigned long i = 0; i < horizon; ++i) + M[i] = diagm(Q)*M[i]; + for (long i = (long)horizon-2; i >= 0; --i) + M[i] += trans(A)*M[i+1]; + for (unsigned long i = 0; i < horizon; ++i) + df[i] = MM[i] + trans(B)*M[i] + diagm(R)*controls[i]; + + + + // Check the stopping condition, which is the magnitude of the largest element + // of the gradient. + double max_df = 0; + unsigned long max_t = 0; + long max_v = 0; + for (unsigned long i = 0; i < horizon; ++i) + { + for (long j = 0; j < controls[i].size(); ++j) + { + // if this variable isn't an active constraint then we care about it's + // derivative. + if (!((controls[i](j) <= lower(j) && df[i](j) > 0) || + (controls[i](j) >= upper(j) && df[i](j) < 0))) + { + if (std::abs(df[i](j)) > max_df) + { + max_df = std::abs(df[i](j)); + max_t = i; + max_v = j; + } + } + } + } + if (max_df < eps) + break; + + + + // We will start out by doing a little bit of coordinate descent because it + // allows us to optimize individual variables exactly. Since we are warm + // starting each iteration with a really good solution this helps speed + // things up a lot. + const unsigned long smo_iters = 50; + if (iter < smo_iters) + { + if (Q_diag[max_t](max_v) == 0) continue; + + // Take the optimal step but just for one variable. + controls[max_t](max_v) = -(df[max_t](max_v)-Q_diag[max_t](max_v)*controls[max_t](max_v))/Q_diag[max_t](max_v); + controls[max_t](max_v) = put_in_range(lower(max_v), upper(max_v), controls[max_t](max_v)); + + // If this is the last SMO iteration then don't forget to initialize v + // for the gradient steps. + if (iter+1 == smo_iters) + { + for (unsigned long i = 0; i < horizon; ++i) + v[i] = controls[i]; + } + } + else + { + // Take a projected gradient step. + for (unsigned long i = 0; i < horizon; ++i) + { + v_old[i] = v[i]; + v[i] = dlib::clamp(controls[i] - 1.0/lambda * df[i], lower, upper); + controls[i] = dlib::clamp(v[i] + (std::sqrt(lambda)-1)/(std::sqrt(lambda)+1)*(v[i]-v_old[i]), lower, upper); + } + } + } + } + + unsigned long max_iterations; + double eps; + + matrix A; + matrix B; + matrix C; + matrix Q; + matrix R; + matrix lower; + matrix upper; + matrix target[horizon]; + + double lambda; // abound on the largest eigenvalue of the hessian matrix. + matrix Q_diag[horizon]; + matrix controls[horizon]; + + }; + +} + +#endif // DLIB_MPC_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/control/mpc_abstract.h b/lib/3rdParty/dlib/include/dlib/control/mpc_abstract.h new file mode 100644 index 00000000..b4421c07 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/control/mpc_abstract.h @@ -0,0 +1,276 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_MPC_ABSTRACT_Hh_ +#ifdef DLIB_MPC_ABSTRACT_Hh_ + +#include "../matrix.h" + +namespace dlib +{ + template < + long S_, + long I_, + unsigned long horizon_ + > + class mpc + { + /*! + REQUIREMENTS ON horizon_ + horizon_ > 0 + + REQUIREMENTS ON S_ + S_ >= 0 + + REQUIREMENTS ON I_ + I_ >= 0 + + WHAT THIS OBJECT REPRESENTS + This object implements a linear model predictive controller. To explain + what that means, suppose you have some process you want to control and the + process dynamics are described by the linear equation: + x_{i+1} = A*x_i + B*u_i + C + That is, the next state the system goes into is a linear function of its + current state (x_i) and the current control (u_i) plus some constant bias + or disturbance. + + A model predictive controller can find the control (u) you should apply to + drive the state (x) to some reference value, or alternatively to make the + state track some reference time-varying sequence. It does this by + simulating the process for horizon_ time steps and selecting the control + that leads to the best performance over the next horizon_ steps. + + To be precise, each time you ask this object for a control, it solves the + following quadratic program: + + min sum_i trans(x_i-target_i)*Q*(x_i-target_i) + trans(u_i)*R*u_i + x_i,u_i + + such that: x_0 == current_state + x_{i+1} == A*x_i + B*u_i + C + lower <= u_i <= upper + 0 <= i < horizon_ + + and reports u_0 as the control you should take given that you are currently + in current_state. Q and R are user supplied matrices that define how we + penalize variations away from the target state as well as how much we want + to avoid generating large control signals. + + Finally, the algorithm we use to solve this quadratic program is based + largely on the method described in: + A Fast Gradient method for embedded linear predictive control (2011) + by Markus Kogel and Rolf Findeisen + !*/ + + public: + + const static long S = S_; + const static long I = I_; + const static unsigned long horizon = horizon_; + + mpc( + ); + /*! + ensures + - #get_max_iterations() == 0 + - The A,B,C,Q,R,lower, and upper parameter matrices are filled with zeros. + Therefore, to use this object you must initialize it via the constructor + that supplies these parameters. + !*/ + + mpc ( + const matrix& A, + const matrix& B, + const matrix& C, + const matrix& Q, + const matrix& R, + const matrix& lower, + const matrix& upper + ); + /*! + requires + - A.nr() > 0 + - B.nc() > 0 + - A.nr() == A.nc() == B.nr() == C.nr() == Q.nr() + - B.nc() == R.nr() == lower.nr() == upper.nr() + - min(Q) >= 0 + - min(R) > 0 + - min(upper-lower) >= 0 + ensures + - #get_A() == A + - #get_B() == B + - #get_C() == C + - #get_Q() == Q + - #get_R() == R + - #get_lower_constraints() == lower + - #get_upper_constraints() == upper + - for all valid i: + - get_target(i) == a vector of all zeros + - get_target(i).size() == A.nr() + - #get_max_iterations() == 10000 + - #get_epsilon() == 0.01 + !*/ + + const matrix& get_A ( + ) const; + /*! + ensures + - returns the A matrix from the quadratic program defined above. + !*/ + + const matrix& get_B ( + ) const; + /*! + ensures + - returns the B matrix from the quadratic program defined above. + !*/ + + const matrix& get_C ( + ) const; + /*! + ensures + - returns the C matrix from the quadratic program defined above. + !*/ + + const matrix& get_Q ( + ) const; + /*! + ensures + - returns the diagonal of the Q matrix from the quadratic program defined + above. + !*/ + + const matrix& get_R ( + ) const; + /*! + ensures + - returns the diagonal of the R matrix from the quadratic program defined + above. + !*/ + + const matrix& get_lower_constraints ( + ) const; + /*! + ensures + - returns the lower matrix from the quadratic program defined above. All + controls generated by this object will have values no less than this + lower bound. That is, any control u will satisfy min(u-lower) >= 0. + !*/ + + const matrix& get_upper_constraints ( + ) const; + /*! + ensures + - returns the upper matrix from the quadratic program defined above. All + controls generated by this object will have values no larger than this + upper bound. That is, any control u will satisfy min(upper-u) >= 0. + !*/ + + const matrix& get_target ( + const unsigned long time + ) const; + /*! + requires + - time < horizon + ensures + - This object will try to find the control sequence that results in the + process obtaining get_target(time) state at the indicated time. Note + that the next time instant after "right now" is time 0. + !*/ + + void set_target ( + const matrix& val, + const unsigned long time + ); + /*! + requires + - time < horizon + ensures + - #get_target(time) == val + !*/ + + void set_target ( + const matrix& val + ); + /*! + ensures + - for all valid t: + - #get_target(t) == val + !*/ + + void set_last_target ( + const matrix& val + ); + /*! + ensures + - performs: set_target(val, horizon-1) + !*/ + + unsigned long get_max_iterations ( + ) const; + /*! + ensures + - When operator() is called it solves an optimization problem to + get_epsilon() precision to determine the next control action. In + particular, we run the optimizer until the magnitude of each element of + the gradient vector is less than get_epsilon() or until + get_max_iterations() solver iterations have been executed. + !*/ + + void set_max_iterations ( + unsigned long max_iter + ); + /*! + ensures + - #get_max_iterations() == max_iter + !*/ + + void set_epsilon ( + double eps + ); + /*! + requires + - eps > 0 + ensures + - #get_epsilon() == eps + !*/ + + double get_epsilon ( + ) const; + /*! + ensures + - When operator() is called it solves an optimization problem to + get_epsilon() precision to determine the next control action. In + particular, we run the optimizer until the magnitude of each element of + the gradient vector is less than get_epsilon() or until + get_max_iterations() solver iterations have been executed. This means + that smaller epsilon values will give more accurate outputs but may take + longer to compute. + !*/ + + matrix operator() ( + const matrix& current_state + ); + /*! + requires + - min(R) > 0 + - A.nr() == current_state.size() + ensures + - Solves the model predictive control problem defined by the arguments to + this objects constructor, assuming that the starting state is given by + current_state. Then we return the control that should be taken in the + current state that best optimizes the quadratic objective function + defined above. + - We also shift over the target states so that you only need to update the + last one (if you are using non-zero target states) via a call to + set_last_target()). In particular, for all valid t, it will be the case + that: + - #get_target(t) == get_target(t+1) + - #get_target(horizon-1) == get_target(horizon-1) + !*/ + + }; + +} + +#endif // DLIB_MPC_ABSTRACT_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/crc32/crc32_kernel_1.h b/lib/3rdParty/dlib/include/dlib/crc32/crc32_kernel_1.h index 1f5067f6..4c679d2f 100644 --- a/lib/3rdParty/dlib/include/dlib/crc32/crc32_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/crc32/crc32_kernel_1.h @@ -5,6 +5,7 @@ #include "../algs.h" #include +#include #include "crc32_kernel_abstract.h" namespace dlib @@ -15,11 +16,9 @@ namespace dlib /*! INITIAL VALUE checksum == 0xFFFFFFFF - table == crc table CONVENTION get_checksum() == checksum ^ 0xFFFFFFFF - table == crc table !*/ public: @@ -34,6 +33,10 @@ namespace dlib const std::string& item ); + inline crc32 ( + const std::vector& item + ); + inline virtual ~crc32 ( ); @@ -48,6 +51,13 @@ namespace dlib const std::string& item ); + inline void add ( + const std::vector& item + ); + + inline operator unsigned long ( + ) const { return get_checksum(); } + inline unsigned long get_checksum ( ) const; @@ -61,12 +71,67 @@ namespace dlib private: - inline void fill_crc_table( - ); - unsigned long checksum; - unsigned long table[256]; + inline unsigned long table ( + unsigned int idx + ) const + { + /* + // This code generates the crc_table used below. + unsigned long crc_table[256]; + for (unsigned long i = 0; i < 256; ++i) + { + unsigned long temp = i; + for (unsigned long j = 0; j < 8; ++j) + { + if (temp&1) + temp = (temp>>1)^0xedb88320; + else + temp >>= 1; + } + crc_table[i] = temp; + std::cout << std::hex << crc_table[i] << std::endl; + } + */ + + const static unsigned long crc_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x76dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0xedb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x9b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x1db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x6b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0xf00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x86d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x3b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x4db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0xd6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0xa00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x26d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x5005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0xcb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0xbdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d + }; + + return crc_table[idx]; + } }; @@ -79,29 +144,6 @@ namespace dlib // ---------------------------------------------------------------------------------------- // member function definitions // ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void crc32:: - fill_crc_table ( - ) - { - unsigned long temp; - - // fill out the crc table - for (unsigned long i = 0; i < 256; ++i) - { - temp = i; - for (unsigned long j = 0; j < 8; ++j) - { - if (temp&1) - temp = (temp>>1)^0xedb88320; - else - temp >>= 1; - } - table[i] = temp; - } - } - // ---------------------------------------------------------------------------------------- crc32:: @@ -109,7 +151,6 @@ namespace dlib ) { checksum = 0xFFFFFFFF; - fill_crc_table(); } // ---------------------------------------------------------------------------------------- @@ -120,7 +161,17 @@ namespace dlib ) { checksum = 0xFFFFFFFF; - fill_crc_table(); + add(item); + } + +// ---------------------------------------------------------------------------------------- + + crc32:: + crc32 ( + const std::vector& item + ) + { + checksum = 0xFFFFFFFF; add(item); } @@ -148,7 +199,7 @@ namespace dlib unsigned char item ) { - checksum = (checksum>>8) ^ table[(checksum^item) & 0xFF]; + checksum = (checksum>>8) ^ table((checksum^item) & 0xFF); } // ---------------------------------------------------------------------------------------- @@ -159,7 +210,18 @@ namespace dlib ) { for (std::string::size_type i = 0; i < item.size(); ++i) - checksum = (checksum>>8) ^ table[(checksum^item[i]) & 0xFF]; + checksum = (checksum>>8) ^ table((checksum^item[i]) & 0xFF); + } + +// ---------------------------------------------------------------------------------------- + + void crc32:: + add ( + const std::vector& item + ) + { + for (unsigned long i = 0; i < item.size(); ++i) + checksum = (checksum>>8) ^ table((checksum^item[i]) & 0xFF); } // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/crc32/crc32_kernel_abstract.h b/lib/3rdParty/dlib/include/dlib/crc32/crc32_kernel_abstract.h index 65acc3e0..76da49fb 100644 --- a/lib/3rdParty/dlib/include/dlib/crc32/crc32_kernel_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/crc32/crc32_kernel_abstract.h @@ -5,6 +5,7 @@ #include "../algs.h" #include +#include namespace dlib { @@ -41,6 +42,17 @@ namespace dlib constructor and then calling add() on item) !*/ + crc32 ( + const std::vector& item + ); + /*! + ensures + - #*this is properly initialized + - calls this->add(item). + (i.e. Using this constructor is the same as using the default + constructor and then calling add() on item) + !*/ + virtual ~crc32 ( ); /*! @@ -73,6 +85,15 @@ namespace dlib concatenated with item. !*/ + void add ( + const std::vector& item + ); + /*! + ensures + - #get_checksum() == The checksum of all items added to *this previously + concatenated with item. + !*/ + unsigned long get_checksum ( ) const; /*! @@ -80,6 +101,13 @@ namespace dlib - returns the current checksum !*/ + operator unsigned long ( + ) const; + /*! + ensures + - returns get_checksum() + !*/ + void swap ( crc32& item ); diff --git a/lib/3rdParty/dlib/include/dlib/cstring b/lib/3rdParty/dlib/include/dlib/cstring deleted file mode 100644 index eb0e59e4..00000000 --- a/lib/3rdParty/dlib/include/dlib/cstring +++ /dev/null @@ -1 +0,0 @@ -#include "dlib_include_path_tutorial.txt" diff --git a/lib/3rdParty/dlib/include/dlib/cuda/cpu_dlib.h b/lib/3rdParty/dlib/include/dlib/cuda/cpu_dlib.h new file mode 100644 index 00000000..330df01a --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cuda/cpu_dlib.h @@ -0,0 +1,505 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DNN_CPU_H_ +#define DLIB_DNN_CPU_H_ + +// This file contains CPU implementations of the GPU based functions in cuda_dlib.h +// and cudnn_dlibapi.h + +#include "tensor.h" +#include "../geometry/rectangle.h" + +namespace dlib +{ + namespace cpu + { + + // ----------------------------------------------------------------------------------- + + void multiply ( + bool add_to, + tensor& dest, + const tensor& src1, + const tensor& src2 + ); + + void multiply_conv ( + bool add_to, + tensor& dest, + const tensor& src1, + const tensor& src2 + ); + + void multiply_zero_padded ( + bool add_to, + tensor& dest, + const tensor& src1, + const tensor& src2 + ); + + void scale_channels ( + bool add_to, + tensor& dest, + const tensor& src, + const tensor& scales + ); + + void add( + float beta, + tensor& dest, + float alpha, + const tensor& src + ); + + void assign_bias_gradient ( + tensor& grad, + const tensor& gradient_input + ); + + void add ( + tensor& dest, + const tensor& src1, + const tensor& src2 + ); + + void assign_conv_bias_gradient ( + tensor& grad, + const tensor& gradient_input + ); + + // ----------------------------------------------------------------------------------- + + void affine_transform( + tensor& dest, + const tensor& src, + const float A, + const float B + ); + + void affine_transform( + tensor& dest, + const tensor& src1, + const tensor& src2, + const float A, + const float B, + const float C + ); + + void affine_transform( + tensor& dest, + const tensor& src1, + const tensor& src2, + const tensor& src3, + const float A, + const float B, + const float C, + const float D + ); + + void affine_transform_range( + size_t begin, + size_t end, + tensor& dest, + const tensor& src1, + const tensor& src2, + const tensor& src3, + const float A, + const float B, + const float C + ); + + // ----------------------------------------------------------------------------------- + + void affine_transform( + tensor& dest, + const tensor& src, + const tensor& A, + const tensor& B + ); + + // ----------------------------------------------------------------------------------- + + void affine_transform_conv( + tensor& dest, + const tensor& src, + const tensor& A, + const tensor& B + ); + + // ----------------------------------------------------------------------------------- + + void affine_transform( + const rectangle& rect, + tensor& dest, + const tensor& src1, + const tensor& src2, + const tensor& src3, + float A, + float B, + float C + ); + + // ----------------------------------------------------------------------------------- + + void compute_adam_update ( + size_t begin, + size_t end, + tensor& s, + tensor& m, + tensor& v, + const float t, + const float learning_rate, + const float weight_decay, + const float momentum1, + const float momentum2, + const tensor& params, + const tensor& params_grad + ); + + // ----------------------------------------------------------------------------------- + + void batch_normalize_inference ( + const double eps, + resizable_tensor& dest, + const tensor& src, + const tensor& gamma, + const tensor& beta, + const tensor& running_means, + const tensor& running_variances + ); + + void batch_normalize ( + const double eps, + resizable_tensor& dest, + resizable_tensor& means, + resizable_tensor& invstds, + const double averaging_factor, + resizable_tensor& running_means, + resizable_tensor& running_variances, + const tensor& src, + const tensor& gamma, + const tensor& beta + ); + + void batch_normalize_gradient ( + const double eps, + const tensor& gradient_input, + const tensor& means, + const tensor& invstds, + const tensor& src, + const tensor& gamma, + tensor& src_grad, + tensor& gamma_grad, + tensor& beta_grad + ); + + void batch_normalize_conv_inference ( + const double eps, + resizable_tensor& dest, + const tensor& src, + const tensor& gamma, + const tensor& beta, + const tensor& running_means, + const tensor& running_variances + ); + + void batch_normalize_conv ( + const double eps, + resizable_tensor& dest, + resizable_tensor& means, + resizable_tensor& invstds, + const double averaging_factor, + resizable_tensor& running_means, + resizable_tensor& running_variances, + const tensor& src, + const tensor& gamma, + const tensor& beta + ); + + void batch_normalize_conv_gradient ( + const double eps, + const tensor& gradient_input, + const tensor& means, + const tensor& invstds, + const tensor& src, + const tensor& gamma, + tensor& src_grad, + tensor& gamma_grad, + tensor& beta_grad + ); + + // ----------------------------------------------------------------------------------- + + void threshold ( + tensor& data, + float thresh + ); + + void dot ( + const tensor& a, + const tensor& b, + tensor& result, + size_t idx + ); + + // ----------------------------------------------------------------------------------- + + void softmax ( + tensor& dest, + const tensor& src + ); + + void softmax_gradient ( + tensor& grad, + const tensor& dest, + const tensor& gradient_input + ); + + // ------------------------------------------------------------------------------------ + + void softmax_all ( + tensor& dest, + const tensor& src + ); + + void softmax_all_gradient ( + tensor& grad, + const tensor& dest, + const tensor& gradient_input + ); + + // ------------------------------------------------------------------------------------ + + void sigmoid ( + tensor& dest, + const tensor& src + ); + + void sigmoid_gradient ( + tensor& grad, + const tensor& dest, + const tensor& gradient_input + ); + + // ------------------------------------------------------------------------------------ + + void relu ( + tensor& dest, + const tensor& src + ); + + void relu_gradient ( + tensor& grad, + const tensor& dest, + const tensor& gradient_input + ); + + // ---------------------------------------------------------------------------------------- + + void prelu ( + tensor& dest, + const tensor& src, + const tensor& param + ); + + void prelu_gradient ( + tensor& grad, + const tensor& src, + const tensor& gradient_input, + const tensor& param, + tensor& params_grad + ); + + // ------------------------------------------------------------------------------------ + + void tanh ( + tensor& dest, + const tensor& src + ); + + void tanh_gradient ( + tensor& grad, + const tensor& dest, + const tensor& gradient_input + ); + + // ---------------------------------------------------------------------------------------- + + void resize_bilinear ( + tensor& dest, + long dest_row_stride, + long dest_channel_stride, + const tensor& src, + long src_row_stride, + long src_channel_stride + ); + + void resize_bilinear_gradient ( + tensor& grad, + long grad_row_stride, + long grad_channel_stride, + const tensor& gradient_input, + long gradient_input_row_stride, + long gradient_input_channel_stride + ); + + inline void resize_bilinear ( + tensor& dest, + const tensor& src + ) { resize_bilinear(dest, dest.nc(), dest.nr()*dest.nc(), src, src.nc(), src.nr()*src.nc()); } + + inline void resize_bilinear_gradient ( + tensor& grad, + const tensor& gradient_input + ) { resize_bilinear_gradient(grad, grad.nc(), grad.nr()*grad.nc(), gradient_input, gradient_input.nc(), gradient_input.nr()*gradient_input.nc()); } + + // ----------------------------------------------------------------------------------- + + class pooling + { + public: + + pooling(const pooling&) = delete; + pooling& operator=(const pooling&) = delete; + + pooling ( + ); + + void clear( + ); + + void setup_max_pooling( + int window_height, + int window_width, + int stride_y, + int stride_x, + int padding_y, + int padding_x + ); + + void setup_avg_pooling( + int window_height, + int window_width, + int stride_y, + int stride_x, + int padding_y, + int padding_x + ); + + bool does_max_pooling( + ) const { return do_max_pooling; } + + void operator() ( + resizable_tensor& dest, + const tensor& src + ); + + void get_gradient( + const tensor& gradient_input, + const tensor& dest, + const tensor& src, + tensor& grad + ); + + private: + int window_height; + int window_width; + int stride_y; + int stride_x; + int padding_y; + int padding_x; + bool do_max_pooling; + + }; + + // ----------------------------------------------------------------------------------- + + class tensor_conv + { + public: + tensor_conv(const tensor_conv&) = delete; + tensor_conv& operator=(const tensor_conv&) = delete; + + tensor_conv() {} + + void clear( + ) {} + + void setup( + const tensor& data, /* not used but required for interface */ + const tensor& filters, /* not used but required for interface */ + int stride_y, + int stride_x, + int padding_y, + int padding_x + ) + { + (void)data; /* silence compiler */ + DLIB_CASSERT(stride_y > 0 && stride_x > 0); + DLIB_CASSERT(0 <= padding_y && padding_y < filters.nr()); + DLIB_CASSERT(0 <= padding_x && padding_x < filters.nc()); + last_stride_y = stride_y; + last_stride_x = stride_x; + last_padding_y = padding_y; + last_padding_x = padding_x; + } + + void operator() ( + const bool add_to_output, + resizable_tensor& output, + const tensor& data, + const tensor& filters + ); + + void operator() ( + const bool add_to_output, + tensor& output, + const tensor& data, + const tensor& filters + ); + + void get_gradient_for_data ( + const bool add_to_output, + const tensor& gradient_input, + const tensor& filters, + tensor& data_gradient + ); + + void get_gradient_for_filters ( + const bool add_to_output, + const tensor& gradient_input, + const tensor& data, + tensor& filters_gradient + ); + + private: + + long last_stride_y = 0; + long last_stride_x = 0; + long last_padding_y = 0; + long last_padding_x = 0; + }; + + // ----------------------------------------------------------------------------------- + + void copy_tensor( + bool add_to, + tensor& dest, + size_t dest_k_offset, + const tensor& src, + size_t src_k_offset, + size_t count_k + ); + + // ----------------------------------------------------------------------------------- + + } +} + +#ifdef NO_MAKEFILE +#include "cpu_dlib.cpp" +#endif + +#endif // DLIB_DNN_CPU_H_ + + diff --git a/lib/3rdParty/dlib/include/dlib/cuda/cublas_dlibapi.h b/lib/3rdParty/dlib/include/dlib/cuda/cublas_dlibapi.h new file mode 100644 index 00000000..b46fd25c --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cuda/cublas_dlibapi.h @@ -0,0 +1,50 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DNN_CuBLAS_H_ +#define DLIB_DNN_CuBLAS_H_ + +#ifdef DLIB_USE_CUDA + +#include "tensor.h" +#include "cuda_errors.h" + +namespace dlib +{ + namespace cuda + { + + // ----------------------------------------------------------------------------------- + + void gemm ( + float beta, + tensor& dest, + float alpha, + const tensor& lhs, + bool trans_lhs, + const tensor& rhs, + bool trans_rhs + ); + /*! + requires + - The dimensions of lhs and rhs must be compatible for matrix + multiplication. In particular: + - Let L == trans_lhs ? trans(mat(lhs)) : mat(lhs) + - Let R == trans_rhs ? trans(mat(rhs)) : mat(rhs) + - Let D == mat(dest) + - D.nr() == L.nr() && D.nc() == R.nc() + (i.e. dest must be preallocated and have the correct output dimensions) + - L.nc() == R.nr() + ensures + - performs: dest = alpha*L*R + beta*mat(dest) + !*/ + + // ------------------------------------------------------------------------------------ + + } +} + +#endif // DLIB_USE_CUDA + +#endif // DLIB_DNN_CuBLAS_H_ + + diff --git a/lib/3rdParty/dlib/include/dlib/cuda/cuda_data_ptr.h b/lib/3rdParty/dlib/include/dlib/cuda/cuda_data_ptr.h new file mode 100644 index 00000000..9ac6a190 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cuda/cuda_data_ptr.h @@ -0,0 +1,256 @@ +// Copyright (C) 2017 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DNN_CuDA_DATA_PTR_H_ +#define DLIB_DNN_CuDA_DATA_PTR_H_ + +#ifdef DLIB_USE_CUDA + +#include +#include +#include "../assert.h" + +namespace dlib +{ + namespace cuda + { + + // ------------------------------------------------------------------------------------ + + class cuda_data_void_ptr + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a block of memory on a CUDA device. + !*/ + public: + + cuda_data_void_ptr() = default; + + cuda_data_void_ptr(size_t n); + /*! + ensures + - This object will allocate a device memory buffer of n bytes. + - #size() == n + !*/ + + void* data() { return pdata.get(); } + const void* data() const { return pdata.get(); } + operator void*() { return pdata.get(); } + operator const void*() const { return pdata.get(); } + + void reset() { pdata.reset(); } + + size_t size() const { return num; } + /*! + ensures + - returns the length of this buffer, in bytes. + !*/ + + cuda_data_void_ptr operator+ (size_t offset) const + /*! + requires + - offset < size() + ensures + - returns a pointer that is offset by the given amount. + !*/ + { + DLIB_CASSERT(offset < num); + cuda_data_void_ptr temp; + temp.num = num-offset; + temp.pdata = std::shared_ptr(pdata, ((char*)pdata.get())+offset); + return temp; + } + + private: + + size_t num = 0; + std::shared_ptr pdata; + }; + + inline cuda_data_void_ptr operator+(size_t offset, const cuda_data_void_ptr& rhs) { return rhs+offset; } + + // ------------------------------------------------------------------------------------ + + void memcpy( + void* dest, + const cuda_data_void_ptr& src + ); + /*! + requires + - dest == a pointer to at least src.size() bytes on the host machine. + ensures + - copies the GPU data from src into dest. + - This routine is equivalent to performing: memcpy(dest,src,src.size()) + !*/ + + void memcpy( + void* dest, + const cuda_data_void_ptr& src, + const size_t num + ); + /*! + requires + - dest == a pointer to at least num bytes on the host machine. + - num <= src.size() + ensures + - copies the GPU data from src into dest. Copies only the first num bytes + of src to dest. + !*/ + + // ------------------------------------------------------------------------------------ + + void memcpy( + cuda_data_void_ptr dest, + const void* src + ); + /*! + requires + - dest == a pointer to at least src.size() bytes on the host machine. + ensures + - copies the host data from src to the GPU memory buffer dest. + - This routine is equivalent to performing: memcpy(dest,src,dest.size()) + !*/ + + void memcpy( + cuda_data_void_ptr dest, + const void* src, + const size_t num + ); + /*! + requires + - dest == a pointer to at least num bytes on the host machine. + - num <= dest.size() + ensures + - copies the host data from src to the GPU memory buffer dest. Copies only + the first num bytes of src to dest. + !*/ + + // ------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ + + template + class cuda_data_ptr + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a block of memory on a CUDA device. It is just a type safe + version of cuda_data_void_ptr. + !*/ + + public: + + static_assert(std::is_standard_layout::value, "You can only create basic standard layout types on the GPU"); + + cuda_data_ptr() = default; + cuda_data_ptr(size_t n) : num(n) + /*! + ensures + - This object will allocate a device memory buffer of n T objects. + - #size() == n + !*/ + { + if (n == 0) + return; + + pdata = cuda_data_void_ptr(n*sizeof(T)); + } + + T* data() { return (T*)pdata.data(); } + const T* data() const { return (T*)pdata.data(); } + + operator T*() { return (T*)pdata.data(); } + operator const T*() const { return (T*)pdata.data(); } + + void reset() { pdata.reset(); } + + size_t size() const { return num; } + + + friend void memcpy( + std::vector& dest, + const cuda_data_ptr& src + ) + { + dest.resize(src.size()); + if (src.size() != 0) + memcpy(dest.data(), src.pdata); + } + + friend void memcpy( + cuda_data_ptr& src, + const std::vector& dest + ) + { + if (dest.size() != src.size()) + dest = cuda_data_ptr(src.size()); + + if (src.size() != 0) + memcpy(src.pdata, dest.data()); + } + + private: + + size_t num = 0; + cuda_data_void_ptr pdata; + }; + + // ------------------------------------------------------------------------------------ + + class resizable_cuda_buffer + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a block of memory on a CUDA device that will be automatically + resized if requested size is larger than allocated. + !*/ + public: + cuda_data_void_ptr get(size_t size) + /*! + ensures + - This object will return the buffer of requested size or larger. + - buffer.size() >= size + - Client code should not hold the returned cuda_data_void_ptr for long + durations, but instead should call get() whenever the buffer is + needed. Doing so ensures that multiple buffers are not kept around + in the event of a resize. + !*/ + { + if (buffer.size() < size) + { + buffer.reset(); + buffer = cuda_data_void_ptr(size); + } + return buffer; + } + private: + cuda_data_void_ptr buffer; + }; + + // ---------------------------------------------------------------------------------------- + + std::shared_ptr device_global_buffer( + ); + /*! + ensures + - Returns a pointer to a globally shared CUDA memory buffer on the + currently selected CUDA device. The buffer is also thread local. So + each host thread will get its own buffer. You can use this global buffer + as scratch space for CUDA computations that all take place on the default + stream. Using it in this way ensures that there aren't any race conditions + involving the use of the buffer. + - The global buffer is deallocated once all references to it are + destructed. It will be reallocated as required. So if you want to avoid + these reallocations then hold a copy of the shared_ptr returned by this + function. + !*/ + + // ---------------------------------------------------------------------------------------- + + } +} + +#endif // DLIB_USE_CUDA + +#endif // DLIB_DNN_CuDA_DATA_PTR_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/cuda/cuda_dlib.h b/lib/3rdParty/dlib/include/dlib/cuda/cuda_dlib.h new file mode 100644 index 00000000..d9c27b26 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cuda/cuda_dlib.h @@ -0,0 +1,530 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DNN_CuDA_H_ +#define DLIB_DNN_CuDA_H_ + + +#include "tensor.h" +#include "../geometry/rectangle.h" + +namespace dlib +{ + namespace cuda + { + + // ---------------------------------------------------------------------------------------- + + void set_device ( + int dev + ); + + int get_device ( + ); + + int get_num_devices ( + ); + + std::string get_device_name ( + int device + ); + + void set_current_device_blocking_sync( + ); + + bool can_access_peer (int device_id, int peer_device_id); + bool can_access_peer (const tensor& device, const tensor& peer_device); + + void device_synchronize (int dev); + void device_synchronize (const tensor& dev); + + + class raii_set_device + { + public: + raii_set_device() = delete; + raii_set_device(const raii_set_device&) = delete; + raii_set_device& operator=(const raii_set_device&) = delete; + + raii_set_device(int dev) + { + prev_dev = get_device(); + set_device(dev); + } + + raii_set_device(const tensor& dev) + { + prev_dev = get_device(); + set_device(dev.device_id()); + } + + void operator() (int dev) + { + set_device(dev); + } + + void operator() (const tensor& dev) + { + set_device(dev.device_id()); + } + + ~raii_set_device() noexcept(false) + { + set_device(prev_dev); + } + + private: + int prev_dev; + }; + + +#ifdef DLIB_USE_CUDA + + class enable_peer_access + { + public: + + enable_peer_access() = delete; + enable_peer_access(const enable_peer_access&) = delete; + enable_peer_access& operator=(const enable_peer_access&) = delete; + + enable_peer_access( + int device_id, + int peer_device_id + ); + + enable_peer_access( + const tensor& device, + const tensor& peer_device + ) : enable_peer_access(device.device_id(), peer_device.device_id()) + {} + + ~enable_peer_access() noexcept(false); + + private: + + bool call_disable; + int device_id; + int peer_device_id; + }; + + // ----------------------------------------------------------------------------------- + + void inverse_norms ( + resizable_tensor& invnorms, + const tensor& data, + const double eps + ); + + void dot_prods ( + resizable_tensor& out, + const tensor& lhs, + const tensor& rhs + ); + + void dot_prods ( + bool add_to, + tensor& out, + const tensor& lhs, + const tensor& rhs + ); + + void scale_columns ( + tensor& out, + const tensor& m, + const tensor& v + ); + + void scale_rows ( + tensor& out, + const tensor& m, + const tensor& v + ); + + void scale_rows2 ( + float beta, + tensor& out, + const tensor& m1, + const tensor& m2, + const tensor& v1, + const tensor& v2 + ); + + void exp ( + tensor& dest, + const tensor& src + ); + + void log ( + tensor& dest, + const tensor& src + ); + + void log10 ( + tensor& dest, + const tensor& src + ); + + // ------------------------------------------------------------------------------------ + + void set_tensor ( + tensor& t, + float value + ); + + void scale_tensor ( + tensor& t, + float value + ); + + // ------------------------------------------------------------------------------------ + + void multiply ( + bool add_to, + tensor& dest, + const tensor& src1, + const tensor& src2 + ); + + void multiply_conv ( + bool add_to, + tensor& dest, + const tensor& src1, + const tensor& src2 + ); + + void multiply_zero_padded ( + bool add_to, + tensor& dest, + const tensor& src1, + const tensor& src2 + ); + + void scale_channels ( + bool add_to, + tensor& dest, + const tensor& src, + const tensor& scales + ); + + void add ( + tensor& dest, + const tensor& src1, + const tensor& src2 + ); + + // ----------------------------------------------------------------------------------- + + void affine_transform( + tensor& dest, + const tensor& src, + const float A, + const float B + ); + + void affine_transform( + tensor& dest, + const tensor& src, + const float A + ); + + void affine_transform( + tensor& dest, + const tensor& src1, + const tensor& src2, + const float A, + const float B, + const float C + ); + + void affine_transform( + tensor& dest, + const tensor& src1, + const tensor& src2, + const float A, + const float B + ); + + void affine_transform( + tensor& dest, + const tensor& src1, + const tensor& src2, + const tensor& src3, + const float A, + const float B, + const float C, + const float D + ); + + void affine_transform_range( + size_t begin, + size_t end, + tensor& dest, + const tensor& src1, + const tensor& src2, + const tensor& src3, + const float A, + const float B, + const float C + ); + + void affine_transform( + const rectangle& rect, + tensor& dest, + const tensor& src1, + const tensor& src2, + const tensor& src3, + float A, + float B, + float C + ); + + // Note that this function isn't in the tt:: namespace because add_scaled() is + // called by cuda::add() so we don't need a tt:: version of add_scaled(). + void add_scaled( + tensor& dest, + const float scale, + const tensor& src + ); + + void add_cv_to_all_columns( + float beta, + tensor& dest, + float alpha, + const tensor& src + ); + + // ----------------------------------------------------------------------------------- + + void affine_transform( + tensor& dest, + const tensor& src, + const tensor& A, + const tensor& B + ); + + // ----------------------------------------------------------------------------------- + + void affine_transform_conv( + tensor& dest, + const tensor& src, + const tensor& A, + const tensor& B + ); + + // ---------------------------------------------------------------------------------------- + + void compute_adam_update ( + size_t begin, + size_t end, + tensor& s, + tensor& m, + tensor& v, + const float t, + const float learning_rate, + const float weight_decay, + const float momentum1, + const float momentum2, + const tensor& params, + const tensor& params_grad + ); + + // ----------------------------------------------------------------------------------- + + void assign_bias_gradient ( + tensor& grad, + const tensor& gradient_input + ); + + // ----------------------------------------------------------------------------------- + + void threshold ( + tensor& data, + float thresh + ); + + // ---------------------------------------------------------------------------------------- + + void dot ( + const tensor& a, + const tensor& b, + tensor& result, + size_t idx + ); + + // ---------------------------------------------------------------------------------------- + + void prelu ( + tensor& dest, + const tensor& src, + const tensor& param + ); + + void prelu_gradient ( + tensor& grad, + const tensor& src, + const tensor& gradient_input, + const tensor& param, + tensor& params_grad + ); + + + // ---------------------------------------------------------------------------------------- + + void resize_bilinear ( + tensor& dest, + long dest_row_stride, + long dest_channel_stride, + const tensor& src, + long src_row_stride, + long src_channel_stride + ); + + void resize_bilinear_gradient ( + tensor& grad, + long grad_row_stride, + long grad_channel_stride, + const tensor& gradient_input, + long gradient_input_row_stride, + long gradient_input_channel_stride + ); + + inline void resize_bilinear ( + tensor& dest, + const tensor& src + ) { resize_bilinear(dest, dest.nc(), dest.nr()*dest.nc(), src, src.nc(), src.nr()*src.nc()); } + + inline void resize_bilinear_gradient ( + tensor& grad, + const tensor& gradient_input + ) { resize_bilinear_gradient(grad, grad.nc(), grad.nr()*grad.nc(), gradient_input, gradient_input.nc(), gradient_input.nr()*gradient_input.nc()); } + + // ---------------------------------------------------------------------------------------- + + void copy_tensor( + bool add_to, + tensor& dest, + size_t dest_k_offset, + const tensor& src, + size_t src_k_offset, + size_t count_k + ); + + + // ---------------------------------------------------------------------------------------- + + class compute_loss_multiclass_log_per_pixel + { + /*! + The point of this class is to compute the loss computed by + loss_multiclass_log_per_pixel, but to do so with CUDA. + !*/ + public: + + compute_loss_multiclass_log_per_pixel( + ) + { + work = device_global_buffer(); + } + + template < + typename const_label_iterator + > + void operator() ( + const_label_iterator truth, + const tensor& subnetwork_output, + tensor& gradient, + double& loss + ) const + { + const size_t bytes_per_plane = subnetwork_output.nr()*subnetwork_output.nc()*sizeof(uint16_t); + // Allocate a cuda buffer to store all the truth images and also one float + // for the scalar loss output. + cuda_data_void_ptr buf = work->get(subnetwork_output.num_samples()*bytes_per_plane + sizeof(float)); + + cuda_data_void_ptr loss_buf = buf; + buf = buf+sizeof(float); + + + // copy the truth data into a cuda buffer. + for (long i = 0; i < subnetwork_output.num_samples(); ++i, ++truth) + { + const matrix& t = *truth; + DLIB_ASSERT(t.nr() == subnetwork_output.nr()); + DLIB_ASSERT(t.nc() == subnetwork_output.nc()); + memcpy(buf + i*bytes_per_plane, &t(0,0), bytes_per_plane); + } + + do_work(static_cast(loss_buf.data()), static_cast(buf.data()), subnetwork_output, gradient, loss); + } + + private: + + static void do_work( + float* loss_cuda_work_buffer, + const uint16_t* truth_buffer, + const tensor& subnetwork_output, + tensor& gradient, + double& loss + ); + + std::shared_ptr work; + }; + + // ------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ + +#else // if DLIB_USE_CUDA NOT DEFINED + + inline void set_device ( + int id + ) + { + DLIB_CASSERT(id == 0, "dlib::cuda::set_device(id) called with an invalid device id."); + } + + inline int get_device ( + ){ return 0; } + + inline int get_num_devices ( + ) { return 1; } + + inline std::string get_device_name ( + int device + ) + { + DLIB_CASSERT(device == 0, "dlib::cuda::set_device(id) called with an invalid device id."); + return "CUDA_DISABLED"; + } + + inline void set_current_device_blocking_sync( + ) {} + + + inline bool can_access_peer (int , int ) + { return false; } + inline bool can_access_peer (const tensor& , const tensor& ) + { return false; } + + inline void device_synchronize (int ){} + inline void device_synchronize (const tensor& ){} + + class enable_peer_access + { + public: + enable_peer_access() = delete; + enable_peer_access(const enable_peer_access&) = delete; + enable_peer_access& operator=(const enable_peer_access&) = delete; + enable_peer_access( int, int ){} + enable_peer_access( const tensor&, const tensor& ) {} + }; + +#endif // DLIB_USE_CUDA + + } +} + + +#endif // DLIB_DNN_CuDA_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/cuda/cuda_errors.h b/lib/3rdParty/dlib/include/dlib/cuda/cuda_errors.h new file mode 100644 index 00000000..fd28693c --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cuda/cuda_errors.h @@ -0,0 +1,70 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CUDA_ERRORs_H_ +#define DLIB_CUDA_ERRORs_H_ + + +#include "../error.h" + +namespace dlib +{ + struct cuda_error : public error + { + /*! + WHAT THIS OBJECT REPRESENTS + This is the exception thrown if any calls to the NVIDIA CUDA runtime + returns an error. + !*/ + + cuda_error(const std::string& message): error(message) {} + }; + + + struct cudnn_error : public cuda_error + { + /*! + WHAT THIS OBJECT REPRESENTS + This is the exception thrown if any calls to the NVIDIA cuDNN library + returns an error. + !*/ + + cudnn_error(const std::string& message): cuda_error(message) {} + }; + + struct curand_error : public cuda_error + { + /*! + WHAT THIS OBJECT REPRESENTS + This is the exception thrown if any calls to the NVIDIA cuRAND library + returns an error. + !*/ + + curand_error(const std::string& message): cuda_error(message) {} + }; + + struct cublas_error : public cuda_error + { + /*! + WHAT THIS OBJECT REPRESENTS + This is the exception thrown if any calls to the NVIDIA cuBLAS library + returns an error. + !*/ + + cublas_error(const std::string& message): cuda_error(message) {} + }; + + struct cusolver_error : public cuda_error + { + /*! + WHAT THIS OBJECT REPRESENTS + This is the exception thrown if any calls to the NVIDIA cuSolver library + returns an error. + !*/ + + cusolver_error(const std::string& message): cuda_error(message) {} + }; +} + + +#endif // DLIB_CUDA_ERRORs_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/cuda/cuda_utils.h b/lib/3rdParty/dlib/include/dlib/cuda/cuda_utils.h new file mode 100644 index 00000000..673a4e8a --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cuda/cuda_utils.h @@ -0,0 +1,413 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CUDA_UtILS_H_ +#define DLIB_CUDA_UtILS_H_ + +#ifndef DLIB_USE_CUDA +#error "This file shouldn't be #included unless DLIB_USE_CUDA is #defined" +#endif + +#include "cuda_errors.h" +#include "../algs.h" +#include + +#include +#include +#include +#include +#include +#include + + +// Check the return value of a call to the CUDA runtime for an error condition. +#define CHECK_CUDA(call) \ +do{ \ + const cudaError_t error = call; \ + if (error != cudaSuccess) \ + { \ + std::ostringstream sout; \ + sout << "Error while calling " << #call << " in file " << __FILE__ << ":" << __LINE__ << ". ";\ + sout << "code: " << error << ", reason: " << cudaGetErrorString(error);\ + throw dlib::cuda_error(sout.str()); \ + } \ +}while(false) + +// ---------------------------------------------------------------------------------------- + +#ifdef __CUDACC__ + +namespace dlib +{ + namespace cuda + { + + // ------------------------------------------------------------------------------------ + + __inline__ __device__ size_t pack_idx ( + size_t dim_size3, + size_t dim_size2, + size_t dim_size1, + size_t idx4, + size_t idx3, + size_t idx2, + size_t idx1 + ) + /*! + ensures + - Converts a 4D array index into a 1D index assuming row major layout. To + understand precisely what this function does, imagine we had an array + declared like this: + int ARRAY[anything][dim_size3][dim_size2][dim_size1]; + Then we could index it like this: + ARRAY[idx4][idx3][idx2][idx1] + or equivalently like this: + ((int*)ARRAY)[pack_idx(dim_size3,dim_size2,dim_size1, idx4,idx3,idx2,idx1)] + !*/ + { + return ((idx4*dim_size3 + idx3)*dim_size2 + idx2)*dim_size1 + idx1; + } + + __inline__ __device__ void unpack_idx ( + size_t idx, + size_t dim_size3, + size_t dim_size2, + size_t dim_size1, + size_t& idx4, + size_t& idx3, + size_t& idx2, + size_t& idx1 + ) + /*! + ensures + - This function computes the inverse of pack_idx(). Therefore, + if PACKED == pack_idx(dim_size3,dim_size2,dim_size1, idx4,idx3,idx2,idx1) + then unpack_idx(PACKED,dim_size3,dim_size2,dim_size1, IDX4,IDX3,IDX2,IDX1) + results in: + - IDX1 == idx1 + - IDX2 == idx2 + - IDX3 == idx3 + - IDX4 == idx4 + !*/ + { + idx1 = idx%dim_size1; + + idx /= dim_size1; + idx2 = idx%dim_size2; + + idx /= dim_size2; + idx3 = idx%dim_size3; + + idx /= dim_size3; + idx4 = idx; + } + + // ------------------------------------------------------------------------------------ + + // This function is from the article: + // http://devblogs.nvidia.com/parallelforall/faster-parallel-reductions-kepler/ + __inline__ __device__ float warp_reduce_sum(float val) + { + for (int offset = warpSize/2; offset > 0; offset /= 2) +#if CUDART_VERSION >= 9000 + val += __shfl_down_sync(0xFFFFFFFF,val, offset); +#else + val += __shfl_down(val, offset); +#endif + return val; + } + + __inline__ __device__ bool is_first_thread_in_warp() + { + return (threadIdx.x & (warpSize - 1)) == 0; + } + + __inline__ __device__ void warp_reduce_atomic_add( + float& out, + float val + ) + /*! + ensures + - Atomically adds all the val variables in the current warp to out. + See this page for an extended discussion: + http://devblogs.nvidia.com/parallelforall/faster-parallel-reductions-kepler/ + !*/ + { + val = warp_reduce_sum(val); + if (is_first_thread_in_warp()) + atomicAdd(&out, val); + } + + // ------------------------------------------------------------------------------------ + + struct max_jobs + { + max_jobs(int x) : num_x(x) {} + max_jobs(int x, int y) : num_x(x), num_y(y) {} + int num_x; + int num_y = 1; + }; + + template + void launch_kernel ( + Kernel K, + T ...args + ) + /*! + ensures + - launches the given kernel K(args...). The point of this function is to + automatically set the kernel launch parameters to something reasonable + based on the properties of the kernel and the current GPU card. + !*/ + { + int num_blocks, num_threads; + CHECK_CUDA(cudaOccupancyMaxPotentialBlockSize(&num_blocks,&num_threads,K)); + K<<>>(args...); + } + + template + void launch_kernel ( + Kernel K, + max_jobs m, + T ...args + ) + /*! + ensures + - This function is just like launch_kernel(K,args...) except that you can + additionally supply a max_jobs number that tells it how many possible + total threads could be used. This is useful when launching potentially + small jobs that might not need the number of threads suggested by + launch_kernel(). + !*/ + { + if (m.num_x == 0 || m.num_y == 0) + return; + int num_blocks, num_threads; + CHECK_CUDA(cudaOccupancyMaxPotentialBlockSize(&num_blocks,&num_threads,K)); + // Check if the job is really small and we don't really need to launch a kernel + // with this many blocks and threads. + if (num_blocks*num_threads > m.num_x*m.num_y) + num_blocks = (m.num_x*m.num_y+num_threads-1)/num_threads; + + if (m.num_y == 1) + { + K<<>>(args...); + } + else + { + /* + In general, the reason m.num_y!=1 (i.e. the reason you are in this + code path) is because we are using nested grid-stride loops. There are + two important things to note about what we are doing here. To + illustrate them we will talk about this little CUDA code snippet: + + // initialize out before we begin. + for (auto i : grid_stride_range_y(0, nr)) + for (auto j : grid_stride_range(0, 1)) + out[i] = 0; + + __syncthreads(); // synchronize threads in block + + // loop over some 2D thing and sum and store things into out. + for (auto i : grid_stride_range_y(0, nr)) + { + float temp = 0; + for (auto j : grid_stride_range(0, nc)) + temp += whatever[i*nc+j]; + + // store the sum into out[i] + warp_reduce_atomic_add(out[i], temp); + } + + First, we make sure the number of x threads is a multiple of 32 so that + you can use warp_reduce_atomic_add() inside the y loop. + + Second, we put the x block size to 1 so inter-block synchronization is + easier. For example, if the number of x blocks wasn't 1 the above code + would have a race condition in it. This is because the execution of + out[i]=0 would be done by blocks with blockIdx.x==0, but then in the + second set of loops, *all* the x blocks use out[i]. Since + __syncthreads() doesn't do any synchronization between blocks some of + the blocks might begin before the out[i]=0 statements finished and that + would be super bad. + */ + + // Try and make sure that the ratio of x to y threads is reasonable based + // on the respective size of our loops. + int x_threads = 32; + int y_threads = num_threads/32; + const int ratio = static_cast(std::round(put_in_range(1, y_threads, m.num_x/(double)m.num_y))); + x_threads *= ratio; + y_threads /= ratio; + + dim3 blocks(1,num_blocks); + dim3 threads(x_threads,y_threads); + K<<>>(args...); + } + } + + // ------------------------------------------------------------------------------------ + + class grid_stride_range + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a tool for making a for loop that loops over an entire block of + memory inside a kernel, but doing so in a way that parallelizes + appropriately across all the threads in a kernel launch. For example, + the following kernel would add the vector a to the vector b and store + the output in out (assuming all vectors are of dimension n): + __global__ void add_arrays( + const float* a, + const float* b, + float* out, + size_t n + ) + { + for (auto i : grid_stride_range(0, n)) + { + out[i] = a[i]+b[i]; + } + } + !*/ + + public: + __device__ grid_stride_range( + size_t ibegin_, + size_t iend_ + ) : + ibegin(ibegin_), + iend(iend_) + {} + + class iterator + { + public: + __device__ iterator() {} + __device__ iterator(size_t pos_) : pos(pos_) {} + + __device__ size_t operator*() const + { + return pos; + } + + __device__ iterator& operator++() + { + pos += gridDim.x * blockDim.x; + return *this; + } + + __device__ bool operator!=(const iterator& item) const + { return pos < item.pos; } + + private: + size_t pos; + }; + + __device__ iterator begin() const + { + return iterator(ibegin+blockDim.x * blockIdx.x + threadIdx.x); + } + __device__ iterator end() const + { + return iterator(iend); + } + private: + + size_t ibegin; + size_t iend; + }; + + // ------------------------------------------------------------------------------------ + + class grid_stride_range_y + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is just like grid_stride_range except that it looks at + CUDA's y thread index (e.g. threadIdx.y) instead of the x index. + Therefore, if you launch a cuda kernel with a statement like: + dim3 blocks(1,10); + dim3 threads(32,32); // You need to have x and y not equal to 1 to get parallelism over both loops. + add_arrays<<>>(a,b,out,nr,nc); + You can perform a nested 2D parallel for loop rather than doing just a + 1D for loop. + + So the code in the kernel would look like this if you wanted to add two + 2D matrices: + __global__ void add_arrays( + const float* a, + const float* b, + float* out, + size_t nr, + size_t nc + ) + { + for (auto r : grid_stride_range_y(0, nr)) + { + for (auto c : grid_stride_range(0, nc)) + { + auto i = r*nc+c; + out[i] = a[i]+b[i]; + } + } + } + !*/ + + public: + __device__ grid_stride_range_y( + size_t ibegin_, + size_t iend_ + ) : + ibegin(ibegin_), + iend(iend_) + {} + + class iterator + { + public: + __device__ iterator() {} + __device__ iterator(size_t pos_) : pos(pos_) {} + + __device__ size_t operator*() const + { + return pos; + } + + __device__ iterator& operator++() + { + pos += gridDim.y * blockDim.y; + return *this; + } + + __device__ bool operator!=(const iterator& item) const + { return pos < item.pos; } + + private: + size_t pos; + }; + + __device__ iterator begin() const + { + return iterator(ibegin+blockDim.y * blockIdx.y + threadIdx.y); + } + __device__ iterator end() const + { + return iterator(iend); + } + private: + + size_t ibegin; + size_t iend; + }; + + // ------------------------------------------------------------------------------------ + + } +} + +#endif // __CUDACC__ + +// ---------------------------------------------------------------------------------------- + +#endif // DLIB_CUDA_UtILS_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/cuda/cudnn_dlibapi.h b/lib/3rdParty/dlib/include/dlib/cuda/cudnn_dlibapi.h new file mode 100644 index 00000000..e9ffe5f6 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cuda/cudnn_dlibapi.h @@ -0,0 +1,518 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DNN_CuDNN_H_ +#define DLIB_DNN_CuDNN_H_ + +#ifdef DLIB_USE_CUDA + +#include "cuda_errors.h" +#include +#include "cuda_data_ptr.h" + +namespace dlib +{ + class tensor; + class resizable_tensor; + + namespace cuda + { + + // ----------------------------------------------------------------------------------- + + class tensor_descriptor + { + /*! + Each tensor object will carry a tensor_descriptor in it when compiled with + CUDA. + !*/ + + public: + // not copyable + tensor_descriptor(const tensor_descriptor&) = delete; + tensor_descriptor& operator=(const tensor_descriptor&) = delete; + // but is movable + tensor_descriptor(tensor_descriptor&& item) : tensor_descriptor() { swap(item); } + tensor_descriptor& operator=(tensor_descriptor&& item) { swap(item); return *this; } + + tensor_descriptor(); + ~tensor_descriptor(); + + void set_size( + int n, + int k, + int nr, + int nc + ); + /*! + ensures + - if any of the arguments are 0 then they are all set to 0 in the tensor. + !*/ + + void get_size ( + int& n, + int& k, + int& nr, + int& nc + ) const; + + const void* get_handle ( + ) const { return handle; } + + private: + + void swap(tensor_descriptor& item) { std::swap(handle, item.handle); } + + void* handle; + }; + + // ------------------------------------------------------------------------------------ + + void add( + float beta, + tensor& dest, + float alpha, + const tensor& src + ); + /*! + requires + - One of the following is true: + - have_same_dimensions(src, dest) + - src.num_samples()==1 && src.k()==dest.k() && src.nr()==1 && src.nc()==1 + - src.num_samples()==1 && src.k()==dest.k() && src.nr()==dest.nr() && src.nc()==dest.nc() + - src.num_samples()==1 && src.k()==1 && src.nr()==dest.nr() && src.nc()==dest.nc() + - is_same_object(src,dest) == false + ensures + - performs: dest = beta*dest + alpha*src + However, how the addition happens depends on the dimensions of src. In + particular, this function adds the scaled values of one src tensor to + dest. Each dimension of the src tensor must match the corresponding + dimension of the dest tensor or must be equal to 1. In the latter case, + the same value from the src tensor, for those dimensions, will be used to + add into the dest tensor. + !*/ + + // ------------------------------------------------------------------------------------ + + void assign_conv_bias_gradient ( + tensor& grad, + const tensor& gradient_input + ); + /*! + requires + - grad.num_samples() == 1 + - grad.k() >= 1 + - grad.nr() == 1 + - grad.nc() == 1 + - gradient_input.k() == grad.k() + - gradient_input.size() > 0 + - is_same_object(grad,gradient_input) == false + ensures + - let BIAS be a tensor with all dimensions equal to 1 except for k which is >= 1. + - let OUT be the output of add(1,OUT,1,BIAS) + - let f(gradient_input,BIAS) == dot(gradient_input,OUT) + - Then this function computes the gradient of f() with respect to BIAS and + assigns it to grad. + !*/ + + // ------------------------------------------------------------------------------------ + + void batch_normalize_inference ( + const double eps, + resizable_tensor& dest, + const tensor& src, + const tensor& gamma, + const tensor& beta, + const tensor& running_means, + const tensor& running_variances + ); + + void batch_normalize ( + const double eps, + resizable_tensor& dest, + resizable_tensor& means, + resizable_tensor& invstds, + const double averaging_factor, + resizable_tensor& running_means, + resizable_tensor& running_variances, + const tensor& src, + const tensor& gamma, + const tensor& beta + ); + + void batch_normalize_gradient( + const double eps, + const tensor& gradient_input, + const tensor& means, + const tensor& invstds, + const tensor& src, + const tensor& gamma, + tensor& src_grad, + tensor& gamma_grad, + tensor& beta_grad + ); + + // ------------------------------------------------------------------------------------ + + void batch_normalize_conv_inference ( + const double eps, + resizable_tensor& dest, + const tensor& src, + const tensor& gamma, + const tensor& beta, + const tensor& running_means, + const tensor& running_variances + ); + + void batch_normalize_conv ( + const double eps, + resizable_tensor& dest, + resizable_tensor& means, + resizable_tensor& invstds, + const double averaging_factor, + resizable_tensor& running_means, + resizable_tensor& running_variances, + const tensor& src, + const tensor& gamma, + const tensor& beta + ); + + void batch_normalize_conv_gradient( + const double eps, + const tensor& gradient_input, + const tensor& means, + const tensor& invstds, + const tensor& src, + const tensor& gamma, + tensor& src_grad, + tensor& gamma_grad, + tensor& beta_grad + ); + + // ------------------------------------------------------------------------------------ + + class tensor_conv + { + public: + tensor_conv(const tensor_conv&) = delete; + tensor_conv& operator=(const tensor_conv&) = delete; + + tensor_conv(); + + void clear( + ); + + ~tensor_conv ( + ); + + void operator() ( + const bool add_to_output, + tensor& output, + const tensor& data, + const tensor& filters + ); + + void operator() ( + const bool add_to_output, + resizable_tensor& output, + const tensor& data, + const tensor& filters + ); + + void get_gradient_for_data ( + const bool add_to_output, + const tensor& gradient_input, + const tensor& filters, + tensor& data_gradient + ); + + void get_gradient_for_filters ( + const bool add_to_output, + const tensor& gradient_input, + const tensor& data, + tensor& filters_gradient + ); + + void setup( + const tensor& data, + const tensor& filters, + int stride_y, + int stride_x, + int padding_y, + int padding_x + ); + + private: + + // These variables record the type of data given to the last call to setup(). + int stride_y; + int stride_x; + int padding_y; + int padding_x; + long data_num_samples, data_k, data_nr, data_nc; + long filters_num_samples, filters_k, filters_nr, filters_nc; + + + void* filter_handle; + void* conv_handle; + + // dimensions of the output tensor from operator() + int out_num_samples; + int out_k; + int out_nr; + int out_nc; + + int forward_algo; + int backward_data_algo; + int backward_filters_algo; + + size_t forward_workspace_size_in_bytes; + size_t backward_data_workspace_size_in_bytes; + size_t backward_filters_workspace_size_in_bytes; + std::shared_ptr workspace; + cuda_data_void_ptr forward_workspace; + cuda_data_void_ptr backward_data_workspace; + cuda_data_void_ptr backward_filters_workspace; + }; + + // ------------------------------------------------------------------------------------ + + class pooling + { + public: + + pooling(const pooling&) = delete; + pooling& operator=(const pooling&) = delete; + + pooling ( + ); + + ~pooling( + ); + + void clear( + ); + + void setup_max_pooling( + int window_height, + int window_width, + int stride_y, + int stride_x, + int padding_y, + int padding_x + ); + + void setup_avg_pooling( + int window_height, + int window_width, + int stride_y, + int stride_x, + int padding_y, + int padding_x + ); + + bool does_max_pooling( + ) const { return do_max_pooling; } + + void operator() ( + resizable_tensor& dest, + const tensor& src + ); + + void get_gradient( + const tensor& gradient_input, + const tensor& dest, + const tensor& src, + tensor& grad + ); + + private: + + void setup( + int window_height, + int window_width, + int stride_y, + int stride_x, + int padding_y, + int padding_x, + int pooling_mode + ); + + void* handle; + int window_height; + int window_width; + int stride_y; + int stride_x; + int padding_y; + int padding_x; + bool do_max_pooling; + }; + + // ------------------------------------------------------------------------------------ + + void softmax ( + tensor& dest, + const tensor& src + ); + /*! + requires + - have_same_dimensions(dest, src) == true + ensures + - Note that the softmax function is a vector valued function: + s(x) == exp(x)/sum(exp(x)) + - Computes the softmax function on src and writes the results to dest. The + softmax is computed per spatial location across the different channels at + each location. That is, softmax() outputs a new tensor, #dest, where + each of the spatial locations in dest (i.e. image idx, row idx, and + column idx) contains the output of s() evaluated over the channel values + at each location. + - This function supports in-place operation, i.e. having + is_same_object(dest, src)==true + !*/ + + void softmax_gradient ( + tensor& grad, + const tensor& dest, + const tensor& gradient_input + ); + /*! + requires + - have_same_dimensions(dest,gradient_input) == true + - have_same_dimensions(dest,grad) == true + - is_same_object(grad, dest)==false + ensures + - We interpret dest as the output of softmax(dest,SRC) for some SRC tensor. + Then let f(SRC) == dot(gradient_input,dest) Then this function computes + the gradient of f() with respect to SRC and assigns it to grad. + - This function supports in-place operation, i.e. having + is_same_object(grad, gradient_input)==true + !*/ + + // ------------------------------------------------------------------------------------ + + void softmax_all ( + tensor& dest, + const tensor& src + ); + + void softmax_all_gradient ( + tensor& grad, + const tensor& dest, + const tensor& gradient_input + ); + + // ------------------------------------------------------------------------------------ + + void sigmoid ( + tensor& dest, + const tensor& src + ); + /*! + requires + - have_same_dimensions(dest, src) == true + ensures + - for all valid i: + - #dest.host()[i] == 1/(1+std::exp(-src.host()[i])) + - This function supports in-place operation, i.e. having + is_same_object(dest, src)==true + !*/ + + void sigmoid_gradient ( + tensor& grad, + const tensor& dest, + const tensor& gradient_input + ); + /*! + requires + - have_same_dimensions(dest,gradient_input) == true + - have_same_dimensions(dest,grad) == true + - is_same_object(grad,dest) == false + ensures + - Recalling that dest is the output of sigmoid(dest,SRC) for some SRC tensor, + let f(SRC) == dot(gradient_input,dest) + - Then this function computes the gradient of f() with respect to SRC and + assigns it to grad. + - This function supports in-place operation, i.e. having + is_same_object(grad, gradient_input)==true + !*/ + + // ------------------------------------------------------------------------------------ + + void relu ( + tensor& dest, + const tensor& src + ); + /*! + requires + - have_same_dimensions(dest, src) == true + ensures + - for all valid i: + - #dest.host()[i] == std::max(0,src.host()[i]) + - This function supports in-place operation, i.e. having + is_same_object(dest, src)==true + !*/ + + void relu_gradient ( + tensor& grad, + const tensor& dest, + const tensor& gradient_input + ); + /*! + requires + - have_same_dimensions(dest,gradient_input) == true + - have_same_dimensions(dest,grad) == true + - is_same_object(grad,dest) == false + ensures + - Recalling that dest is the output of relu(dest,SRC) for some SRC tensor, + let f(SRC) == dot(gradient_input,dest) + - Then this function computes the gradient of f() with respect to SRC and + assigns it to grad. + - This function supports in-place operation, i.e. having + is_same_object(grad, gradient_input)==true + !*/ + + // ------------------------------------------------------------------------------------ + + void tanh ( + tensor& dest, + const tensor& src + ); + /*! + requires + - have_same_dimensions(dest, src) == true + ensures + - for all valid i: + - #dest.host()[i] == std::tanh(src.host()[i]) + - This function supports in-place operation, i.e. having + is_same_object(dest, src)==true + !*/ + + void tanh_gradient ( + tensor& grad, + const tensor& dest, + const tensor& gradient_input + ); + /*! + requires + - have_same_dimensions(dest,gradient_input) == true + - have_same_dimensions(dest,grad) == true + - is_same_object(grad,dest) == false + ensures + - Recalling that dest is the output of tanh(dest,SRC) for some SRC tensor, + let f(SRC) == dot(gradient_input,dest) + - Then this function computes the gradient of f() with respect to SRC and + assigns it to grad. + - This function supports in-place operation, i.e. having + is_same_object(grad, gradient_input)==true + !*/ + + + + // ------------------------------------------------------------------------------------ + + } +} + +#endif // DLIB_USE_CUDA + +#endif // DLIB_DNN_CuDNN_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/cuda/curand_dlibapi.h b/lib/3rdParty/dlib/include/dlib/cuda/curand_dlibapi.h new file mode 100644 index 00000000..cd51fece --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cuda/curand_dlibapi.h @@ -0,0 +1,75 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DNN_CuRAND_H_ +#define DLIB_DNN_CuRAND_H_ + +#ifdef DLIB_USE_CUDA + +#include "tensor.h" +#include "cuda_errors.h" +#include "cuda_data_ptr.h" + +namespace dlib +{ + namespace cuda + { + + // ----------------------------------------------------------------------------------- + + class curand_generator + { + public: + // not copyable + curand_generator(const curand_generator&) = delete; + curand_generator& operator=(const curand_generator&) = delete; + + curand_generator() : curand_generator(0) {} + curand_generator(unsigned long long seed); + ~curand_generator(); + + void fill ( + cuda_data_ptr& data + ); + /*! + ensures + - Fills data with random 32-bit unsigned integers. + !*/ + + void fill_gaussian ( + tensor& data, + float mean = 0, + float stddev = 1 + ); + /*! + requires + - data.size()%2 == 0 + - stddev >= 0 + ensures + - Fills data with random numbers drawn from a Gaussian distribution + with the given mean and standard deviation. + !*/ + + void fill_uniform ( + tensor& data + ); + /*! + ensures + - Fills data with uniform random numbers in the range (0.0, 1.0]. + !*/ + + private: + + void* handle; + }; + + // ----------------------------------------------------------------------------------- + + } +} + +#endif // DLIB_USE_CUDA + +#endif // DLIB_DNN_CuRAND_H_ + + + diff --git a/lib/3rdParty/dlib/include/dlib/cuda/cusolver_dlibapi.h b/lib/3rdParty/dlib/include/dlib/cuda/cusolver_dlibapi.h new file mode 100644 index 00000000..e5c77c15 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cuda/cusolver_dlibapi.h @@ -0,0 +1,75 @@ +// Copyright (C) 2017 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DNN_CuSOLVER_H_ +#define DLIB_DNN_CuSOLVER_H_ + +#ifdef DLIB_USE_CUDA + +#include "tensor.h" +#include "cuda_errors.h" +#include "cuda_data_ptr.h" +#include "../noncopyable.h" + +namespace dlib +{ + namespace cuda + { + + // ----------------------------------------------------------------------------------- + + class inv : noncopyable + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a functor for doing matrix inversion on the GPU. The only + reason it's an object is to avoid the reallocation of some GPU memory + blocks if you want to do a bunch of matrix inversions in a row. + !*/ + + public: + + inv() = default; + ~inv(); + + void operator() ( + const tensor& m, + resizable_tensor& out + ); + /*! + requires + - m.size() == m.num_samples()*m.num_samples() + (i.e. mat(m) must be a square matrix) + ensures + - out == inv(mat(m)); + !*/ + + int get_last_status( + ); + /*! + ensures + - returns 0 if the last matrix inversion was successful and != 0 + otherwise. + !*/ + + private: + + void sync_if_needed(); + + bool did_work_lately = false; + resizable_tensor m; + cuda_data_ptr workspace; + cuda_data_ptr Ipiv; + cuda_data_ptr info; + }; + + // ------------------------------------------------------------------------------------ + + } +} + +#endif // DLIB_USE_CUDA + +#endif // DLIB_DNN_CuSOLVER_H_ + + + diff --git a/lib/3rdParty/dlib/include/dlib/cuda/gpu_data.h b/lib/3rdParty/dlib/include/dlib/cuda/gpu_data.h new file mode 100644 index 00000000..022a05f7 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cuda/gpu_data.h @@ -0,0 +1,266 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_GPU_DaTA_H_ +#define DLIB_GPU_DaTA_H_ + +#include "gpu_data_abstract.h" +#include +#include +#include "cuda_errors.h" +#include "../serialize.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class gpu_data + { + /*! + CONVENTION + - if (size() != 0) then + - data_host == a pointer to size() floats in CPU memory. + - if (data_device) then + - data_device == a pointer to size() floats in device memory. + + - if (there might be an active async transfer from host to device) then + - have_active_transfer == true + + - We use the host_current and device_current bools to keep track of which + copy of the data (or both) are most current. e.g. if the CPU has + modified the data and it hasn't been copied to the device yet then + host_current==true and device_current==false. + + Similarly, we use device_in_use==true to indicate that device() has been + called and no operation to wait for all CUDA kernel completion has been + executed. So if device_in_use==true then there might be a CUDA kernel + executing that is using the device memory block contained in this object. + + !*/ + public: + + gpu_data( + ) : data_size(0), host_current(true), device_current(true),have_active_transfer(false),device_in_use(false), the_device_id(0) + { + } + + // Not copyable + gpu_data(const gpu_data&) = delete; + gpu_data& operator=(const gpu_data&) = delete; + + // but is movable + gpu_data(gpu_data&& item) : gpu_data() { swap(item); } + gpu_data& operator=(gpu_data&& item) { swap(item); return *this; } + + int device_id() const { return the_device_id; } + +#ifdef DLIB_USE_CUDA + void async_copy_to_device() const; + void set_size(size_t new_size); +#else + // Note that calls to host() or device() will block until any async transfers are complete. + void async_copy_to_device() const{} + + void set_size(size_t new_size) + { + if (new_size == 0) + { + data_size = 0; + host_current = true; + device_current = true; + device_in_use = false; + data_host.reset(); + data_device.reset(); + } + else if (new_size != data_size) + { + data_size = new_size; + host_current = true; + device_current = true; + device_in_use = false; + data_host.reset(new float[new_size], std::default_delete()); + data_device.reset(); + } + } +#endif + + const float* host() const + { + copy_to_host(); + return data_host.get(); + } + + float* host() + { + copy_to_host(); + device_current = false; + return data_host.get(); + } + + float* host_write_only() + { + host_current = true; + device_current = false; + return data_host.get(); + } + + const float* device() const + { +#ifndef DLIB_USE_CUDA + DLIB_CASSERT(false, "CUDA NOT ENABLED"); +#endif + copy_to_device(); + device_in_use = true; + return data_device.get(); + } + + float* device() + { +#ifndef DLIB_USE_CUDA + DLIB_CASSERT(false, "CUDA NOT ENABLED"); +#endif + copy_to_device(); + host_current = false; + device_in_use = true; + return data_device.get(); + } + + float* device_write_only() + { +#ifndef DLIB_USE_CUDA + DLIB_CASSERT(false, "CUDA NOT ENABLED"); +#endif + wait_for_transfer_to_finish(); + host_current = false; + device_current = true; + device_in_use = true; + return data_device.get(); + } + + bool host_ready ( + ) const { return host_current; } + + bool device_ready ( + ) const { return device_current && !have_active_transfer; } + + size_t size() const { return data_size; } + + void swap (gpu_data& item) + { + std::swap(data_size, item.data_size); + std::swap(host_current, item.host_current); + std::swap(device_current, item.device_current); + std::swap(have_active_transfer, item.have_active_transfer); + std::swap(data_host, item.data_host); + std::swap(data_device, item.data_device); + std::swap(cuda_stream, item.cuda_stream); + std::swap(the_device_id, item.the_device_id); + } + + private: + +#ifdef DLIB_USE_CUDA + void copy_to_device() const; + void copy_to_host() const; + void wait_for_transfer_to_finish() const; +#else + void copy_to_device() const{} + void copy_to_host() const{} + void wait_for_transfer_to_finish() const{} +#endif + + + size_t data_size; + mutable bool host_current; + mutable bool device_current; + mutable bool have_active_transfer; + mutable bool device_in_use; + + std::shared_ptr data_host; + std::shared_ptr data_device; + std::shared_ptr cuda_stream; + int the_device_id; + }; + + inline void serialize(const gpu_data& item, std::ostream& out) + { + int version = 1; + serialize(version, out); + serialize(item.size(), out); + auto data = item.host(); + for (size_t i = 0; i < item.size(); ++i) + serialize(data[i], out); + } + + inline void deserialize(gpu_data& item, std::istream& in) + { + int version; + deserialize(version, in); + if (version != 1) + throw serialization_error("Unexpected version found while deserializing dlib::gpu_data."); + size_t s; + deserialize(s, in); + item.set_size(s); + auto data = item.host(); + for (size_t i = 0; i < item.size(); ++i) + deserialize(data[i], in); + } + +#ifdef DLIB_USE_CUDA + void memcpy (gpu_data& dest, const gpu_data& src); + + void memcpy ( + gpu_data& dest, + size_t dest_offset, + const gpu_data& src, + size_t src_offset, + size_t num + ); + +#else + + inline void memcpy (gpu_data& dest, const gpu_data& src) + { + DLIB_CASSERT(dest.size() == src.size()); + if (src.size() == 0 || &dest == &src) + return; + std::memcpy(dest.host_write_only(), src.host(), sizeof(float)*src.size()); + } + + inline void memcpy ( + gpu_data& dest, + size_t dest_offset, + const gpu_data& src, + size_t src_offset, + size_t num + ) + { + DLIB_CASSERT(dest_offset + num <= dest.size()); + DLIB_CASSERT(src_offset + num <= src.size()); + if (num == 0) + return; + if (&dest == &src && std::max(dest_offset, src_offset) < std::min(dest_offset,src_offset)+num) + { + // if they perfectly alias each other then there is nothing to do + if (dest_offset == src_offset) + return; + else + std::memmove(dest.host()+dest_offset, src.host()+src_offset, sizeof(float)*num); + } + else + { + // if we write to the entire thing then we can use host_write_only() + if (dest_offset == 0 && num == dest.size()) + std::memcpy(dest.host_write_only(), src.host()+src_offset, sizeof(float)*num); + else + std::memcpy(dest.host()+dest_offset, src.host()+src_offset, sizeof(float)*num); + } + } +#endif + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_GPU_DaTA_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/cuda/gpu_data_abstract.h b/lib/3rdParty/dlib/include/dlib/cuda/gpu_data_abstract.h new file mode 100644 index 00000000..f2423dee --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cuda/gpu_data_abstract.h @@ -0,0 +1,266 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_GPU_DaTA_ABSTRACT_H_ +#ifdef DLIB_GPU_DaTA_ABSTRACT_H_ + +#include "cuda_errors.h" +#include "../serialize.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class gpu_data + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a block of size() floats, all stored contiguously in memory. + Importantly, it keeps two copies of the floats, one on the host CPU side + and another on the GPU device side. It automatically performs the necessary + host/device transfers to keep these two copies of the data in sync. + + All transfers to the device happen asynchronously with respect to the + default CUDA stream so that CUDA kernel computations can overlap with data + transfers. However, any transfers from the device to the host happen + synchronously in the default CUDA stream. Therefore, you should perform + all your CUDA kernel launches on the default stream so that transfers back + to the host do not happen before the relevant computations have completed. + + If DLIB_USE_CUDA is not #defined then this object will not use CUDA at all. + Instead, it will simply store one host side memory block of floats. + + THREAD SAFETY + Instances of this object are not thread-safe. So don't touch one from + multiple threads at the same time. + !*/ + public: + + gpu_data( + ); + /*! + ensures + - #size() == 0 + - #host() == nullptr + - #device() == nullptr + - #host_ready() == true + - #device_ready() == true + - #device_id() == 0 + !*/ + + // This object is not copyable, however, it is movable. + gpu_data(const gpu_data&) = delete; + gpu_data& operator=(const gpu_data&) = delete; + gpu_data(gpu_data&& item); + gpu_data& operator=(gpu_data&& item); + + int device_id( + ) const; + /*! + ensures + - returns the ID of the CUDA device that allocated this memory. I.e. the + number returned by cudaGetDevice() when the memory was allocated. + - If CUDA is not being used then this function always returns 0. + !*/ + + void async_copy_to_device( + ); + /*! + ensures + - if (!device_ready()) then + - Begins asynchronously copying host data to the device once it is safe + to do so. I.e. This function will wait until any previously + scheduled CUDA kernels, which are using the device() memory block, + have completed before transferring the new data to the device. + - A call to device() that happens before the transfer completes will + block until the transfer is complete. That is, it is safe to call + async_copy_to_device() and then immediately call device(). + !*/ + + void set_size( + size_t new_size + ); + /*! + ensures + - #size() == new_size + !*/ + + bool host_ready ( + ) const; + /*! + ensures + - returns true if and only if the host's copy of the data is current. The + host's data is current if there aren't any modifications to the data + which were made on the device side that have yet to be copied to the + host. + !*/ + + bool device_ready ( + ) const; + /*! + ensures + - returns true if and only if the device's copy of the data is current. + The device's data is current if there aren't any modifications to the + data which were made on the host side that have yet to be copied to the + device. + !*/ + + const float* host( + ) const; + /*! + ensures + - returns a pointer to the host memory block of size() contiguous float + values or nullptr if size()==0. + - if (!host_ready()) then + - copies the data from the device to the host, while this is happening + the call to host() blocks. + - #host_ready() == true + !*/ + + float* host( + ); + /*! + ensures + - returns a pointer to the host memory block of size() contiguous float + values or nullptr if size()==0. + - if (!host_ready()) then + - copies the data from the device to the host, while this is happening + the call to host() blocks. + - #host_ready() == true + - #device_ready() == false + I.e. Marks the device side data as out of date so that the next call to + device() will perform a host to device transfer. If you want to begin + the transfer immediately then you can call async_copy_to_device() after + calling host(). + !*/ + + float* host_write_only( + ); + /*! + ensures + - This function returns the same pointer as host(), except that it never + performs a device to host memory copy. Instead, it immediately marks the + device side data as out of date, effectively discarding it. Therefore, + the values in the data pointed to by host_write_only() are undefined and + you should only call host_write_only() if you are going to assign to + every memory location in the returned memory block. + - #host_ready() == true + - #device_ready() == false + !*/ + + const float* device( + ) const; + /*! + requires + - DLIB_USE_CUDA is #defined + ensures + - returns a pointer to the device memory block of size() contiguous float + values or nullptr if size()==0. + - if (!device_ready()) then + - copies the data from the host to the device, while this is happening + the call to device() blocks. + - #device_ready() == true + !*/ + + float* device( + ); + /*! + requires + - DLIB_USE_CUDA is #defined + ensures + - returns a pointer to the device memory block of size() contiguous float + values or nullptr if size()==0. + - if (!device_ready()) then + - copies the data from the host to the device, while this is happening + the call to device() blocks. + - #host_ready() == false + - #device_ready() == true + !*/ + + float* device_write_only( + ); + /*! + requires + - DLIB_USE_CUDA is #defined + ensures + - This function returns the same pointer as device(), except that it never + performs a host to device memory copy. Instead, it immediately marks the + host side data as out of date, effectively discarding it. Therefore, the + values in the data pointed to by device_write_only() are undefined and + you should only call device_write_only() if you are going to assign to + every memory location in the returned memory block. + - #host_ready() == false + - #device_ready() == true + !*/ + + + size_t size( + ) const; + /*! + ensures + - returns the number of floats contained in this object. + !*/ + + void swap ( + gpu_data& item + ); + /*! + ensures + - swaps the state of *this and item + !*/ + + }; + + void serialize(const gpu_data& item, std::ostream& out); + void deserialize(gpu_data& item, std::istream& in); + /*! + provides serialization support + !*/ + + void memcpy ( + gpu_data& dest, + const gpu_data& src + ); + /*! + requires + - dest.size() == src.size() + ensures + - Copies the data in src to dest. If the device data is current (i.e. + device_ready()==true) on both src and dest then the copy will happen entirely + on the device side. + - It doesn't matter what GPU device is selected by cudaSetDevice(). You can + always copy gpu_data objects to and from each other regardless. + - This function blocks until the copy has completed. + !*/ + + void memcpy ( + gpu_data& dest, + size_t dest_offset, + const gpu_data& src, + size_t src_offset, + size_t num + ); + /*! + requires + - dest_offset + num <= dest.size() + - src_offset + num <= src.size() + ensures + - Copies the data in src to dest, but only copies data in the range + [src.host()+src_offset, src.host()+src_offset+num) to + [dest.host()+dest_offset, dest.host()+dest_offset+num). Therefore, it is + just like the above memcpy() except that you can specify some subset of data + in a gpu_data object to be copied. + - Like the above version of memcpy(), the copy will happen in the most + efficient way, automatically using the appropriate type of host/device + transfers based on where data is currently resident. + - It doesn't matter what GPU device is selected by cudaSetDevice(). You can + always copy gpu_data objects to and from each other regardless. + - This function blocks until the copy has completed. + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_GPU_DaTA_ABSTRACT_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/cuda/tensor.h b/lib/3rdParty/dlib/include/dlib/cuda/tensor.h new file mode 100644 index 00000000..8039fe66 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cuda/tensor.h @@ -0,0 +1,686 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DNn_TENSOR_H_ +#define DLIB_DNn_TENSOR_H_ + +#include "tensor_abstract.h" +#include +#include "../matrix.h" +#include "cudnn_dlibapi.h" +#include "gpu_data.h" +#include "../byte_orderer.h" +#include +#include "../any.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class tensor; + namespace cuda + { + void set_tensor ( + tensor& t, + float value + ); + + void scale_tensor ( + tensor& t, + float value + ); + } + +// ---------------------------------------------------------------------------------------- + + class tensor + { + public: + + tensor ( + ) : + m_n(0), m_k(0), m_nr(0), m_nc(0), m_size(0) + { + } + + virtual ~tensor() {} + + long long num_samples() const { return m_n; } + long long k() const { return m_k; } + long long nr() const { return m_nr; } + long long nc() const { return m_nc; } + size_t size() const { return m_size; } + + typedef float* iterator; + typedef const float* const_iterator; + iterator begin() { return host(); } + const_iterator begin() const { return host(); } + iterator end() { return host()+size(); } + const_iterator end() const { return host()+size(); } + + void async_copy_to_device() const + { + data().async_copy_to_device(); + } + + virtual const float* host() const = 0; + virtual float* host() = 0; + virtual float* host_write_only() = 0; + virtual const float* device() const = 0; + virtual float* device() = 0; + virtual float* device_write_only() = 0; + + virtual const any& annotation() const = 0; + virtual any& annotation() = 0; + + int device_id() const { return data().device_id(); } + + tensor& operator= (float val) + { +#ifdef DLIB_USE_CUDA + // If you are using CUDA then presumably you will be mostly using tensors on + // the GPU. So unless you seem to be actively working with the host side's + // data then we do this initialization on the device side since this avoids a + // host to device transfer that would likely immediately follow. + if (data().device_ready()) + { + cuda::set_tensor(*this, val); + return *this; + } +#endif + auto d = host_write_only(); + for (size_t i = 0; i < size(); ++i) + d[i] = val; + + return *this; + } + + tensor& operator*= (float val) + { +#ifdef DLIB_USE_CUDA + cuda::scale_tensor(*this, val); + return *this; +#else + for (auto& d : *this) + d *= val; + + return *this; +#endif + } + + tensor& operator/= (float val) + { + *this *= 1.0/val; + return *this; + } + + template + tensor& operator= (const matrix_exp& item) + { + DLIB_CASSERT(num_samples() == item.nr() && + nr()*nc()*k() == item.nc()); + static_assert((is_same_type::value == true), + "To assign a matrix to a tensor the matrix must contain float values"); + + set_ptrm(host_write_only(), m_n, m_nr*m_nc*m_k) = item; + return *this; + } + + template + tensor& operator+= (const matrix_exp& item) + { + DLIB_CASSERT(num_samples() == item.nr() && + nr()*nc()*k() == item.nc()); + static_assert((is_same_type::value == true), + "To assign a matrix to a tensor the matrix must contain float values"); + set_ptrm(host(), m_n, m_nr*m_nc*m_k) += item; + return *this; + } + + template + tensor& operator-= (const matrix_exp& item) + { + DLIB_CASSERT(num_samples() == item.nr() && + nr()*nc()*k() == item.nc()); + static_assert((is_same_type::value == true), + "To assign a matrix to a tensor the matrix must contain float values"); + set_ptrm(host(), m_n, m_nr*m_nc*m_k) -= item; + return *this; + } + + template + void set_sample ( + unsigned long long idx, + const matrix_exp& item + ) + { + DLIB_CASSERT(idx < (unsigned long long)num_samples()); + DLIB_CASSERT(item.size() == nr()*nc()*k()); + static_assert((is_same_type::value == true), + "To assign a matrix to a tensor the matrix must contain float values"); + set_ptrm(host()+idx*item.size(), item.nr(), item.nc()) = item; + } + + + template + void add_to_sample ( + unsigned long long idx, + const matrix_exp& item + ) + { + DLIB_CASSERT(idx < (unsigned long long)num_samples()); + DLIB_CASSERT(item.size() == nr()*nc()*k()); + static_assert((is_same_type::value == true), + "To assign a matrix to a tensor the matrix must contain float values"); + set_ptrm(host()+idx*item.size(), item.nr(), item.nc()) += item; + } + + +#ifdef DLIB_USE_CUDA + virtual const cuda::tensor_descriptor& get_cudnn_tensor_descriptor ( + ) const = 0; +#endif + + friend void memcpy ( + tensor& dest, + const tensor& src + ) + { + DLIB_CASSERT(dest.size() == src.size()); + memcpy(dest.data(), dest.get_alias_offset(), + src.data(), src.get_alias_offset(), + src.size()); + } + + + protected: + + friend class alias_tensor; + + virtual gpu_data& data() = 0; + virtual const gpu_data& data() const = 0; + virtual size_t get_alias_offset() const { return 0; } // needed by alias_tensor. + + long long m_n; + long long m_k; + long long m_nr; + long long m_nc; + long long m_size; // always equal to m_n*m_k*m_nr*m_nc + }; + +// ---------------------------------------------------------------------------------------- + + inline bool is_vector ( + const tensor& t + ) + { + return t.size() == (size_t)t.num_samples() || + t.size() == (size_t)t.k() || + t.size() == (size_t)t.nr() || + t.size() == (size_t)t.nc(); + } + +// ---------------------------------------------------------------------------------------- + + inline const matrix_op > mat ( + const tensor& t, + long long nr, + long long nc + ) + { + DLIB_ASSERT(nr >= 0 && nc >= 0 , + "\tconst matrix_exp mat(tensor, nr, nc)" + << "\n\t nr and nc must be >= 0" + << "\n\t nr: " << nr + << "\n\t nc: " << nc + ); + DLIB_ASSERT(nr*nc == (long long)t.size() , + "\tconst matrix_exp mat(tensor, nr, nc)" + << "\n\t The sizes don't match up." + << "\n\t nr*nc: " << nr*nc + << "\n\t t.size(): " << t.size() + ); + typedef op_pointer_to_mat op; + return matrix_op(op(t.host(),nr,nc)); + } + + inline const matrix_op > mat ( + const tensor& t + ) + { + if (t.size() != 0) + return mat(t, t.num_samples(), t.size()/t.num_samples()); + else + return mat((float*)0,0,0); + } + + inline const matrix_op > image_plane ( + const tensor& t, + long long sample = 0, + long long k = 0 + ) + { + DLIB_ASSERT(0 <= sample && sample < t.num_samples() && + 0 <= k && k < t.k() && + t.size() != 0, + "\tconst matrix_exp image_plane(tensor,sample,k)" + << "\n\t Invalid arguments were given to this function." + << "\n\t sample: " << sample + << "\n\t k: " << k + << "\n\t t.num_samples(): " << t.num_samples() + << "\n\t t.k(): " << t.k() + << "\n\t t.size(): " << t.size() + ); + + + typedef op_pointer_to_mat op; + return matrix_op(op(t.host() + ((sample*t.k() + k)*t.nr())*t.nc(), + t.nr(), + t.nc())); + } + +// ---------------------------------------------------------------------------------------- + + inline bool have_same_dimensions ( + const tensor& a, + const tensor& b + ) + { + return a.num_samples() == b.num_samples() && + a.k() == b.k() && + a.nr() == b.nr() && + a.nc() == b.nc(); + } + +// ---------------------------------------------------------------------------------------- + + class resizable_tensor : public tensor + { + public: + resizable_tensor( + ) + {} + + template + resizable_tensor( + const matrix_exp& item + ) + { + set_size(item.nr(), item.nc()); + *this = item; + } + + explicit resizable_tensor( + long long n_, long long k_ = 1, long long nr_ = 1, long long nc_ = 1 + ) + { + DLIB_ASSERT( n_ >= 0 && k_ >= 0 && nr_ >= 0 && nc_ >= 0); + + set_size(n_,k_,nr_,nc_); + } + + resizable_tensor(const resizable_tensor& item) : _annotation(item.annotation()) + { + copy_size(item); + memcpy(*this, item); + } + resizable_tensor(const tensor& item) : _annotation(item.annotation()) + { + copy_size(item); + memcpy(*this, item); + } + + resizable_tensor(resizable_tensor&& item) { swap(item); } + resizable_tensor& operator=(resizable_tensor&& item) { swap(item); return *this; } + + virtual const float* host() const { return data_instance.host(); } + virtual float* host() { return data_instance.host(); } + virtual float* host_write_only() { return data_instance.host_write_only(); } + virtual const float* device() const { return data_instance.device(); } + virtual float* device() { return data_instance.device(); } + virtual float* device_write_only() { return data_instance.device_write_only(); } + + virtual const any& annotation() const { return _annotation; } + virtual any& annotation() { return _annotation; } + + void clear( + ) + { + set_size(0,0,0,0); + _annotation.clear(); + // free underlying memory + data_instance.set_size(0); + } + + void copy_size ( + const tensor& item + ) + { + set_size(item.num_samples(), item.k(), item.nr(), item.nc()); + } + + resizable_tensor& operator= (float val) + { + tensor::operator=(val); + return *this; + } + + template + resizable_tensor& operator= ( + const matrix_exp& item + ) + { + if (!(num_samples() == item.nr() && k()*nr()*nc() == item.nc())) + set_size(item.nr(), item.nc()); + tensor::operator=(item); + return *this; + } + + void set_size( + long long n_, long long k_ = 1, long long nr_ = 1, long long nc_ = 1 + ) + { + DLIB_ASSERT( n_ >= 0 && k_ >= 0 && nr_ >= 0 && nc_ >= 0); + + m_n = n_; + m_k = k_; + m_nr = nr_; + m_nc = nc_; + m_size = n_*k_*nr_*nc_; + if ((long long)data_instance.size() < m_size) + data_instance.set_size(m_size); +#ifdef DLIB_USE_CUDA + cudnn_descriptor.set_size(m_n,m_k,m_nr,m_nc); +#endif + } + + + resizable_tensor& operator= (const resizable_tensor& item) + { + resizable_tensor temp(item); + temp.swap(*this); + return *this; + } + + resizable_tensor& operator= (const tensor& item) + { + resizable_tensor temp(item); + temp.swap(*this); + return *this; + } + + + void swap(resizable_tensor& item) + { + std::swap(m_n, item.m_n); + std::swap(m_k, item.m_k); + std::swap(m_nr, item.m_nr); + std::swap(m_nc, item.m_nc); + std::swap(m_size, item.m_size); + std::swap(data_instance, item.data_instance); + std::swap(_annotation, item._annotation); +#ifdef DLIB_USE_CUDA + std::swap(cudnn_descriptor, item.cudnn_descriptor); +#endif + } + +#ifdef DLIB_USE_CUDA + virtual const cuda::tensor_descriptor& get_cudnn_tensor_descriptor ( + ) const { return cudnn_descriptor; } +#endif + + private: + +#ifdef DLIB_USE_CUDA + cuda::tensor_descriptor cudnn_descriptor; +#endif + + gpu_data data_instance; + any _annotation; + virtual gpu_data& data() { return data_instance; } + virtual const gpu_data& data() const { return data_instance; } + }; + + inline void serialize(const tensor& item, std::ostream& out) + { + int version = 2; + serialize(version, out); + serialize(item.num_samples(), out); + serialize(item.k(), out); + serialize(item.nr(), out); + serialize(item.nc(), out); + byte_orderer bo; + auto sbuf = out.rdbuf(); + for (auto d : item) + { + // Write out our data as 4byte little endian IEEE floats rather than using + // dlib's default float serialization. We do this because it will result in + // more compact outputs. It's slightly less portable but it seems doubtful + // that any CUDA enabled platform isn't going to use IEEE floats. But if one + // does we can just update the serialization code here to handle it if such a + // platform is encountered. + bo.host_to_little(d); + static_assert(sizeof(d)==4, "This serialization code assumes we are writing 4 byte floats"); + sbuf->sputn((char*)&d, sizeof(d)); + } + } + + inline void deserialize(resizable_tensor& item, std::istream& in) + { + int version; + deserialize(version, in); + if (version != 2) + throw serialization_error("Unexpected version found while deserializing dlib::resizable_tensor."); + + long long num_samples=0, k=0, nr=0, nc=0; + deserialize(num_samples, in); + deserialize(k, in); + deserialize(nr, in); + deserialize(nc, in); + item.set_size(num_samples, k, nr, nc); + byte_orderer bo; + auto sbuf = in.rdbuf(); + for (auto& d : item) + { + static_assert(sizeof(d)==4, "This serialization code assumes we are writing 4 byte floats"); + if (sbuf->sgetn((char*)&d,sizeof(d)) != sizeof(d)) + { + in.setstate(std::ios::badbit); + throw serialization_error("Error reading data while deserializing dlib::resizable_tensor."); + } + bo.little_to_host(d); + } + } + +// ---------------------------------------------------------------------------------------- + + inline double dot( + const tensor& a, + const tensor& b + ) + { + DLIB_CASSERT(a.size() == b.size()); + const float* da = a.host(); + const float* db = b.host(); + double sum = 0; + for (size_t i = 0; i < a.size(); ++i) + sum += da[i]*db[i]; + return sum; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class alias_tensor_instance : public tensor + { + alias_tensor_instance( + ) : data_instance(0), _annotation(0), data_offset(0) {} + + public: + friend class alias_tensor; + friend class alias_tensor_const_instance; + + alias_tensor_instance& operator= (float val) + { + tensor::operator=(val); + return *this; + } + + template + alias_tensor_instance& operator= (const matrix_exp& item) + { + tensor::operator=(item); + return *this; + } + + virtual const float* host() const { return data_instance->host()+data_offset; } + virtual float* host() { return data_instance->host()+data_offset; } + virtual float* host_write_only() { return data_instance->host()+data_offset; } + virtual const float* device() const { return data_instance->device()+data_offset; } + virtual float* device() { return data_instance->device()+data_offset; } + virtual float* device_write_only() { return data_instance->device()+data_offset; } + + virtual const any& annotation() const { return *_annotation; } + virtual any& annotation() { return *_annotation; } + +#ifdef DLIB_USE_CUDA + virtual const cuda::tensor_descriptor& get_cudnn_tensor_descriptor ( + ) const { return *cudnn_descriptor; } +#endif + private: + + virtual size_t get_alias_offset() const { return data_offset; } + +#ifdef DLIB_USE_CUDA + std::shared_ptr cudnn_descriptor; +#endif + gpu_data* data_instance; + any* _annotation; + size_t data_offset; + virtual gpu_data& data() { return *data_instance; } + virtual const gpu_data& data() const { return *data_instance; } + }; + +// ---------------------------------------------------------------------------------------- + + class alias_tensor_const_instance + { + public: + const tensor& get() const { return inst; } + operator const tensor& () { return inst; } + + alias_tensor_const_instance(const alias_tensor_instance& item) : inst(item) {} + + private: + alias_tensor_instance inst; + + friend class alias_tensor; + alias_tensor_const_instance() {} + }; + +// ---------------------------------------------------------------------------------------- + + class alias_tensor + { + public: + + alias_tensor ( + ) {} + + alias_tensor ( + long long n_, long long k_ = 1, long long nr_ = 1, long long nc_ = 1 + ) + { + DLIB_ASSERT( n_ >= 0 && k_ >= 0 && nr_ >= 0 && nc_ >= 0); + + inst.m_n = n_; + inst.m_k = k_; + inst.m_nr = nr_; + inst.m_nc = nc_; + inst.m_size = n_*k_*nr_*nc_; + } + + long long num_samples( + ) const { return inst.m_n; } + + long long k( + ) const { return inst.m_k; } + + long long nr( + ) const { return inst.m_nr; } + + long long nc( + ) const { return inst.m_nc; } + + size_t size( + ) const { return inst.m_size; } + + alias_tensor_instance operator() ( + tensor& t, + size_t offset = 0 + ) const + { + DLIB_CASSERT(offset+size() <= t.size(), + "offset: "<(); + inst.cudnn_descriptor->set_size(inst.m_n, inst.m_k, inst.m_nr, inst.m_nc); + } +#endif + inst.data_instance = &t.data(); + inst._annotation = &t.annotation(); + // Note that t might already be an aliasing tensor so we need to take that into + // account. + inst.data_offset = t.get_alias_offset()+offset; + return inst; + } + + alias_tensor_const_instance operator() ( + const tensor& t, + size_t offset = 0 + ) const + { + alias_tensor_const_instance temp; + temp.inst = (*this)(const_cast(t),offset); + return temp; + } + + private: + mutable alias_tensor_instance inst; + }; + + inline void serialize(const alias_tensor& item, std::ostream& out) + { + int version = 1; + serialize(version, out); + serialize(item.num_samples(), out); + serialize(item.k(), out); + serialize(item.nr(), out); + serialize(item.nc(), out); + } + + inline void deserialize(alias_tensor& item, std::istream& in) + { + int version = 0; + deserialize(version, in); + if (version != 1) + throw serialization_error("Unexpected version found while deserializing dlib::alias_tensor."); + long long num_samples, k, nr, nc; + deserialize(num_samples, in); + deserialize(k, in); + deserialize(nr, in); + deserialize(nc, in); + item = alias_tensor(num_samples, k, nr, nc); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DNn_TENSOR_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/cuda/tensor_abstract.h b/lib/3rdParty/dlib/include/dlib/cuda/tensor_abstract.h new file mode 100644 index 00000000..73a9fff7 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cuda/tensor_abstract.h @@ -0,0 +1,727 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_DNn_TENSOR_ABSTRACT_H_ +#ifdef DLIB_DNn_TENSOR_ABSTRACT_H_ + +#include "../matrix.h" +#include "../any/any_abstract.h" + +namespace dlib +{ +// ---------------------------------------------------------------------------------------- + + class tensor + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a 4D array of float values, all stored contiguously + in memory. Importantly, it keeps two copies of the floats, one on the host + CPU side and another on the GPU device side. It automatically performs the + necessary host/device transfers to keep these two copies of the data in + sync. + + All transfers to the device happen asynchronously with respect to the + default CUDA stream so that CUDA kernel computations can overlap with data + transfers. However, any transfers from the device to the host happen + synchronously in the default CUDA stream. Therefore, you should perform + all your CUDA kernel launches on the default stream so that transfers back + to the host do not happen before the relevant computations have completed. + + If DLIB_USE_CUDA is not #defined then this object will not use CUDA at all. + Instead, it will simply store one host side memory block of floats. + + Finally, the convention in dlib code is to interpret the tensor as a set of + num_samples() 3D arrays, each of dimension k() by nr() by nc(). Also, + while this class does not specify a memory layout, the convention is to + assume that indexing into an element at coordinates (sample,k,r,c) can be + accomplished via: + host()[((sample*t.k() + k)*t.nr() + r)*t.nc() + c] + + THREAD SAFETY + Instances of this object are not thread-safe. So don't touch one from + multiple threads at the same time. + !*/ + + public: + + virtual ~tensor(); + + long long num_samples( + ) const; + /*! + ensures + - returns the number of 3D arrays of dimension k() by nr() by nc() there + are in this object. + !*/ + + long long k( + ) const; + /*! + ensures + - returns the k dimension of this tensor. Generally, we think of a tensor + as containing num_samples() images of nr() by nc() rows and columns, each + with k() channels. + !*/ + + long long nr( + ) const; + /*! + ensures + - returns the number of rows in this tensor. + !*/ + + long long nc( + ) const; + /*! + ensures + - returns the number of columns in this tensor. + !*/ + + size_t size( + ) const; + /*! + ensures + - returns num_samples()*k()*nr()*nc() + (i.e. the total number of floats in this tensor) + !*/ + + void async_copy_to_device( + ) const; + /*! + ensures + - This function does not block. + - if (the host version of the data is newer than the device's copy) then + - Begins asynchronously copying host data to the device. + - A call to device() that happens before the transfer completes will + block until the transfer is complete. That is, it is safe to call + async_copy_to_device() and then immediately call device(). + !*/ + + typedef float* iterator; + typedef const float* const_iterator; + iterator begin() { return host(); } + const_iterator begin() const { return host(); } + iterator end() { return host()+size(); } + const_iterator end() const { return host()+size(); } + /*! + ensures + - makes a tensor iterable just like the STL containers. + !*/ + + virtual const float* host( + ) const = 0; + /*! + ensures + - returns a pointer to the host memory block of size() contiguous float + values or nullptr if size()==0. + - if (the host's copy of the data is out of date) then + - copies the data from the device to the host, while this is happening + the call to host() blocks. + !*/ + + virtual float* host( + ) = 0; + /*! + ensures + - returns a pointer to the host memory block of size() contiguous float + values or nullptr if size()==0. + - if (the host's copy of the data is out of date) then + - copies the data from the device to the host, while this is happening + the call to host() blocks. + - Marks the device side data as out of date so that the next call to + device() will perform a host to device transfer. If you want to begin + the transfer immediately then you can call async_copy_to_device() after + calling host(). + !*/ + + virtual float* host_write_only( + ) = 0; + /*! + ensures + - This function returns the same pointer as host(), except that it never + performs a device to host memory copy. Instead, it immediately marks the + device side data as out of date, effectively discarding it. Therefore, + the values in the data pointed to by host_write_only() are undefined and + you should only call host_write_only() if you are going to assign to + every memory location in the returned memory block. + !*/ + + virtual const float* device( + ) const = 0; + /*! + requires + - DLIB_USE_CUDA is #defined + ensures + - returns a pointer to the device memory block of size() contiguous float + values or nullptr if size()==0. + - if (the device's copy of the data is out of date) then + - copies the data from the host to the device, while this is happening + the call to device() blocks. + !*/ + + virtual float* device( + ) = 0; + /*! + requires + - DLIB_USE_CUDA is #defined + ensures + - returns a pointer to the device memory block of size() contiguous float + values or nullptr if size()==0. + - if (the device's copy of the data is out of date) then + - copies the data from the host to the device, while this is happening + the call to device() blocks. + - Marks the host side data as out of date so that the next call to + host() will perform a device to host transfer. + !*/ + + virtual float* device_write_only( + ) = 0; + /*! + requires + - DLIB_USE_CUDA is #defined + ensures + - This function returns the same pointer as device(), except that it never + performs a host to device memory copy. Instead, it immediately marks the + host side data as out of date, effectively discarding it. Therefore, the + values in the data pointed to by device_write_only() are undefined and + you should only call device_write_only() if you are going to assign to + every memory location in the returned memory block. + !*/ + + virtual const any& annotation( + ) const = 0; + /*! + ensures + - returns a const reference to the any object in this tensor. The any + object can be used to store any additional annotation you like in a + tensor. However, it should be noted that the annotation() is ignored by + serialize() and therefore not saved when a tensor is serialized. + !*/ + + virtual any& annotation( + ) = 0; + /*! + ensures + - returns a non-const reference to the any object in this tensor. The any + object can be used to store any additional annotation you like in a + tensor. However, it should be noted that the annotation() is ignored by + serialize() and therefore not saved when a tensor is serialized. + !*/ + + int device_id( + ) const; + /*! + ensures + - returns the ID of the CUDA device that allocated this memory. I.e. the + number returned by cudaGetDevice() when the memory was allocated. + - If CUDA is not being used then this function always returns 0. + !*/ + + tensor& operator= ( + float val + ); + /*! + ensures + - sets all elements of this tensor equal to val. + - returns *this + !*/ + + tensor& operator*= ( + float val + ); + /*! + ensures + - pointwise multiplies all elements of *this tensor with val. + - returns *this + !*/ + + tensor& operator/= ( + float val + ); + /*! + ensures + - pointwise divides all elements of *this tensor with val. + - returns *this + !*/ + + template + tensor& operator= ( + const matrix_exp& item + ); + /*! + requires + - num_samples() == item.nr() + - k()*nr()*nc() == item.nc() + - item contains float values + ensures + - Assigns item to *this tensor by performing: + set_ptrm(host(), num_samples(), k()*nr()*nc()) = item; + !*/ + + template + tensor& operator+= ( + const matrix_exp& item + ); + /*! + requires + - num_samples() == item.nr() + - k()*nr()*nc() == item.nc() + - item contains float values + ensures + - Adds item to *this tensor by performing: + set_ptrm(host(), num_samples(), k()*nr()*nc()) += item; + !*/ + + template + tensor& operator-= ( + const matrix_exp& item + ); + /*! + requires + - num_samples() == item.nr() + - k()*nr()*nc() == item.nc() + - item contains float values + ensures + - Subtracts item from *this tensor by performing: + set_ptrm(host(), num_samples(), k()*nr()*nc()) -= item; + !*/ + + template + void set_sample ( + unsigned long long idx, + const matrix_exp& item + ); + /*! + requires + - idx < num_samples() + - k()*nr()*nc() == item.size() + - item contains float values + ensures + - Assigns item to the idx'th sample in *this by performing: + set_ptrm(host()+idx*item.size(), item.nr(), item.nc()) = item; + !*/ + + + template + void add_to_sample ( + unsigned long long idx, + const matrix_exp& item + ); + /*! + requires + - idx < num_samples() + - k()*nr()*nc() == item.size() + - item contains float values + ensures + - Adds item to the idx'th sample in *this by performing: + set_ptrm(host()+idx*item.size(), item.nr(), item.nc()) += item; + !*/ + + protected: + + // You can't move or copy another tensor into *this since that might modify the + // tensor's dimensions. If you want to do that sort of thing then use a + // resizable_tensor. + tensor(const tensor& item); + tensor& operator= (const tensor& item); + tensor(tensor&& item); + tensor& operator=(tensor&& item); + }; + +// ---------------------------------------------------------------------------------------- + + void memcpy ( + tensor& dest, + const tensor& src + ); + /*! + requires + - dest.size() == src.size() + ensures + - Copies the data in src to dest. If the device data is current on both src + and dest then the copy will happen entirely on the device side. + - It doesn't matter what GPU device is selected by cudaSetDevice(). You can + always copy tensor objects to and from each other regardless. + - This function blocks until the copy has completed. + !*/ + +// ---------------------------------------------------------------------------------------- + + bool is_vector ( + const tensor& t + ); + /*! + ensures + - returns true if and only if one of the following is true: + - t.size() == t.num_samples() + - t.size() == t.k() + - t.size() == t.nr() + - t.size() == t.nc() + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp mat ( + const tensor& t, + long long nr, + long long nc + ); + /*! + requires + - nr >= 0 + - nc >= 0 + - nr*nc == t.size() + ensures + - returns a matrix M such that: + - M.nr() == nr + - m.nc() == nc + - for all valid r and c: + M(r,c) == t.host()[r*nc + c] + (i.e. the tensor is interpreted as a matrix laid out in memory + in row major order) + !*/ + + const matrix_exp mat ( + const tensor& t + ); + /*! + ensures + - if (t.size() != 0) then + - returns mat(t, t.num_samples(), t.size()/t.num_samples()) + - else + - returns an empty matrix. + !*/ + + const matrix_exp image_plane ( + const tensor& t, + long long sample = 0, + long long k = 0 + ); + /*! + requires + - t.size() != 0 + - 0 <= sample < t.num_samples() + - 0 <= k < t.k() + ensures + - returns the k-th image plane from the sample-th image in t. That is, + returns a matrix M such that: + - M contains float valued elements. + - M.nr() == t.nr() + - M.nc() == t.nc() + - for all valid r and c: + - M(r,c) == t.host()[((sample*t.k() + k)*t.nr() + r)*t.nc() + c] + !*/ + +// ---------------------------------------------------------------------------------------- + + bool have_same_dimensions ( + const tensor& a, + const tensor& b + ); + /*! + ensures + - returns true if and only if all of the fallowing are satisfied: + - a.num_samples() == b.num_samples() + - a.k() == b.k() + - a.nr() == b.nr() + - a.nc() == b.nc() + !*/ + +// ---------------------------------------------------------------------------------------- + + class resizable_tensor : public tensor + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is just a tensor with the additional ability to be resized. + !*/ + + public: + resizable_tensor( + ); + /*! + ensures + - #size() == 0 + - #num_samples() == 0 + - #k() == 0 + - #nr() == 0 + - #nc() == 0 + - #capacity() == 0 + !*/ + + template + resizable_tensor( + const matrix_exp& item + ); + /*! + requires + - item contains float values + ensures + - #num_samples() == item.nr() + - #k() == item.nc() + - #nr() == 1 + - #nc() == 1 + - Assigns item to *this tensor by performing: + set_ptrm(host(), num_samples(), k()*nr()*nc()) = item; + - #capacity() == size() + !*/ + + explicit resizable_tensor( + long long n_, long long k_ = 1, long long nr_ = 1, long long nc_ = 1 + ); + /*! + requires + - n_ >= 0 + - k_ >= 0 + - nr_ >= 0 + - nc_ >= 0 + ensures + - #size() == n_*k_*nr_*nc_ + - #num_samples() == n_ + - #k() == k_ + - #nr() == nr_ + - #nc() == nc_ + - #capacity() == size() + !*/ + + // This object is copyable and movable + resizable_tensor(const resizable_tensor&) = default; + resizable_tensor(resizable_tensor&&) = default; + resizable_tensor& operator= (const resizable_tensor&) = default; + resizable_tensor& operator= (resizable_tensor&&) = default; + + size_t capacity ( + ) const; + /*! + ensures + - returns the total number of floats allocated. This might be different + from the size() since calls to set_size() that make a tensor smaller + don't trigger reallocations. They simply adjust the nominal dimensions + while keeping the same allocated memory block. This makes calls to + set_size() very fast. If you need to deallocate a tensor then use + clear(). + !*/ + + void clear( + ); + /*! + ensures + - #size() == 0 + - #num_samples() == 0 + - #k() == 0 + - #nr() == 0 + - #nc() == 0 + - #annotation().is_empty() == true + - #capacity() == 0 + !*/ + + void copy_size ( + const tensor& item + ); + /*! + ensures + - resizes *this so that: have_same_dimensions(#*this, item)==true + !*/ + + void set_size( + long long n_, long long k_ = 1, long long nr_ = 1, long long nc_ = 1 + ); + /*! + requires + - n_ >= 0 + - k_ >= 0 + - nr_ >= 0 + - nc_ >= 0 + ensures + - #size() == n_*k_*nr_*nc_ + - #num_samples() == n_ + - #k() == k_ + - #nr() == nr_ + - #nc() == nc_ + - #capacity() == max(#size(), capacity()) + (i.e. capacity() never goes down when calling set_size().) + !*/ + + template + resizable_tensor& operator= ( + const matrix_exp& item + ); + /*! + requires + - item contains float values + ensures + - if (num_samples() == item.nr() && k()*nr()*nc() == item.nc()) then + - the dimensions of this tensor are not changed + - else + - #num_samples() == item.nr() + - #k() == item.nc() + - #nr() == 1 + - #nc() == 1 + - Assigns item to *this tensor by performing: + set_ptrm(host(), num_samples(), k()*nr()*nc()) = item; + !*/ + }; + + void serialize(const tensor& item, std::ostream& out); + void deserialize(resizable_tensor& item, std::istream& in); + /*! + provides serialization support for tensor and resizable_tensor. Note that you can + serialize to/from any combination of tenor and resizable_tensor objects. + !*/ + +// ---------------------------------------------------------------------------------------- + + double dot( + const tensor& a, + const tensor& b + ); + /*! + requires + - a.size() == b.size() + ensures + - returns the dot product between a and b when they are both treated as + a.size() dimensional vectors. That is, this function pointwise multiplies + the vectors together, then sums the result and returns it. + + !*/ + +// ---------------------------------------------------------------------------------------- + + class alias_tensor_instance : public tensor + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a tensor that aliases another tensor. That is, it doesn't + have its own block of memory but instead simply holds pointers to the + memory of another tensor object. It therefore allows you to efficiently + break a tensor into pieces and pass those pieces into functions. + + An alias_tensor_instance doesn't own the resources it points to in any sense. + So it is important to make sure that the underlying owning tensor doesn't get + destructed before any alias tensors which point to it are destructed. + !*/ + + // You can't default initialize this object. You can only get instances of it from + // alias_tensor::operator(). + alias_tensor_instance( + ); + }; + + class alias_tensor_const_instance + { + /*! + WHAT THIS OBJECT REPRESENTS + This is essentially a const version of alias_tensor_instance and therefore + represents a tensor. However, due to the mechanics of C++, this object + can't inherit from tensor. So instead it provides a get() and an implicit + conversion to const tensor. + !*/ + + public: + + // non-const alias tensors are convertible to const ones. + alias_tensor_const_instance(const alias_tensor_instance& item); + + // Methods that cast the alias to a tensor. + const tensor& get() const; + operator const tensor& (); + + private: + // You can't default initialize this object. You can only get instances of it from + // alias_tensor::operator(). + alias_tensor_const_instance(); + }; + + class alias_tensor + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a tool for creating tensor objects that alias other tensor objects. + That is, it allows you to make a tensor that references the memory space of + another tensor object rather than owning its own memory. This allows you + to do things like interpret a single tensor in different ways or even as a + group of multiple tensors. + !*/ + public: + + alias_tensor ( + ); + /*! + ensures + - #size() == 0 + - #num_samples() == 0 + - #k() == 0 + - #nr() == 0 + - #nc() == 0 + !*/ + + alias_tensor ( + long long n_, long long k_ = 1, long long nr_ = 1, long long nc_ = 1 + ); + /*! + requires + - n_ >= 0 + - k_ >= 0 + - nr_ >= 0 + - nc_ >= 0 + ensures + - #size() == n_*k_*nr_*nc_ + - #num_samples() == n_ + - #k() == k_ + - #nr() == nr_ + - #nc() == nc_ + !*/ + + long long num_samples() const; + long long k() const; + long long nr() const; + long long nc() const; + size_t size() const; + + alias_tensor_instance operator() ( + tensor& t, + size_t offset = 0 + ) const; + /*! + requires + - offset+size() <= t.size() + ensures + - Returns a tensor that simply aliases the elements of t beginning with t's + offset'th element. Specifically, this function returns an aliasing + tensor T such that: + - T.size() == size() + - T.num_samples() == num_samples() + - T.k() == k() + - T.nr() == nr() + - T.nc() == nc() + - T.host() == t.host()+offset + - T.device() == t.device()+offset + - &T.annotation() == &t.annotation() + !*/ + + alias_tensor_const_instance operator() ( + const tensor& t, + size_t offset = 0 + ) const; + /*! + requires + - offset+size() <= t.size() + ensures + - This function is identical to the above version of operator() except that + it takes and returns const tensors instead of non-const tensors. + !*/ + }; + + void serialize(const alias_tensor& item, std::ostream& out); + void deserialize(alias_tensor& item, std::istream& in); + /*! + provides serialization support for alias_tensor. + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DNn_TENSOR_ABSTRACT_H_ + + diff --git a/lib/3rdParty/dlib/include/dlib/cuda/tensor_tools.h b/lib/3rdParty/dlib/include/dlib/cuda/tensor_tools.h new file mode 100644 index 00000000..51eb2729 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/cuda/tensor_tools.h @@ -0,0 +1,1711 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_TeNSOR_TOOLS_H_ +#define DLIB_TeNSOR_TOOLS_H_ + +#include "tensor.h" +#include "cudnn_dlibapi.h" +#include "cublas_dlibapi.h" +#include "cusolver_dlibapi.h" +#include "curand_dlibapi.h" +#include "cpu_dlib.h" +#include "cuda_dlib.h" +#include "../rand.h" +#include +#include "../geometry/rectangle.h" +#include "../test_for_odr_violations.h" + +namespace dlib +{ + bool dnn_prefer_fastest_algorithms(); + void set_dnn_prefer_fastest_algorithms(); + void set_dnn_prefer_smallest_algorithms(); +} + +namespace dlib { namespace tt +{ + +// ---------------------------------------------------------------------------------------- + + void inverse_norms ( + resizable_tensor& invnorms, + const tensor& data, + const double eps + ); + /*! + ensures + - #invnorms == reciprocal(sqrt(sum_cols(squared(mat(data))) + eps)) + !*/ + + void dot_prods ( + resizable_tensor& out, + const tensor& lhs, + const tensor& rhs + ); + /*! + requires + - have_same_dimensions(lhs,rhs) == true + ensures + - #out.num_samples() == lhs.num_samples() + - #out.k() == #out.nr() == #out.nc() == 1 + - #out == sum_cols(pointwise_multiply(mat(lhs), mat(rhs))); + !*/ + + void dot_prods ( + bool add_to, + tensor& out, + const tensor& lhs, + const tensor& rhs + ); + /*! + requires + - have_same_dimensions(lhs,rhs) == true + - out.size() == lhs.num_samples() + - out.k() == out.nr() == out.nc() == 1 + ensures + - if (add_to) then + - #out == mat(out) + sum_cols(pointwise_multiply(mat(lhs), mat(rhs))); + - else + - #out == sum_cols(pointwise_multiply(mat(lhs), mat(rhs))); + !*/ + + void scale_columns ( + tensor& out, + const tensor& m, + const tensor& v + ); + /*! + requires + - have_same_dimensions(out,m) == true + - is_vector(v) == true + - v.size() == mat(m).nc() + ensures + - performs: out = scale_columns(mat(m),mat(v)); + !*/ + + void scale_rows ( + tensor& out, + const tensor& m, + const tensor& v + ); + /*! + requires + - have_same_dimensions(out,m) == true + - is_vector(v) == true + - v.size() == m.num_samples() + ensures + - performs: out = scale_rows(mat(m),mat(v)); + !*/ + + void scale_rows2 ( + float beta, + tensor& out, + const tensor& m1, + const tensor& m2, + const tensor& v1, + const tensor& v2 + ); + /*! + requires + - have_same_dimensions(out,m1) == true + - have_same_dimensions(out,m2) == true + - have_same_dimensions(v1,v2) == true + - is_vector(v1) == true + - v1.size() == m1.num_samples() + ensures + - performs: + out = beta*out + scale_rows(mat(m1) - scale_rows(mat(m2),mat(v1)), mat(v2)); + !*/ + +// ---------------------------------------------------------------------------------------- + + void exp ( + tensor& dest, + const tensor& src + ); + /*! + requires + - dest.size() == src.size() + ensures + - performs: dest = exp(mat(src)) + !*/ + +// ---------------------------------------------------------------------------------------- + + void log ( + tensor& dest, + const tensor& src + ); + /*! + requires + - dest.size() == src.size() + ensures + - performs: dest = log(mat(src)) + !*/ + +// ---------------------------------------------------------------------------------------- + + void log10 ( + tensor& dest, + const tensor& src + ); + /*! + requires + - dest.size() == src.size() + ensures + - performs: dest = log10(mat(src)) + !*/ + +// ---------------------------------------------------------------------------------------- + + void gemm ( + float beta, + tensor& dest, + float alpha, + const tensor& lhs, + bool trans_lhs, + const tensor& rhs, + bool trans_rhs + ); + /*! + requires + - dest does not alias the memory of lhs or rhs + - The dimensions of lhs and rhs must be compatible for matrix multiplication. + In particular: + - Let L == trans_lhs ? trans(mat(lhs)) : mat(lhs) + - Let R == trans_rhs ? trans(mat(rhs)) : mat(rhs) + - Let D == mat(dest) + - D.nr() == L.nr() && D.nc() == R.nc() + (i.e. dest must be preallocated and have the correct output dimensions) + - L.nc() == R.nr() + ensures + - performs: dest = alpha*L*R + beta*mat(dest) + !*/ + +// ---------------------------------------------------------------------------------------- + + class inv + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a functor for doing matrix inversion on the GPU. The only + reason it's an object is to avoid the reallocation of some GPU memory + blocks if you want to do a bunch of matrix inversions in a row. + !*/ + public: + + void operator() ( + const tensor& m, + resizable_tensor& out + ); + /*! + requires + - m.size() == m.num_samples()*m.num_samples() + (i.e. mat(m) must be a square matrix) + ensures + - out == inv(mat(m)); + !*/ + + private: +#ifdef DLIB_USE_CUDA + cuda::inv finv; +#endif + }; + +// ---------------------------------------------------------------------------------------- + + class tensor_rand + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a tool for filling a tensor with random numbers. + + Note that the sequence of random numbers output by this object is different + when dlib is compiled with DLIB_USE_CUDA. So you should not write code + that depends on any specific sequence of numbers coming out of a + tensor_rand. + + !*/ + + public: + // not copyable + tensor_rand(const tensor_rand&) = delete; + tensor_rand& operator=(const tensor_rand&) = delete; + + tensor_rand() : tensor_rand(0) {} + tensor_rand(unsigned long long seed); + + void fill_gaussian ( + tensor& data, + float mean = 0, + float stddev = 1 + ); + /*! + requires + - data.size()%2 == 0 + ensures + - Fills data with random numbers drawn from a Gaussian distribution + with the given mean and standard deviation. + !*/ + + void fill_uniform ( + tensor& data + ); + /*! + ensures + - Fills data with uniform random numbers in the range (0.0, 1.0]. + !*/ + +#ifdef DLIB_USE_CUDA + cuda::curand_generator rnd; +#else + dlib::rand rnd; +#endif + }; + +// ---------------------------------------------------------------------------------------- + + void multiply ( + bool add_to, + tensor& dest, + const tensor& src1, + const tensor& src2 + ); + /*! + requires + - dest.k() == src1.k() == src2.k() + - dest.nr() == src1.nr() == src2.nr() + - dest.nc() == src1.nc() == src2.nc() + - dest.num_samples(), src1.num_samples(), and src2.num_samples() must each + either be 1 or whichever ones aren't equal to 1 must have the same values. + ensures + - let MD = max(dest.num_samples(), src1.num_samples(), src2.num_samples) + - This function pointwise multiplies src1 with src2 and stores the result into + #dest. However, how the multiplication happens depends on the dimensions of + the tensors. First, when src1 and src2 are multiplied together, if either + has a num_samples() dimension that is != MD, then it is first replicated to + produce a tensor with num_samples()==MD dimensions and then they are + pointwise multiplied together. + + Second, if dest.num_samples()==1, then after the pointwise multiplication of + src1 with src2, the result has its samples summed to produce an output tensor + with num_samples()==1 which is then assigned to #dest. + - if (add_to) then + - Instead of assigning the result to dest, this function adds the result to dest. + !*/ + + void scale_channels ( + bool add_to, + tensor& dest, + const tensor& src, + const tensor& scales + ); + /*! + requires + - have_same_dimensions(dest, src) == true + - scales.num_samples() == src.num_samples() + - scales.k() == src.k() + - scales.nr() == 1 + - scales.nc() == 1 + ensures + - Scales each channel of src by the corresponding value in scales. To be + precise, we will have: + - #dest(n,k,r,c) == src(n,k,r,c)*scales(n,k,1,1) + - if (add_to) then + - Instead of assigning the result to dest, this function adds the result to dest. + !*/ + + void multiply_conv ( + bool add_to, + tensor& dest, + const tensor& src1, + const tensor& src2 + ); + /*! + requires + - if (have_same_dimensions(dest, src1) == true) then + - src2.num_samples() == 1 + - src2.nr() == 1 + - src2.nc() == 1 + - src2.k() == src1.k() + - else + - have_same_dimensions(src1, src2) == true) + - dest.num_samples() == 1 + - dest.nr() == 1 + - dest.nc() == 1 + - dest.k() == src1.k() + ensures + - Performs #dest == src1*src2 + In particular, if the elements of dest, src1, and src2 were indexed by (n,k,r,c) then + we would have: + - if (have_same_dimensions(dest,src1)) then + #dest(n,k,r,c) == src1(n,k,r,c)*src2(k) + - else + #dest(k) == sum over {n,r,c} of src1(n,k,r,c)*src2(n,k,r,c) + - if (add_to) then + - Instead of assigning the result to dest, this function adds the result to dest. + !*/ + + void multiply_zero_padded ( + bool add_to, + tensor& dest, + const tensor& src1, + const tensor& src2 + ); + /*! + ensures + - if (add_to) then + - performs: dest += src1 * src2 + - else + - performs: dest = src1 * src2 + - In either case, the multiplication happens pointwise according to 4D tensor + arithmetic. If the dimensions don't match then missing elements are presumed + to be equal to 0. + !*/ + +// ---------------------------------------------------------------------------------------- + + void affine_transform( + tensor& dest, + const tensor& src, + const float A, + const float B + ); + /*! + requires + - dest.size()==src.size() + ensures + - #dest == A*src + B + !*/ + + void affine_transform( + tensor& dest, + const tensor& src, + const float A + ); + /*! + requires + - dest.size()==src.size() + ensures + - #dest == A*src + !*/ + + void affine_transform( + tensor& dest, + const tensor& src1, + const tensor& src2, + const float A, + const float B, + const float C + ); + /*! + requires + - dest.size()==src1.size() + - dest.size()==src2.size() + ensures + - #dest == A*src1 + B*src2 + C + !*/ + + void affine_transform( + tensor& dest, + const tensor& src1, + const tensor& src2, + const float A, + const float B + ); + /*! + requires + - dest.size()==src1.size() + - dest.size()==src2.size() + ensures + - #dest == A*src1 + B*src2 + !*/ + + void affine_transform( + tensor& dest, + const tensor& src1, + const tensor& src2, + const tensor& src3, + const float A, + const float B, + const float C, + const float D + ); + /*! + requires + - dest.size()==src1.size() + - dest.size()==src2.size() + - dest.size()==src3.size() + ensures + - #dest == A*src1 + B*src2 + C*src3 + D + !*/ + + void affine_transform( + tensor& dest, + const tensor& src1, + const tensor& src2, + const tensor& src3, + const float A, + const float B, + const float C + ); + /*! + requires + - dest.size()==src1.size() + - dest.size()==src2.size() + - dest.size()==src3.size() + ensures + - #dest == A*src1 + B*src2 + C*src3 + !*/ + + void affine_transform_range( + size_t begin, + size_t end, + tensor& dest, + const tensor& src1, + const tensor& src2, + const tensor& src3, + const float A, + const float B, + const float C + ); + /*! + requires + - dest.size()==src1.size() + - dest.size()==src2.size() + - dest.size()==src3.size() + - begin <= end <= dest.size() + ensures + - This function operates much like + affine_transform(dest,src1,src2,src3,A,B,C,0), except that it runs over only + the half open range [begin,end) rather than processing the entire tensor. + Specifically, it does this: + - for i in the range [begin, end): + - #dest.host()[i] == A*src1.host()[i] + B*src2.host()[i] + C*src3.host()[i] + !*/ + + void affine_transform( + const rectangle& rect, + tensor& dest, + const tensor& src1, + const tensor& src2, + const tensor& src3, + float A, + float B, + float C + ); + /*! + requires + - dest.size()==src1.size() + - dest.size()==src2.size() + - dest.size()==src3.size() + - dest.num_samples()==src1.num_samples() + - dest.num_samples()==src2.num_samples() + - dest.num_samples()==src3.num_samples() + - get_rect(mat(dest)).contains(rect) == true + (i.e. rect must be entirely contained within dest) + ensures + - This function operates much like + affine_transform(dest,src1,src2,src3,A,B,C,0), except that it runs over only + the sub-rectangle indicated by rect. In particular, this function is equivalent + to: + set_subm(dest,rect) = A*subm(mat(src1),rect) + B*subm(mat(src2),rect) + C*subm(mat(src3),rect) + !*/ + +// ---------------------------------------------------------------------------------------- + + void affine_transform( + tensor& dest, + const tensor& src, + const tensor& A, + const tensor& B + ); + /*! + requires + - have_same_dimensions(dest,src) == true + - if (A.num_samples() == 1) then + - B.num_samples() == 1 + - else + - A.num_samples() == src.num_samples() + - B.num_samples() == src.num_samples() + - A.nr() == B.nr() == src.nr() + - A.nc() == B.nc() == src.nc() + - A.k() == B.k() == src.k() + ensures + - if (A.num_samples() == 1) then + - #dest == A*src + B + (done for each sample in src) + - else + - for all valid i: + - #dest.host()[i] == A.host()[i]*src.host()[i] + B.host()[i] + !*/ + +// ---------------------------------------------------------------------------------------- + + void affine_transform_conv( + tensor& dest, + const tensor& src, + const tensor& A, + const tensor& B + ); + /*! + requires + - have_same_dimensions(dest,src) == true + - have_same_dimensions(A, B) == true + - A.num_samples() == 1 + - A.nr() == 1 + - A.nc() == 1 + - A.k() == src.k() + ensures + - Performs #dest == A*src + B + In particular, if the elements of dest and src were indexed by (n,k,r,c) then + we would have: + #dest(n,k,r,c) == A(k)*src(n,k,r,c) + B(k). + !*/ + +// ---------------------------------------------------------------------------------------- + + void compute_adam_update ( + size_t begin, + size_t end, + tensor& s, + tensor& m, + tensor& v, + const float t, + const float learning_rate, + const float weight_decay, + const float momentum1, + const float momentum2, + const tensor& params, + const tensor& params_grad + ); + /*! + requires + - s.size() == m.size() = v.size() == params.size() == params_grad.size() + - t > 0 + - learning_rate > 0 + - weight_decay >= 0 + - 0 <= momentum1 < 1 + - 0 <= momentum2 < 1 + - begin <= end <= params.size() + ensures + - This function implements the ADAM parameter update method described in the paper: + Kingma, Diederik P., and Jimmy Ba Adam. "A method for stochastic + optimization." International Conference on Learning Representation. 2015. + Specifically, it implements the method shown as Algorithm 1. + - #s is the update vector that should be added to the parameters. + - The function only operates in the half open range [begin,end) of the memory + blocks of each tensor. E.g. to make this function run on the entire tensor + set begin to 0 and end to params.size(). + !*/ + +// ---------------------------------------------------------------------------------------- + + void batch_normalize_inference ( + const double eps, + resizable_tensor& dest, + const tensor& src, + const tensor& gamma, + const tensor& beta, + const tensor& running_means, + const tensor& running_variances + ); + /*! + requires + - eps > 0 + - gamma.num_samples() == 1 + - gamma.nr() == src.nr() + - gamma.nc() == src.nc() + - gamma.k() == src.k() + - have_same_dimensions(gamma, beta) + - have_same_dimensions(gamma, running_means) + - have_same_dimensions(gamma, running_variances) + ensures + - Linearly transforms src as a call to batch_normalize() would if src had means + and variances as given by running_means and running_variances. That is, this + function performs: + dest = gamma*(src-running_means)/sqrt(running_variances+eps) + beta + Note that it does it in a pointwise fashion over the samples in src. + !*/ + + void batch_normalize ( + const double eps, + resizable_tensor& dest, + resizable_tensor& means, + resizable_tensor& invstds, + const double averaging_factor, + resizable_tensor& running_means, + resizable_tensor& running_variances, + const tensor& src, + const tensor& gamma, + const tensor& beta + ); + /*! + requires + - eps > 0 + - src.num_samples() > 1 + - gamma.num_samples() == 1 + - beta.num_samples() == 1 + - gamma.nr() == beta.nr() == src.nr() + - gamma.nc() == beta.nc() == src.nc() + - gamma.k() == beta.k() == src.k() + - 0 <= averaging_factor <= 1 + - if (averaging_factor != 1) + - have_same_dimensions(running_means, means) == true + - have_same_dimensions(running_variances, invstds) == true + ensures + - have_same_dimensions(#dest, src) == true + - #means.num_samples() == 1 + - #invstds.num_samples() == 1 + - means.nr() == invstds.nr() == src.nr() + - means.nc() == invstds.nc() == src.nc() + - means.k() == invstds.k() == src.k() + - #src == the batch normalized version of src. + - #means == the mean values of the contents of src. + - #invstds == 1/(the standard deviation values of the contents of src). + - #running_means = (1-averaging_factor)*mat(#running_means) + averaging_factor*mat(#means); + - #running_variances = (1-averaging_factor)*mat(#running_variances) + averaging_factor*(variance of contents of src); + !*/ + + void batch_normalize_gradient ( + const double eps, + const tensor& gradient_input, + const tensor& means, + const tensor& invstds, + const tensor& src, + const tensor& gamma, + tensor& src_grad, + tensor& gamma_grad, + tensor& beta_grad + ); + /*! + requires + - eps > 0 + - invstds and means should be the output of a call to + batch_normalize(eps,dest,means,invstds,src,gamma,beta) + - have_same_dimensions(gradient_input, src) == true + - have_same_dimensions(src, src_grad) == true + - src.num_samples() > 1 + - gamma.num_samples() == 1 + - have_same_dimensions(gamma, gamma_grad) == true + - have_same_dimensions(gamma, beta_grad) == true + - gamma.nr() == src.nr() + - gamma.nc() == src.nc() + - gamma.k() == src.k() + - have_same_dimensions(means, gamma) == true + - have_same_dimensions(invstds, gamma) == true + ensures + - Let f(src,gamma,beta) == dot(gradient_input, dest output of + batch_normalize(eps,dest,means,invstds,src,gamma,beta)) + - Adds the gradient of f() with respect to src to #src_grad. + - Assigns the gradient of f() with respect to gamma to #gamma_grad. + - Assigns the gradient of f() with respect to beta to #beta_grad. + !*/ + +// ---------------------------------------------------------------------------------------- + + void batch_normalize_conv_inference ( + const double eps, + resizable_tensor& dest, + const tensor& src, + const tensor& gamma, + const tensor& beta, + const tensor& running_means, + const tensor& running_variances + ); + /*! + requires + - eps > 0 + - gamma.num_samples() == 1 + - gamma.nr() == 1 + - gamma.nc() == 1 + - gamma.k() == src.k() + - have_same_dimensions(gamma, beta) + - have_same_dimensions(gamma, running_means) + - have_same_dimensions(gamma, running_variances) + ensures + - Linearly transforms src as a call to batch_normalize_conv() would if src had + means and variances as given by running_means and running_variances. That + is, this function performs: + dest = gamma*(src-running_means)/sqrt(running_variances+eps) + beta + Note that it does this in a pointwise fashion over the samples, rows, and + columns in src. + !*/ + + void batch_normalize_conv ( + const double eps, + resizable_tensor& dest, + resizable_tensor& means, + resizable_tensor& invstds, + const double averaging_factor, + resizable_tensor& running_means, + resizable_tensor& running_variances, + const tensor& src, + const tensor& gamma, + const tensor& beta + ); + /*! + requires + - eps > 0 + - src.num_samples() > 1 + - gamma.num_samples()==gamma.nr()==gamma.nc() == 1 + - beta.num_samples() ==beta.nr() ==gamma.nc() == 1 + - gamma.k() == beta.k() == src.k() + - 0 <= averaging_factor <= 1 + - if (averaging_factor != 1) + - have_same_dimensions(running_means, means) == true + - have_same_dimensions(running_variances, invstds) == true + ensures + - have_same_dimensions(#dest, src) == true + - #means.num_samples()==means.nr()==means.nc() == 1 + - #invstds.num_samples() ==invstds.nr() ==invstds.nc() == 1 + - means.k() == invstds.k() == src.k() + - #src == the batch normalized version of src. + - #means == the mean values of the contents of src. + - #invstds == 1/(the standard deviation values of the contents of src). + - #running_means = (1-averaging_factor)*mat(#running_means) + averaging_factor*mat(#means); + - #running_variances = (1-averaging_factor)*mat(#running_variances) + averaging_factor*(variance of contents of src); + !*/ + + void batch_normalize_conv_gradient ( + const double eps, + const tensor& gradient_input, + const tensor& means, + const tensor& invstds, + const tensor& src, + const tensor& gamma, + tensor& src_grad, + tensor& gamma_grad, + tensor& beta_grad + ); + /*! + requires + - eps > 0 + - invstds and means should be the output of a call to + batch_normalize_conv(eps,dest,means,invstds,src,gamma,beta) + - have_same_dimensions(gradient_input, src) == true + - have_same_dimensions(src, src_grad) == true + - src.num_samples() > 1 + - gamma.num_samples()==gamma.nr()==gamma.nc() == 1 + - have_same_dimensions(gamma, gamma_grad) == true + - have_same_dimensions(gamma, beta_grad) == true + - gamma.k() == src.k() + - have_same_dimensions(means, gamma) == true + - have_same_dimensions(invstds, gamma) == true + ensures + - Let f(src,gamma,beta) == dot(gradient_input, dest output of + batch_normalize_conv(eps,dest,means,invstds,src,gamma,beta)) + - Adds the gradient of f() with respect to src to #src_grad. + - Assigns the gradient of f() with respect to gamma to #gamma_grad. + - Assigns the gradient of f() with respect to beta to #beta_grad. + !*/ + +// ----------------------------------------------------------------------------------- + + void threshold ( + tensor& data, + float thresh + ); + /*! + ensures + - Sets all elements of data to 1 or 0 depending on if they are above or below + the given threshold. Specifically, for all valid i: + - #data.host()[i] == data.host()[i]>thresh ? 1 : 0 + !*/ + + void dot ( + const tensor& a, + const tensor& b, + tensor& result, + size_t idx + ); + /*! + requires + - a.size() == b.size() + - idx < result.size() + ensures + - #result.host()[idx] == result.host()[idx] + dot(a,b); + I.e. Adds the dot product between a and b into the idx-th element of result. + The reason you might want to use this more complex version of dot() is + because, when using CUDA, it runs by generating asynchronous kernel launches + whereas the version of dot() that returns the result immediately as a scalar + must block the host while we wait for the result to be computed and then + transferred from the GPU do the host for return by dot(). So this version of + dot() might be much faster in some cases. + !*/ + +// ---------------------------------------------------------------------------------------- + + void add( + float beta, + tensor& dest, + float alpha, + const tensor& src + ); + /*! + requires + - One of the following is true: + - have_same_dimensions(src, dest) + - src.num_samples()==1 && src.k()==dest.k() && src.nr()==1 && src.nc()==1 + - src.num_samples()==1 && src.k()==dest.k() && src.nr()==dest.nr() && src.nc()==dest.nc() + - src.num_samples()==1 && src.k()==1 && src.nr()==dest.nr() && src.nc()==dest.nc() + - src.num_samples()==dest.num_samples() && src.k()==1 && src.nr()==1 && src.nc()==1 + - is_same_object(src,dest) == false + ensures + - performs: dest = beta*dest + alpha*src + However, how the addition happens depends on the dimensions of src. In + particular, this function adds the scaled values of one src tensor to dest. + Each dimension of the src tensor must match the corresponding dimension of + the dest tensor or must be equal to 1. In the latter case, the same value + from the src tensor, for those dimensions, will be used to add into the dest + tensor. + !*/ + +// ---------------------------------------------------------------------------------------- + + void add ( + tensor& dest, + const tensor& src1, + const tensor& src2 + ); + /*! + ensures + - performs: dest = src1 + src2 + The addition happens pointwise according to 4D tensor arithmetic. If the + dimensions don't match then missing elements are presumed to be equal to 0. + !*/ + +// ---------------------------------------------------------------------------------------- + + void assign_conv_bias_gradient ( + tensor& grad, + const tensor& gradient_input + ); + /*! + requires + - grad.num_samples() == 1 + - grad.k() >= 1 + - grad.nr() == 1 + - grad.nc() == 1 + - gradient_input.k() == grad.k() + - gradient_input.size() > 0 + - is_same_object(grad,gradient_input) == false + ensures + - let BIAS be a tensor with the same dimensions as grad. + - let OUT be the output of add(1,OUT,1,BIAS) + - let f(gradient_input,BIAS) == dot(gradient_input,OUT) + - Then this function computes the gradient of f() with respect to BIAS and + assigns it to grad. + !*/ + +// ---------------------------------------------------------------------------------------- + + void assign_bias_gradient ( + tensor& grad, + const tensor& gradient_input + ); + /*! + requires + - grad.num_samples() == 1 + - gradient_input.k() == grad.k() + - gradient_input.nr() == grad.nr() + - gradient_input.nc() == grad.nc() + - gradient_input.size() > 0 + - is_same_object(grad,gradient_input) == false + ensures + - let BIAS be a tensor with the same dimensions as grad. + - let OUT be the output of add(1,OUT,1,BIAS) + - let f(gradient_input,BIAS) == dot(gradient_input,OUT) + - Then this function computes the gradient of f() with respect to BIAS and + assigns it to grad. + !*/ + +// ---------------------------------------------------------------------------------------- + + class tensor_conv + { + public: + tensor_conv(const tensor_conv&) = delete; + tensor_conv& operator=(const tensor_conv&) = delete; + + tensor_conv() {} + + void clear( + ) { impl.clear(); } + + void operator() ( + const bool add_to_output, + tensor& output, + const tensor& data, + const tensor& filters + ) { impl(add_to_output,output,data,filters); } + /*! + requires + - setup() has been called. Specifically, setup() has been called like this: + this->setup(data, filters, stride_y, stride_x, padding_y, padding_x); + - is_same_object(output,data) == false + - is_same_object(output,filters) == false + - filters.k() == data.k() + - filters.nr() <= src.nr() + 2*padding_y + - filters.nc() <= src.nc() + 2*padding_x + - #output.num_samples() == data.num_samples() + - #output.k() == filters.num_samples() + - #output.nr() == 1+(data.nr() + 2*padding_y - filters.nr())/stride_y + - #output.nc() == 1+(data.nc() + 2*padding_x - filters.nc())/stride_x + ensures + - Convolves filters over data. If add_to_output==true then we add the + results to output, otherwise we assign to output, overwriting the + previous values in output. + - filters contains filters.num_samples() filters. + !*/ + + void operator() ( + const bool add_to_output, + resizable_tensor& output, + const tensor& data, + const tensor& filters + ) { impl(add_to_output,output,data,filters); } + /*! + requires + - setup() has been called. Specifically, setup() has been called like this: + this->setup(data, filters, stride_y, stride_x, padding_y, padding_x); + - is_same_object(output,data) == false + - is_same_object(output,filters) == false + - filters.k() == data.k() + - filters.nr() <= src.nr() + 2*padding_y + - filters.nc() <= src.nc() + 2*padding_x + ensures + - Convolves filters over data. If add_to_output==true then we add the + results to output, otherwise we assign to output, overwriting the + previous values in output. + - filters contains filters.num_samples() filters. + - #output.num_samples() == data.num_samples() + - #output.k() == filters.num_samples() + - #output.nr() == 1+(data.nr() + 2*padding_y - filters.nr())/stride_y + - #output.nc() == 1+(data.nc() + 2*padding_x - filters.nc())/stride_x + !*/ + + void get_gradient_for_data ( + const bool add_to_output, + const tensor& gradient_input, + const tensor& filters, + tensor& data_gradient + ) { impl.get_gradient_for_data(add_to_output,gradient_input,filters,data_gradient); } + /*! + requires + - One of the following must be true: + - filters has the same dimensions as the filters object given to the + last call to operator(). Also, data_gradient has the same dimensions + as the data object given to the last call to operator(). + - setup() has been called. Specifically, setup() has been called like this: + this->setup(data_gradient, filters, stride_y, stride_x, padding_y, padding_x); + - gradient_input has the following dimensions: + - gradient_input.num_samples() == data_gradient.num_samples() + - gradient_input.k() == filters.num_samples() + - gradient_input.nr() == 1+(data_gradient.nr() + 2*padding_y - filters.nr())/stride_y + - gradient_input.nc() == 1+(data_gradient.nc() + 2*padding_x - filters.nc())/stride_x + - NOTE, these dimensions are what you would obtain if gradient_input + has the same dimensions as the last output of operator(). + - is_same_object(data_gradient,filters) == false + - is_same_object(data_gradient,gradient_input) == false + ensures + - let OUT be the output of (*this)(OUT,data,filters,sx,sy). + - let f(data,filters) == dot(OUT, gradient_input) + - if (add_to_output) then + - This function finds the gradient of f() with respect to data and adds + this gradient to data_gradient. + - else + - This function finds the gradient of f() with respect to data and + assigns this gradient to data_gradient, overwriting the previous + values in data_gradient. + !*/ + + void get_gradient_for_filters ( + const bool add_to_output, + const tensor& gradient_input, + const tensor& data, + tensor& filters_gradient + ) { impl.get_gradient_for_filters(add_to_output,gradient_input,data,filters_gradient); } + /*! + requires + - One of the following must be true: + - filters_gradient has the same dimensions as the filters object given + to the last call to operator(). Also, data has the same dimensions + as the data object given to the last call to operator(). + - setup() has been called. Specifically, setup() has been called like this: + this->setup(data, filters_gradient, stride_y, stride_x, padding_y, padding_x); + - gradient_input has the following dimensions: + - gradient_input.num_samples() == data.num_samples() + - gradient_input.k() == filters.num_samples() + - gradient_input.nr() == 1+(data.nr() + 2*padding_y - filters.nr())/stride_y + - gradient_input.nc() == 1+(data.nc() + 2*padding_x - filters.nc())/stride_x + - NOTE, these dimensions are what you would obtain if gradient_input + has the same dimensions as the last output of operator(). + - is_same_object(filters_gradient,data) == false + - is_same_object(filters_gradient,gradient_input) == false + ensures + - let OUT be the output of (*this)(OUT,data,filters,sx,sy). + - let f(data,filters) == dot(OUT, gradient_input) + - if (add_to_output) then + - This function finds the gradient of f() with respect to filters and + adds this gradient to filters_gradient. + - else + - This function finds the gradient of f() with respect to filters and + assigns this gradient to filters_gradient, overwriting the previous + values in filters_gradient. + !*/ + + + void setup( + const tensor& data, + const tensor& filters, + int stride_y, + int stride_x, + int padding_y, + int padding_x + ) {impl.setup(data,filters,stride_y,stride_x,padding_y,padding_x); } + /*! + requires + - filters.k() == data.k() + - stride_y > 0 + - stride_x > 0 + - 0 <= padding_y < filters.nr() + - 0 <= padding_x < filters.nc() + ensures + - When operator() is called, the output tensor will have these dimensions: + - output.nr() == 1+(data.nr() + 2*padding_y - filters.nr())/stride_y + - output.nc() == 1+(data.nc() + 2*padding_x - filters.nc())/stride_x + - output.num_samples() == data.num_samples() + - output.k() == filters.num_samples() + - The point of setup() is to allow this object to gather information about + all the tensor sizes and filter layouts involved in the computation. In + particular, the reason the tensors are input into setup() is just to + observe their sizes. setup() doesn't do anything with the contents of + the tensors, or store any kind of references to the data or filter + tensors. + !*/ + + private: +#ifdef DLIB_USE_CUDA + cuda::tensor_conv impl; +#else + cpu::tensor_conv impl; +#endif + + }; + +// ---------------------------------------------------------------------------------------- + + class pooling + { + /*! + WHAT THIS OBJECT REPRESENTS + The pooling object is a tool for performing spatial pooling over a tensor. + It can be configured to do either max or average pooling. + !*/ + public: + + pooling(const pooling&) = delete; + pooling& operator=(const pooling&) = delete; + + pooling ( + ) = default; + + void clear( + ) { impl.clear(); } + + void setup_max_pooling( + int window_height, + int window_width, + int stride_y, + int stride_x, + int padding_y, + int padding_x + ) { impl.setup_max_pooling(window_height, window_width, stride_y, stride_x, padding_y, padding_x); } + /*! + requires + - window_height > 0 + - window_width > 0 + - stride_y > 0 + - stride_x > 0 + - 0 <= padding_y < window_height + - 0 <= padding_x < window_width + ensures + - When you call operator() it will do max pooling with the given + parameters. + !*/ + + void setup_avg_pooling( + int window_height, + int window_width, + int stride_y, + int stride_x, + int padding_y, + int padding_x + ) { impl.setup_avg_pooling(window_height, window_width, stride_y, stride_x, padding_y, padding_x); } + /*! + requires + - window_height > 0 + - window_width > 0 + - stride_y > 0 + - stride_x > 0 + - 0 <= padding_y < window_height + - 0 <= padding_x < window_width + ensures + - When you call operator() it will do average pooling with the given + parameters. + !*/ + + bool does_max_pooling( + ) const { return impl.does_max_pooling(); } + + void operator() ( + resizable_tensor& dest, + const tensor& src + ) { impl(dest, src); } + /*! + requires + - is_same_object(dest,src) == false + - either setup_max_pooling() or setup_avg_pooling() has been called. + - window_width <= src.nc() + 2*padding_x + - window_height <= src.nr() + 2*padding_y + ensures + - #dest.num_samples() == src.num_samples() + - #dest.k() == src.k() + - #dest.nr() == 1 + (src.nr() + 2*padding_y - window_height)/stride_y + - #dest.nc() == 1 + (src.nc() + 2*padding_x - window_width)/stride_x + - WINDOW == centered_rect(x*stride_x + window_width/2 - padding_x, + y*stride_y + window_height/2 - padding_y, + window_width, + window_height) + - for all valid s, k, r, and c: + - if (does_max_pooling()) then + - image_plane(#dest,s,k)(r,c) == max(subm_clipped(image_plane(src,s,k),WINDOW(c,r))) + - else + - image_plane(#dest,s,k)(r,c) == mean(subm_clipped(image_plane(src,s,k),WINDOW(c,r))) + !*/ + + void get_gradient( + const tensor& gradient_input, + const tensor& dest, + const tensor& src, + tensor& grad + ) { impl.get_gradient(gradient_input, dest, src, grad); } + /*! + requires + - have_same_dimensions(gradient_input,dest) == true + - have_same_dimensions(src,grad) == true + - dest contains the result of calling (*this)(dest,src) + - is_same_object(grad,gradient_input) == false + - is_same_object(grad,dest) == false + - is_same_object(grad,src) == false + ensures + - Recalling that dest is the output of (*this)(dest,src), + let f(src) == dot(gradient_input,dest) + - Then this function computes the gradient of f() with respect to src and + adds it to grad. + !*/ + + private: +#ifdef DLIB_USE_CUDA + cuda::pooling impl; +#else + cpu::pooling impl; +#endif + }; + +// ---------------------------------------------------------------------------------------- + + void softmax ( + tensor& dest, + const tensor& src + ); + /*! + requires + - have_same_dimensions(dest, src) == true + ensures + - Note that the softmax function is a vector valued function: + s(x) == exp(x)/sum(exp(x)) + - Computes the softmax function on src and writes the results to dest. The + softmax is computed per spatial location across the different channels at + each location. That is, softmax() outputs a new tensor, #dest, where each of + the spatial locations in dest (i.e. image idx, row idx, and column idx) + contains the output of s() evaluated over the channel values at each + location. + - This function supports in-place operation, i.e. having + is_same_object(dest, src)==true + !*/ + + void softmax_gradient ( + tensor& grad, + const tensor& dest, + const tensor& gradient_input + ); + /*! + requires + - have_same_dimensions(dest,gradient_input) == true + - have_same_dimensions(dest,grad) == true + ensures + - We interpret dest as the output of softmax(dest,SRC) for some SRC tensor. + Then let f(SRC) == dot(gradient_input,dest). Then this function computes the + gradient of f() with respect to SRC and stores it to grad. Moreover, if + is_same_object(grad,gradient_input)==true then the output is assigned to + grad, replacing its previous contents. Otherwise the output is added to + grad. + - This function supports in-place operation, i.e. having + is_same_object(grad, gradient_input)==true + !*/ + +// ---------------------------------------------------------------------------------------- + + void softmax_all ( + tensor& dest, + const tensor& src + ); + /*! + requires + - have_same_dimensions(dest, src) == true + ensures + - Note that the softmax function is a vector valued function: + s(x) == exp(x)/sum(exp(x)) + - Computes the softmax function on src and writes the results to dest. The + softmax is computed over the entire tensor with one invocation of s(). So + unlike softmax() which computes many s() evaluations, one for each spatial + location, softmax_all() calls s() once for the entire tensor. + - This function supports in-place operation, i.e. having + is_same_object(dest, src)==true + !*/ + + void softmax_all_gradient ( + tensor& grad, + const tensor& dest, + const tensor& gradient_input + ); + /*! + requires + - have_same_dimensions(dest,gradient_input) == true + - have_same_dimensions(dest,grad) == true + - is_same_object(grad, dest)==false + ensures + - We interpret dest as the output of softmax_all(dest,SRC) for some SRC tensor. + Then let f(SRC) == dot(gradient_input,dest) Then this function computes the + gradient of f() with respect to SRC and assigns it to grad. + - This function supports in-place operation, i.e. having + is_same_object(grad, gradient_input)==true + !*/ + +// ---------------------------------------------------------------------------------------- + + void sigmoid ( + tensor& dest, + const tensor& src + ); + /*! + requires + - have_same_dimensions(dest, src) == true + ensures + - for all valid i: + - #dest.host()[i] == 1/(1+std::exp(-src.host()[i])) + - This function supports in-place operation, i.e. having + is_same_object(dest, src)==true + !*/ + + void sigmoid_gradient ( + tensor& grad, + const tensor& dest, + const tensor& gradient_input + ); + /*! + requires + - have_same_dimensions(dest,gradient_input) == true + - have_same_dimensions(dest,grad) == true + ensures + - Recalling that dest is the output of sigmoid(dest,SRC) for some SRC tensor, + let f(SRC) == dot(gradient_input,dest). Then this function computes the + gradient of f() with respect to SRC and stores it to grad. Moreover, if + is_same_object(grad,gradient_input)==true then the output is assigned to + grad, replacing its previous contents. Otherwise the output is added to + grad. + - This function supports in-place operation, i.e. having + is_same_object(grad, gradient_input)==true + !*/ + +// ---------------------------------------------------------------------------------------- + + void relu ( + tensor& dest, + const tensor& src + ); + /*! + requires + - have_same_dimensions(dest, src) == true + ensures + - for all valid i: + - #dest.host()[i] == std::max(0,src.host()[i]) + - This function supports in-place operation, i.e. having + is_same_object(dest, src)==true + !*/ + + void relu_gradient ( + tensor& grad, + const tensor& dest, + const tensor& gradient_input + ); + /*! + requires + - have_same_dimensions(dest,gradient_input) == true + - have_same_dimensions(dest,grad) == true + ensures + - Recalling that dest is the output of relu(dest,SRC) for some SRC tensor, + let f(SRC) == dot(gradient_input,dest). Then this function computes the + gradient of f() with respect to SRC and stores it to grad. Moreover, if + is_same_object(grad,gradient_input)==true then the output is assigned to + grad, replacing its previous contents. Otherwise the output is added to + grad. + - This function supports in-place operation, i.e. having + is_same_object(grad, gradient_input)==true + !*/ + +// ---------------------------------------------------------------------------------------- + + void prelu ( + tensor& dest, + const tensor& src, + const tensor& param + ); + /*! + requires + - have_same_dimensions(dest, src) == true + - param.size() == 1 + ensures + - for all valid i: + - if (src.host()[i] > 0) then + - #dest.host()[i] == src.host()[i] + - else + - #dest.host()[i] == src.host()[i] * param.host()[0] + - This function supports in-place operation, i.e. having + is_same_object(dest, src)==true + !*/ + + void prelu_gradient ( + tensor& grad, + const tensor& src, + const tensor& gradient_input, + const tensor& param, + tensor& params_grad + ); + /*! + requires + - have_same_dimensions(grad,src) == true + - have_same_dimensions(grad,gradient_input) == true + - param.size() == 1 + - params_grad.size() == 1 + - is_same_object(grad, gradient_input) == false + ensures + - Recalling that dest is the output of prelu(dest,src,param) let + f(src,param) == dot(gradient_input,dest) + - Then this function computes the gradient of f() with respect to src and + param. It assigns the gradient with respect to param to #params_grad and + adds the gradient with respect to src to #grad. + !*/ + +// ---------------------------------------------------------------------------------------- + + void tanh ( + tensor& dest, + const tensor& src + ); + /*! + requires + - have_same_dimensions(dest, src) == true + ensures + - for all valid i: + - #dest.host()[i] == std::tanh(src.host()[i]) + - This function supports in-place operation, i.e. having + is_same_object(dest, src)==true + !*/ + + void tanh_gradient ( + tensor& grad, + const tensor& dest, + const tensor& gradient_input + ); + /*! + requires + - have_same_dimensions(dest,gradient_input) == true + - have_same_dimensions(dest,grad) == true + ensures + - Recalling that dest is the output of tanh(dest,SRC) for some SRC tensor, + let f(SRC) == dot(gradient_input,dest). Then this function computes the + gradient of f() with respect to SRC and stores it to grad. Moreover, if + is_same_object(grad,gradient_input)==true then the output is assigned to + grad, replacing its previous contents. Otherwise the output is added to + grad. + - This function supports in-place operation, i.e. having + is_same_object(grad, gradient_input)==true + !*/ + +// ---------------------------------------------------------------------------------------- + + void resize_bilinear ( + tensor& dest, + long dest_row_stride, + long dest_channel_stride, + const tensor& src, + long src_row_stride, + long src_channel_stride + ); + /*! + requires + - is_same_object(dest, src)==false + - dest.num_samples() == src.num_samples() + - dest.k() == src.k() + ensures + - for all valid i,k: image_plane(dest,i,k) is a copy of image_plane(src,i,k) + that has been bilinearly interpolated to fit into the shape of + image_plane(dest,i,k). + - Instead of supposing the row stride and channel stride in the tensors is + given by tensor::nc() and tensor::nr()*tensor::nc() respectively, we use the + provided stride values to transition from one row and channel to the next. + This is useful in combination with alias_tensor objects since it allows you + to operate on subwindows in an image. + !*/ + + void resize_bilinear_gradient ( + tensor& grad, + long grad_row_stride, + long grad_channel_stride, + const tensor& gradient_input, + long gradient_input_row_stride, + long gradient_input_channel_stride + ); + /*! + requires + - is_same_object(grad, gradient_input)==false + - gradient_input.num_samples() == grad.num_samples() + - gradient_input.k() == grad.k() + ensures + - Suppose that DEST is the output of resize_bilinear(DEST,SRC) for some SRC + tensor, let f(SRC) == dot(gradient_input,DEST). Then this function computes + the gradient of f() with respect to SRC and adds it to grad. It should be + noted that we don't need to know the contents of DEST to compute this + gradient. All that matters is that gradient_input have the same dimensions + as DEST. + - Instead of supposing the row stride and channel stride in the tensors is + given by tensor::nc() and tensor::nr()*tensor::nc() respectively, we use the + provided stride values to transition from one row and channel to the next. + This is useful in combination with alias_tensor objects since it allows you + to operate on subwindows in an image. + !*/ + + inline void resize_bilinear ( + tensor& dest, + const tensor& src + ) { resize_bilinear(dest, dest.nc(), dest.nr()*dest.nc(), src, src.nc(), src.nr()*src.nc()); } + /*! + requires + - is_same_object(dest, src)==false + - dest.num_samples() == src.num_samples() + - dest.k() == src.k() + ensures + - for all valid i,k: image_plane(dest,i,k) is a copy of image_plane(src,i,k) + that has been bilinearly interpolated to fit into the shape of + image_plane(dest,i,k). + !*/ + + inline void resize_bilinear_gradient ( + tensor& grad, + const tensor& gradient_input + ) { resize_bilinear_gradient(grad, grad.nc(), grad.nr()*grad.nc(), gradient_input, gradient_input.nc(), gradient_input.nr()*gradient_input.nc()); } + /*! + requires + - is_same_object(grad, gradient_input)==false + - gradient_input.num_samples() == grad.num_samples() + - gradient_input.k() == grad.k() + ensures + - Suppose that DEST is the output of resize_bilinear(DEST,SRC) for some SRC + tensor, let f(SRC) == dot(gradient_input,DEST). Then this function computes + the gradient of f() with respect to SRC and adds it to grad. It should be + noted that we don't need to know the contents of DEST to compute this + gradient. All that matters is that gradient_input have the same dimensions + as DEST. + !*/ + +// ---------------------------------------------------------------------------------------- + + class multi_device_tensor_averager + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a tool for very quickly averaging a bunch of tensors + together. + !*/ + public: + + multi_device_tensor_averager(const multi_device_tensor_averager&) = delete; + multi_device_tensor_averager& operator=(const multi_device_tensor_averager&) = delete; + + multi_device_tensor_averager() = default; + + void set( + std::vector items + ) + /*! + requires + - All the tensors in items are the same size + ensures + - When you call average() we will average the tensors in items. + - It's important that the tensors already be allocated to their devices + before you call set(). This is because set() will setup the types of + between device transfers now and use them when you call average(). + !*/ + { + using namespace ::dlib::cuda; + accessible_groups.clear(); + epa.clear(); + if (items.size() < 1) + return; + + scale = 1.0/items.size(); + + // split item into groups of accessible devices + std::vector group, unused; + while(items.size() > 0) + { + group.push_back(items[0]); + for(size_t i = 1; i < items.size(); ++i) + { + if (can_access_peer(*items[0], *items[i])) + group.push_back(items[i]); + else + unused.push_back(items[i]); + } + accessible_groups.push_back(group); + unused.swap(items); + unused.clear(); + group.clear(); + } + for (auto&& g : accessible_groups) + { + for (size_t i = 1; i < g.size(); ++i) + { + epa.emplace_back(new enable_peer_access(*g[0], *g[i])); + } + } + } + + size_t num_device_groups( + ) const { return accessible_groups.size(); } + /*! + ensures + - The devices given to set() are grouped together when they can directly + access each other using GPUDirect. This function returns the number of + such groups. For example, if all devices can directly access each other + then the number of groups is 1. + !*/ + + void average() + /*! + requires + - All the devices have stopped writing to the tensors given to set(). So + you should probably call cudaDeviceSynchronize() on each of the relevant + devices before calling average(). + ensures + - Computes the average of all the tensors given to set() and then sets them + all equal to the average. + !*/ + { + using namespace ::dlib::cuda; + + + // First we average things within each group + for (auto&& g : accessible_groups) + { + raii_set_device set_dev(*g[0]); + if (g.size() == 1) + tt::affine_transform(*g[0], *g[0], scale); + else + tt::affine_transform(*g[0], *g[0], *g[1], scale, scale); + + for (size_t i = 2; i < g.size(); ++i) + tt::affine_transform(*g[0], *g[0], *g[i], 1, scale); + } + + if (accessible_groups.size() > 1) + { + tensor& total_avg = *accessible_groups[0][0]; + raii_set_device set_dev(total_avg); + accum_buffer.copy_size(total_avg); + // now we need to average things across groups + for (size_t i = 1; i < accessible_groups.size(); ++i) + { + memcpy(accum_buffer, *accessible_groups[i][0]); + tt::add(total_avg, total_avg, accum_buffer); + } + + // Now total_avg has the final average in it. So we need to send + // copies of it back to each of the groups. + for (size_t i = 1; i < accessible_groups.size(); ++i) + { + memcpy(*accessible_groups[i][0], total_avg); + } + } + + + // Now propagate averages back out to each element using point to point + // communication inside a group. + for (auto&& g : accessible_groups) + { + raii_set_device set_dev(*g[0]); + for (size_t i = 1; i < g.size(); ++i) + memcpy(*g[i], *g[0]); + } + } + + private: + std::vector> epa; + std::vector> accessible_groups; + float scale; + + resizable_tensor accum_buffer; + }; + +// ---------------------------------------------------------------------------------------- + + void copy_tensor( + bool add_to, + tensor& dest, + size_t dest_k_offset, + const tensor& src, + size_t src_k_offset, + size_t count_k + ); + /*! + requires + - dest.nc() == src.nc() + - dest.nr() == src.nr() + - dest.num_samples() == src.num_samples() + - dest.k() - dest_k_offset >= count_k + - src.k() - src_k_offset >= count_k + - is_same_object(dest,src) == false + - The memory areas of src and dest do not overlap. + ensures + - if (add_to) then + - performs: dest[i, k + dest_k_offset, r, c] += src[i, k + src_k_offset, r, c], where k in [0..count_k] + i.e., adds content of each sample from src in to corresponding place of sample at dest. + - else + - performs: dest[i, k + dest_k_offset, r, c] = src[i, k + src_k_offset, r, c], where k in [0..count_k] + i.e., copies content of each sample from src in to corresponding place of sample at dest. + !*/ + +// ---------------------------------------------------------------------------------------- + +}} + +#ifdef NO_MAKEFILE +#include "tensor_tools.cpp" +#endif + +#endif // DLIB_TeNSOR_TOOLS_H_ + + diff --git a/lib/3rdParty/dlib/include/dlib/data_io.h b/lib/3rdParty/dlib/include/dlib/data_io.h index 171caa06..845e95f4 100644 --- a/lib/3rdParty/dlib/include/dlib/data_io.h +++ b/lib/3rdParty/dlib/include/dlib/data_io.h @@ -5,6 +5,7 @@ #include "data_io/libsvm_io.h" #include "data_io/image_dataset_metadata.h" +#include "data_io/mnist.h" #ifndef DLIB_ISO_CPP_ONLY #include "data_io/load_image_dataset.h" diff --git a/lib/3rdParty/dlib/include/dlib/data_io/image_dataset_metadata.cpp b/lib/3rdParty/dlib/include/dlib/data_io/image_dataset_metadata.cpp deleted file mode 100644 index 7e958175..00000000 --- a/lib/3rdParty/dlib/include/dlib/data_io/image_dataset_metadata.cpp +++ /dev/null @@ -1,387 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_IMAGE_DAtASET_METADATA_CPPh_ -#define DLIB_IMAGE_DAtASET_METADATA_CPPh_ - -#include "image_dataset_metadata.h" - -#include -#include -#include "../compress_stream.h" -#include "../base64.h" -#include "../xml_parser.h" -#include "../string.h" - -// ---------------------------------------------------------------------------------------- - -namespace dlib -{ - namespace image_dataset_metadata - { - - // ------------------------------------------------------------------------------------ - - const std::string get_decoded_string(); - void create_image_metadata_stylesheet_file(const std::string& main_filename) - { - std::string path; - std::string::size_type pos = main_filename.find_last_of("/\\"); - if (pos != std::string::npos) - path = main_filename.substr(0,pos+1); - - std::ofstream fout((path + "image_metadata_stylesheet.xsl").c_str()); - if (!fout) - throw dlib::error("ERROR: Unable to open image_metadata_stylesheet.xsl for writing."); - - fout << get_decoded_string(); - - if (!fout) - throw dlib::error("ERROR: Unable to write to image_metadata_stylesheet.xsl."); - } - - void save_image_dataset_metadata ( - const dataset& meta, - const std::string& filename - ) - { - create_image_metadata_stylesheet_file(filename); - - const std::vector& images = meta.images; - - std::ofstream fout(filename.c_str()); - if (!fout) - throw dlib::error("ERROR: Unable to open " + filename + " for writing."); - - fout << "\n"; - fout << "\n"; - fout << "\n"; - fout << "" << meta.name << "\n"; - fout << "" << meta.comment << "\n"; - fout << "\n"; - for (unsigned long i = 0; i < images.size(); ++i) - { - fout << " \n"; - - // save all the boxes - for (unsigned long j = 0; j < images[i].boxes.size(); ++j) - { - const box& b = images[i].boxes[j]; - fout << " \n"; - - if (b.has_label()) - fout << " \n"; - - // save all the parts - std::map::const_iterator itr; - for (itr = b.parts.begin(); itr != b.parts.end(); ++itr) - { - fout << " \n"; - } - - fout << " \n"; - } - else - { - fout << "/>\n"; - } - } - - - - fout << " \n"; - - if (!fout) - throw dlib::error("ERROR: Unable to write to " + filename + "."); - } - fout << "\n"; - fout << ""; - } - - // ------------------------------------------------------------------------------------ - // ------------------------------------------------------------------------------------ - // ------------------------------------------------------------------------------------ - - class doc_handler : public document_handler - { - std::vector ts; - image temp_image; - box temp_box; - - dataset& meta; - - public: - - doc_handler( - dataset& metadata_ - ): - meta(metadata_) - {} - - - virtual void start_document ( - ) - { - meta = dataset(); - ts.clear(); - temp_image = image(); - temp_box = box(); - } - - virtual void end_document ( - ) - { - } - - virtual void start_element ( - const unsigned long line_number, - const std::string& name, - const dlib::attribute_list& atts - ) - { - try - { - if (ts.size() == 0) - { - if (name != "dataset") - { - std::ostringstream sout; - sout << "Invalid XML document. Root tag must be . Found <" << name << "> instead."; - throw dlib::error(sout.str()); - } - else - { - ts.push_back(name); - return; - } - } - - - if (name == "box") - { - if (atts.is_in_list("top")) temp_box.rect.top() = sa = atts["top"]; - else throw dlib::error(" missing required attribute 'top'"); - - if (atts.is_in_list("left")) temp_box.rect.left() = sa = atts["left"]; - else throw dlib::error(" missing required attribute 'left'"); - - if (atts.is_in_list("width")) temp_box.rect.right() = sa = atts["width"]; - else throw dlib::error(" missing required attribute 'width'"); - - if (atts.is_in_list("height")) temp_box.rect.bottom() = sa = atts["height"]; - else throw dlib::error(" missing required attribute 'height'"); - - if (atts.is_in_list("difficult")) temp_box.difficult = sa = atts["difficult"]; - if (atts.is_in_list("truncated")) temp_box.truncated = sa = atts["truncated"]; - if (atts.is_in_list("occluded")) temp_box.occluded = sa = atts["occluded"]; - if (atts.is_in_list("ignore")) temp_box.ignore = sa = atts["ignore"]; - if (atts.is_in_list("angle")) temp_box.angle = sa = atts["angle"]; - - temp_box.rect.bottom() += temp_box.rect.top()-1; - temp_box.rect.right() += temp_box.rect.left()-1; - } - else if (name == "part" && ts.back() == "box") - { - point temp; - if (atts.is_in_list("x")) temp.x() = sa = atts["x"]; - else throw dlib::error(" missing required attribute 'x'"); - - if (atts.is_in_list("y")) temp.y() = sa = atts["y"]; - else throw dlib::error(" missing required attribute 'y'"); - - if (atts.is_in_list("name")) - { - if (temp_box.parts.count(atts["name"])==0) - { - temp_box.parts[atts["name"]] = temp; - } - else - { - throw dlib::error(" with name '" + atts["name"] + "' is defined more than one time in a single box."); - } - } - else - { - throw dlib::error(" missing required attribute 'name'"); - } - } - else if (name == "image") - { - temp_image.boxes.clear(); - - if (atts.is_in_list("file")) temp_image.filename = atts["file"]; - else throw dlib::error(" missing required attribute 'file'"); - } - - ts.push_back(name); - } - catch (error& e) - { - throw dlib::error("Error on line " + cast_to_string(line_number) + ": " + e.what()); - } - } - - virtual void end_element ( - const unsigned long , - const std::string& name - ) - { - ts.pop_back(); - if (ts.size() == 0) - return; - - if (name == "box" && ts.back() == "image") - { - temp_image.boxes.push_back(temp_box); - temp_box = box(); - } - else if (name == "image" && ts.back() == "images") - { - meta.images.push_back(temp_image); - temp_image = image(); - } - } - - virtual void characters ( - const std::string& data - ) - { - if (ts.size() == 2 && ts[1] == "name") - { - meta.name = trim(data); - } - else if (ts.size() == 2 && ts[1] == "comment") - { - meta.comment = trim(data); - } - else if (ts.size() >= 2 && ts[ts.size()-1] == "label" && - ts[ts.size()-2] == "box") - { - temp_box.label = trim(data); - } - } - - virtual void processing_instruction ( - const unsigned long , - const std::string& , - const std::string& - ) - { - } - }; - - // ---------------------------------------------------------------------------------------- - - class xml_error_handler : public error_handler - { - public: - virtual void error ( - const unsigned long - ) { } - - virtual void fatal_error ( - const unsigned long line_number - ) - { - std::ostringstream sout; - sout << "There is a fatal error on line " << line_number << " so parsing will now halt."; - throw dlib::error(sout.str()); - } - }; - - // ------------------------------------------------------------------------------------ - - void load_image_dataset_metadata ( - dataset& meta, - const std::string& filename - ) - { - xml_error_handler eh; - doc_handler dh(meta); - - std::ifstream fin(filename.c_str()); - if (!fin) - throw dlib::error("ERROR: unable to open " + filename + " for reading."); - - xml_parser parser; - parser.add_document_handler(dh); - parser.add_error_handler(eh); - parser.parse(fin); - } - - // ------------------------------------------------------------------------------------ - // ------------------------------------------------------------------------------------ - // ------------------------------------------------------------------------------------ - - // This function returns the contents of the file 'images.xsl' - const std::string get_decoded_string() - { - dlib::base64 base64_coder; - dlib::compress_stream::kernel_1ea compressor; - std::ostringstream sout; - std::istringstream sin; - - // The base64 encoded data from the file 'image_metadata_stylesheet.xsl' we want to decode and return. - sout << "PFWfgmWfCHr1DkV63lbjjeY2dCc2FbHDOVh0Kd7dkvaOfRYrOG24f0x77/5iMVq8FtE3UBxtGwSd"; - sout << "1ZHOHRSHgieNoeBv8ssJQ75RRxYtFKRY3OTPX5eKQoCN9jUaUnHnR4QZtEHgmKqXSs50Yrdd+2Ah"; - sout << "gNyarPZCiR6nvqNvCjtP2MP5FxleqNf8Fylatm2KdsXmrv5K87LYVN7i7JMkmZ++cTXYSOxDmxZi"; - sout << "OiCH8funXUdF9apDW547gCjz9HOQUI6dkz5dYUeFjfp6dFugpnaJyyprFLKq048Qk7+QiL4CNF/G"; - sout << "7e0VpBw8dMpiyRNi2fSQGSZGfIAUQKKT6+rPwQoRH2spdjsdXVWj4XQAqBX87nmqMnqjMhn/Vd1s"; - sout << "W5aoC0drwRGu3Xe3gn9vBL8hBkRXcJvEy6q/lb9bYnsLemhE5Zp/+nTmTBjfT9UFYLcsmgsjON9M"; - sout << "gbE5Q8tCa+WXXXsVP1ai5tLU3G1RUjctr/VtV55PKl2xKjjgb4zDldHKrKFQ23NkQR94PFHG25WM"; - sout << "a/VSFVSzLJWdeV/SK3uDq/zUdwQ1JohWp2i+0vJuTXNGCmyT3zHxqtue3HcEw7OpGIDQ+EN0nPCV"; - sout << "90Seu55zuS14zuWdRfXln3/g/hiA7Jj72Ah8Kiz3F3gwCfFbyFaMDYTbT4sda0fDkx1M9sKJ2pN8"; - sout << "3Jd7T8SU+Rk2/oDc8RuTTbFaRvulLWHfdLGPuIJpLT7FUkxGpdlIvxPypjGf0wVA8kgcYGgoKLIX"; - sout << "uUgWFEvqwDJtxvOYVApV2foeOMgfw53TRiFDqwxmaYC41gB32cGgKYuC90mmqGY1MWAD0KLl5+bF"; - sout << "GQiRmckXmDmowK5cxibnB5nTyJX1LmXaqkHFFNGPfidznTHoSqtlAF4wnCyBMuCAdgJgC0AF5gr4"; - sout << "1KNWDg042CVs3li6Nep6G9arGOkEcL7vWamNC9vvkYwOWidjDFqINBxEWGTRQCyG9RDzPX2dckEh"; - sout << "jWYwrXDOFyBNbac16Yym1ftn322+sE+RnaXq9WIoTGnrK/A1paSzdCjpfiIAAizaRnwoa6Ue9xnZ"; - sout << "HvSSQetmzyOErvK6IOWu2VwvqO3aOC28RP63JEztmiT7pF+Zl0NMHVWgW13WejABamVXvjDAlMSA"; - sout << "iBKSBqTuyC0YbuNk14G2MfQE0pg1QrAHhOi9u2KsTRN56381lxxqAhEEGvI/h+ONsveGuuDjXgcy"; - sout << "wvObjIKOawnh820yMrPBzDOx/ExSJtwqbWXBc0MGZxLXA3OgfeKsoaGB/OSB3AznJd40B1ktnmXO"; - sout << "pThos8Tl3Cs6xxFdFhob0vf3ml6WumTtNnAA"; - - - - // Put the data into the istream sin - sin.str(sout.str()); - sout.str(""); - - // Decode the base64 text into its compressed binary form - base64_coder.decode(sin,sout); - sin.clear(); - sin.str(sout.str()); - sout.str(""); - - // Decompress the data into its original form - compressor.decompress(sin,sout); - - // Return the decoded and decompressed data - return sout.str(); - } - - - } -} - -// ---------------------------------------------------------------------------------------- - -#endif // DLIB_IMAGE_DAtASET_METADATA_CPPh_ - - diff --git a/lib/3rdParty/dlib/include/dlib/data_io/image_dataset_metadata.h b/lib/3rdParty/dlib/include/dlib/data_io/image_dataset_metadata.h index b052ed1c..3dac29ba 100644 --- a/lib/3rdParty/dlib/include/dlib/data_io/image_dataset_metadata.h +++ b/lib/3rdParty/dlib/include/dlib/data_io/image_dataset_metadata.h @@ -14,6 +14,15 @@ namespace dlib namespace image_dataset_metadata { + // ------------------------------------------------------------------------------------ + + enum gender_t + { + UNKNOWN, + MALE, + FEMALE + }; + // ------------------------------------------------------------------------------------ struct box @@ -34,7 +43,11 @@ namespace dlib truncated(false), occluded(false), ignore(false), - angle(0) + pose(0), + detection_score(0), + angle(0), + gender(UNKNOWN), + age(0) {} box ( @@ -45,7 +58,11 @@ namespace dlib truncated(false), occluded(false), ignore(false), - angle(0) + pose(0), + detection_score(0), + angle(0), + gender(UNKNOWN), + age(0) {} rectangle rect; @@ -58,6 +75,8 @@ namespace dlib bool truncated; bool occluded; bool ignore; + double pose; + double detection_score; // The angle of the object in radians. Positive values indicate that the // object at the center of the box is rotated clockwise by angle radians. A @@ -66,6 +85,9 @@ namespace dlib // image counter-clockwise by angle radians. double angle; + gender_t gender; + double age; + bool has_label() const { return label.size() != 0; } /*! ensures diff --git a/lib/3rdParty/dlib/include/dlib/data_io/libsvm_io.h b/lib/3rdParty/dlib/include/dlib/data_io/libsvm_io.h index 875639b9..f365e82d 100644 --- a/lib/3rdParty/dlib/include/dlib/data_io/libsvm_io.h +++ b/lib/3rdParty/dlib/include/dlib/data_io/libsvm_io.h @@ -85,12 +85,14 @@ namespace dlib if (sin.get() != ':') throw sample_data_io_error("On line: " + cast_to_string(line_num) + ", error while reading file " + file_name); - sin >> value >> ws; + sin >> value; if (sin && value != 0) { sample.insert(sample.end(), make_pair(key, value)); } + + sin >> ws; } samples.push_back(sample); diff --git a/lib/3rdParty/dlib/include/dlib/data_io/load_image_dataset.h b/lib/3rdParty/dlib/include/dlib/data_io/load_image_dataset.h index 52ab5920..5664d96b 100644 --- a/lib/3rdParty/dlib/include/dlib/data_io/load_image_dataset.h +++ b/lib/3rdParty/dlib/include/dlib/data_io/load_image_dataset.h @@ -14,6 +14,9 @@ #include #include #include "../image_processing/full_object_detection.h" +#include +#include +#include "../image_transforms/image_pyramid.h" namespace dlib @@ -29,6 +32,7 @@ namespace dlib _skip_empty_images = false; _have_parts = false; _filename = filename; + _box_area_thresh = std::numeric_limits::infinity(); } image_dataset_file boxes_match_label( @@ -56,6 +60,15 @@ namespace dlib return temp; } + image_dataset_file shrink_big_images( + double new_box_area_thresh = 150*150 + ) const + { + image_dataset_file temp(*this); + temp._box_area_thresh = new_box_area_thresh; + return temp; + } + bool should_load_box ( const image_dataset_metadata::box& box ) const @@ -72,6 +85,7 @@ namespace dlib const std::string& get_filename() const { return _filename; } bool should_skip_empty_images() const { return _skip_empty_images; } bool should_boxes_have_parts() const { return _have_parts; } + double box_area_thresh() const { return _box_area_thresh; } const std::set& get_selected_box_labels() const { return _labels; } private: @@ -79,23 +93,23 @@ namespace dlib std::set _labels; bool _skip_empty_images; bool _have_parts; + double _box_area_thresh; + }; // ---------------------------------------------------------------------------------------- template < - typename image_type, - typename MM + typename array_type > std::vector > load_image_dataset ( - array& images, + array_type& images, std::vector >& object_locations, const image_dataset_file& source ) { images.clear(); object_locations.clear(); - const std::string old_working_dir = get_current_dir(); std::vector > ignored_rects; @@ -106,15 +120,17 @@ namespace dlib // Set the current directory to be the one that contains the // metadata file. We do this because the file might contain // file paths which are relative to this folder. - set_current_dir(get_parent_directory(file(source.get_filename()))); + locally_change_current_dir chdir(get_parent_directory(file(source.get_filename()))); + typedef typename array_type::value_type image_type; image_type img; std::vector rects, ignored; for (unsigned long i = 0; i < data.images.size(); ++i) { + double min_rect_size = std::numeric_limits::infinity(); rects.clear(); ignored.clear(); for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j) @@ -122,25 +138,147 @@ namespace dlib if (source.should_load_box(data.images[i].boxes[j])) { if (data.images[i].boxes[j].ignore) + { ignored.push_back(data.images[i].boxes[j].rect); + } else + { rects.push_back(data.images[i].boxes[j].rect); + min_rect_size = std::min(min_rect_size, rects.back().area()); + } } } if (!source.should_skip_empty_images() || rects.size() != 0) { + load_image(img, data.images[i].filename); + if (rects.size() != 0) + { + // if shrinking the image would still result in the smallest box being + // bigger than the box area threshold then shrink the image. + while(min_rect_size/2/2 > source.box_area_thresh()) + { + pyramid_down<2> pyr; + pyr(img); + min_rect_size *= (1.0/2.0)*(1.0/2.0); + for (auto&& r : rects) + r = pyr.rect_down(r); + for (auto&& r : ignored) + r = pyr.rect_down(r); + } + while(min_rect_size*(2.0/3.0)*(2.0/3.0) > source.box_area_thresh()) + { + pyramid_down<3> pyr; + pyr(img); + min_rect_size *= (2.0/3.0)*(2.0/3.0); + for (auto&& r : rects) + r = pyr.rect_down(r); + for (auto&& r : ignored) + r = pyr.rect_down(r); + } + } + images.push_back(img); object_locations.push_back(rects); ignored_rects.push_back(ignored); - load_image(img, data.images[i].filename); - images.push_back(img); } } - set_current_dir(old_working_dir); return ignored_rects; } +// ---------------------------------------------------------------------------------------- + + namespace impl + { + inline size_t num_non_ignored_boxes (const std::vector& rects) + { + size_t cnt = 0; + for (auto& b : rects) + { + if (!b.ignore) + cnt++; + } + return cnt; + } + } + + template < + typename array_type + > + void load_image_dataset ( + array_type& images, + std::vector >& object_locations, + const image_dataset_file& source + ) + { + images.clear(); + object_locations.clear(); + + using namespace dlib::image_dataset_metadata; + dataset data; + load_image_dataset_metadata(data, source.get_filename()); + + // Set the current directory to be the one that contains the + // metadata file. We do this because the file might contain + // file paths which are relative to this folder. + locally_change_current_dir chdir(get_parent_directory(file(source.get_filename()))); + + typedef typename array_type::value_type image_type; + + image_type img; + std::vector rects; + for (unsigned long i = 0; i < data.images.size(); ++i) + { + double min_rect_size = std::numeric_limits::infinity(); + rects.clear(); + for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j) + { + if (source.should_load_box(data.images[i].boxes[j])) + { + if (data.images[i].boxes[j].ignore) + { + rects.push_back(ignored_mmod_rect(data.images[i].boxes[j].rect)); + } + else + { + rects.push_back(mmod_rect(data.images[i].boxes[j].rect)); + min_rect_size = std::min(min_rect_size, rects.back().rect.area()); + } + rects.back().label = data.images[i].boxes[j].label; + + } + } + + if (!source.should_skip_empty_images() || impl::num_non_ignored_boxes(rects) != 0) + { + load_image(img, data.images[i].filename); + if (rects.size() != 0) + { + // if shrinking the image would still result in the smallest box being + // bigger than the box area threshold then shrink the image. + while(min_rect_size/2/2 > source.box_area_thresh()) + { + pyramid_down<2> pyr; + pyr(img); + min_rect_size *= (1.0/2.0)*(1.0/2.0); + for (auto&& r : rects) + r.rect = pyr.rect_down(r.rect); + } + while(min_rect_size*(2.0/3.0)*(2.0/3.0) > source.box_area_thresh()) + { + pyramid_down<3> pyr; + pyr(img); + min_rect_size *= (2.0/3.0)*(2.0/3.0); + for (auto&& r : rects) + r.rect = pyr.rect_down(r.rect); + } + } + images.push_back(std::move(img)); + object_locations.push_back(std::move(rects)); + } + } + } + // ---------------------------------------------------------------------------------------- // ******* THIS FUNCTION IS DEPRECATED, you should use another version of load_image_dataset() ******* @@ -167,11 +305,10 @@ namespace dlib // ---------------------------------------------------------------------------------------- template < - typename image_type, - typename MM + typename array_type > std::vector > load_image_dataset ( - array& images, + array_type& images, std::vector >& object_locations, const std::string& filename ) @@ -179,25 +316,38 @@ namespace dlib return load_image_dataset(images, object_locations, image_dataset_file(filename)); } +// ---------------------------------------------------------------------------------------- + + template < + typename array_type + > + void load_image_dataset ( + array_type& images, + std::vector>& object_locations, + const std::string& filename + ) + { + load_image_dataset(images, object_locations, image_dataset_file(filename)); + } + // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- template < - typename image_type, - typename MM + typename array_type > std::vector > load_image_dataset ( - array& images, + array_type& images, std::vector >& object_locations, const image_dataset_file& source, std::vector& parts_list ) { + typedef typename array_type::value_type image_type; parts_list.clear(); images.clear(); object_locations.clear(); - const std::string old_working_dir = get_current_dir(); using namespace dlib::image_dataset_metadata; dataset data; @@ -206,7 +356,7 @@ namespace dlib // Set the current directory to be the one that contains the // metadata file. We do this because the file might contain // file paths which are relative to this folder. - set_current_dir(get_parent_directory(file(source.get_filename()))); + locally_change_current_dir chdir(get_parent_directory(file(source.get_filename()))); std::set all_parts; @@ -243,6 +393,7 @@ namespace dlib std::vector object_dets; for (unsigned long i = 0; i < data.images.size(); ++i) { + double min_rect_size = std::numeric_limits::infinity(); object_dets.clear(); ignored.clear(); for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j) @@ -266,20 +417,57 @@ namespace dlib } object_dets.push_back(full_object_detection(data.images[i].boxes[j].rect, partlist)); + min_rect_size = std::min(min_rect_size, object_dets.back().get_rect().area()); } } } if (!source.should_skip_empty_images() || object_dets.size() != 0) { + load_image(img, data.images[i].filename); + if (object_dets.size() != 0) + { + // if shrinking the image would still result in the smallest box being + // bigger than the box area threshold then shrink the image. + while(min_rect_size/2/2 > source.box_area_thresh()) + { + pyramid_down<2> pyr; + pyr(img); + min_rect_size *= (1.0/2.0)*(1.0/2.0); + for (auto&& r : object_dets) + { + r.get_rect() = pyr.rect_down(r.get_rect()); + for (unsigned long k = 0; k < r.num_parts(); ++k) + r.part(k) = pyr.point_down(r.part(k)); + } + for (auto&& r : ignored) + { + r = pyr.rect_down(r); + } + } + while(min_rect_size*(2.0/3.0)*(2.0/3.0) > source.box_area_thresh()) + { + pyramid_down<3> pyr; + pyr(img); + min_rect_size *= (2.0/3.0)*(2.0/3.0); + for (auto&& r : object_dets) + { + r.get_rect() = pyr.rect_down(r.get_rect()); + for (unsigned long k = 0; k < r.num_parts(); ++k) + r.part(k) = pyr.point_down(r.part(k)); + } + for (auto&& r : ignored) + { + r = pyr.rect_down(r); + } + } + } + images.push_back(img); object_locations.push_back(object_dets); ignored_rects.push_back(ignored); - load_image(img, data.images[i].filename); - images.push_back(img); } } - set_current_dir(old_working_dir); return ignored_rects; } @@ -287,11 +475,10 @@ namespace dlib // ---------------------------------------------------------------------------------------- template < - typename image_type, - typename MM + typename array_type > std::vector > load_image_dataset ( - array& images, + array_type& images, std::vector >& object_locations, const image_dataset_file& source ) @@ -303,11 +490,10 @@ namespace dlib // ---------------------------------------------------------------------------------------- template < - typename image_type, - typename MM + typename array_type > std::vector > load_image_dataset ( - array& images, + array_type& images, std::vector >& object_locations, const std::string& filename ) diff --git a/lib/3rdParty/dlib/include/dlib/data_io/load_image_dataset_abstract.h b/lib/3rdParty/dlib/include/dlib/data_io/load_image_dataset_abstract.h index 8a8637b4..b0625209 100644 --- a/lib/3rdParty/dlib/include/dlib/data_io/load_image_dataset_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/data_io/load_image_dataset_abstract.h @@ -36,6 +36,7 @@ namespace dlib This means that, initially, all boxes will be loaded. Therefore, for all possible boxes B we have: - #should_load_box(B) == true + - #box_area_thresh() == infinity !*/ const std::string& get_filename( @@ -50,8 +51,9 @@ namespace dlib ) const; /*! ensures - - returns true if we are supposed to skip images that don't have any boxes - to load when loading an image dataset using load_image_dataset(). + - returns true if we are supposed to skip images that don't have any + non-ignored boxes to load when loading an image dataset using + load_image_dataset(). !*/ image_dataset_file boxes_match_label( @@ -115,24 +117,45 @@ namespace dlib - returns false !*/ + image_dataset_file shrink_big_images( + double new_box_area_thresh = 150*150 + ) const; + /*! + ensures + - returns a copy of *this that is identical in all respects to *this except + that #box_area_thresh() == new_box_area_thresh + !*/ + + double box_area_thresh( + ) const; + /*! + ensures + - If the smallest non-ignored rectangle in an image has an area greater + than box_area_thresh() then we will shrink the image until the area of + the box is about equal to box_area_thresh(). This is useful if you have + a dataset containing very high resolution images and you don't want to + load it in its native high resolution. Setting the box_area_thresh() + allows you to control the resolution of the loaded images. + !*/ }; // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- template < - typename image_type, - typename MM + typename array_type > std::vector > load_image_dataset ( - array& images, + array_type& images, std::vector >& object_locations, const image_dataset_file& source ); /*! requires - - image_type == is an implementation of array2d/array2d_kernel_abstract.h - - pixel_traits is defined + - array_type == An array of images. This is anything with an interface that + looks like std::vector where a "generic image" is + anything that implements the generic image interface defined in + dlib/image_processing/generic_image.h. ensures - This routine loads the images and their associated object boxes from the image metadata file indicated by source.get_filename(). This metadata file @@ -162,40 +185,88 @@ namespace dlib // ---------------------------------------------------------------------------------------- template < - typename image_type, - typename MM + typename array_type > std::vector > load_image_dataset ( - array& images, + array_type& images, std::vector >& object_locations, const std::string& filename ); /*! requires - - image_type == is an implementation of array2d/array2d_kernel_abstract.h - - pixel_traits is defined + - array_type == An array of images. This is anything with an interface that + looks like std::vector where a "generic image" is + anything that implements the generic image interface defined in + dlib/image_processing/generic_image.h. ensures - performs: return load_image_dataset(images, object_locations, image_dataset_file(filename)); (i.e. it ignores box labels and therefore loads all the boxes in the dataset) !*/ +// ---------------------------------------------------------------------------------------- + + template < + typename array_type + > + void load_image_dataset ( + array_type& images, + std::vector >& object_locations, + const image_dataset_file& source + ); + /*! + requires + - array_type == An array of images. This is anything with an interface that + looks like std::vector where a "generic image" is + anything that implements the generic image interface defined in + dlib/image_processing/generic_image.h. + ensures + - This function has essentially the same behavior as the above + load_image_dataset() routines, except here we output to a vector of + mmod_rects instead of rectangles. In this case, both ignore and non-ignore + rectangles go into object_locations since mmod_rect has an ignore boolean + field that records the ignored/non-ignored state of each rectangle. We also store + a each box's string label into the mmod_rect::label field as well. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename array_type + > + void load_image_dataset ( + array_type& images, + std::vector >& object_locations, + const std::string& filename + ); + /*! + requires + - array_type == An array of images. This is anything with an interface that + looks like std::vector where a "generic image" is + anything that implements the generic image interface defined in + dlib/image_processing/generic_image.h. + ensures + - performs: load_image_dataset(images, object_locations, image_dataset_file(filename)); + (i.e. it ignores box labels and therefore loads all the boxes in the dataset) + !*/ + // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- template < - typename image_type, - typename MM + typename array_type > std::vector > load_image_dataset ( - array& images, + array_type& images, std::vector >& object_locations, const image_dataset_file& source, std::vector& parts_list ); /*! requires - - image_type == is an implementation of array2d/array2d_kernel_abstract.h - - pixel_traits is defined + - array_type == An array of images. This is anything with an interface that + looks like std::vector where a "generic image" is + anything that implements the generic image interface defined in + dlib/image_processing/generic_image.h. ensures - This routine loads the images and their associated object locations from the image metadata file indicated by source.get_filename(). This metadata file @@ -237,18 +308,19 @@ namespace dlib // ---------------------------------------------------------------------------------------- template < - typename image_type, - typename MM + typename array_type > std::vector > load_image_dataset ( - array& images, + array_type& images, std::vector >& object_locations, const image_dataset_file& source ); /*! requires - - image_type == is an implementation of array2d/array2d_kernel_abstract.h - - pixel_traits is defined + - array_type == An array of images. This is anything with an interface that + looks like std::vector where a "generic image" is + anything that implements the generic image interface defined in + dlib/image_processing/generic_image.h. ensures - performs: return load_image_dataset(images, object_locations, source, parts_list); (i.e. this function simply calls the above function and discards the output @@ -259,18 +331,19 @@ namespace dlib // ---------------------------------------------------------------------------------------- template < - typename image_type, - typename MM + typename array_type > std::vector > load_image_dataset ( - array& images, + array_type& images, std::vector >& object_locations, const std::string& filename ); /*! requires - - image_type == is an implementation of array2d/array2d_kernel_abstract.h - - pixel_traits is defined + - array_type == An array of images. This is anything with an interface that + looks like std::vector where a "generic image" is + anything that implements the generic image interface defined in + dlib/image_processing/generic_image.h. ensures - performs: return load_image_dataset(images, object_locations, image_dataset_file(filename)); (i.e. it ignores box labels and therefore loads all the boxes in the dataset) diff --git a/lib/3rdParty/dlib/include/dlib/data_io/mnist.h b/lib/3rdParty/dlib/include/dlib/data_io/mnist.h new file mode 100644 index 00000000..e71be6f2 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/data_io/mnist.h @@ -0,0 +1,32 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MNIST_Hh_ +#define DLIB_MNIST_Hh_ + +#include "mnist_abstract.h" +#include +#include +#include "../matrix.h" + +// ---------------------------------------------------------------------------------------- + +namespace dlib +{ + void load_mnist_dataset ( + const std::string& folder_name, + std::vector >& training_images, + std::vector& training_labels, + std::vector >& testing_images, + std::vector& testing_labels + ); +} + +// ---------------------------------------------------------------------------------------- + +#ifdef NO_MAKEFILE +#include "mnist.cpp" +#endif + +#endif // DLIB_MNIST_Hh_ + + diff --git a/lib/3rdParty/dlib/include/dlib/data_io/mnist_abstract.h b/lib/3rdParty/dlib/include/dlib/data_io/mnist_abstract.h new file mode 100644 index 00000000..09121633 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/data_io/mnist_abstract.h @@ -0,0 +1,46 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_MNIST_ABSTRACT_Hh_ +#ifdef DLIB_MNIST_ABSTRACT_Hh_ + +#include +#include +#include "../matrix.h" + +// ---------------------------------------------------------------------------------------- + +namespace dlib +{ + void load_mnist_dataset ( + const std::string& folder_name, + std::vector >& training_images, + std::vector& training_labels, + std::vector >& testing_images, + std::vector& testing_labels + ); + /*! + ensures + - Attempts to load the MNIST dataset from the hard drive. This is the dataset + of handwritten digits available from http://yann.lecun.com/exdb/mnist/. In + particular, the 4 files comprising the MNIST dataset should be present in the + folder indicated by folder_name. These four files are: + - train-images-idx3-ubyte + - train-labels-idx1-ubyte + - t10k-images-idx3-ubyte + - t10k-labels-idx1-ubyte + - #training_images == The 60,000 training images from the dataset. + - #training_labels == The labels for the contents of #training_images. + I.e. #training_labels[i] is the label of #training_images[i]. + - #testing_images == The 10,000 testing images from the dataset. + - #testing_labels == The labels for the contents of #testing_images. + I.e. #testing_labels[i] is the label of #testing_images[i]. + throws + - dlib::error if some problem prevents us from loading the data or the files + can't be found. + !*/ +} + +// ---------------------------------------------------------------------------------------- + +#endif // DLIB_MNIST_ABSTRACT_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_extensions.cpp b/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_extensions.cpp deleted file mode 100644 index 55a4e2dc..00000000 --- a/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_extensions.cpp +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (C) 2009 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_DIR_NAV_EXTENSIONs_CPP_ -#define DLIB_DIR_NAV_EXTENSIONs_CPP_ - -#include "dir_nav_extensions.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - namespace implementation_details - { - void get_all_sub_dirs ( - const directory& top_of_tree, - unsigned long max_depth, - std::vector& result, - std::vector& temp - ) - { - if (max_depth > 0) - { - top_of_tree.get_dirs(temp); - const unsigned long start = result.size(); - result.insert(result.end(), temp.begin(), temp.end()); - const unsigned long end = start + temp.size(); - - for (unsigned long i = start; i < end; ++i) - { - get_all_sub_dirs(result[i], max_depth-1, result, temp); - } - } - } - } - -// ---------------------------------------------------------------------------------------- - - bool file_exists ( - const std::string& filename - ) - { - try - { - dlib::file temp(filename); - return true; - } - catch (file::file_not_found&) - { - return false; - } - } - -// ---------------------------------------------------------------------------------------- - - directory get_parent_directory ( - const directory& dir - ) - { - return dir.get_parent(); - } - -// ---------------------------------------------------------------------------------------- - - directory get_parent_directory ( - const file& f - ) - { - if (f.full_name().size() == 0) - return directory(); - - std::string::size_type pos = f.full_name().find_last_of("\\/"); - - if (pos == std::string::npos) - return directory(); - - return directory(f.full_name().substr(0,pos)); - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_DIR_NAV_EXTENSIONs_CPP_ - - - diff --git a/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_extensions.h b/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_extensions.h index 1bb75add..93dde115 100644 --- a/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_extensions.h +++ b/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_extensions.h @@ -146,6 +146,20 @@ namespace dlib const file& f ); +// ---------------------------------------------------------------------------------------- + + std::string select_oldest_file ( + const std::string& filename1, + const std::string& filename2 + ); + +// ---------------------------------------------------------------------------------------- + + std::string select_newest_file ( + const std::string& filename1, + const std::string& filename2 + ); + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_extensions_abstract.h b/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_extensions_abstract.h index 3a2d7791..4aa6cc4f 100644 --- a/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_extensions_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_extensions_abstract.h @@ -165,6 +165,35 @@ namespace dlib - returns a default initialized directory (i.e. directory()) !*/ +// ---------------------------------------------------------------------------------------- + + std::string select_oldest_file ( + const std::string& filename1, + const std::string& filename2 + ); + /*! + ensures + - Checks the last modification times of the two given files and returns the + filename of the oldest file, i.e., the file that has gone longest since being + modified. Ties are broken arbitrarily. + - For the purpose of comparison, a file that doesn't exist is presumed to have + a last modification time of -infinity (i.e. very far in the past). + !*/ + +// ---------------------------------------------------------------------------------------- + + std::string select_newest_file ( + const std::string& filename1, + const std::string& filename2 + ); + /*! + ensures + - Checks the last modification times of the two given files and returns the + filename that was most recently modified. Ties are broken arbitrarily. + - For the purpose of comparison, a file that doesn't exist is presumed to have + a last modification time of -infinity (i.e. very far in the past). + !*/ + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_kernel_1.cpp b/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_kernel_1.cpp deleted file mode 100644 index 173e63db..00000000 --- a/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_kernel_1.cpp +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_DIR_NAV_KERNEL_1_CPp_ -#define DLIB_DIR_NAV_KERNEL_1_CPp_ -#include "../platform.h" - -#ifdef WIN32 - -#include "dir_nav_kernel_1.h" -#include "../string.h" - - -#ifdef __BORLANDC__ -// Apparently the borland compiler doesn't define this. -#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) -#endif - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // file object implementation -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void file:: - init ( - const std::string& name - ) - { - using namespace std; - - - char buf[3000]; - char* str; - if (GetFullPathNameA(name.c_str(),sizeof(buf),buf,&str) == 0) - { - // the file was not found - throw file_not_found("Unable to find file " + name); - } - state.full_name = buf; - - - string::size_type pos = state.full_name.find_last_of(directory::get_separator()); - if (pos == string::npos) - { - // no valid full path has no separator characters. - throw file_not_found("Unable to find file " + name); - } - state.name = state.full_name.substr(pos+1); - - - // now find the size of this file - WIN32_FIND_DATAA data; - HANDLE ffind = FindFirstFileA(state.full_name.c_str(), &data); - if (ffind == INVALID_HANDLE_VALUE || - (data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != 0) - { - throw file_not_found("Unable to find file " + name); - } - else - { - uint64 temp = data.nFileSizeHigh; - temp <<= 32; - temp |= data.nFileSizeLow; - state.file_size = temp; - FindClose(ffind); - } - - } - -// ---------------------------------------------------------------------------------------- - - bool file:: - operator == ( - const file& rhs - ) const - { - using namespace std; - - if (state.full_name.size() != rhs.state.full_name.size()) - return false; - - // compare the strings but ignore the case because file names - // are not case sensitive on windows - return tolower(state.full_name) == tolower(rhs.state.full_name); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // directory object implementation -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void directory:: - init ( - const std::string& name - ) - { - using namespace std; - - - char buf[3000]; - char* str; - if (GetFullPathNameA(name.c_str(),sizeof(buf),buf,&str) == 0) - { - // the directory was not found - throw dir_not_found("Unable to find directory " + name); - } - state.full_name = buf; - - - const char sep = get_separator(); - if (is_root_path(state.full_name) == false) - { - // ensure that thre is not a trialing separator - if (state.full_name[state.full_name.size()-1] == sep) - state.full_name.erase(state.full_name.size()-1); - - // pick out the directory name - string::size_type pos = state.full_name.find_last_of(sep); - state.name = state.full_name.substr(pos+1); - } - else - { - // ensure that there is a trailing separator - if (state.full_name[state.full_name.size()-1] != sep) - state.full_name += sep; - } - - - // now check that this is actually a valid directory - DWORD attribs = GetFileAttributesA(state.full_name.c_str()); - if (attribs == INVALID_FILE_ATTRIBUTES || - (attribs&FILE_ATTRIBUTE_DIRECTORY) == 0) - { - // the directory was not found - throw dir_not_found("Unable to find directory " + name); - } - - } - -// ---------------------------------------------------------------------------------------- - - char directory:: - get_separator ( - ) - { - return '\\'; - } - -// ---------------------------------------------------------------------------------------- - - bool directory:: - operator == ( - const directory& rhs - ) const - { - using namespace std; - - if (state.full_name.size() != rhs.state.full_name.size()) - return false; - - // compare the strings but ignore the case because file names - // are not case sensitive on windows - return tolower(state.full_name) == tolower(rhs.state.full_name); - } - -// ---------------------------------------------------------------------------------------- - - const directory directory:: - get_parent ( - ) const - { - using namespace std; - // if *this is the root then just return *this - if (is_root()) - { - return *this; - } - else - { - directory temp; - - const char sep = get_separator(); - - string::size_type pos = state.full_name.find_last_of(sep); - temp.state.full_name = state.full_name.substr(0,pos); - - if ( is_root_path(temp.state.full_name)) - { - temp.state.full_name += sep; - } - else - { - pos = temp.state.full_name.find_last_of(sep); - if (pos != string::npos) - { - temp.state.name = temp.state.full_name.substr(pos+1); - } - else - { - temp.state.full_name += sep; - } - } - return temp; - } - } - -// ---------------------------------------------------------------------------------------- - - bool directory:: - is_root_path ( - const std::string& path - ) const - { - using namespace std; - const char sep = get_separator(); - bool root_path = false; - if (path.size() > 2 && path[0] == sep && path[1] == sep) - { - // in this case this is a windows share path - string::size_type pos = path.find_first_of(sep,2); - if (pos != string::npos) - { - pos = path.find_first_of(sep,pos+1); - - if (pos == string::npos && path[path.size()-1] != sep) - root_path = true; - else if (pos == path.size()-1) - root_path = true; - } - - } - else if ( (path.size() == 2 || path.size() == 3) && path[1] == ':') - { - // if this is a valid windows path then it must be a root path - root_path = true; - } - - return root_path; - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // WIN32 - -#endif // DLIB_DIR_NAV_KERNEL_1_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_kernel_1.h b/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_kernel_1.h index cae23a03..a31f689d 100644 --- a/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_kernel_1.h @@ -21,6 +21,7 @@ #include "../stl_checked.h" #include "../enable_if.h" #include "../queue.h" +#include namespace dlib { @@ -39,11 +40,13 @@ namespace dlib state.name == name() state.full_name == full_name() state.file_size == size() + state.last_modified == last_modified() CONVENTION state.name == name() state.full_name == full_name() state.file_size == size() + state.last_modified == last_modified() !*/ @@ -54,6 +57,7 @@ namespace dlib uint64 file_size; std::string name; std::string full_name; + std::chrono::time_point last_modified; }; @@ -66,12 +70,14 @@ namespace dlib const std::string& name, const std::string& full_name, const uint64 file_size, + const std::chrono::time_point& last_modified, private_constructor ) { state.file_size = file_size; state.name = name; state.full_name = full_name; + state.last_modified = last_modified; } @@ -107,6 +113,9 @@ namespace dlib inline uint64 size ( ) const { return state.file_size; } + inline std::chrono::time_point last_modified ( + ) const { return state.last_modified; } + bool operator == ( const file& rhs ) const; @@ -413,8 +422,15 @@ namespace dlib uint64 file_size = data.nFileSizeHigh; file_size <<= 32; file_size |= data.nFileSizeLow; + + ULARGE_INTEGER ull; + ull.LowPart = data.ftLastWriteTime.dwLowDateTime; + ull.HighPart = data.ftLastWriteTime.dwHighDateTime; + std::chrono::nanoseconds epoch(100 * (ull.QuadPart - 116444736000000000)); + auto last_modified = std::chrono::time_point(std::chrono::duration_cast(epoch)); + // this is a file so add it to the queue - file temp(data.cFileName,path+data.cFileName,file_size, private_constructor()); + file temp(data.cFileName,path+data.cFileName,file_size, last_modified, private_constructor()); files.enqueue(temp); } diff --git a/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_kernel_2.cpp b/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_kernel_2.cpp deleted file mode 100644 index 16f20f5a..00000000 --- a/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_kernel_2.cpp +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_DIR_NAV_KERNEL_2_CPp_ -#define DLIB_DIR_NAV_KERNEL_2_CPp_ - -#include "../platform.h" - -#ifdef POSIX - - -#include "dir_nav_kernel_2.h" - - - - - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // file object implementation -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void file:: - init ( - const std::string& name - ) - { - using namespace std; - - - - char buf[PATH_MAX]; - if (realpath(name.c_str(),buf) == 0) - { - // the file was not found - throw file_not_found("Unable to find file " + name); - } - state.full_name = buf; - - - string::size_type pos = state.full_name.find_last_of(directory::get_separator()); - if (pos == string::npos) - { - // no valid full path has no separtor characters. - throw file_not_found("Unable to find file " + name); - } - state.name = state.full_name.substr(pos+1); - - - // now find the size of this file - struct stat64 buffer; - if (::stat64(state.full_name.c_str(), &buffer) || - S_ISDIR(buffer.st_mode)) - { - // there was an error during the call to stat64 or - // name is actually a directory - throw file_not_found("Unable to find file " + name); - } - else - { - state.file_size = static_cast(buffer.st_size); - } - - } - -// ---------------------------------------------------------------------------------------- - - bool file:: - operator == ( - const file& rhs - ) const - { - using namespace std; - if (state.full_name.size() == 0 && rhs.state.full_name.size() == 0) - return true; - - // These files might have different names but actually represent the same - // file due to the presence of symbolic links. - char buf[PATH_MAX]; - string left, right; - if (realpath(state.full_name.c_str(),buf) == 0) - return false; - left = buf; - - if (realpath(rhs.state.full_name.c_str(),buf) == 0) - return false; - right = buf; - - return (left == right); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // directory object implementation -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void directory:: - init ( - const std::string& name - ) - { - using namespace std; - - - char buf[PATH_MAX]; - if (realpath(name.c_str(),buf) == 0) - { - // the directory was not found - throw dir_not_found("Unable to find directory " + name); - } - state.full_name = buf; - - - const char sep = get_separator(); - if (is_root_path(state.full_name) == false) - { - // ensure that thre is not a trialing separator - if (state.full_name[state.full_name.size()-1] == sep) - state.full_name.erase(state.full_name.size()-1); - - // pick out the directory name - string::size_type pos = state.full_name.find_last_of(sep); - state.name = state.full_name.substr(pos+1); - } - else - { - // ensure that there is a trailing separator - if (state.full_name[state.full_name.size()-1] != sep) - state.full_name += sep; - } - - - struct stat64 buffer; - // now check that this is actually a valid directory - if (::stat64(state.full_name.c_str(),&buffer)) - { - // the directory was not found - throw dir_not_found("Unable to find directory " + name); - } - else if (S_ISDIR(buffer.st_mode) == 0) - { - // It is not a directory - throw dir_not_found("Unable to find directory " + name); - } - } - -// ---------------------------------------------------------------------------------------- - - char directory:: - get_separator ( - ) - { - return '/'; - } - -// ---------------------------------------------------------------------------------------- - - bool directory:: - operator == ( - const directory& rhs - ) const - { - using namespace std; - if (state.full_name.size() == 0 && rhs.state.full_name.size() == 0) - return true; - - // These directories might have different names but actually represent the same - // directory due to the presence of symbolic links. - char buf[PATH_MAX]; - string left, right; - if (realpath(state.full_name.c_str(),buf) == 0) - return false; - left = buf; - - if (realpath(rhs.state.full_name.c_str(),buf) == 0) - return false; - right = buf; - - return (left == right); - } - -// ---------------------------------------------------------------------------------------- - - const directory directory:: - get_parent ( - ) const - { - using namespace std; - // if *this is the root then just return *this - if (is_root()) - { - return *this; - } - else - { - directory temp; - - const char sep = get_separator(); - - string::size_type pos = state.full_name.find_last_of(sep); - temp.state.full_name = state.full_name.substr(0,pos); - - if ( is_root_path(temp.state.full_name)) - { - temp.state.full_name += sep; - } - else - { - pos = temp.state.full_name.find_last_of(sep); - if (pos != string::npos) - { - temp.state.name = temp.state.full_name.substr(pos+1); - } - else - { - temp.state.full_name += sep; - } - } - return temp; - } - } - -// ---------------------------------------------------------------------------------------- - - bool directory:: - is_root_path ( - const std::string& path - ) const - { - const char sep = get_separator(); - if (path.size() == 1 && path[0] == sep) - return true; - else - return false; - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // POSIX - -#endif // DLIB_DIR_NAV_KERNEL_2_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_kernel_2.h b/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_kernel_2.h index bebf1895..af2f3d5d 100644 --- a/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_kernel_2.h +++ b/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_kernel_2.h @@ -22,6 +22,7 @@ #include #include #include +#include #if !defined(__USE_LARGEFILE64 ) && !defined(_LARGEFILE64_SOURCE) #define stat64 stat @@ -48,11 +49,13 @@ namespace dlib state.name == name() state.full_name == full_name() state.file_size == size() + state.last_modified == last_modified() CONVENTION state.name == name() state.full_name == full_name() state.file_size == size() + state.last_modified == last_modified() !*/ @@ -63,6 +66,7 @@ namespace dlib uint64 file_size; std::string name; std::string full_name; + std::chrono::time_point last_modified; }; void init(const std::string& name); @@ -74,12 +78,14 @@ namespace dlib const std::string& name, const std::string& full_name, const uint64 file_size, + const std::chrono::time_point& last_modified, private_constructor ) { state.file_size = file_size; state.name = name; state.full_name = full_name; + state.last_modified = last_modified; } @@ -110,6 +116,9 @@ namespace dlib inline uint64 size ( ) const { return state.file_size; } + inline std::chrono::time_point last_modified ( + ) const { return state.last_modified; } + operator std::string ( ) const { return full_name(); } @@ -383,6 +392,10 @@ namespace dlib { file_size = static_cast(buffer.st_size); } + auto last_modified = std::chrono::system_clock::from_time_t(buffer.st_mtime); +#ifdef _BSD_SOURCE + last_modified += std::chrono::duration_cast(std::chrono::nanoseconds(buffer.st_atim.tv_nsec)); +#endif if (S_ISDIR(buffer.st_mode) == 0) { @@ -391,6 +404,7 @@ namespace dlib data->d_name, path+data->d_name, file_size, + last_modified, file::private_constructor() ); files.enqueue(temp); diff --git a/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_kernel_abstract.h b/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_kernel_abstract.h index 6ddb32d4..53254ee0 100644 --- a/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_kernel_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/dir_nav/dir_nav_kernel_abstract.h @@ -7,6 +7,7 @@ #include #include "../uintn.h" #include "../algs.h" +#include namespace dlib { @@ -139,6 +140,13 @@ namespace dlib - returns the size of this file in bytes. !*/ + std::chrono::time_point last_modified ( + ) const; + /*! + ensures + - returns the time the file was last modified. + !*/ + operator std::string ( ) const; /*! diff --git a/lib/3rdParty/dlib/include/dlib/directed_graph/directed_graph_kernel_1.h b/lib/3rdParty/dlib/include/dlib/directed_graph/directed_graph_kernel_1.h index 2726e90c..b0cc6a2c 100644 --- a/lib/3rdParty/dlib/include/dlib/directed_graph/directed_graph_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/directed_graph/directed_graph_kernel_1.h @@ -3,12 +3,13 @@ #ifndef DLIB_DIRECTED_GRAPH_KERNEl_1_ #define DLIB_DIRECTED_GRAPH_KERNEl_1_ +#include +#include + #include "../serialize.h" #include "../noncopyable.h" #include "../std_allocator.h" -#include "../smart_pointers.h" #include "../algs.h" -#include #include "directed_graph_kernel_abstract.h" #include "../is_kind.h" @@ -357,18 +358,18 @@ namespace dlib private: friend class directed_graph_kernel_1; typedef std_allocator alloc_type; - typedef std_allocator,mem_manager> alloc_edge_type; + typedef std_allocator,mem_manager> alloc_edge_type; std::vector parents; std::vector children; - std::vector,alloc_edge_type> edge_parents; - std::vector,alloc_edge_type> edge_children; + std::vector,alloc_edge_type> edge_parents; + std::vector,alloc_edge_type> edge_children; unsigned long idx; }; private: - typedef std_allocator,mem_manager> alloc_type; - typedef std::vector, alloc_type> vector_type; + typedef std_allocator,mem_manager> alloc_type; + typedef std::vector, alloc_type> vector_type; vector_type nodes; }; @@ -574,7 +575,7 @@ namespace dlib p.children.push_back(&c); c.parents.push_back(&p); - p.edge_children.push_back(shared_ptr(new E)); + p.edge_children.push_back(std::shared_ptr(new E)); c.edge_parents.push_back(p.edge_children.back()); } catch (...) @@ -632,7 +633,7 @@ namespace dlib { try { - shared_ptr n(new node_type); + std::shared_ptr n(new node_type); n->idx = nodes.size(); nodes.push_back(n); return n->idx; diff --git a/lib/3rdParty/dlib/include/dlib/disjoint_subsets.h b/lib/3rdParty/dlib/include/dlib/disjoint_subsets.h index 50923c40..d33ef63f 100644 --- a/lib/3rdParty/dlib/include/dlib/disjoint_subsets.h +++ b/lib/3rdParty/dlib/include/dlib/disjoint_subsets.h @@ -5,6 +5,7 @@ #include "disjoint_subsets/disjoint_subsets.h" +#include "disjoint_subsets/disjoint_subsets_sized.h" #endif // DLIB_DISJOINt_SUBSETS_ diff --git a/lib/3rdParty/dlib/include/dlib/disjoint_subsets/disjoint_subsets.h b/lib/3rdParty/dlib/include/dlib/disjoint_subsets/disjoint_subsets.h index b69099a8..7fab9eba 100644 --- a/lib/3rdParty/dlib/include/dlib/disjoint_subsets/disjoint_subsets.h +++ b/lib/3rdParty/dlib/include/dlib/disjoint_subsets/disjoint_subsets.h @@ -17,7 +17,7 @@ namespace dlib public: void clear ( - ) + ) noexcept { items.clear(); } @@ -34,22 +34,22 @@ namespace dlib } } - unsigned long size ( - ) const + size_t size ( + ) const noexcept { return items.size(); } unsigned long find_set ( - unsigned long item + unsigned long item ) const { // make sure requires clause is not broken - DLIB_ASSERT(item < size(), + DLIB_ASSERT(item < size(), "\t unsigned long disjoint_subsets::find_set()" << "\n\t item must be less than size()" - << "\n\t item: " << item - << "\n\t size(): " << size() + << "\n\t item: " << item + << "\n\t size(): " << size() << "\n\t this: " << this ); @@ -88,16 +88,16 @@ namespace dlib // make sure requires clause is not broken DLIB_ASSERT(a != b && a < size() && - b < size() && + b < size() && find_set(a) == a && find_set(b) == b, "\t unsigned long disjoint_subsets::merge_sets(a,b)" << "\n\t invalid arguments were given to this function" - << "\n\t a: " << a - << "\n\t b: " << b - << "\n\t size(): " << size() - << "\n\t find_set(a): " << find_set(a) - << "\n\t find_set(b): " << find_set(b) + << "\n\t a: " << a + << "\n\t b: " << b + << "\n\t size(): " << size() + << "\n\t find_set(a): " << find_set(a) + << "\n\t find_set(b): " << find_set(b) << "\n\t this: " << this ); @@ -139,4 +139,3 @@ namespace dlib } #endif // DLIB_DISJOINT_SUBsETS_Hh_ - diff --git a/lib/3rdParty/dlib/include/dlib/disjoint_subsets/disjoint_subsets_abstract.h b/lib/3rdParty/dlib/include/dlib/disjoint_subsets/disjoint_subsets_abstract.h index 7660ca7f..bd67d0d5 100644 --- a/lib/3rdParty/dlib/include/dlib/disjoint_subsets/disjoint_subsets_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/disjoint_subsets/disjoint_subsets_abstract.h @@ -20,13 +20,13 @@ namespace dlib WHAT THIS OBJECT REPRESENTS This object represents a set of integers which is partitioned into a number of disjoint subsets. It supports the two fundamental operations - of finding which subset a particular integer belongs to as well as + of finding which subset a particular integer belongs to as well as merging subsets. !*/ public: void clear ( - ); + ) noexcept; /*! ensures - #size() == 0 @@ -44,29 +44,29 @@ namespace dlib (i.e. this object contains new_size subsets, each containing exactly one element) !*/ - unsigned long size ( - ) const; + size_t size ( + ) const noexcept; /*! ensures - returns the total number of integer elements represented - by this object. + by this object. !*/ unsigned long find_set ( - unsigned long item + unsigned long item ) const; /*! requires - item < size() ensures - - Each disjoint subset can be represented by any of its elements (since - the sets are all disjoint). In particular, for each subset we define - a special "representative element" which is used to represent it. - Therefore, this function returns the representative element for the + - Each disjoint subset can be represented by any of its elements (since + the sets are all disjoint). In particular, for each subset we define + a special "representative element" which is used to represent it. + Therefore, this function returns the representative element for the set which contains item. - find_set(find_set(item)) == find_set(item) - Note that if A and B are both elements of the same subset then we always - have find_set(A) == find_set(B). + have find_set(A) == find_set(B). !*/ unsigned long merge_sets ( @@ -87,7 +87,6 @@ namespace dlib (i.e. merges the set's containing a and b) - returns #find_set(a) !*/ - }; // ---------------------------------------------------------------------------------------- @@ -95,5 +94,3 @@ namespace dlib } #endif // DLIB_DISJOINT_SUBsETS_ABSTRACT_Hh_ - - diff --git a/lib/3rdParty/dlib/include/dlib/disjoint_subsets/disjoint_subsets_sized.h b/lib/3rdParty/dlib/include/dlib/disjoint_subsets/disjoint_subsets_sized.h new file mode 100644 index 00000000..9aa657f4 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/disjoint_subsets/disjoint_subsets_sized.h @@ -0,0 +1,130 @@ +// Copyright (C) 2011 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DISJOINT_SUBsETS_SIZED_Hh_ +#define DLIB_DISJOINT_SUBsETS_SIZED_Hh_ + +#include "disjoint_subsets_sized_abstract.h" +#include "disjoint_subsets.h" +#include +#include "../algs.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class disjoint_subsets_sized + { + public: + + void clear ( + ) noexcept + { + disjoint_subsets_.clear(); + sets_size.clear(); + number_of_sets = 0; + } + + void set_size ( + unsigned long new_size + ) + { + disjoint_subsets_.set_size(new_size); + sets_size.assign(new_size, 1); + number_of_sets = new_size; + } + + size_t size ( + ) const noexcept + { + return disjoint_subsets_.size(); + } + + unsigned long find_set ( + unsigned long item + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT(item < size(), + "\t unsigned long disjoint_subsets::find_set()" + << "\n\t item must be less than size()" + << "\n\t item: " << item + << "\n\t size(): " << size() + << "\n\t this: " << this + ); + + return disjoint_subsets_.find_set(item); + } + + unsigned long merge_sets ( + unsigned long a, + unsigned long b + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(a != b && + a < size() && + b < size() && + find_set(a) == a && + find_set(b) == b, + "\t unsigned long disjoint_subsets::merge_sets(a,b)" + << "\n\t invalid arguments were given to this function" + << "\n\t a: " << a + << "\n\t b: " << b + << "\n\t size(): " << size() + << "\n\t find_set(a): " << find_set(a) + << "\n\t find_set(b): " << find_set(b) + << "\n\t this: " << this + ); + + disjoint_subsets_.merge_sets(a, b); + + if (find_set(a) == a) sets_size[a] += sets_size[b]; + else sets_size[b] += sets_size[a]; + --number_of_sets; + + return find_set(a); + } + + unsigned long get_number_of_sets ( + ) const noexcept + { + return number_of_sets; + } + + unsigned long get_size_of_set( + unsigned long item + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT(item < size() && + find_set(item) == item, + "\t unsigned long disjoint_subsets::get_size_of_set()" + << "\n\t invalid arguments were given to this function" + << "\n\t item: " << item + << "\n\t size(): " << size() + << "\n\t find_set(item): " << find_set(item) + << "\n\t this: " << this + ); + + return sets_size[item]; + } + + private: + + /* + See the book Introduction to Algorithms by Cormen, Leiserson, Rivest and Stein + for a discussion of how this algorithm works. + */ + + mutable std::vector sets_size; + unsigned long number_of_sets{0}; + disjoint_subsets disjoint_subsets_; + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DISJOINT_SUBsETS_SIZED_Hh_ diff --git a/lib/3rdParty/dlib/include/dlib/disjoint_subsets/disjoint_subsets_sized_abstract.h b/lib/3rdParty/dlib/include/dlib/disjoint_subsets/disjoint_subsets_sized_abstract.h new file mode 100644 index 00000000..ecc5ef00 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/disjoint_subsets/disjoint_subsets_sized_abstract.h @@ -0,0 +1,123 @@ +// Copyright (C) 2011 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_DISJOINT_SUBsETS_SIZED_ABSTRACT_Hh_ +#ifdef DLIB_DISJOINT_SUBsETS_SIZED_ABSTRACT_Hh_ + +#include +#include "../algs.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class disjoint_subsets_sized + { + /*! + INITIAL VALUE + - size() == 0 + - get_number_of_sets() == 0 + + WHAT THIS OBJECT REPRESENTS + This object represents a set of integers which is partitioned into + a number of disjoint subsets. It supports the two fundamental operations + of finding which subset a particular integer belongs to as well as + merging subsets. It also allows you to find out how big each subset is. It + is therefore essentially the same thing as dlib::disjoint_subsets, except + it also keeps track of of the size of each subset. + !*/ + public: + + void clear ( + ) noexcept; + /*! + ensures + - #size() == 0 + - #get_number_of_sets() == 0 + - returns this object to its initial value + !*/ + + void set_size ( + unsigned long new_size + ); + /*! + ensures + - #size() == new_size + - #get_number_of_sets() == new_size + - for all valid i: + - #find_set(i) == i + (i.e. this object contains new_size subsets, each containing exactly one element) + - #get_size_of_set(i) == 1 + !*/ + + size_t size ( + ) const noexcept; + /*! + ensures + - returns the total number of integer elements represented + by this object. + !*/ + + unsigned long find_set ( + unsigned long item + ) const; + /*! + requires + - item < size() + ensures + - Each disjoint subset can be represented by any of its elements (since + the sets are all disjoint). In particular, for each subset we define + a special "representative element" which is used to represent it. + Therefore, this function returns the representative element for the + set which contains item. + - find_set(find_set(item)) == find_set(item) + - Note that if A and B are both elements of the same subset then we always + have find_set(A) == find_set(B). + !*/ + + unsigned long merge_sets ( + unsigned long a, + unsigned long b + ); + /*! + requires + - a != b + - a < size() + - b < size() + - find_set(a) == a + (i.e. a is the representative element of some set) + - find_set(b) == b + (i.e. b is the representative element of some set) + ensures + - #find_set(a) == #find_set(b) + (i.e. merges the set's containing a and b) + - #get_size_of_set(#find_set(a)) == get_size_of_set(a) + get_size_of_set(b) + - #get_number_of_sets() == get_number_of_sets() - 1 + - returns #find_set(a) + !*/ + + unsigned long get_number_of_sets ( + ) const noexcept; + /*! + ensures + - returns the current number of different subsets. + !*/ + + unsigned long get_size_of_set( + unsigned long item + ) const; + /*! + requires + - item < size() + - find_set(item) == item + (i.e. item is the representative element of some set) + ensures + - returns the number of elements which belongs to the set where item is the representative element. + !*/ + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DISJOINT_SUBsETS_ABSTRACT_Hh_ diff --git a/lib/3rdParty/dlib/include/dlib/dlib_include_path_tutorial.txt b/lib/3rdParty/dlib/include/dlib/dlib_include_path_tutorial.txt deleted file mode 100644 index f279ce10..00000000 --- a/lib/3rdParty/dlib/include/dlib/dlib_include_path_tutorial.txt +++ /dev/null @@ -1,20 +0,0 @@ -#error "Don't put the dlib folder in your include path" -/* - You are getting this error because you have added the dlib folder to your - compiler's include search path. - - You should *NOT* add the dlib folder itself to your compiler's include path. - Doing so will cause the build to fail because of name collisions (such as - dlib/string.h and string.h from the standard library). Instead you should - add the folder that contains the dlib folder to your include search path - and then use include statements of the form #include or - #include "dlib/queue.h". This will ensure that everything builds correctly. - - XCode: - The XCode IDE often puts all folders that it knows about into - the compiler search path. So if you are using XCode then either - don't drag the whole dlib folder into the project or alternatively - modify your XCode project settings to not auto-add all folders to - the include path. Instead just make sure that the dlib folder is - itself inside a folder in your include path. -*/ diff --git a/lib/3rdParty/dlib/include/dlib/dnn.h b/lib/3rdParty/dlib/include/dlib/dnn.h new file mode 100644 index 00000000..c5ded777 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/dnn.h @@ -0,0 +1,37 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DNn_ +#define DLIB_DNn_ + +// DNN module uses template-based network declaration that leads to very long +// type names. Visual Studio will produce Warning C4503 in such cases +#ifdef _MSC_VER +# pragma warning( disable: 4503 ) +#endif + +#include "cuda/tensor.h" +#include "dnn/input.h" + +// Problem: Visual Studio's vcpkgsrv.exe constantly uses a single CPU core, +// apparently never finishing whatever it's trying to do. Moreover, +// this issue prevents some operations like switching from Debug to +// Release (and vice versa) in the IDE. (Your mileage may vary.) +// Workaround: Keep manually killing the vcpkgsrv.exe process. +// Solution: Disable IntelliSense for some files. Which files? Unfortunately +// this seems to be a trial-and-error process. +#ifndef __INTELLISENSE__ +#include "dnn/layers.h" +#endif // __INTELLISENSE__ + +#include "dnn/loss.h" +#include "dnn/core.h" +#include "dnn/solvers.h" +#include "dnn/trainer.h" +#include "cuda/cpu_dlib.h" +#include "cuda/tensor_tools.h" +#include "dnn/utilities.h" +#include "dnn/validation.h" + +#endif // DLIB_DNn_ + + diff --git a/lib/3rdParty/dlib/include/dlib/dnn/core.h b/lib/3rdParty/dlib/include/dlib/dnn/core.h new file mode 100644 index 00000000..5c8ed4d4 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/dnn/core.h @@ -0,0 +1,3599 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DNn_CORE_H_ +#define DLIB_DNn_CORE_H_ + +#include "core_abstract.h" +#include "../cuda/tensor.h" +#include +#include +#include +#include +#include "../statistics.h" +#include "../rand.h" +#include "../algs.h" +#include +#include +#include +#include +#include "../cuda/tensor_tools.h" +#include +#include "../metaprogramming.h" + +#ifdef _MSC_VER +// Tell Visual Studio not to recursively inline functions very much because otherwise it +// takes hours to compile the DNN code sometimes. It's crazy. Hopefully we can remove +// this some day when the visual studio compiler is more efficient. +#pragma inline_depth(2) +#endif + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template ::type = 0> + double get_learning_rate_multiplier ( + const T& obj, + special_ + ) { return obj.get_learning_rate_multiplier(); } + + template + double get_learning_rate_multiplier ( const T& , general_) { return 1; } + } + template + double get_learning_rate_multiplier(const T& obj) { return impl::get_learning_rate_multiplier(obj, special_()); } + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template ::type = 0> + double get_weight_decay_multiplier ( + const T& obj, + special_ + ) { return obj.get_weight_decay_multiplier(); } + + template + double get_weight_decay_multiplier ( const T& , general_) { return 1; } + } + template + double get_weight_decay_multiplier(const T& obj) { return impl::get_weight_decay_multiplier(obj, special_()); } + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + // The reason we return an int for this version rather than doing the more straight forward thing (like we do above) is to avoid a bug in visual studio 2015. + template + auto call_clean_method_if_exists ( + T& obj, + special_ + ) -> typename int_::type { obj.clean(); return 0; } + + template + void call_clean_method_if_exists (T& , general_) {} + } + template + void call_clean_method_if_exists(T& obj) { impl::call_clean_method_if_exists(obj, special_()); } + /*! + ensures + - calls obj.clean() if obj has a .clean() method. + !*/ + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + class repeat_input_layer + { + /*! + None of the declarations in this object are really used. The only reason it + exists is to allow the repeat object to use a special input layer in its + internal networks which will cause add_tag_layer objects that happen to be + right at the input to not create copies of their input tensors. So + introducing the repeat_input_layer object allows us to optimize the + implementation of add_tag_layer for a special case that arises when it's + used in the context of the repeat layer. + !*/ + public: + typedef int input_type; + + template + void to_tensor ( + forward_iterator , + forward_iterator , + resizable_tensor& + ) const + { + } + + friend void serialize(const repeat_input_layer&, std::ostream&){} + friend void deserialize(repeat_input_layer&, std::istream&){} + friend std::ostream& operator<<(std::ostream& out, const repeat_input_layer&) { return out; } + }; + + inline std::string tensor_to_str ( + const tensor& t, + int& min_length + ) + { + if (t.size() == 0) + return ""; + + std::ostringstream sout; + sout << "output size=(num:"<< t.num_samples() << ", "; + sout << "k:" << t.k() << ","; + while (sout.tellp() < 28) sout << " "; + sout << "nr:" << t.nr() << ","; + while (sout.tellp() < 28+8) sout << " "; + sout << "nc:" << t.nc() << ")"; + while (sout.tellp() < min_length) sout << " "; + min_length = sout.tellp(); + sout << "\t"; + return sout.str(); + } + } + +// ---------------------------------------------------------------------------------------- + + // Tell us if T is one of the special layer types (i.e. add_layer, repeat, add_tag_layer, or + // add_skip_layer). + template struct is_nonloss_layer_type : std::false_type {}; + // Tell us if T is an instance of add_loss_layer. + template struct is_loss_layer_type : std::false_type {}; + // Tell us if T is an instance of add_layer + template struct is_add_layer : std::false_type {}; + + namespace impl + { + template + auto tuple_subset( + const Tuple& item, + compile_time_integer_list + ) -> decltype(std::make_tuple(std::get(item)...)) + { + return std::make_tuple(std::get(item)...); + } + + template + std::tuple basic_tuple_tail( + const std::tuple& item + ) + { + return tuple_subset(item, typename make_compile_time_integer_range::type()); + } + + template + std::tuple tuple_flatten(const T& t) + { + return std::make_tuple(t); + } + + template + auto tuple_flatten( + const std::tuple& item + ) -> decltype(tuple_flatten(item, typename make_compile_time_integer_range::type())) + { + return tuple_flatten(item, typename make_compile_time_integer_range::type()); + } + + template + auto tuple_flatten( + const std::tuple& item, + compile_time_integer_list + ) -> decltype(std::tuple_cat(tuple_flatten(std::get(item))...)) + { + return std::tuple_cat(tuple_flatten(std::get(item))...); + } + + template + struct tuple_head_helper + { + typedef T type; + static const type& get(const T& item) + { + return item; + } + }; + + template + struct tuple_head_helper> + { + typedef typename tuple_head_helper::type type; + static const type& get(const std::tuple& item) + { + return tuple_head_helper::get(std::get<0>(item)); + } + }; + + template struct alwaysbool { typedef bool type; }; + // one more structure for VS 2015 UP3 support workaround + template struct alwaysbool2 { typedef bool type; }; + + resizable_tensor& rt(); + + // The significance of a layer's backward method requiring forward's outputs is + // that such as layer can't have an in-place layer stacked on top of it because + // in-place layers overwrite the output of the layer they sit on top of. + template + constexpr auto backward_requires_forward_output( + layer_type& layer, + SUBNET& sub + ) -> typename alwaysbool::type + { + return true; + } + + template + constexpr auto backward_requires_forward_output( + layer_type& layer, + SUBNET& sub + ) -> typename alwaysbool::type + { + return false; + } + + template + constexpr auto backward_requires_forward_output( + layer_type& layer, + SUBNET& sub + ) -> typename alwaysbool::type + { + return true; + } + + template + constexpr auto backward_requires_forward_output( + layer_type& layer, + SUBNET& sub + ) -> typename alwaysbool::type + { + return false; + } + + template + constexpr auto has_inplace_backward( + layer_type& layer, + SUBNET& sub + ) -> typename alwaysbool2::type + { + return false; + } + + template + constexpr auto has_inplace_backward( + layer_type& layer, + SUBNET& sub + ) -> typename alwaysbool2::type + { + return false; + } + + template + constexpr auto has_inplace_backward( + layer_type& layer, + SUBNET& sub + ) -> typename alwaysbool2::type + { + return true; + } + + template + constexpr auto has_inplace_backward( + layer_type& layer, + SUBNET& sub + ) -> typename alwaysbool2::type + { + return true; + } + + template + constexpr auto is_inplace_layer( + layer_type& layer, + const SUBNET& sub + ) -> typename alwaysbool2::type + { + return false; + } + + template + constexpr auto is_inplace_layer( + layer_type& layer, + const SUBNET& sub + ) -> typename alwaysbool::type + { + return true; + } + + template + auto call_layer_backward( + layer_type& layer, + const tensor& computed_output, + const tensor& gradient_input, + SUBNET& sub, + tensor& params_grad + ) -> decltype(layer.backward(computed_output,gradient_input,sub,params_grad)) + { + layer.backward(computed_output,gradient_input,sub,params_grad); + } + + template + auto call_layer_backward( + layer_type& layer, + const tensor& , + const tensor& gradient_input, + SUBNET& sub, + tensor& params_grad + ) -> decltype(layer.backward(gradient_input,sub,params_grad)) + { + layer.backward(gradient_input,sub,params_grad); + } + + template + auto call_layer_backward( + layer_type& layer, + const tensor& computed_output, + const tensor& gradient_input, + SUBNET& sub, + tensor& params_grad + ) -> decltype(layer.backward_inplace(computed_output,gradient_input,sub.get_gradient_input(),params_grad)) + { + layer.backward_inplace(computed_output,gradient_input,sub.get_gradient_input(),params_grad); + } + + template + auto call_layer_backward( + layer_type& layer, + const tensor& , + const tensor& gradient_input, + SUBNET& sub, + tensor& params_grad + ) -> decltype(layer.backward_inplace(gradient_input,sub.get_gradient_input(),params_grad)) + { + layer.backward_inplace(gradient_input,sub.get_gradient_input(),params_grad); + } + + + template + auto call_layer_forward( + layer_type& layer, + const SUBNET& sub, + tensor& /*data_output*/ + ) -> decltype(layer.forward(sub,rt())) + { + // This overload of call_layer_forward() is here because this template + // naturally gets instantiated but only on code paths that never get executed. + // So rather than writing a bunch of hard to read template magic around call + // sites we just have this overload that doesn't do anything (and an assert to + // make sure that's the case). + DLIB_CASSERT(false, "This should never happen"); + } + + template + auto call_layer_forward( + layer_type& layer, + const SUBNET& sub, + resizable_tensor& data_output + ) -> decltype(layer.forward(sub,data_output)) + { + layer.forward(sub,data_output); + } + + template + auto call_layer_forward( + layer_type& layer, + const SUBNET& sub, + tensor& data_output + ) -> decltype(layer.forward_inplace(sub.get_output(),data_output)) + { + layer.forward_inplace(sub.get_output(),data_output); + } + + template + auto call_layer_forward( + layer_type& layer, + const SUBNET& sub, + resizable_tensor& data_output + ) -> decltype(layer.forward_inplace(sub.get_output(),data_output)) + { + if (!have_same_dimensions(data_output, sub.get_output())) + data_output.copy_size(sub.get_output()); + layer.forward_inplace(sub.get_output(),static_cast(data_output)); + } + + + } // end namespace impl + + template + typename impl::tuple_head_helper>::type tuple_head ( + const std::tuple& item + ) + { + return impl::tuple_head_helper>::get(item); + } + + template + auto tuple_tail( + const std::tuple& item + ) -> decltype(impl::basic_tuple_tail(impl::tuple_flatten(item))) + { + return impl::basic_tuple_tail(impl::tuple_flatten(item)); + } + + inline std::tuple<> tuple_tail( + const std::tuple<>& item + ) + { + return item; + } +// ---------------------------------------------------------------------------------------- + + template + class sstack + { + public: + typedef T value_type; + + sstack() = delete; + + sstack ( + T* data_, + size_t s + ) : data(data_), mysize(s) {} + + const T& top() const + { + DLIB_CASSERT(size() != 0, "You can't call top() on an empty stack"); + return *data; + } + T& top() + { + DLIB_CASSERT(size() != 0, "You can't call top() on an empty stack"); + return *data; + } + + size_t size() const { return mysize; } + + sstack pop(size_t num=1) + { + DLIB_CASSERT(num <= size(), "You can't pop more things from the stack than it has in it."); + return sstack(data+num, mysize-num); + } + + private: + + T* data; + size_t mysize; + }; + + template + sstack make_sstack(std::vector& item) + { + return sstack(item.data(), item.size()); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + namespace dimpl + { + template + class subnet_wrapper + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a tool that makes an add_layer or add_loss_layer object + expose only the part of its interface defined by the SUBNET + type in layers_abstract.h. This way, when we pass subnetwork + objects to the layer callbacks those callbacks won't be able to + interact with the subnetworks in a way other than specified + by the SUBNET interface spec. + + We also allow the top layer of a subnet_wrapper stack to call the + private_get_output() and private_get_gradient_input() functions. This + way, layers that have had their output/gradient overwritten by in-place + layers can only be accessed from the in-place layers that sit directly + on top of them since those in-place layers are the only layers that + know how to interact with them properly. + !*/ + + public: + subnet_wrapper(const subnet_wrapper&) = delete; + subnet_wrapper& operator=(const subnet_wrapper&) = delete; + + subnet_wrapper(T& l_, unsigned int sef) : l(l_),_sample_expansion_factor(sef) {} + // Not much here because in this case T is one of the input layer types + // that doesn't have anything in it. + typedef T layer_details_type; + const layer_details_type& layer_details() const { return l; } + unsigned int sample_expansion_factor() const { return _sample_expansion_factor; } + private: + T& l; + unsigned int _sample_expansion_factor; + }; + + template + class subnet_wrapper::value>::type> + { + + public: + subnet_wrapper(const subnet_wrapper&) = delete; + subnet_wrapper& operator=(const subnet_wrapper&) = delete; + + typedef T wrapped_type; + const static size_t num_computational_layers = T::num_computational_layers; + const static size_t num_layers = T::num_layers; + typedef typename T::layer_details_type layer_details_type; + + subnet_wrapper(T& l_, unsigned int = 0) : l(l_),subnetwork(l.subnet(), l.sample_expansion_factor()) {} + + const tensor& get_output() const { return l.private_get_output(); } + tensor& get_gradient_input() { return l.private_get_gradient_input(); } + + const layer_details_type& layer_details() const { return l.layer_details(); } + + const subnet_wrapper& subnet() const { return subnetwork; } + subnet_wrapper& subnet() { return subnetwork; } + unsigned int sample_expansion_factor() const { return l.sample_expansion_factor(); } + + private: + T& l; + subnet_wrapper subnetwork; + }; + + template + class subnet_wrapper::value>::type> + { + + public: + subnet_wrapper(const subnet_wrapper&) = delete; + subnet_wrapper& operator=(const subnet_wrapper&) = delete; + + typedef T wrapped_type; + const static size_t num_computational_layers = T::num_computational_layers; + const static size_t num_layers = T::num_layers; + typedef typename T::layer_details_type layer_details_type; + + subnet_wrapper(T& l_, unsigned int = 0) : l(l_),subnetwork(l.subnet(), l.sample_expansion_factor()) {} + + const tensor& get_output() const { return l.get_output(); } + tensor& get_gradient_input() { return l.get_gradient_input(); } + + const layer_details_type& layer_details() const { return l.layer_details(); } + + const subnet_wrapper& subnet() const { return subnetwork; } + subnet_wrapper& subnet() { return subnetwork; } + unsigned int sample_expansion_factor() const { return l.sample_expansion_factor(); } + + private: + T& l; + subnet_wrapper subnetwork; + }; + } + +// ---------------------------------------------------------------------------------------- + + template + class add_layer; + + template + void serialize(const add_layer& item, std::ostream& out); + template + void deserialize(add_layer& item, std::istream& in); + + template + struct is_nonloss_layer_type> : std::true_type {}; + + template + class add_layer::value>::type> + { + public: + typedef LAYER_DETAILS layer_details_type; + typedef SUBNET subnet_type; + typedef typename subnet_type::input_type input_type; + const static size_t num_layers = subnet_type::num_layers + 1; + const static size_t num_computational_layers = subnet_type::num_computational_layers + 1; + + add_layer( + ): + subnetwork(new subnet_type()), + this_layer_setup_called(false), + gradient_input_is_stale(true), + get_output_and_gradient_input_disabled(false) + { + if (this_layer_operates_inplace()) + subnetwork->disable_output_and_gradient_getters(); + } + + add_layer(const add_layer& item) + { + details = item.details; + subnetwork.reset(new subnet_type(*item.subnetwork)); + this_layer_setup_called = item.this_layer_setup_called; + gradient_input_is_stale = item.gradient_input_is_stale; + get_output_and_gradient_input_disabled = item.get_output_and_gradient_input_disabled; + x_grad = item.x_grad; + cached_output = item.cached_output; + params_grad = item.params_grad; + temp_tensor = item.temp_tensor; + } + add_layer& operator=(const add_layer& item) { add_layer(item).swap(*this); return *this;} + add_layer(add_layer&& item) : add_layer() { swap(item); } + add_layer& operator=(add_layer&& item) { swap(item); return *this; } + + template + friend class add_layer; + template + friend class dimpl::subnet_wrapper; + template + friend class add_tag_layer; + template class T, typename U> + friend class add_skip_layer; + template class L, typename S> + friend class repeat; + + // Allow copying networks from one to another as long as their corresponding + // layers can be constructed from each other. + template + add_layer( + const add_layer& item + ) : + details(item.layer_details()), + subnetwork(new subnet_type(item.subnet())), + this_layer_setup_called(item.this_layer_setup_called), + gradient_input_is_stale(item.gradient_input_is_stale), + get_output_and_gradient_input_disabled(item.get_output_and_gradient_input_disabled), + x_grad(item.x_grad), + cached_output(item.cached_output) + { + if (this_layer_operates_inplace()) + subnetwork->disable_output_and_gradient_getters(); + } + + template + add_layer( + const LAYER_DETAILS& layer_det, + T&& ...args + ) : + details(layer_det), + subnetwork(new subnet_type(std::forward(args)...)), + this_layer_setup_called(false), + gradient_input_is_stale(true), + get_output_and_gradient_input_disabled(false) + { + if (this_layer_operates_inplace()) + subnetwork->disable_output_and_gradient_getters(); + } + + template + struct disable_forwarding_constr + { + const static bool value = std::is_constructible::value; + }; + template + struct disable_forwarding_constr,U...> + { + const static bool value = disable_forwarding_constr::type...>::value; + }; + template + struct disable_forwarding_constr,U...> + { + const static bool value = disable_forwarding_constr::type>::value; + }; + template + struct disable_forwarding_constr,U...> + { + const static bool value = true; + }; + template + struct disable_forwarding_constr> + { + const static bool value = true; + }; + + template < + typename ...T, + typename = typename std::enable_if::type...>::value>::type + > + add_layer( + T&& ...args + ) : + subnetwork(new subnet_type(std::forward(args)...)), + this_layer_setup_called(false), + gradient_input_is_stale(true), + get_output_and_gradient_input_disabled(false) + { + if (this_layer_operates_inplace()) + subnetwork->disable_output_and_gradient_getters(); + } + + template + add_layer( + LAYER_DETAILS&& layer_det, + T&& ...args + ) : + details(std::move(layer_det)), + subnetwork(new subnet_type(std::forward(args)...)), + this_layer_setup_called(false), + gradient_input_is_stale(true), + get_output_and_gradient_input_disabled(false) + { + if (this_layer_operates_inplace()) + subnetwork->disable_output_and_gradient_getters(); + } + + template + add_layer( + const std::tuple& layer_det, + T&& ...args + ) : + details(tuple_head(layer_det)), + subnetwork(new subnet_type(tuple_tail(layer_det),std::forward(args)...)), + this_layer_setup_called(false), + gradient_input_is_stale(true), + get_output_and_gradient_input_disabled(false) + { + if (this_layer_operates_inplace()) + subnetwork->disable_output_and_gradient_getters(); + } + + template + add_layer( + std::tuple<>, + const std::tuple& layer_det, + T&& ...args + ) : add_layer(layer_det,args...) { } + + add_layer ( + std::tuple<> + ) : add_layer() {} + + template + add_layer( + std::tuple<>, + LAYER_DETAILS&& layer_det, + T&& ...args + ) : add_layer(layer_det, args...) { } + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const + { + subnetwork->to_tensor(ibegin,iend,data); + } + + template + const tensor& operator() ( + forward_iterator ibegin, + forward_iterator iend + ) + { + to_tensor(ibegin,iend,temp_tensor); + return forward(temp_tensor); + } + + + const tensor& operator() (const input_type& x) + { + return (*this)(&x, &x+1); + } + + const tensor& forward(const tensor& x) + { + subnetwork->forward(x); + const dimpl::subnet_wrapper wsub(*subnetwork); + if (!this_layer_setup_called) + { + details.setup(wsub); + this_layer_setup_called = true; + } + if (this_layer_operates_inplace()) + impl::call_layer_forward(details, wsub, private_get_output()); + else + impl::call_layer_forward(details, wsub, cached_output); + + gradient_input_is_stale = true; + return private_get_output(); + } + + private: + tensor& private_get_output() const + { + if (const_cast(*this).this_layer_operates_inplace()) + return subnetwork->private_get_output(); + else + return const_cast(cached_output); + } + tensor& private_get_gradient_input() + { + if (this_layer_operates_inplace()) + { + return subnetwork->private_get_gradient_input(); + } + else + { + if (gradient_input_is_stale) + { + gradient_input_is_stale = false; + x_grad.copy_size(private_get_output()); + x_grad = 0; + } + return x_grad; + } + } + void disable_output_and_gradient_getters ( + ) { get_output_and_gradient_input_disabled = true; } + public: + const tensor& get_output() const + { + if (get_output_and_gradient_input_disabled) + throw dlib::error("Accessing this layer's get_output() is disabled because an in-place layer has been stacked on top of it."); + return private_get_output(); + } + tensor& get_gradient_input() + { + if (get_output_and_gradient_input_disabled) + throw dlib::error("Accessing this layer's get_gradient_input() is disabled because an in-place layer has been stacked on top of it."); + return private_get_gradient_input(); + } + + const tensor& get_final_data_gradient( + ) const { return subnetwork->get_final_data_gradient(); } + + void back_propagate_error(const tensor& x) + { + back_propagate_error(x, private_get_gradient_input()); + } + void back_propagate_error(const tensor& x, const tensor& gradient_input) + { + dimpl::subnet_wrapper wsub(*subnetwork); + params_grad.copy_size(details.get_layer_params()); + impl::call_layer_backward(details, private_get_output(), + gradient_input, wsub, static_cast(params_grad)); + + subnetwork->back_propagate_error(x); + + // zero out get_gradient_input() + gradient_input_is_stale = true; + } + + template + void update_parameters(sstack solvers, double learning_rate) + { + DLIB_CASSERT(solvers.size()>=num_computational_layers); + // Don't try to adjust the parameters if this layer doesn't have any or the + // learning rate is disabled for this layer. + if (params_grad.size() != 0 && get_learning_rate_multiplier(details) != 0) + { + const tensor& step = solvers.top()(learning_rate, details, static_cast(params_grad)); + tt::add(details.get_layer_params(), details.get_layer_params(), step); + } + subnetwork->update_parameters(solvers.pop(), learning_rate); + } + + const tensor& get_parameter_gradient( + ) const { return params_grad; } + + tensor& get_parameter_gradient ( + ) { return params_grad; } + + const subnet_type& subnet() const { return *subnetwork; } + subnet_type& subnet() { return *subnetwork; } + + const layer_details_type& layer_details() const { return details; } + layer_details_type& layer_details() { return details; } + + unsigned int sample_expansion_factor() const { return subnet().sample_expansion_factor(); } + + void clean() + { + x_grad.clear(); + cached_output.clear(); + params_grad.clear(); + temp_tensor.clear(); + gradient_input_is_stale = true; + subnetwork->clean(); + call_clean_method_if_exists(details); + } + + friend void serialize(const add_layer& item, std::ostream& out) + { + int version = 2; + serialize(version, out); + serialize(*item.subnetwork, out); + serialize(item.details, out); + serialize(item.this_layer_setup_called, out); + serialize(item.gradient_input_is_stale, out); + serialize(item.get_output_and_gradient_input_disabled, out); + serialize(item.x_grad, out); + serialize(item.cached_output, out); + serialize(item.params_grad, out); + } + + friend void deserialize(add_layer& item, std::istream& in) + { + int version = 0; + deserialize(version, in); + if (!(1 <= version && version <= 2)) + throw serialization_error("Unexpected version found while deserializing dlib::add_layer."); + deserialize(*item.subnetwork, in); + deserialize(item.details, in); + deserialize(item.this_layer_setup_called, in); + deserialize(item.gradient_input_is_stale, in); + deserialize(item.get_output_and_gradient_input_disabled, in); + deserialize(item.x_grad, in); + deserialize(item.cached_output, in); + if (version == 2) + deserialize(item.params_grad, in); + } + + friend std::ostream& operator<< (std::ostream& out, const add_layer& item) + { + int min_length = 0; + item.print(out, 0, min_length); + return out; + } + + void print (std::ostream& out, unsigned long idx, int& min_length) const + { + out << "layer<" << idx << ">\t" << impl::tensor_to_str(private_get_output(), min_length) << layer_details() << "\n"; + subnet().print(out, idx+1, min_length); + } + + private: + + bool this_layer_operates_inplace( + ) + { + // This layer can run in-place if it's an in-place capable layer and also if + // the layer it's on top of doesn't need its own output tensor (since in-place + // layers overwrite that tensor) + return impl::is_inplace_layer(details, *subnetwork) && !subnetwork->this_layer_requires_forward_output(); + } + bool this_layer_requires_forward_output( + ) + { + return impl::backward_requires_forward_output(details, *subnetwork); + } + + void swap(add_layer& item) + { + std::swap(subnetwork,item.subnetwork); + std::swap(details, item.details); + std::swap(this_layer_setup_called, item.this_layer_setup_called); + std::swap(gradient_input_is_stale, item.gradient_input_is_stale); + std::swap(get_output_and_gradient_input_disabled, item.get_output_and_gradient_input_disabled); + std::swap(x_grad, item.x_grad); + std::swap(cached_output, item.cached_output); + std::swap(params_grad, item.params_grad); + } + + + LAYER_DETAILS details; + std::unique_ptr subnetwork; + bool this_layer_setup_called; + bool gradient_input_is_stale; + bool get_output_and_gradient_input_disabled; + // Note that if this_layer_operates_inplace()==true then x_grad and cached_output + // are not used at all. Instead, this layer uses these variables from the lower + // layer. + resizable_tensor x_grad; + resizable_tensor cached_output; + + resizable_tensor params_grad; + + // temp_tensor doesn't logically contribute to the state of this object. + // It is here only to prevent it from being reallocated over and over. + resizable_tensor temp_tensor; + + }; + + template + struct is_add_layer> : std::true_type {}; + template + struct is_add_layer> : std::true_type {}; + template + struct is_add_layer&> : std::true_type {}; + template + struct is_add_layer&> : std::true_type {}; + +// ---------------------------------------------------------------------------------------- + +// This version of add_layer handles the special case where the subnetwork being given is +// just an input layer object. + template + class add_layer + { + public: + typedef LAYER_DETAILS layer_details_type; + typedef INPUT_LAYER subnet_type; + typedef typename INPUT_LAYER::input_type input_type; + const static size_t num_layers = 2; + const static size_t num_computational_layers = 1; + + add_layer( + ): + this_layer_setup_called(false), + gradient_input_is_stale(true), + get_output_and_gradient_input_disabled(false), + _sample_expansion_factor(0) + {} + + add_layer(const add_layer&) = default; + add_layer(add_layer&& item) : add_layer() { swap(item); } + add_layer& operator=(const add_layer&) = default; + add_layer& operator=(add_layer&& item) { swap(item); return *this; } + + template + friend class add_layer; + template + friend class dimpl::subnet_wrapper; + template + friend class add_tag_layer; + template class T, typename U> + friend class add_skip_layer; + template class L, typename S> + friend class repeat; + + // Allow copying networks from one to another as long as their corresponding + // layers can be constructed from each other. + template + add_layer( + const add_layer& item + ): + input_layer(item.subnet()), + details(item.layer_details()), + this_layer_setup_called(item.this_layer_setup_called), + gradient_input_is_stale(item.gradient_input_is_stale), + get_output_and_gradient_input_disabled(false), + _sample_expansion_factor(item._sample_expansion_factor), + x_grad(item.x_grad), + cached_output(item.cached_output), + grad_final(item.grad_final) + { + } + + add_layer( + const LAYER_DETAILS& layer_det + ) : + details(layer_det), + this_layer_setup_called(false), + gradient_input_is_stale(true), + get_output_and_gradient_input_disabled(false), + _sample_expansion_factor(0) + {} + + add_layer( + const INPUT_LAYER& il + ) : + input_layer(il), + this_layer_setup_called(false), + gradient_input_is_stale(true), + get_output_and_gradient_input_disabled(false), + _sample_expansion_factor(0) + {} + + add_layer( + LAYER_DETAILS&& layer_det + ) : + details(std::move(layer_det)), + this_layer_setup_called(false), + gradient_input_is_stale(true), + get_output_and_gradient_input_disabled(false), + _sample_expansion_factor(0) + {} + + add_layer( + LAYER_DETAILS layer_det, + INPUT_LAYER il + ) : + details(std::move(layer_det)), + input_layer(std::move(il)), + this_layer_setup_called(false), + gradient_input_is_stale(true), + get_output_and_gradient_input_disabled(false), + _sample_expansion_factor(0) + {} + + add_layer( + std::tuple<>, + const LAYER_DETAILS& layer_det + ) : add_layer(layer_det) {} + + add_layer( + std::tuple<>, + LAYER_DETAILS&& layer_det + ) : add_layer(layer_det) {} + + add_layer( + std::tuple<>, + LAYER_DETAILS layer_det, + INPUT_LAYER il + ) : add_layer(layer_det,il) {} + + add_layer( + const std::tuple& layer_det + ) : add_layer(tuple_head(layer_det)) {} + + add_layer( + const std::tuple& layer_det, + INPUT_LAYER il + ) : add_layer(tuple_head(layer_det),il) {} + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const + { + input_layer.to_tensor(ibegin, iend, data); + // make sure the input layer's to_tensor() function is implemented properly. + DLIB_CASSERT(data.num_samples() >= std::distance(ibegin,iend), + "The input layer can't produce fewer output tensors than there are inputs."); + DLIB_CASSERT(data.num_samples()%std::distance(ibegin,iend) == 0, + "The number of tensors produced by the input layer must be an integer multiple of the number of input objects."); + + _sample_expansion_factor = data.num_samples()/std::distance(ibegin,iend); + data.async_copy_to_device(); + } + + + template + const tensor& operator() ( + forward_iterator ibegin, + forward_iterator iend + ) + { + to_tensor(ibegin,iend,temp_tensor); + return forward(temp_tensor); + } + + + const tensor& operator() (const input_type& x) + { + return (*this)(&x, &x+1); + } + + const tensor& forward (const tensor& x) + { + DLIB_CASSERT(sample_expansion_factor() != 0, "You must call to_tensor() before this function can be used."); + DLIB_CASSERT(x.num_samples()%sample_expansion_factor() == 0); + subnet_wrapper wsub(x, grad_final, _sample_expansion_factor); + if (!this_layer_setup_called) + { + details.setup(wsub); + this_layer_setup_called = true; + } + impl::call_layer_forward(details, wsub, cached_output); + gradient_input_is_stale = true; + return private_get_output(); + } + + private: + tensor& private_get_output() const { return const_cast(cached_output); } + tensor& private_get_gradient_input() + { + if (gradient_input_is_stale) + { + gradient_input_is_stale = false; + x_grad.copy_size(private_get_output()); + x_grad = 0; + } + return x_grad; + } + void disable_output_and_gradient_getters ( + ) { get_output_and_gradient_input_disabled = true; } + public: + const tensor& get_output() const + { + if (get_output_and_gradient_input_disabled) + throw dlib::error("Accessing this layer's get_output() is disabled because an in-place layer has been stacked on top of it."); + return private_get_output(); + } + tensor& get_gradient_input() + { + if (get_output_and_gradient_input_disabled) + throw dlib::error("Accessing this layer's get_gradient_input() is disabled because an in-place layer has been stacked on top of it."); + return private_get_gradient_input(); + } + + const tensor& get_final_data_gradient( + ) const { return grad_final; } + + void back_propagate_error(const tensor& x) + { + back_propagate_error(x, private_get_gradient_input()); + } + void back_propagate_error(const tensor& x, const tensor& gradient_input) + { + // make sure grad_final is initialized to 0 + if (!have_same_dimensions(x, grad_final)) + grad_final.copy_size(x); + grad_final = 0; + + subnet_wrapper wsub(x, grad_final, _sample_expansion_factor); + params_grad.copy_size(details.get_layer_params()); + impl::call_layer_backward(details, private_get_output(), + gradient_input, wsub, static_cast(params_grad)); + + // zero out get_gradient_input() + gradient_input_is_stale = true; + } + + template + void update_parameters(sstack solvers, double learning_rate) + { + DLIB_CASSERT(solvers.size()>=num_computational_layers); + // Don't try to adjust the parameters if this layer doesn't have any or the + // learning rate is disabled for this layer. + if (params_grad.size() != 0 && get_learning_rate_multiplier(details) != 0) + { + const tensor& step = solvers.top()(learning_rate, details, static_cast(params_grad)); + tt::add(details.get_layer_params(), details.get_layer_params(), step); + } + } + + const tensor& get_parameter_gradient( + ) const { return params_grad; } + + tensor& get_parameter_gradient ( + ) { return params_grad; } + + const subnet_type& subnet() const { return input_layer; } + subnet_type& subnet() { return input_layer; } + + const layer_details_type& layer_details() const { return details; } + layer_details_type& layer_details() { return details; } + + unsigned int sample_expansion_factor() const { return _sample_expansion_factor; } + + void clean() + { + x_grad.clear(); + grad_final.clear(); + cached_output.clear(); + params_grad.clear(); + temp_tensor.clear(); + gradient_input_is_stale = true; + call_clean_method_if_exists(details); + } + + friend void serialize(const add_layer& item, std::ostream& out) + { + int version = 3; + serialize(version, out); + serialize(item.input_layer, out); + serialize(item.details, out); + serialize(item.this_layer_setup_called, out); + serialize(item.gradient_input_is_stale, out); + serialize(item.get_output_and_gradient_input_disabled, out); + serialize(item.x_grad, out); + serialize(item.cached_output, out); + serialize(item.grad_final, out); + serialize(item._sample_expansion_factor, out); + } + + friend void deserialize(add_layer& item, std::istream& in) + { + int version = 0; + deserialize(version, in); + if (!(2 <= version && version <= 3)) + throw serialization_error("Unexpected version found while deserializing dlib::add_layer."); + deserialize(item.input_layer, in); + deserialize(item.details, in); + deserialize(item.this_layer_setup_called, in); + deserialize(item.gradient_input_is_stale, in); + deserialize(item.get_output_and_gradient_input_disabled, in); + deserialize(item.x_grad, in); + deserialize(item.cached_output, in); + deserialize(item.grad_final, in); + if (version >= 3) + deserialize(item._sample_expansion_factor, in); + else + item._sample_expansion_factor = 1; // all layer types set this to 1 in older dlib versions, so that's what we put here. + } + + friend std::ostream& operator<< (std::ostream& out, const add_layer& item) + { + int min_length = 0; + item.print(out, 0, min_length); + return out; + } + + void print (std::ostream& out, unsigned long idx, int& min_length) const + { + out << "layer<" << idx << ">\t" << impl::tensor_to_str(private_get_output(), min_length) << layer_details() << "\n"; + + // Don't print the repeat_input_layer since it doesn't exist from the user's + // point of view. It's just an artifact of how repeat<> works. + if (!std::is_same::value) + out << "layer<" << idx+1 << ">\t" << subnet() << "\n"; + } + + private: + + bool this_layer_requires_forward_output( + ) + { + subnet_wrapper wsub(grad_final, grad_final, _sample_expansion_factor); + return impl::backward_requires_forward_output(details, wsub); + } + + class subnet_wrapper + { + public: + subnet_wrapper(const tensor& x_, resizable_tensor& grad_final_, unsigned int sef) : + x(x_), grad_final(grad_final_), _sample_expansion_factor(sef) {} + + subnet_wrapper(const subnet_wrapper&) = delete; + subnet_wrapper& operator=(const subnet_wrapper&) = delete; + + unsigned int sample_expansion_factor() const { return _sample_expansion_factor;} + const tensor& get_output() const { return x; } + tensor& get_gradient_input() + { + if (!have_same_dimensions(x, grad_final)) + { + grad_final.copy_size(x); + grad_final = 0; + } + return grad_final; + } + + private: + const tensor& x; + resizable_tensor& grad_final; + unsigned int _sample_expansion_factor; + }; + + void swap(add_layer& item) + { + std::swap(input_layer, item.input_layer); + std::swap(details, item.details); + std::swap(this_layer_setup_called, item.this_layer_setup_called); + std::swap(gradient_input_is_stale, item.gradient_input_is_stale); + std::swap(get_output_and_gradient_input_disabled, item.get_output_and_gradient_input_disabled); + std::swap(x_grad, item.x_grad); + std::swap(cached_output, item.cached_output); + std::swap(grad_final, item.grad_final); + std::swap(_sample_expansion_factor, item._sample_expansion_factor); + } + + subnet_type input_layer; + LAYER_DETAILS details; + bool this_layer_setup_called; + bool gradient_input_is_stale; + bool get_output_and_gradient_input_disabled; + mutable unsigned int _sample_expansion_factor; + resizable_tensor x_grad; + resizable_tensor cached_output; + resizable_tensor grad_final; + + // The following 2 objects don't logically contribute to the state of this class. + // They are only here to prevent them from being reallocated over and over in + // member functions. + resizable_tensor params_grad; + resizable_tensor temp_tensor; + }; + +// ---------------------------------------------------------------------------------------- + + template + class add_tag_layer; + + template class tag> + struct tag_id + { + const static unsigned long id = tag::id; + }; + + template + class add_tag_layer::value>::type> + { + public: + typedef SUBNET subnet_type; + typedef typename subnet_type::input_type input_type; + typedef int layer_details_type; // not really used anywhere, but required by subnet_wrapper. + const static size_t num_layers = subnet_type::num_layers + 1; + const static size_t num_computational_layers = subnet_type::num_computational_layers; + const static unsigned long id = ID; + + add_tag_layer() {}; + add_tag_layer(const add_tag_layer&) = default; + add_tag_layer(add_tag_layer&&) = default; + add_tag_layer& operator=(add_tag_layer&&) = default; + add_tag_layer& operator=(const add_tag_layer&) = default; + + template + add_tag_layer( + const add_tag_layer& item + ) : subnetwork(item.subnet()) + {} + + template + add_tag_layer( + T ...args + ) : + subnetwork(std::move(args)...) + { + } + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const + { + subnetwork.to_tensor(ibegin,iend,data); + } + + template + const tensor& operator() ( + forward_iterator ibegin, + forward_iterator iend + ) + { + return subnetwork(ibegin,iend); + } + + const tensor& operator() (const input_type& x) + { + return subnetwork(x); + } + + const tensor& forward(const tensor& x) + { + return subnetwork.forward(x); + } + + const tensor& get_output() const { return subnetwork.get_output(); } + + tensor& get_gradient_input() + { + return subnetwork.get_gradient_input(); + } + + const tensor& get_final_data_gradient( + ) const { return subnetwork.get_final_data_gradient(); } + + void back_propagate_error(const tensor& x) + { + subnetwork.back_propagate_error(x); + } + void back_propagate_error(const tensor& x, const tensor& gradient_input) + { + subnetwork.back_propagate_error(x,gradient_input); + } + + template + void update_parameters(sstack solvers, double learning_rate) + { + subnetwork.update_parameters(solvers, learning_rate); + } + + const tensor& get_parameter_gradient( + ) const { return params_grad; } + + tensor& get_parameter_gradient ( + ) { return params_grad; } + + const subnet_type& subnet() const { return subnetwork; } + subnet_type& subnet() { return subnetwork; } + + unsigned int sample_expansion_factor() const { return subnet().sample_expansion_factor(); } + + void clean() + { + subnetwork.clean(); + } + + friend void serialize(const add_tag_layer& item, std::ostream& out) + { + int version = 1; + serialize(version, out); + serialize(item.subnetwork, out); + } + + friend void deserialize(add_tag_layer& item, std::istream& in) + { + int version = 0; + deserialize(version, in); + if (version != 1) + throw serialization_error("Unexpected version found while deserializing dlib::add_tag_layer."); + deserialize(item.subnetwork, in); + } + + friend std::ostream& operator<< (std::ostream& out, const add_tag_layer& item) + { + int min_length = 0; + item.print(out, 0, min_length); + return out; + } + + void print (std::ostream& out, unsigned long idx, int& min_length) const + { + out << "layer<" << idx << ">\t" << impl::tensor_to_str(private_get_output(), min_length) << "tag" << ID << "\n"; + subnet().print(out, idx+1, min_length); + } + + private: + + template + friend class add_layer; + template + friend class dimpl::subnet_wrapper; + template + friend class add_tag_layer; + template class T, typename U> + friend class add_skip_layer; + template class L, typename S> + friend class repeat; + + // You wouldn't put a tag on a layer if you didn't want to access its forward + // outputs. So this is always true. + bool this_layer_requires_forward_output( + ) { return true; } + + void disable_output_and_gradient_getters ( + ) + { + // This should never happen because only inplace layers call + // disable_output_and_gradient_getters(), however, putting a tag layer right + // before an inplace layer basically means you don't want the following layer + // to operate in place. So the inplace layer should turn itself into an + // out-of-place layer and not call disable_output_and_gradient_getters(). + DLIB_CASSERT(false,"This should never happen"); + } + + tensor& private_get_output() const + { return subnetwork.private_get_output(); } + tensor& private_get_gradient_input() + { return subnetwork.private_get_gradient_input(); } + + subnet_type subnetwork; + + // This member doesn't logically contribute to the state of the object since it is + // always empty. It's just here so we can have the get_parameter_gradient() methods + // which have to return something. So they return this empty tensor. + resizable_tensor params_grad; + }; + +// ---------------------------------------------------------------------------------------- + + template + struct decorator_repeat_group + { + decorator_repeat_group( + T&& ...args + ) : data(std::forward(args)...) {} + + std::tuple data; + }; + template + decorator_repeat_group repeat_group ( + T&& ...args + ) + { + return decorator_repeat_group(std::forward(args)...); + } + + template < + size_t num, + template class REPEATED_LAYER, + typename SUBNET + > + class repeat + { + static_assert(num > 0, "You can't have a layer repeated 0 times."); + public: + typedef SUBNET subnet_type; + typedef typename SUBNET::input_type input_type; + typedef int layer_details_type; // not really used anywhere, but required by subnet_wrapper. + const static size_t comp_layers_in_each_group = (REPEATED_LAYER::num_computational_layers-SUBNET::num_computational_layers); + const static size_t comp_layers_in_repeated_group = comp_layers_in_each_group*num; + const static size_t num_computational_layers = comp_layers_in_repeated_group + SUBNET::num_computational_layers; + + const static size_t layers_in_each_group = (REPEATED_LAYER::num_layers-SUBNET::num_layers); + const static size_t layers_in_repeated_group = layers_in_each_group*num; + const static size_t num_layers = subnet_type::num_layers + layers_in_repeated_group; + + + typedef REPEATED_LAYER repeated_layer_type; + + repeat( + ) : + details(num) + { + } + + size_t num_repetitions ( + ) const { return num; } + + const repeated_layer_type& get_repeated_layer ( + size_t i + ) const + { + DLIB_CASSERT(i < num_repetitions()); + return details[i]; + } + + repeated_layer_type& get_repeated_layer ( + size_t i + ) + { + DLIB_CASSERT(i < num_repetitions()); + return details[i]; + } + + repeat(const repeat&) = default; + repeat(repeat&&) = default; + repeat& operator=(repeat&&) = default; + repeat& operator=(const repeat&) = default; + + template class T, typename U> + repeat( + const repeat& item + ) : + subnetwork(item.subnetwork) + { + for (auto&& d : item.details) + details.emplace_back(d); + } + + template + repeat( + T arg1, + U ...args2 + ): + details(num, std::move(arg1)), + subnetwork(std::move(args2)...) + { + } + + template + repeat( + decorator_repeat_group&& arg1, + U ...args2 + ): + details(num, arg1.data), + subnetwork(std::move(args2)...) + { + } + + template + repeat( + std::tuple<>, + T arg1, + U ...args2 + ): + details(num, std::move(arg1)), + subnetwork(std::move(args2)...) + { + } + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const + { + subnetwork.to_tensor(ibegin,iend,data); + // call to_tensor on the networks in details just to populate the + // _sample_expansion_factor values in those networks. Other than that this + // call is a noop. + for (auto& d : details) + d.to_tensor(ibegin, iend, data); + } + + template + const tensor& operator() ( + forward_iterator ibegin, + forward_iterator iend + ) + { + to_tensor(ibegin,iend,temp_tensor); + return forward(temp_tensor); + } + + const tensor& operator() (const input_type& x) + { + return (*this)(&x, &x+1); + } + + const tensor& forward(const tensor& x) + { + subnetwork.forward(x); + details[details.size()-1].forward(subnetwork.get_output()); + for (long i = details.size()-2; i >= 0; --i) + details[i].forward(details[i+1].get_output()); + return private_get_output(); + } + + private: + tensor& private_get_output() const + { + return details[0].private_get_output(); + } + tensor& private_get_gradient_input() + { + return details[0].private_get_gradient_input(); + } + public: + const tensor& get_output() const + { + return details[0].get_output(); + } + tensor& get_gradient_input() + { + return details[0].get_gradient_input(); + } + + const tensor& get_parameter_gradient( + ) const { return details[0].get_parameter_gradient(); } + + tensor& get_parameter_gradient ( + ) { return details[0].get_parameter_gradient(); } + + void back_propagate_error(const tensor& x) + { + back_propagate_error(x, private_get_gradient_input()); + } + void back_propagate_error(const tensor& x, const tensor& gradient_input) + { + if (details.size() > 1) + { + details[0].back_propagate_error(details[1].get_output(), gradient_input); + for (size_t i = 1; i < details.size(); ++i) + { + if (i+1 < details.size()) + details[i].back_propagate_error(details[i+1].get_output(), details[i-1].get_final_data_gradient()); + else + details[i].back_propagate_error(subnetwork.get_output(), details[i-1].get_final_data_gradient()); + } + } + else + { + details[0].back_propagate_error(subnetwork.get_output(), gradient_input); + } + subnetwork.back_propagate_error(x, details.back().get_final_data_gradient()); + } + + template + void update_parameters(sstack solvers, double learning_rate) + { + for (size_t i = 0; i < details.size(); ++i) + details[i].update_parameters(solvers.pop(comp_layers_in_each_group*i),learning_rate); + subnetwork.update_parameters(solvers.pop(comp_layers_in_each_group*details.size()),learning_rate); + } + + const subnet_type& subnet() const { return subnetwork; } + subnet_type& subnet() { return subnetwork; } + + unsigned int sample_expansion_factor() const { return subnet().sample_expansion_factor(); } + + void clean() + { + temp_tensor.clear(); + subnetwork.clean(); + for (auto&& d : details) + d.clean(); + } + + friend void serialize(const repeat& item, std::ostream& out) + { + int version = 1; + serialize(version, out); + serialize(item.details, out); + serialize(item.subnetwork, out); + } + + friend void deserialize(repeat& item, std::istream& in) + { + int version = 0; + deserialize(version, in); + if (version != 1) + throw serialization_error("Unexpected version found while deserializing dlib::repeat."); + deserialize(item.details, in); + deserialize(item.subnetwork, in); + } + + friend std::ostream& operator<< (std::ostream& out, const repeat& item) + { + int min_length = 0; + item.print(out, 0, min_length); + return out; + } + + void print (std::ostream& out, unsigned long idx, int& min_length) const + { + for (size_t i = 0; i < num_repetitions(); ++i) + { + get_repeated_layer(i).print(out, idx, min_length); + idx += layers_in_each_group; + } + subnet().print(out, idx, min_length); + } + private: + + + template + friend class add_layer; + template + friend class dimpl::subnet_wrapper; + template + friend class add_tag_layer; + template class T, typename U> + friend class add_skip_layer; + template class L, typename S> + friend class repeat; + + bool this_layer_requires_forward_output( + ) + { + return details[0].this_layer_requires_forward_output(); + } + + void disable_output_and_gradient_getters ( + ) + { + details[0].disable_output_and_gradient_getters(); + } + + + std::vector details; + subnet_type subnetwork; + + // temp_tensor doesn't logically contribute to the state of this class. + // It is here only to void needing to reallocate it over and over. + resizable_tensor temp_tensor; + }; + + template < + size_t num, + template class REPEATED_LAYER, + typename SUBNET + > + struct is_nonloss_layer_type> : std::true_type {}; + +// ---------------------------------------------------------------------------------------- + +// This version of add_tag_layer handles the special case where the subnetwork being given +// is just an input layer object. + template + class add_tag_layer + { + public: + typedef INPUT_LAYER subnet_type; + typedef typename subnet_type::input_type input_type; + typedef int layer_details_type; // not really used anywhere, but required by subnet_wrapper. + const static size_t num_computational_layers = 0; + const static size_t num_layers = 2; + const static unsigned long id = ID; + + add_tag_layer():cached_output_ptr(nullptr),gradient_input_is_stale(true),_sample_expansion_factor(0) {} + + add_tag_layer(const add_tag_layer&) = default; + add_tag_layer& operator=(const add_tag_layer&) = default; + add_tag_layer(add_tag_layer&& item) : add_tag_layer() { swap(item); } + add_tag_layer& operator=(add_tag_layer&& item) { swap(item); return *this; } + + template + add_tag_layer( + const add_tag_layer& item + ) : input_layer(item.subnet()), + cached_output(item.cached_output), + cached_output_ptr(nullptr), + grad_final(item.grad_final), + gradient_input_is_stale(item.gradient_input_is_stale), + _sample_expansion_factor(0) + {} + + template + add_tag_layer( + T ...args + ) : + input_layer(std::move(args)...), + cached_output_ptr(nullptr), + gradient_input_is_stale(true), + _sample_expansion_factor(0) + { + } + + add_tag_layer ( + std::tuple<> + ) : + cached_output_ptr(nullptr), + gradient_input_is_stale(true), + _sample_expansion_factor(0) + {} + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const + { + input_layer.to_tensor(ibegin,iend,data); + + // make sure the input layer's to_tensor() function is implemented properly. + DLIB_CASSERT(data.num_samples() >= std::distance(ibegin,iend), + "The input layer can't produce fewer output tensors than there are inputs."); + DLIB_CASSERT(data.num_samples()%std::distance(ibegin,iend) == 0, + "The number of tensors produced by the input layer must be an integer multiple of the number of input objects."); + + _sample_expansion_factor = data.num_samples()/std::distance(ibegin,iend); + data.async_copy_to_device(); + } + + unsigned int sample_expansion_factor() const { return _sample_expansion_factor; } + + template + const tensor& operator() ( + forward_iterator ibegin, + forward_iterator iend + ) + { + input_layer.to_tensor(ibegin,iend,cached_output); + cached_output_ptr = nullptr; + return get_output(); + } + + const tensor& operator() (const input_type& x) + { + return (*this)(&x, &x+1); + } + + const tensor& forward(const tensor& x) + { + // If this tag is the first layer in one of the sub networks inside a repeat + // layer then we don't want it to be creating copies of x. This is because, we + // can just hold a pointer to x since the way repeat is constructed guarantees + // that x will have a lifetime larger than this pointer. + if (is_same_type::value) + cached_output_ptr = const_cast(&x); + else + cached_output = x; + gradient_input_is_stale = true; + return get_output(); + } + + const tensor& get_output() const + { + if (cached_output_ptr) + return *cached_output_ptr; + else + return cached_output; + } + + const tensor& get_final_data_gradient( + ) const { return grad_final; } + + tensor& get_gradient_input() + { + if (!have_same_dimensions(get_output(), grad_final) || + gradient_input_is_stale) + { + grad_final.copy_size(get_output()); + grad_final = 0; + gradient_input_is_stale = false; + } + return grad_final; + } + + void back_propagate_error(const tensor& /*x*/) + { + // nothing to do + } + void back_propagate_error(const tensor& /*x*/, const tensor& /*gradient_input*/) + { + // nothing to do + } + + template + void update_parameters(sstack /*solvers*/, double /*learning_rate*/) + { + // nothing to do + } + + const subnet_type& subnet() const { return input_layer; } + subnet_type& subnet() { return input_layer; } + + void clean() + { + grad_final.clear(); + cached_output.clear(); + cached_output_ptr = 0; + } + + friend void serialize(const add_tag_layer& item, std::ostream& out) + { + int version = 2; + serialize(version, out); + serialize(item.input_layer, out); + serialize(item.cached_output, out); + serialize(item.grad_final, out); + serialize(item.gradient_input_is_stale, out); + serialize(item._sample_expansion_factor, out); + } + + friend void deserialize(add_tag_layer& item, std::istream& in) + { + int version = 0; + deserialize(version, in); + if (!(1 <= version && version <= 2)) + throw serialization_error("Unexpected version found while deserializing dlib::add_tag_layer."); + deserialize(item.input_layer, in); + deserialize(item.cached_output, in); + deserialize(item.grad_final, in); + deserialize(item.gradient_input_is_stale, in); + item.cached_output_ptr = nullptr; + if (version >= 2) + deserialize(item._sample_expansion_factor, in); + else + item._sample_expansion_factor = 1; // all layer types set this to 1 in older dlib versions, so that's what we put here. + + } + + friend std::ostream& operator<< (std::ostream& out, const add_tag_layer& item) + { + int min_length = 0; + item.print(out, 0, min_length); + return out; + } + + void print (std::ostream& out, unsigned long idx, int& min_length) const + { + out << "layer<"<\t"< works. + if (!std::is_same::value) + out << "layer<"<< idx+1 << ">\t" << subnet() << "\n"; + } + + private: + + template + friend class add_layer; + template + friend class dimpl::subnet_wrapper; + template + friend class add_tag_layer; + template class T, typename U> + friend class add_skip_layer; + template class L, typename S> + friend class repeat; + + // You woudln't put a tag on a layer if you didn't want to access its forward + // outputs. So this is always true. + bool this_layer_requires_forward_output( + ) { return true; } + + void disable_output_and_gradient_getters ( + ) + { + // This should never happen because only inplace layers call + // disable_output_and_gradient_getters(), however, putting a tag layer right + // before an inplace layer basically means you don't want the following layer + // to operate in place. So the inplace layer should turn itself into an + // out-of-place layer and not call disable_output_and_gradient_getters(). + DLIB_CASSERT(false,"This should never happen"); + } + + tensor& private_get_output() const + { return const_cast(get_output()); } + tensor& private_get_gradient_input() + { return get_gradient_input(); } + + void swap(add_tag_layer& item) + { + std::swap(input_layer, item.input_layer); + std::swap(cached_output, item.cached_output); + std::swap(cached_output_ptr, item.cached_output_ptr); + std::swap(grad_final, item.grad_final); + std::swap(gradient_input_is_stale, item.gradient_input_is_stale); + std::swap(_sample_expansion_factor, item._sample_expansion_factor); + } + + subnet_type input_layer; + resizable_tensor cached_output; + tensor* cached_output_ptr; + resizable_tensor grad_final; + bool gradient_input_is_stale; + mutable unsigned int _sample_expansion_factor; + }; + + template + struct is_nonloss_layer_type> : std::true_type {}; + + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template + class add_loss_layer; + + class no_label_type + { + private: + // We don't want anyone making these no_label_type objects. They are here only to + // allow add_loss_layer::training_label_type and dnn_trainer::training_label_type + // to exist which avoids needing to overload add_loss_layer and dnn_trainer for + // supervised an unsupervised losses. It also can be a type to use in template + // metaprogramming to indicate "no label". So here we make the constructor private + // with the exception that add_loss_layer objects can make it (again, just to + // simplify add_loss_layer's implementation). + no_label_type(){}; + template friend class add_loss_layer; + template < typename net_type, typename solver_type > friend class dnn_trainer; + }; + +// ---------------------------------------------------------------------------------------- + + template + class add_loss_layer + { + template + struct get_loss_layer_training_label_type + { + typedef no_label_type type; + }; + template + struct get_loss_layer_training_label_type::type> + { + typedef typename T::training_label_type type; + }; + + template + struct get_loss_layer_output_label_type + { + typedef no_label_type type; + }; + template + struct get_loss_layer_output_label_type::type> + { + typedef typename T::output_label_type type; + }; + + public: + typedef LOSS_DETAILS loss_details_type; + typedef SUBNET subnet_type; + typedef typename subnet_type::input_type input_type; + const static size_t num_layers = subnet_type::num_layers + 1; + // Note that the loss layer doesn't count as an additional computational layer. + const static size_t num_computational_layers = subnet_type::num_computational_layers; + typedef typename get_loss_layer_training_label_type::type training_label_type; + typedef typename get_loss_layer_output_label_type::type output_label_type; + + static_assert(is_nonloss_layer_type::value, + "SUBNET must be of type add_layer, add_skip_layer, or add_tag_layer."); + + + add_loss_layer() {}; + add_loss_layer(const add_loss_layer&) = default; + add_loss_layer& operator=(const add_loss_layer&) = default; + add_loss_layer(add_loss_layer&& item) : add_loss_layer() { swap(item); } + add_loss_layer& operator=(add_loss_layer&& item) { swap(item); return *this; } + + template + add_loss_layer( + const add_loss_layer& item + ) : + loss(item.loss_details()), + subnetwork(item.subnet()) + {} + + template + add_loss_layer( + const LOSS_DETAILS& layer_det, + T&& ...args + ) : + loss(layer_det), + subnetwork(std::forward(args)...) + { + } + + template + add_loss_layer( + LOSS_DETAILS&& layer_det, + T&& ...args + ) : + loss(std::move(layer_det)), + subnetwork(std::forward(args)...) + { + } + + template + struct disable_forwarding_constr + { + const static bool value = std::is_constructible::value; + }; + template + struct disable_forwarding_constr> + { + const static bool value = true; + }; + + template < + typename ...T, + typename = typename std::enable_if::type...>::value>::type + > + add_loss_layer( + T&& ...args + ) : + subnetwork(std::forward(args)...) + { + } + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const + { + subnetwork.to_tensor(ibegin,iend,data); + } + + unsigned int sample_expansion_factor() const { return subnet().sample_expansion_factor(); } + + template + void operator() ( + const tensor& x, + output_iterator obegin + ) + { + subnetwork.forward(x); + const dimpl::subnet_wrapper wsub(subnetwork); + loss.to_label(x, wsub, obegin); + } + + template + void operator() ( + forward_iterator ibegin, + forward_iterator iend, + output_iterator obegin + ) + { + to_tensor(ibegin,iend,temp_tensor); + (*this)(temp_tensor, obegin); + } + + const output_label_type& operator() (const input_type& x) + { + (*this)(&x, &x+1, &temp_label); + return temp_label; + } + + template + const output_label_type& process (const input_type& x, T&& ...args) + { + to_tensor(&x,&x+1,temp_tensor); + subnetwork.forward(temp_tensor); + const dimpl::subnet_wrapper wsub(subnetwork); + loss.to_label(temp_tensor, wsub, &temp_label, std::forward(args)...); + return temp_label; + } + + template + std::vector process_batch (const iterable_type& data, size_t batch_size, T&& ...args) + { + std::vector results(std::distance(data.begin(), data.end())); + auto o = results.begin(); + auto i = data.begin(); + auto num_remaining = results.size(); + while(num_remaining != 0) + { + auto inc = std::min(batch_size, num_remaining); + to_tensor(i,i+inc,temp_tensor); + subnetwork.forward(temp_tensor); + const dimpl::subnet_wrapper wsub(subnetwork); + loss.to_label(temp_tensor, wsub, o, std::forward(args)...); + + i += inc; + o += inc; + num_remaining -= inc; + } + return results; + } + + template + std::vector operator() ( + const iterable_type& data, + size_t batch_size = 128 + ) + { + std::vector results(std::distance(data.begin(), data.end())); + auto o = results.begin(); + auto i = data.begin(); + auto num_remaining = results.size(); + while(num_remaining != 0) + { + auto inc = std::min(batch_size, num_remaining); + (*this)(i, i+inc, o); + i += inc; + o += inc; + num_remaining -= inc; + } + return results; + } + + template + double compute_loss ( + const tensor& x, + label_iterator lbegin + ) + { + subnetwork.forward(x); + dimpl::subnet_wrapper wsub(subnetwork); + return loss.compute_loss_value_and_gradient(x, lbegin, wsub); + } + + template + double compute_loss ( + forward_iterator ibegin, + forward_iterator iend, + label_iterator lbegin + ) + { + to_tensor(ibegin,iend,temp_tensor); + return compute_loss(temp_tensor, lbegin); + } + + double compute_loss ( + const tensor& x + ) + { + subnetwork.forward(x); + dimpl::subnet_wrapper wsub(subnetwork); + return loss.compute_loss_value_and_gradient(x, wsub); + } + + template + double compute_loss ( + forward_iterator ibegin, + forward_iterator iend + ) + { + to_tensor(ibegin,iend,temp_tensor); + return compute_loss(temp_tensor); + } + + template + double compute_parameter_gradients ( + const tensor& x, + label_iterator lbegin + ) + { + subnetwork.forward(x); + dimpl::subnet_wrapper wsub(subnetwork); + double l = loss.compute_loss_value_and_gradient(x, lbegin, wsub); + subnetwork.back_propagate_error(x); + return l; + } + template + double compute_parameter_gradients ( + forward_iterator ibegin, + forward_iterator iend, + label_iterator lbegin + ) + { + to_tensor(ibegin,iend,temp_tensor); + return compute_parameter_gradients(temp_tensor, lbegin); + } + double compute_parameter_gradients ( + const tensor& x + ) + { + subnetwork.forward(x); + dimpl::subnet_wrapper wsub(subnetwork); + double l = loss.compute_loss_value_and_gradient(x, wsub); + subnetwork.back_propagate_error(x); + return l; + } + template + double compute_parameter_gradients ( + forward_iterator ibegin, + forward_iterator iend + ) + { + to_tensor(ibegin,iend,temp_tensor); + return compute_parameter_gradients(temp_tensor); + } + + template + void update_parameters ( + sstack solvers, + double learning_rate + ) + { + subnetwork.update_parameters(solvers, learning_rate); + } + + const subnet_type& subnet() const { return subnetwork; } + subnet_type& subnet() { return subnetwork; } + const loss_details_type& loss_details() const { return loss; } + loss_details_type& loss_details() { return loss; } + + void clean ( + ) + { + temp_tensor.clear(); + subnetwork.clean(); + } + + template + friend void serialize(const add_loss_layer& item, std::ostream& out); + template + friend void deserialize(add_loss_layer& item, std::istream& in); + + friend std::ostream& operator<< (std::ostream& out, const add_loss_layer& item) + { + int min_length = 0; + item.print(out, 0, min_length); + return out; + } + + void print (std::ostream& out, unsigned long idx, int& min_length) const + { + out << "layer<" << idx << ">\t" << loss_details() << "\n"; + subnet().print(out, idx+1, min_length); + } + + private: + + + void swap(add_loss_layer& item) + { + std::swap(loss, item.loss); + std::swap(subnetwork, item.subnetwork); + } + + loss_details_type loss; + subnet_type subnetwork; + + // These two objects don't logically contribute to the state of this object. They + // are here to prevent them from being reallocated over and over. + output_label_type temp_label; + resizable_tensor temp_tensor; + }; + + template + void serialize(const add_loss_layer& item, std::ostream& out) + { + int version = 1; + serialize(version, out); + serialize(item.loss, out); + serialize(item.subnetwork, out); + } + + template + void deserialize(add_loss_layer& item, std::istream& in) + { + int version = 0; + deserialize(version, in); + if (version != 1) + throw serialization_error("Unexpected version found while deserializing dlib::add_loss_layer."); + deserialize(item.loss, in); + deserialize(item.subnetwork, in); + } + + + template + struct is_loss_layer_type> : std::true_type {}; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template + struct layer_helper + { + static_assert(i < T::num_layers, "Call to layer() attempted to access non-existing layer in neural network."); + static T& makeT(); + using next_type = typename std::remove_reference::type; + using type = typename layer_helper::type; + static type& layer(T& n) + { + return layer_helper::layer(n.subnet()); + } + }; + template < + unsigned int i, + size_t N, template class L, typename S + > + struct layer_helper, typename std::enable_if<(i!=0&&i>=repeat::layers_in_repeated_group)>::type> + { + const static size_t layers_in_repeated_group = repeat::layers_in_repeated_group; + + static repeat& makeT(); + using next_type = typename std::remove_reference::type; + using type = typename layer_helper::type; + static type& layer(repeat& n) + { + return layer_helper::layer(n.subnet()); + } + }; + template < + unsigned int i, + size_t N, template class L, typename S + > + struct layer_helper, typename std::enable_if<(i!=0&&i::layers_in_repeated_group)>::type> + { + const static size_t layers_in_each_group = repeat::layers_in_each_group; + typedef typename repeat::repeated_layer_type repeated_layer_type; + using next_type = repeated_layer_type; + using type = typename layer_helper::type; + static type& layer(repeat& n) + { + return layer_helper::layer(n.get_repeated_layer(i/layers_in_each_group)); + } + }; + template < + size_t N, template class L, typename S + > + struct layer_helper<0,repeat, void> + { + typedef typename repeat::repeated_layer_type repeated_layer_type; + using type = repeated_layer_type; + static type& layer(repeat& n) + { + return n.get_repeated_layer(0); + } + }; + + + + template < + unsigned int i, + size_t N, template class L, typename S + > + struct layer_helper, typename std::enable_if<(i!=0&&i>=repeat::layers_in_repeated_group)>::type> + { + const static size_t layers_in_repeated_group = repeat::layers_in_repeated_group; + + static const repeat& makeT(); + using next_type = const typename std::remove_reference::type; + using type = const typename layer_helper::type; + static type& layer(const repeat& n) + { + return layer_helper::layer(n.subnet()); + } + }; + template < + unsigned int i, + size_t N, template class L, typename S + > + struct layer_helper, typename std::enable_if<(i!=0&&i::layers_in_repeated_group)>::type> + { + const static size_t layers_in_each_group = repeat::layers_in_each_group; + typedef typename repeat::repeated_layer_type repeated_layer_type; + using next_type = const repeated_layer_type; + using type = const typename layer_helper::type; + static type& layer(const repeat& n) + { + return layer_helper::layer(n.get_repeated_layer(i/layers_in_each_group)); + } + }; + template < + size_t N, template class L, typename S + > + struct layer_helper<0,const repeat, void> + { + typedef typename repeat::repeated_layer_type repeated_layer_type; + using type = const repeated_layer_type; + static type& layer(const repeat& n) + { + return n.get_repeated_layer(0); + } + }; + + + + template + struct layer_helper<0,T,void> + { + using type = T; + static type& layer(T& n) + { + return n; + } + }; + + template class Match, typename T, unsigned int i, typename enabled = void> + struct layer_helper_match + { + static T& makeT(); + using next_type = typename std::remove_reference::type; + using type = typename layer_helper_match::type; + static type& layer(T& n) + { + return layer_helper_match::layer(n.subnet()); + } + }; + // This overload catches add_layer and add_loss_layer templates. + template class Match, typename T, unsigned int i> + struct layer_helper_match>::value>::type> + { + using type = typename layer_helper::type; + static type& layer(T& n) + { + return layer_helper::layer(n); + } + }; + // This overload catches input templates. + template class Match, typename T, unsigned int i> + struct layer_helper_match>::value>::type> + { + using type = typename layer_helper::type; + static type& layer(T& n) + { + return layer_helper::layer(n); + } + }; + // This overload catches subnet_wrapper templates. + template class Match, typename T, unsigned int i> + struct layer_helper_match>::value>::type> + { + using type = typename layer_helper::type; + static type& layer(T& n) + { + return layer_helper::layer(n); + } + }; + } + + template + typename impl::layer_helper::type& layer (T& n) + { + return impl::layer_helper::layer(n); + } + + template class Match, typename T> + typename impl::layer_helper_match::type& layer (T& n) + { + return impl::layer_helper_match::layer(n); + } + + template class Match, unsigned int i, typename T> + typename impl::layer_helper_match::type& layer (T& n) + { + return impl::layer_helper_match::layer(n); + } + +// ---------------------------------------------------------------------------------------- + + + namespace dimpl + { + template + T& get_input_details ( + T& net + ) + { + return net; + } + + template + auto get_input_details ( + dimpl::subnet_wrapper& net + ) -> decltype(net.layer_details())& + { + return net.layer_details(); + } + + template + auto get_input_details ( + const dimpl::subnet_wrapper& net + ) -> decltype(net.layer_details())& + { + return net.layer_details(); + } + } + + template + auto input_layer ( + net_type& net + ) -> decltype(dimpl::get_input_details(layer(net)))& + { + // Calling input_layer() on a subnet_wrapper is a little funny since the behavior of + // .subnet() returns another subnet_wrapper rather than an input details object as it + // does in add_layer. + return dimpl::get_input_details(layer(net)); + } + +// ---------------------------------------------------------------------------------------- + + template class TAG_TYPE, typename SUBNET> + class add_skip_layer + { + public: + typedef SUBNET subnet_type; + typedef typename subnet_type::input_type input_type; + typedef int layer_details_type; // not really used anywhere, but required by subnet_wrapper. + const static size_t num_layers = subnet_type::num_layers + 1; + const static size_t num_computational_layers = subnet_type::num_computational_layers; + const static unsigned long id = tag_id::id; + + add_skip_layer() {}; + add_skip_layer(const add_skip_layer&) = default; + add_skip_layer(add_skip_layer&&) = default; + add_skip_layer& operator=(add_skip_layer&&) = default; + add_skip_layer& operator=(const add_skip_layer&) = default; + + template + add_skip_layer( + const add_skip_layer& item + ) : subnetwork(item.subnet()) + {} + + template + add_skip_layer( + T ...args + ) : + subnetwork(std::move(args)...) + { + } + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const + { + subnetwork.to_tensor(ibegin,iend,data); + } + + template + const tensor& operator() ( + forward_iterator ibegin, + forward_iterator iend + ) + { + subnetwork(ibegin,iend); + return layer(subnetwork).get_output(); + } + + const tensor& operator() (const input_type& x) + { + subnetwork(x); + return layer(subnetwork).get_output(); + } + + const tensor& forward(const tensor& x) + { + subnetwork.forward(x); + return layer(subnetwork).get_output(); + } + + const tensor& get_output() const + { + return layer(subnetwork).get_output(); + } + + tensor& get_gradient_input() + { + return layer(subnetwork).get_gradient_input(); + } + + const tensor& get_final_data_gradient( + ) const + { + return subnetwork.get_final_data_gradient(); + } + + void back_propagate_error(const tensor& x) + { + subnetwork.back_propagate_error(x); + } + + template + void update_parameters(sstack solvers, double learning_rate) + { + subnetwork.update_parameters(solvers, learning_rate); + } + + const tensor& get_parameter_gradient( + ) const { return params_grad; } + + tensor& get_parameter_gradient ( + ) { return params_grad; } + + + const subnet_type& subnet() const + { + return subnetwork; + } + + subnet_type& subnet() + { + return subnetwork; + } + + unsigned int sample_expansion_factor() const { return subnet().sample_expansion_factor(); } + + void clean() + { + subnetwork.clean(); + } + + friend void serialize(const add_skip_layer& item, std::ostream& out) + { + int version = 1; + serialize(version, out); + serialize(item.subnetwork, out); + } + + friend void deserialize(add_skip_layer& item, std::istream& in) + { + int version = 0; + deserialize(version, in); + if (version != 1) + throw serialization_error("Unexpected version found while deserializing dlib::add_skip_layer."); + deserialize(item.subnetwork, in); + } + + friend std::ostream& operator<< (std::ostream& out, const add_skip_layer& item) + { + int min_length = 0; + item.print(out, 0, min_length); + return out; + } + + void print (std::ostream& out, unsigned long idx, int& min_length) const + { + out << "layer<" << idx << ">\t"< + friend class add_layer; + template + friend class dimpl::subnet_wrapper; + template + friend class add_tag_layer; + template class T, typename U> + friend class add_skip_layer; + template class L, typename S> + friend class repeat; + + bool this_layer_requires_forward_output( + ) { return layer(subnetwork).this_layer_requires_forward_output(); } + + void disable_output_and_gradient_getters ( + ) { layer(subnetwork).disable_output_and_gradient_getters(); } + + tensor& private_get_output() const + { return layer(subnetwork).private_get_output(); } + tensor& private_get_gradient_input() + { return layer(subnetwork).private_get_gradient_input(); } + + subnet_type subnetwork; + + // This member doesn't logically contribute to the state of the object since it is + // always empty. It's just here so we can have the get_parameter_gradient() methods + // which have to return something. So they return this empty tensor. + resizable_tensor params_grad; + }; + template class T, typename U> + struct is_nonloss_layer_type> : std::true_type {}; + + template using tag1 = add_tag_layer< 1, SUBNET>; + template using tag2 = add_tag_layer< 2, SUBNET>; + template using tag3 = add_tag_layer< 3, SUBNET>; + template using tag4 = add_tag_layer< 4, SUBNET>; + template using tag5 = add_tag_layer< 5, SUBNET>; + template using tag6 = add_tag_layer< 6, SUBNET>; + template using tag7 = add_tag_layer< 7, SUBNET>; + template using tag8 = add_tag_layer< 8, SUBNET>; + template using tag9 = add_tag_layer< 9, SUBNET>; + template using tag10 = add_tag_layer<10, SUBNET>; + + template using skip1 = add_skip_layer< tag1, SUBNET>; + template using skip2 = add_skip_layer< tag2, SUBNET>; + template using skip3 = add_skip_layer< tag3, SUBNET>; + template using skip4 = add_skip_layer< tag4, SUBNET>; + template using skip5 = add_skip_layer< tag5, SUBNET>; + template using skip6 = add_skip_layer< tag6, SUBNET>; + template using skip7 = add_skip_layer< tag7, SUBNET>; + template using skip8 = add_skip_layer< tag8, SUBNET>; + template using skip9 = add_skip_layer< tag9, SUBNET>; + template using skip10 = add_skip_layer; + +// ---------------------------------------------------------------------------------------- + + namespace timpl + { + inline void fill_with_gassuan_random_numbers ( + tensor& t, + dlib::rand& rnd, + double sigma = 1 + ) + { + float* data = t.host(); + for (size_t i = 0; i < t.size(); ++i) + data[i] = rnd.get_random_gaussian()*sigma; + } + + class test_layer_subnet + { + public: + test_layer_subnet ( + dlib::rand& rnd_ + ) : rnd(rnd_) + { + // Output and gradient_input have to have the same dimensions in each + // layer. + const long num_samples = rnd.get_random_32bit_number()%4+3; + const long k = rnd.get_random_32bit_number()%4+2; + const long nr = rnd.get_random_32bit_number()%4+2; + const long nc = rnd.get_random_32bit_number()%4+2; + + output.set_size(num_samples, k, nr, nc); + gradient_input.set_size(num_samples, k, nr, nc); + + // Use a non-zero initial gradient to make sure the layers add to it + // rather than assign and blow away the initial value. + fill_with_gassuan_random_numbers(gradient_input, rnd, 0.01); + + fill_with_gassuan_random_numbers(output, rnd); + } + + + tensor& get_mutable_output() { return output; } + const tensor& get_output() const { return output; } + const tensor& private_get_output() const { return get_output(); } + const test_layer_subnet& subnet() const { init_sub(); return *subnetwork; } + + tensor& get_gradient_input() { return gradient_input; } + tensor& private_get_gradient_input() { return get_gradient_input(); } + test_layer_subnet& subnet() { init_sub(); return *subnetwork; } + + + + unsigned long count_outputs() const + { + if (subnetwork) + return subnetwork->count_outputs() + output.size(); + else + return output.size(); + } + + float& get_output_element(unsigned long i) + { + if (i < output.size()) + return output.host()[i]; + else + return subnet().get_output_element(i-output.size()); + } + + float get_gradient_input_element(unsigned long i) const + { + if (i < gradient_input.size()) + return gradient_input.host()[i]; + else + return subnet().get_gradient_input_element(i-gradient_input.size()); + } + + + private: + // We lazily initialize sub-layers as needed when someone tries to call + // subnet() + void init_sub() const + { + if (!subnetwork) + subnetwork.reset(new test_layer_subnet(rnd)); + } + + dlib::rand& rnd; + mutable std::unique_ptr subnetwork; + resizable_tensor output; + resizable_tensor gradient_input; + }; + + } + + struct layer_test_results + { + layer_test_results() : was_good(true) {} + explicit layer_test_results(const std::string& l) : log(l),was_good(false) {} + + std::string log; + bool was_good; + + operator bool() const { return was_good; } + }; + + inline std::ostream& operator<< (std::ostream& out, const layer_test_results& item) + { + out << item.log; + return out; + } + + template < + typename layer_details_type + > + layer_test_results impl_test_layer ( + layer_details_type l, + const float base_eps + ) + { + using namespace timpl; + // Do some setup + running_stats rs_data, rs_params; + dlib::rand rnd; + std::ostringstream sout; + for (int iter = 0; iter < 10; ++iter) + { + test_layer_subnet subnetwork(rnd); + resizable_tensor output, out2, out3; + // Run setup() and forward() as well to make sure any calls to subnet() have + // happened before we start assuming we know how many data elements there are + // (since we do a lazy layer creation thing based on calls to subnet() inside + // test_layer_subnet). + l.setup(subnetwork); + impl::call_layer_forward(l, subnetwork, output); + + resizable_tensor input_grad; + input_grad.copy_size(output); + fill_with_gassuan_random_numbers(input_grad, rnd); + + + // The f() we are computing gradients of is this thing. It's value at the current + // parameter and data values is: + //sout << "f(data,params): " << dot(output, input_grad) << std::endl; + + // We are going to save a copy of the subnetwork.get_gradient_input() data before we do + // backpropagation since the backward() function is supposed to *add* to the + // gradients rather than overwrite them. We will use this saved data to check if + // that is the case. + const unsigned long num_data_inputs = subnetwork.count_outputs(); + std::vector initial_gradient_input(num_data_inputs); + for (unsigned long i = 0; i < num_data_inputs; ++i) + initial_gradient_input[i] = subnetwork.get_gradient_input_element(i); + + + // Now tell the layer to compute all the gradients. In the rest of this function + // we will just be checking that these gradients were computed correctly by + // comparing them to a central differences approximation. + resizable_tensor params_grad; + params_grad.copy_size(l.get_layer_params()); + // But first, set the params grad to something crazy so that it's very obvious if + // it doesn't get fully assigned. + params_grad = std::numeric_limits::infinity(); + impl::call_layer_backward(l, output, input_grad, subnetwork, params_grad); + + static_assert(impl::is_inplace_layer(l, subnetwork) == impl::has_inplace_backward(l, subnetwork), + "Layer not defined correctly. forward and backward methods must either both be in-place or both out-of-place. "); + + // Make sure the outputs of forward() and backward() are the same when they are run + // in in-place mode. + if (impl::is_inplace_layer(l, subnetwork)) + { + test_layer_subnet subnetwork2(rnd); + layer_details_type ll(l); + ll.setup(subnetwork2); + resizable_tensor ip_out; + impl::call_layer_forward(ll, subnetwork2, ip_out); + impl::call_layer_forward(ll, subnetwork2, subnetwork2.get_mutable_output()); + const auto forward_error = max(abs(mat(ip_out) - mat(subnetwork2.get_output()))); + if (forward_error > 0.00001) + { + using namespace std; + sout << "This layer is supposed to support in-place computations but the output of forward_inplace()\n"; + sout << "changes when invoked in-place vs. out-of-place. The error was: " << forward_error << endl; + return layer_test_results(sout.str()); + } + + resizable_tensor params_grad; + params_grad.copy_size(ll.get_layer_params()); + params_grad = std::numeric_limits::infinity(); + + resizable_tensor input_grad; + input_grad.copy_size(ip_out); + fill_with_gassuan_random_numbers(input_grad, rnd); + resizable_tensor params_grad1, params_grad2, data_grad1, data_grad2; + params_grad1 = params_grad; + params_grad2 = params_grad; + // Now call backward() and make sure it works as well. Recall that when an + // in-place layer works in-place it assigns to it's outputs but when it's + // not running in-place it adds. So we initialize to a non-zero value to + // check that this is the behavior that really executes. + subnetwork2.get_gradient_input() = 9; + impl::call_layer_backward(ll, ip_out, input_grad, subnetwork2, params_grad1); + data_grad1 = subnetwork2.get_gradient_input(); + + subnetwork2.get_gradient_input() = mat(input_grad); + impl::call_layer_backward(ll, ip_out, subnetwork2.get_gradient_input(), subnetwork2, params_grad2); + data_grad2 = subnetwork2.get_gradient_input(); + if (params_grad.size() != 0) + { + const auto backward_param_error = max(abs(mat(params_grad1) - mat(params_grad2))); + if (backward_param_error > 0.00001) + { + using namespace std; + sout << "This layer is supposed to support in-place computations but the output of backward_inplace()\n"; + sout << "changes when invoked in-place vs. out-of-place. The error was: " << backward_param_error << endl; + return layer_test_results(sout.str()); + } + } + const auto backward_data_error = max(abs(mat(data_grad1)-9 - mat(data_grad2))); + if (backward_data_error > 0.00001) + { + using namespace std; + sout << "This layer is supposed to support in-place computations but the output of backward_inplace()\n"; + sout << "changes when invoked in-place vs. out-of-place. The error was: " << backward_data_error << endl; + return layer_test_results(sout.str()); + } + } + + // ================================================================== + // first validate the way the parameter gradients are computed + for (unsigned long i = 0; i < params_grad.size(); ++i) + { + layer_details_type l1(l); + + float eps = l1.get_layer_params().host()[i]*base_eps; + if (eps == 0) + eps = base_eps; + const float oldval = l1.get_layer_params().host()[i]; + l1.get_layer_params().host()[i] = oldval+eps; + impl::call_layer_forward(l1, subnetwork, out2); + l1.get_layer_params().host()[i] = oldval-eps; + impl::call_layer_forward(l1, subnetwork, out3); + l1.get_layer_params().host()[i] = oldval; + + // Compute a reference derivative via a central differences approximation and + // compare it to the one output by the layer and make sure they match. + double reference_derivative = (dot(out2,input_grad)-dot(out3, input_grad))/(2*eps); + double output_derivative = params_grad.host()[i]; + double relative_error; + if (reference_derivative*output_derivative != 0) + relative_error = (reference_derivative - output_derivative)/(reference_derivative); + else + relative_error = (reference_derivative - output_derivative); + double absolute_error = (reference_derivative - output_derivative); + rs_params.add(std::abs(relative_error)); + if (std::abs(relative_error) > 0.05 && std::abs(absolute_error) > 0.006) + { + using namespace std; + sout << "Gradient error in parameter #" << i <<". Relative error: "<< relative_error << endl; + sout << "expected derivative: " << reference_derivative << endl; + sout << "output derivative: " << output_derivative << endl; + sout << "iteration: " << iter << endl; + return layer_test_results(sout.str()); + } + } + + // ================================================================== + // now validate the data gradients + for (unsigned long i = 0; i < num_data_inputs; ++i) + { + const float oldval = subnetwork.get_output_element(i); + float eps = oldval*base_eps; + if (eps == 0) + eps = base_eps; + subnetwork.get_output_element(i) = oldval+eps; + impl::call_layer_forward(l, subnetwork, out2); + subnetwork.get_output_element(i) = oldval-eps; + impl::call_layer_forward(l, subnetwork, out3); + subnetwork.get_output_element(i) = oldval; + + // Compute a reference derivative via a central differences approximation and + // compare it to the one output by the layer and make sure they match. + double reference_derivative = (dot(out2,input_grad)-dot(out3, input_grad))/(2*eps); + double output_derivative = subnetwork.get_gradient_input_element(i); + output_derivative -= initial_gradient_input[i]; + double relative_error; + if (reference_derivative*output_derivative != 0) + relative_error = (reference_derivative - output_derivative)/(reference_derivative); + else + relative_error = (reference_derivative - output_derivative); + double absolute_error = (reference_derivative - output_derivative); + rs_data.add(std::abs(relative_error)); + if (std::abs(relative_error) > 0.05 && std::abs(absolute_error) > 0.006) + { + using namespace std; + sout << "Gradient error in data variable #" << i <<". Relative error: "<< relative_error << endl; + sout << "expected derivative: " << reference_derivative << endl; + sout << "output derivative: " << output_derivative << endl; + sout << "iteration: " << iter << endl; + return layer_test_results(sout.str()); + } + } + + } // end for (int iter = 0; iter < 10; ++iter) + + if (rs_params.mean() > 0.003) + { + using namespace std; + sout << "Average parameter gradient error is somewhat large at: "<< rs_params.mean() << endl; + return layer_test_results(sout.str()); + } + if (rs_data.mean() > 0.003) + { + using namespace std; + sout << "Average data gradient error is somewhat large at: "<< rs_data.mean() << endl; + return layer_test_results(sout.str()); + } + + return layer_test_results(); + } + + template < + typename layer_details_type + > + layer_test_results test_layer ( + layer_details_type l + ) + { + // Try a few different derivative step sizes to see if any work. + for (float base_eps = 0.0001; base_eps < 0.1; base_eps *= 2) + { + auto result = impl_test_layer(l, base_eps); + if (result) + return result; + } + // However, if none of the step sizes worked then try this one and probably result + // in returning an error. + return impl_test_layer(l, 0.01); + } + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template + struct vlp_loop + { + template + static typename std::enable_if::value>::type invoke_functor(T&& , size_t& , U&& ) + { + // intentionally left empty + } + + template + static typename std::enable_if::value>::type invoke_functor(T&& v , size_t& comp_i, U&& l ) + { + v(comp_i, l.layer_details().get_layer_params()); + ++comp_i; + } + + template < + typename net_type, + typename visitor + > + static void visit( + size_t comp_i, + net_type& net, + visitor&& v + ) + { + invoke_functor(v, comp_i, layer(net)); + vlp_loop::visit(comp_i, net,v); + } + }; + + template + struct vlp_loop + { + template < + typename net_type, + typename visitor + > + static void visit( + size_t, + net_type&, + visitor&& + ) + { + // Base case of recursion. Don't do anything. + } + }; + + } + + template < + typename net_type, + typename visitor + > + void visit_layer_parameters( + net_type& net, + visitor v + ) + { + size_t comp_i = 0; + impl::vlp_loop<0, net_type::num_layers>::visit(comp_i, net, v); + } + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template + struct vlpg_loop + { + template + static typename std::enable_if::value>::type invoke_functor(T&& , size_t& , U&& ) + { + // intentionally left empty + } + + template + static typename std::enable_if::value>::type invoke_functor(T&& v , size_t& comp_i, U&& l ) + { + v(comp_i, l.get_parameter_gradient()); + ++comp_i; + } + + template < + typename net_type, + typename visitor + > + static void visit( + size_t comp_i, + net_type& net, + visitor&& v + ) + { + invoke_functor(v, comp_i, layer(net)); + vlpg_loop::visit(comp_i, net,v); + } + }; + + template + struct vlpg_loop + { + template < + typename net_type, + typename visitor + > + static void visit( + size_t, + net_type&, + visitor&& + ) + { + // Base case of recursion. Don't do anything. + } + }; + + } + + template < + typename net_type, + typename visitor + > + void visit_layer_parameter_gradients( + net_type& net, + visitor v + ) + { + size_t comp_i = 0; + impl::vlpg_loop<0, net_type::num_layers>::visit(comp_i, net, v); + } + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template + struct vl_loop + { + template < + typename net_type, + typename visitor + > + static void visit( + net_type& net, + visitor&& v + ) + { + v(i, layer(net)); + vl_loop::visit(net,v); + } + }; + + template + struct vl_loop + { + template < + typename net_type, + typename visitor + > + static void visit( + net_type&, + visitor&& + ) + { + // Base case of recursion. Don't do anything. + } + }; + + template + struct vl_loop_backwards + { + template < + typename net_type, + typename visitor + > + static void visit( + net_type& net, + visitor&& v + ) + { + vl_loop_backwards::visit(net,v); + v(i, layer(net)); + } + }; + + template + struct vl_loop_backwards + { + template < + typename net_type, + typename visitor + > + static void visit( + net_type&, + visitor&& + ) + { + // Base case of recursion. Don't do anything. + } + }; + + } + + template < + typename net_type, + typename visitor + > + void visit_layers( + net_type& net, + visitor v + ) + { + impl::vl_loop<0, net_type::num_layers>::visit(net, v); + } + + template < + typename net_type, + typename visitor + > + void visit_layers_backwards( + net_type& net, + visitor v + ) + { + impl::vl_loop_backwards<0, net_type::num_layers>::visit(net, v); + } + + template < + size_t begin, + size_t end, + typename net_type, + typename visitor + > + void visit_layers_range( + net_type& net, + visitor v + ) + { + static_assert(begin <= end, "Invalid range"); + static_assert(end <= net_type::num_layers, "Invalid range"); + impl::vl_loop::visit(net, v); + } + + template < + size_t begin, + size_t end, + typename net_type, + typename visitor + > + void visit_layers_backwards_range( + net_type& net, + visitor v + ) + { + static_assert(begin <= end, "Invalid range"); + static_assert(end <= net_type::num_layers, "Invalid range"); + impl::vl_loop_backwards::visit(net, v); + } + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template + struct vl_until_tag + { + template < + typename net_type, + typename next_net_type, + typename visitor + > + static void visit( + net_type& net, + next_net_type& next_net, + visitor&& v + ) + { + v(next_net); + vl_until_tag::visit(net,layer(net),v); + } + + template < + typename net_type, + typename SUBNET, + typename visitor + > + static void visit( + net_type& net, + const add_tag_layer& next_net, + visitor&& v + ) + { + v(next_net); + } + + template < + typename net_type, + typename SUBNET, + typename visitor + > + static void visit( + net_type& net, + add_tag_layer& next_net, + visitor&& v + ) + { + v(next_net); + } + }; + } + + template < + unsigned long tag_id, + typename net_type, + typename visitor + > + void visit_layers_until_tag( + net_type& net, + visitor v + ) + { + impl::vl_until_tag<0,tag_id>::visit(net, net, v); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DNn_CORE_H_ + + diff --git a/lib/3rdParty/dlib/include/dlib/dnn/core_abstract.h b/lib/3rdParty/dlib/include/dlib/dnn/core_abstract.h new file mode 100644 index 00000000..12f872af --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/dnn/core_abstract.h @@ -0,0 +1,1700 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_DNn_CORE_ABSTRACT_H_ +#ifdef DLIB_DNn_CORE_ABSTRACT_H_ + +#include "../cuda/tensor_abstract.h" +#include +#include +#include +#include +#include "../rand.h" + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename... T + > + auto tuple_tail( + const std::tuple& item + ); + /*! + ensures + - returns a tuple that contains everything in item except for tuple_head(item). + The items will be in the same order as they are in item, just without + tuple_head(item). + - This function will correctly handle nested tuples. + !*/ + + template + auto tuple_head ( + const std::tuple& item + ); + /*! + ensures + - returns a copy of the first thing in the tuple that isn't a std::tuple. + Essentially, this function calls std::get<0>() recursively on item until + a non-std::tuple object is found. + !*/ + +// ---------------------------------------------------------------------------------------- + + template + double get_learning_rate_multiplier( + const T& obj + ); + /*! + ensures + - if (obj has a get_learning_rate_multiplier() member function) then + - returns obj.get_learning_rate_multiplier() + - else + - returns 1 + !*/ + + template + double get_weight_decay_multiplier( + const T& obj + ); + /*! + ensures + - if (obj has a get_weight_decay_multiplier() member function) then + - returns obj.get_weight_decay_multiplier() + - else + - returns 1 + !*/ + +// ---------------------------------------------------------------------------------------- + + bool dnn_prefer_fastest_algorithms( + ); + /*! + ensures + - If dlib should prefer to use fast algorithms rather than ones that use less + RAM then this function returns true and false otherwise. + - On program startup this function will default to true. + !*/ + + void set_dnn_prefer_fastest_algorithms( + ); + /*! + ensures + - #dnn_prefer_fastest_algorithms() == true + !*/ + + void set_dnn_prefer_smallest_algorithms( + ); + /*! + ensures + - #dnn_prefer_fastest_algorithms() == false + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + class sstack + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a basic stack of T objects. It contains no data itself but simply + points to a memory range of T object and allows you to access that block of + T objects as a stack. + !*/ + + public: + typedef T value_type; + + sstack() = delete; + + sstack ( + T* data, + size_t s + ); + /*! + ensures + - #size() == s + - #top() == *data + - #pop(i).top() == data[i] + !*/ + + const T& top( + ) const; + /*! + requires + - size() != 0 + ensures + - returns the top element of the stack. + !*/ + + T& top( + ); + /*! + requires + - size() != 0 + ensures + - returns the top element of the stack. + !*/ + + size_t size( + ) const; + /*! + ensures + - returns the number of elements in this stack. + !*/ + + sstack pop( + size_t num = 1 + ); + /*! + requires + - num <= size() + ensures + - returns a reference to the sub-stack S such that: + - S.size() == size()-num. + - S.top() is num elements down the stack. + !*/ + }; + + template < + typename T + > + sstack make_sstack( + std::vector& item + ) { return sstack(item.data(), item.size()); } + /*! + ensures + - returns a sstack that sits on top of the given std::vector. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename LAYER_DETAILS, + typename SUBNET + > + class add_layer + { + /*! + REQUIREMENTS ON LAYER_DETAILS + - Must be a type that implements the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined in layers_abstract.h + + REQUIREMENTS ON SUBNET + - One of the following must be true: + - SUBNET implements the EXAMPLE_INPUT_LAYER interface defined in + input_abstract.h. + - SUBNET is an add_layer object. + - SUBNET is an add_tag_layer object. + - SUBNET is an add_skip_layer object. + - SUBNET is a repeat object. + + WHAT THIS OBJECT REPRESENTS + This object represents a deep neural network. In particular, it is a tool + for adding another layer on top of the neural network of type SUBNET, which + is specified as a template argument. The specific layer added is defined + by the LAYER_DETAILS details template argument. + !*/ + + public: + typedef LAYER_DETAILS layer_details_type; + typedef SUBNET subnet_type; + typedef typename subnet_type::input_type input_type; + // num_computational_layers will always give the number of layers in the network + // that transform tensors (i.e. layers defined by something that implements the + // EXAMPLE_COMPUTATIONAL_LAYER_ interface). This is all the layers except for + // loss, tag, and skip layers. + const static size_t num_computational_layers = subnet_type::num_computational_layers + 1; + // num_layers counts all the layers in the network regardless of their type. + const static size_t num_layers = subnet_type::num_layers + 1; + + add_layer( + ); + /*! + ensures + - default constructs all the layers in this network. + - #sample_expansion_factor() == 0 + !*/ + + add_layer(const add_layer&) = default; + add_layer(add_layer&&) = default; + add_layer& operator=(add_layer&&) = default; + add_layer& operator=(const add_layer&) = default; + /*! + ensures + - this object is copyable and movable. + !*/ + + template + add_layer( + const add_layer& item + ); + /*! + ensures + - This constructor allows you to copy neural network objects from one to + another as long as their corresponding layers can be constructed from + each other. + - #layer_details() == layer_details_type(item.layer_details()) + - #subnet() == subnet_type(item.subnet()) + - #sample_expansion_factor() == item.sample_expansion_factor() + !*/ + + template + add_layer( + const std::tuple& layer_det, + T&& ...args + ); + /*! + ensures + - #layer_details() == layer_details_type(tuple_head(layer_det)) + - #subnet() == subnet_type(tuple_tail(layer_det),args) + - #sample_expansion_factor() == 0 + !*/ + + template + add_layer( + const layer_details_type& layer_det, + T&& ...args + ); + /*! + ensures + - #layer_details() == layer_details_type(layer_det) + - #subnet() == subnet_type(args) + - #sample_expansion_factor() == 0 + !*/ + + template + add_layer( + T&& ...args + ); + /*! + ensures + - This version of the constructor is only called if layer_details_type + can't be constructed from the first thing in args. In this case, the + args are simply passed on to the sub layers in their entirety. + - #layer_details() == layer_details_type() + - #subnet() == subnet_type(args) + - #sample_expansion_factor() == 0 + !*/ + + template + add_layer( + layer_details_type&& layer_det, + T&& ...args + ); + /*! + ensures + - #layer_details() == layer_det + - #subnet() == subnet_type(args) + - #sample_expansion_factor() == 0 + !*/ + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const; + /*! + requires + - [ibegin, iend) is an iterator range over input_type objects. + - std::distance(ibegin,iend) > 0 + ensures + - Converts the iterator range into a tensor and stores it into #data. + - #data.num_samples()%distance(ibegin,iend) == 0. + - #sample_expansion_factor() == #data.num_samples()/distance(ibegin,iend). + - #sample_expansion_factor() > 0 + - The data in the ith sample of #data corresponds to the input_type object + *(ibegin+i/#sample_expansion_factor()). + - Invokes data.async_copy_to_device() so that the data begins transferring + to the GPU device, if present. + - This function is implemented by calling the to_tensor() routine defined + at the input layer of this network. + !*/ + + unsigned int sample_expansion_factor ( + ) const; + /*! + ensures + - When to_tensor() is invoked on this network's input layer it converts N + input objects into M samples, all stored inside a resizable_tensor. It + is always the case that M is some integer multiple of N. + sample_expansion_factor() returns the value of this multiplier. To be + very specific, it is always true that M==I*N where I is some integer. + This integer I is what is returned by sample_expansion_factor(). + !*/ + + const subnet_type& subnet( + ) const; + /*! + ensures + - returns the immediate subnetwork of *this network. + !*/ + + subnet_type& subnet( + ); + /*! + ensures + - returns the immediate subnetwork of *this network. + !*/ + + const layer_details_type& layer_details( + ) const; + /*! + ensures + - returns the layer_details_type instance that defines the behavior of the + layer at the top of this network. I.e. returns the layer details that + defines the behavior of the layer nearest to the network output rather + than the input layer. + !*/ + + layer_details_type& layer_details( + ); + /*! + ensures + - returns the layer_details_type instance that defines the behavior of the + layer at the top of this network. I.e. returns the layer details that + defines the behavior of the layer nearest to the network output rather + than the input layer. + !*/ + + template + const tensor& operator() ( + forward_iterator ibegin, + forward_iterator iend + ); + /*! + requires + - [ibegin, iend) is an iterator range over input_type objects. + - std::distance(ibegin,iend) > 0 + ensures + - runs [ibegin,iend) through the network and returns the results. + In particular, this function performs: + to_tensor(ibegin,iend,temp_tensor); + return forward(temp_tensor); + - The return value from this function is also available in #get_output(). + i.e. this function returns #get_output(). + - have_same_dimensions(#get_gradient_input(), #get_output()) == true. + - All elements of #get_gradient_input() are set to 0. + i.e. calling this function clears out #get_gradient_input() and ensures + it has the same dimensions as the most recent output. + !*/ + + const tensor& operator() ( + const input_type& x + ); + /*! + ensures + - runs a single x through the network and returns the output. + I.e. returns (*this)(&x, &x+1); + !*/ + + const tensor& forward( + const tensor& x + ); + /*! + requires + - sample_expansion_factor() != 0 + (i.e. to_tensor() must have been called to set sample_expansion_factor() + to something non-zero.) + - x.num_samples()%sample_expansion_factor() == 0 + - x.num_samples() > 0 + ensures + - Runs x through the network and returns the results. In particular, this + function performs the equivalent of: + subnet().forward(x); + if (this is the first time forward() has been called) then + layer_details().setup(subnet()); + layer_details().forward(subnet(), get_output()); + - The return value from this function is also available in #get_output(). + i.e. this function returns #get_output(). + - have_same_dimensions(#get_gradient_input(), #get_output()) == true + - All elements of #get_gradient_input() are set to 0. + i.e. calling this function clears out #get_gradient_input() and ensures + it has the same dimensions as the most recent output. + !*/ + + const tensor& get_output( + ) const; + /*! + ensures + - returns the output for the last tensor that was run through the network. + If nothing has been run through the network yet then returns an empty + tensor. + !*/ + + tensor& get_gradient_input( + ); + /*! + ensures + - returns the error gradient for this network. That is, this is the error + gradient that this network will use to compute parameter gradients when + back_propagate_error() is called. Therefore, when performing back + propagation, layers that sit on top of this network layer write their + back-propagated error gradients into get_gradient_input(). Or to put it + another way, during back-propagation, layers take the contents of their + get_gradient_input() and back-propagate it through themselves and store + the result into their subnetwork's get_gradient_input(). + + This means you should consider get_gradient_input() as an input to the + back_propagate_error() method. + !*/ + + const tensor& get_final_data_gradient( + ) const; + /*! + ensures + - if back_propagate_error() has been called to back-propagate a gradient + through this network then you can call get_final_data_gradient() to + obtain the last data gradient computed. That is, this function returns + the gradient of the network with respect to its inputs. + - Note that there is only one "final data gradient" for an entire network, + not one per layer, since there is only one input to the entire network. + !*/ + + const tensor& get_parameter_gradient( + ) const; + /*! + ensures + - if back_propagate_error() has been called then you can call + get_parameter_gradient() to find the gradient of this layer's parameters. + When we update the parameters by calling update_parameters(), it will use + the gradient in get_parameter_gradient() to perform the update. + Therefore, you should consider get_parameter_gradient() as an input to + update_parameters(). + !*/ + + tensor& get_parameter_gradient ( + ); + /*! + ensures + - returns a non-const reference to the tensor returned by the above + get_parameter_gradient() method. You could use this method to modify the + parameter gradient in some way before invoking update_parameters(). + !*/ + + void back_propagate_error( + const tensor& x + ); + /*! + requires + - forward(x) was called to forward propagate x though the network. + Moreover, this was the most recent call to forward() and x has not been + subsequently modified in any way. + - get_gradient_input() has been set equal to the gradient of this network's + output with respect to some loss function. + ensures + - Back propagates the error gradient, get_gradient_input(), through this + network and computes parameter and data gradients, via backpropagation. + Specifically, this function populates get_final_data_gradient() and also, + for each layer, the tensor returned by get_parameter_gradient(). + - All elements of #get_gradient_input() are set to 0. + - have_same_dimensions(#get_final_data_gradient(), x) == true. + - have_same_dimensions(#get_parameter_gradient(), layer_details().get_layer_params()) == true. + - #get_final_data_gradient() contains the gradient of the network with + respect to x. + !*/ + + void back_propagate_error( + const tensor& x, + const tensor& gradient_input + ); + /*! + requires + - forward(x) was called to forward propagate x though the network. + Moreover, this was the most recent call to forward() and x has not been + subsequently modified in any way. + - have_same_dimensions(gradient_input, get_output()) == true + ensures + - This function is identical to the version of back_propagate_error() + defined immediately above except that it back-propagates gradient_input + through the network instead of get_gradient_input(). Therefore, this + version of back_propagate_error() is equivalent to performing: + get_gradient_input() = gradient_input; + back_propagate_error(x); + Except that calling back_propagate_error(x,gradient_input) avoids the + copy and is therefore slightly more efficient. + - All elements of #get_gradient_input() are set to 0. + - have_same_dimensions(#get_final_data_gradient(), x) == true. + - have_same_dimensions(#get_parameter_gradient(), layer_details().get_layer_params()) == true. + - #get_final_data_gradient() contains the gradient of the network with + respect to x. + !*/ + + template + void update_parameters( + sstack solvers, + double learning_rate + ); + /*! + requires + - solver_type is an implementation of the EXAMPLE_SOLVER interface defined + in solvers_abstract.h + - back_propagate_error() has been called. + - The given solvers have only ever been used with this network. That is, + if you want to call update_parameters() on some other neural network + object then you must NOT reuse the same solvers object. + - solvers.size() >= num_computational_layers + - 0 < learning_rate <= 1 + ensures + - Updates all the parameters in the network. In particular, we pass each + layer's parameter gradient (i.e. the tensor returned by the layer's + get_parameter_gradient() member) through that layer's corresponding + solver object. This produces a parameter delta vector which we add to + the layer's parameters. + - The solvers use the given learning rate. + !*/ + + void clean( + ); + /*! + ensures + - Causes the network to forget about everything but its parameters. + That is, for each layer we will have: + - get_output().num_samples() == 0 + - get_gradient_input().num_samples() == 0 + However, running new input data though this network will still produce + the same output it would have produced regardless of any calls to + clean(). The purpose of clean() is to compact the network object prior + to saving it to disk so that it takes up less space and the IO is + quicker. + - This also calls the .clean() method on any layer details objects that + define a .clean() method. + !*/ + + }; + + template + std::ostream& operator<<(std::ostream& out, const add_layer& item); + /*! + prints the network architecture to the given output stream. + !*/ + + template + void serialize(const add_layer& item, std::ostream& out); + template + void deserialize(add_layer& item, std::istream& in); + /*! + provides serialization support + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class no_label_type; + + template < + typename LOSS_DETAILS, + typename SUBNET + > + class add_loss_layer + { + /*! + REQUIREMENTS ON LOSS_DETAILS + - Must be a type that implements the EXAMPLE_LOSS_LAYER_ interface defined + in loss_abstract.h + + REQUIREMENTS ON SUBNET + - One of the following must be true: + - SUBNET is an add_layer object. + - SUBNET is an add_tag_layer object. + - SUBNET is an add_skip_layer object. + - SUBNET is a repeat object. + + WHAT THIS OBJECT REPRESENTS + This object represents a deep neural network. In particular, it is a tool + for adding a loss layer on top of the neural network of type SUBNET, which + is specified as a template argument. The specific layer added is defined + by the LOSS_DETAILS details template argument. Importantly, a loss layer + is the last layer in a deep neural network. So once it is added you can't + add any other layers of any type. + !*/ + + public: + typedef LOSS_DETAILS loss_details_type; + typedef SUBNET subnet_type; + typedef typename subnet_type::input_type input_type; + const static size_t num_computational_layers = subnet_type::num_computational_layers; + const static size_t num_layers = subnet_type::num_layers + 1; + // If LOSS_DETAILS is an unsupervised loss then training_label_type==no_label_type. + // Otherwise it is defined as follows: + typedef typename LOSS_DETAILS::training_label_type training_label_type; + // Similarly, if LOSS_DETAILS doesn't provide any output conversion then + // output_label_type==no_label_type. + typedef typename LOSS_DETAILS::output_label_type output_label_type; + + + + add_loss_layer() = default; + /*! + ensures + - default constructs all the layers in this network. + !*/ + + add_loss_layer(const add_loss_layer&) = default; + add_loss_layer(add_loss_layer&&) = default; + add_loss_layer& operator=(add_loss_layer&&) = default; + add_loss_layer& operator=(const add_loss_layer&) = default; + /*! + ensures + - this object is copyable and movable. + !*/ + + template + add_loss_layer( + const add_loss_layer& item + ); + /*! + ensures + - This constructor allows you to copy neural network objects from one to + another as long as their corresponding layers can be constructed from + each other. + - #loss_details() == loss_details_type(item.loss_details()) + - #subnet() == subnet_type(item.subnet()) + !*/ + + template + add_loss_layer( + const LOSS_DETAILS& layer_det, + T&& ...args + ); + /*! + ensures + - #loss_details() == loss_details_type(layer_det) + - #subnet() == subnet_type(args) + !*/ + + template + add_loss_layer( + LOSS_DETAILS&& layer_det, + T&& ...args + ); + /*! + ensures + - #loss_details() == loss_details_type(layer_det) + - #subnet() == subnet_type(args) + !*/ + + template + add_loss_layer( + T&& ...args + ); + /*! + ensures + - This version of the constructor is only called if loss_details_type can't + be constructed from the first thing in args. In this case, the args are + simply passed on to the sub layers in their entirety. + - #loss_details() == loss_details_type() + - #subnet() == subnet_type(args) + !*/ + + const subnet_type& subnet( + ) const; + /*! + ensures + - returns the immediate subnetwork of *this network. + !*/ + + subnet_type& subnet( + ); + /*! + ensures + - returns the immediate subnetwork of *this network. + !*/ + + const loss_details_type& loss_details( + ) const; + /*! + ensures + - returns the loss_details_type instance that defines the behavior of the + loss layer used by this network. + !*/ + + loss_details_type& loss_details( + ); + /*! + ensures + - returns the loss_details_type instance that defines the behavior of the + loss layer used by this network. + !*/ + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const; + /*! + requires + - [ibegin, iend) is an iterator range over input_type objects. + - std::distance(ibegin,iend) > 0 + ensures + - Converts the iterator range into a tensor and stores it into #data. + - #data.num_samples()%distance(ibegin,iend) == 0. + - #sample_expansion_factor() == #data.num_samples()/distance(ibegin,iend). + - #sample_expansion_factor() > 0 + - The data in the ith sample of #data corresponds to the input_type object + *(ibegin+i/sample_expansion_factor()). + - Invokes data.async_copy_to_device() so that the data begins transferring + to the GPU device, if present. + - This function is implemented by calling the to_tensor() routine defined + at the input layer of this network. + !*/ + + unsigned int sample_expansion_factor ( + ) const; + /*! + ensures + - When to_tensor() is invoked on this network's input layer it converts N + input objects into M samples, all stored inside a resizable_tensor. It + is always the case that M is some integer multiple of N. + sample_expansion_factor() returns the value of this multiplier. To be + very specific, it is always true that M==I*N where I is some integer. + This integer I is what is returned by sample_expansion_factor(). + !*/ + + // ------------- + + template + void operator() ( + const tensor& x, + output_iterator obegin + ); + /*! + requires + - sample_expansion_factor() != 0 + (i.e. to_tensor() must have been called to set sample_expansion_factor() + to something non-zero.) + - x.num_samples()%sample_expansion_factor() == 0 + - x.num_samples() > 0 + - obegin == iterator pointing to the start of a range of + x.num_samples()/sample_expansion_factor() output_label_type elements. + ensures + - runs x through the network and writes the output to the range at obegin. + - loss_details().to_label() is used to write the network output into + obegin. + !*/ + + template + void operator() ( + forward_iterator ibegin, + forward_iterator iend, + label_iterator obegin + ); + /*! + requires + - [ibegin, iend) is an iterator range over input_type objects. + - std::distance(ibegin,iend) > 0 + - obegin == iterator pointing to the start of a range of + std::distance(ibegin,iend) output_label_type elements. + ensures + - runs [ibegin,iend) through the network and writes the output to the range + at obegin. + - loss_details().to_label() is used to write the network output into + obegin. + !*/ + + // ------------- + + const output_label_type& operator() ( + const input_type& x + ); + /*! + ensures + - runs a single object, x, through the network and returns the output. + - loss_details().to_label() is used to convert the network output into a + output_label_type. + !*/ + + template + std::vector operator() ( + const iterable_type& data, + size_t batch_size = 128 + ); + /*! + requires + - batch_size > 0 + - data must have a .begin() and .end() that supply iterators over a + sequence of input_type elements. E.g. data could have a type of + std::vector + ensures + - runs all the objects in data through the network and returns their + predicted labels. This means this function returns a vector V such that: + - V.size() == data.size() + - for all valid i: V[i] == the predicted label of data[i]. + - Elements of data are run through the network in batches of batch_size + items. Using a batch_size > 1 can be faster because it better exploits + the available hardware parallelism. + - loss_details().to_label() is used to convert the network output into a + output_label_type. + !*/ + + template + const output_label_type& process ( + const input_type& x, + T&& ...args + ); + /*! + ensures + - This function is just like (*this)(x), i.e. it runs a single object, x, + through the network and returns the output. But we additionally pass the + given args to loss_details().to_label() as the 4th argument (or more, + depending on how many things are in args) when converting the network + output to an output_label_type. This is useful, for instance, with loss + layers like loss_mmod_ which has an optional adjust_threshold argument to + to_label() that adjusts the detection threshold. Therefore, for such + networks you could call them like: net.process(some_image, -0.5), and -0.5 + would be passed so the adjust_threshold argument of to_tensor(). + !*/ + + template + std::vector process_batch ( + const iterable_type& data, + size_t batch_size, + T&& ...args + ); + /*! + requires + - batch_size > 0 + - data must have a .begin() and .end() that supply iterators over a + sequence of input_type elements. E.g. data could have a type of + std::vector + ensures + - This function is just like (*this)(data,batch_size), i.e. it runs a + bunch of objects through the network and returns the outputs. But we + additionally pass the given args to loss_details().to_label() as the 4th + argument (or more, depending on how many things are in args) when + converting the network output to output_label_types. This is useful, + for instance, with loss layers like loss_mmod_ which has an optional + adjust_threshold argument to to_label() that adjusts the detection + threshold. Therefore, for such networks you could call them like: + net.process_batch(std::vector({some_image, another_image}), 128, -0.5), + and -0.5 would be passed so the adjust_threshold argument of to_tensor(). + !*/ + + // ------------- + + template + double compute_loss ( + const tensor& x, + label_iterator lbegin + ); + /*! + requires + - sample_expansion_factor() != 0 + (i.e. to_tensor() must have been called to set sample_expansion_factor() + to something non-zero.) + - x.num_samples()%sample_expansion_factor() == 0 + - x.num_samples() > 0 + - lbegin == iterator pointing to the start of a range of + x.num_samples()/sample_expansion_factor() training_label_type elements. + ensures + - runs x through the network, compares the output to the expected output + pointed to by lbegin, and returns the resulting loss. + - for all valid k: + - the expected label of the kth sample in x is *(lbegin+k/sample_expansion_factor()). + - This function does not update the network parameters. + !*/ + + template + double compute_loss ( + forward_iterator ibegin, + forward_iterator iend, + label_iterator lbegin + ); + /*! + requires + - [ibegin, iend) is an iterator range over input_type objects. + - std::distance(ibegin,iend) > 0 + - lbegin == iterator pointing to the start of a range of + std::distance(ibegin,iend) training_label_type elements. + ensures + - runs [ibegin,iend) through the network, compares the output to the + expected output pointed to by lbegin, and returns the resulting loss. + - for all valid k: + - the expected label of *(ibegin+k) is *(lbegin+k). + - This function does not update the network parameters. + !*/ + + // ------------- + + double compute_loss ( + const tensor& x + ); + /*! + requires + - LOSS_DETAILS is an unsupervised loss. i.e. training_label_type==no_label_type. + - sample_expansion_factor() != 0 + (i.e. to_tensor() must have been called to set sample_expansion_factor() + to something non-zero.) + - x.num_samples()%sample_expansion_factor() == 0 + - x.num_samples() > 0 + ensures + - runs x through the network and returns the resulting loss. + - This function does not update the network parameters. + !*/ + + template + double compute_loss ( + forward_iterator ibegin, + forward_iterator iend, + ); + /*! + requires + - LOSS_DETAILS is an unsupervised loss. i.e. training_label_type==no_label_type. + - [ibegin, iend) is an iterator range over input_type objects. + - std::distance(ibegin,iend) > 0 + ensures + - runs [ibegin,iend) through the network and returns the resulting loss. + - This function does not update the network parameters. + !*/ + + // ------------- + + template + double compute_parameter_gradients ( + const tensor& x, + label_iterator lbegin + ); + /*! + requires + - sample_expansion_factor() != 0 + (i.e. to_tensor() must have been called to set sample_expansion_factor() + to something non-zero.) + - x.num_samples()%sample_expansion_factor() == 0 + - x.num_samples() > 0 + - lbegin == iterator pointing to the start of a range of + x.num_samples()/sample_expansion_factor() training_label_type elements. + ensures + - runs x through the network, compares the output to the expected output + pointed to by lbegin, and computes parameter and data gradients with + respect to the loss, via backpropagation. Specifically, this function + updates get_final_data_gradient() and also, for each layer, the tensor + returned by get_parameter_gradient(). + - for all valid k: + - the expected label of the kth sample in x is *(lbegin+k/sample_expansion_factor()). + - returns compute_loss(x,lbegin) + !*/ + + template + double compute_parameter_gradients ( + forward_iterator ibegin, + forward_iterator iend, + label_iterator lbegin + ); + /*! + requires + - [ibegin, iend) is an iterator range over input_type objects. + - std::distance(ibegin,iend) > 0 + - lbegin == iterator pointing to the start of a range of + std::distance(ibegin,iend) training_label_type elements. + ensures + - runs [ibegin,iend) through the network, compares the output to the + expected output pointed to by lbegin, and computes parameter and data + gradients with respect to the loss, via backpropagation. Specifically, + this function updates get_final_data_gradient() and also, for each layer, + the tensor returned by get_parameter_gradient(). + - for all valid k: + - the expected label of *(ibegin+k) is *(lbegin+k). + - returns compute_loss(ibegin,iend,lbegin) + !*/ + + double compute_parameter_gradients ( + const tensor& x + ); + /*! + requires + - LOSS_DETAILS is an unsupervised loss. i.e. training_label_type==no_label_type. + - sample_expansion_factor() != 0 + (i.e. to_tensor() must have been called to set sample_expansion_factor() + to something non-zero.) + - x.num_samples()%sample_expansion_factor() == 0 + - x.num_samples() > 0 + ensures + - runs x through the network and computes parameter and data gradients with + respect to the loss, via backpropagation. Specifically, this function + updates get_final_data_gradient() and also, for each layer, the tensor + returned by get_parameter_gradient(). + - returns compute_loss(x) + !*/ + + template + double compute_parameter_gradients ( + forward_iterator ibegin, + forward_iterator iend + ); + /*! + requires + - LOSS_DETAILS is an unsupervised loss. i.e. training_label_type==no_label_type. + - [ibegin, iend) is an iterator range over input_type objects. + - std::distance(ibegin,iend) > 0 + ensures + - runs [ibegin,iend) through the network and computes parameter and data + gradients with respect to the loss, via backpropagation. Specifically, + this function updates get_final_data_gradient() and also, for each layer, + the tensor returned by get_parameter_gradient(). + - returns compute_loss(ibegin,iend) + !*/ + + template + void update_parameters ( + sstack solvers, + double learning_rate + ); + /*! + requires + - solver_type is an implementation of the EXAMPLE_SOLVER interface defined + in solvers_abstract.h + - compute_parameter_gradients() has been called. + - The given solvers have only ever been used with this network. That + is, if you want to call update_parameters() on some other neural network + object then you must NOT reuse the same solvers object. + - solvers.size() >= num_computational_layers + - 0 < learning_rate <= 1 + ensures + - Updates all the parameters in the network. In particular, we pass each + layer's parameter gradient (i.e. the tensor returned by the layer's + get_parameter_gradient() member) through that layer's corresponding + solver object. This produces a parameter delta vector which we add to + the layer's parameters. + - The solvers use the given learning rate. + !*/ + + // ------------- + + void clean ( + ); + /*! + ensures + - Causes the network to forget about everything but its parameters. + - invokes subnet().clean() + !*/ + }; + + template + std::ostream& operator<<(std::ostream& out, const add_loss_layer& item); + /*! + prints the network architecture to the given output stream. + !*/ + + template + void serialize(const add_loss_layer& item, std::ostream& out); + template + void deserialize(add_loss_layer& item, std::istream& in); + /*! + provides serialization support + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template + decorator_repeat_group repeat_group ( + T&& ...args + ); + /*! + ensures + - Decorates a group of variables. This is essentially like std::make_tuple() + except it's only purpose is to group variables together so they can be passed + to the repeat object's constructor. + !*/ + + template < + size_t num, + template class REPEATED_LAYER, + typename SUBNET + > + class repeat + { + /*! + REQUIREMENTS ON num + - num > 0 + + REQUIREMENTS ON REPEATED_LAYER + - REPEATED_LAYER must be a template that stacks more layers onto a deep neural + network. For example, if net_type were a network without a loss layer, + then it should be legal to create a deeper network with a type of + REPEATED_LAYER. + + REQUIREMENTS ON SUBNET + - One of the following must be true: + - SUBNET is an add_layer object. + - SUBNET is an add_tag_layer object. + - SUBNET is an add_skip_layer object. + - SUBNET is a repeat object. + + WHAT THIS OBJECT REPRESENTS + This object adds more layers to a deep neural network. In particular, it + adds REPEATED_LAYER on top of SUBNET num times. So for example, if num were 2 then + repeat<2,REPEATED_LAYER,SUBNET> would create a network equivalent to REPEATED_LAYER>. + + Also, this object provides an interface identical to the one defined by the + add_layer object except that we add the num_repetitions() and + get_repeated_layer() methods. These additions are shown below along with + some additional explanatory comments. + !*/ + + public: + + typedef SUBNET subnet_type; + typedef typename SUBNET::input_type input_type; + const static size_t num_computational_layers = (REPEATED_LAYER::num_computational_layers-SUBNET::num_computational_layers)*num + SUBNET::num_computational_layers; + const static size_t num_layers = (REPEATED_LAYER::num_layers-SUBNET::num_layers)*num + SUBNET::num_layers; + typedef REPEATED_LAYER repeated_layer_type; + + template + repeat( + T arg1, + U ...args2 + ); + /*! + ensures + - arg1 is used to initialize the num_repetitions() copies of REPEATED_LAYER inside + this object. That is, all the REPEATED_LAYER elements are initialized identically + by being given copies of arg1. + - The rest of the arguments to the constructor, i.e. args2, are passed to + SUBNET's constructor. + !*/ + + template + repeat( + decorator_repeat_group&& arg1, + U ...args2 + ); + /*! + ensures + - arg1 is used to initialize the num_repetitions() copies of REPEATED_LAYER inside + this object. That is, all the REPEATED_LAYER elements are initialized identically + by being given copies of an undecorated arg1. + - The rest of the arguments to the constructor, i.e. args2, are passed to + SUBNET's constructor. + !*/ + + size_t num_repetitions ( + ) const; + /*! + ensures + - returns num (i.e. the number of times REPEATED_LAYER was stacked on top of SUBNET) + !*/ + + const repeated_layer_type& get_repeated_layer ( + size_t i + ) const; + /*! + requires + - i < num_repetitions() + ensures + - returns a reference to the i-th instance of REPEATED_LAYER. For example, + get_repeated_layer(0) returns the instance of REPEATED_LAYER that is on the top of + the network while get_repeated_layer(num_repetitions()-1) returns the + instance of REPEATED_LAYER that is stacked immediately on top of SUBNET. + !*/ + + repeated_layer_type& get_repeated_layer ( + size_t i + ); + /*! + requires + - i < num_repetitions() + ensures + - returns a reference to the i-th instance of REPEATED_LAYER. For example, + get_repeated_layer(0) returns the instance of REPEATED_LAYER that is on the top of + the network while get_repeated_layer(num_repetitions()-1) returns the + instance of REPEATED_LAYER that is stacked immediately on top of SUBNET. + !*/ + + const subnet_type& subnet( + ) const; + /*! + ensures + - returns the SUBNET base network that repeat sits on top of. If you want + to access the REPEATED_LAYER components then you must use get_repeated_layer(). + !*/ + + subnet_type& subnet( + ); + /*! + ensures + - returns the SUBNET base network that repeat sits on top of. If you want + to access the REPEATED_LAYER components then you must use get_repeated_layer(). + !*/ + }; + + template < size_t num, template class T, typename U > + std::ostream& operator<<(std::ostream& out, const repeat& item); + /*! + prints the network architecture to the given output stream. + !*/ + + template < size_t num, template class T, typename U > + void serialize(const repeat& item, std::ostream& out); + template < size_t num, template class T, typename U > + void deserialize(repeat& item, std::istream& in); + /*! + provides serialization support + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long ID, + typename SUBNET + > + class add_tag_layer + { + /*! + REQUIREMENTS ON SUBNET + - One of the following must be true: + - SUBNET implements the EXAMPLE_INPUT_LAYER interface defined in + input_abstract.h. + - SUBNET is an add_layer object. + - SUBNET is an add_tag_layer object. + - SUBNET is an add_skip_layer object. + - SUBNET is a repeat object. + + WHAT THIS OBJECT REPRESENTS + This object adds a new layer to a deep neural network. However, this layer + simply performs the identity transform. This means it is a no-op and its + presence does not change the behavior of the network. It exists solely to + be used by add_skip_layer to reference a particular part of a network. + + Also, this object provides an interface identical to the one defined by the + add_layer object. + !*/ + }; + + template + std::ostream& operator<<(std::ostream& out, const add_tag_layer& item); + /*! + prints the network architecture to the given output stream. + !*/ + + template + void serialize(const add_tag_layer& item, std::ostream& out); + template + void deserialize(add_tag_layer& item, std::istream& in); + /*! + provides serialization support + !*/ + + template using tag1 = add_tag_layer< 1, SUBNET>; + template using tag2 = add_tag_layer< 2, SUBNET>; + template using tag3 = add_tag_layer< 3, SUBNET>; + template using tag4 = add_tag_layer< 4, SUBNET>; + template using tag5 = add_tag_layer< 5, SUBNET>; + template using tag6 = add_tag_layer< 6, SUBNET>; + template using tag7 = add_tag_layer< 7, SUBNET>; + template using tag8 = add_tag_layer< 8, SUBNET>; + template using tag9 = add_tag_layer< 9, SUBNET>; + template using tag10 = add_tag_layer<10, SUBNET>; + + template class tag> + struct tag_id + { + /*! + REQUIREMENTS ON tag + Tag should be an add_tag_layer template such as tag1, tag2, etc. + + WHAT THIS OBJECT REPRESENTS + This is a tool for finding the numeric ID of a tag layer. For example, + tag_id::id == 3. + !*/ + + const static unsigned long id; + }; + +// ---------------------------------------------------------------------------------------- + + template < + template class TAG_TYPE, + typename SUBNET + > + class add_skip_layer + { + /*! + REQUIREMENTS ON SUBNET + - One of the following must be true: + - SUBNET is an add_layer object. + - SUBNET is an add_tag_layer object. + - SUBNET is an add_skip_layer object. + - SUBNET is a repeat object. + + WHAT THIS OBJECT REPRESENTS + This object adds a new layer to a deep neural network which draws its + inputs from layer(subnet()) and performs the identity transform. + + Also, this object provides an interface identical to the one defined by the + add_layer object. + !*/ + }; + + template class T, typename U> + std::ostream& operator<<(std::ostream& out, const add_skip_layer& item); + /*! + prints the network architecture to the given output stream. + !*/ + + template class T, typename U> + void serialize(const add_skip_layer& item, std::ostream& out); + template class T, typename U> + void deserialize(add_skip_layer& item, std::istream& in); + /*! + provides serialization support + !*/ + + template using skip1 = add_skip_layer< tag1, SUBNET>; + template using skip2 = add_skip_layer< tag2, SUBNET>; + template using skip3 = add_skip_layer< tag3, SUBNET>; + template using skip4 = add_skip_layer< tag4, SUBNET>; + template using skip5 = add_skip_layer< tag5, SUBNET>; + template using skip6 = add_skip_layer< tag6, SUBNET>; + template using skip7 = add_skip_layer< tag7, SUBNET>; + template using skip8 = add_skip_layer< tag8, SUBNET>; + template using skip9 = add_skip_layer< tag9, SUBNET>; + template using skip10 = add_skip_layer; + +// ---------------------------------------------------------------------------------------- + + template < + unsigned int i, + typename net_type + > + auto& layer ( + net_type& n + ); + /*! + requires + - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or + add_tag_layer. + - i < net_type::num_layers + ensures + - This function allows you to access any layer in a network by its layer index + i. Therefore, it will walk i steps down the network and return the layer + object there. Since networks can be big, the best way to find layer index + numbers is to print a network to the screen since the print out will include + indexes for each layer. + - In general, this function chains together i calls to n.subnet() and returns + the result. So for example: + - if (i == 0) + - returns n + - else if (i == 1) + - returns n.subnet() + - else if (i == 2) + - returns n.subnet().subnet() + - else if (i == 3) + - returns n.subnet().subnet().subnet() + - else + - etc. + Except that when it hits a repeat layer it recurses into the repeated layers + contained inside. That is, if the layer index indicates a layer in a repeat + object this function will make the appropriate call to get_repeated_layer() + and do the right thing. + !*/ + + template < + template class Match, + typename net_type + > + auto& layer ( + net_type& n + ); + /*! + requires + - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or + add_tag_layer. + ensures + - returns the first layer in n that is of type Match. E.g. if net_type is + fc>>> then calling layer(n) would return + layer<1>(n), that is, a reference to the relu layer. + !*/ + + template < + template class Match, + unsigned int i, + typename net_type + > + auto& layer ( + net_type& n + ); + /*! + requires + - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or + add_tag_layer. + ensures + - returns layer(layer(n)) + !*/ + +// ---------------------------------------------------------------------------------------- + + template + auto& input_layer ( + net_type& net + ); + /*! + requires + - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or + add_tag_layer. + ensures + - returns the input later of the given network object. Specifically, this + function is equivalent to calling: + layer(net); + That is, you get the input layer details object for the network. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename net_type, + typename visitor + > + void visit_layer_parameters( + net_type& net, + visitor v + ); + /*! + requires + - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or + add_tag_layer. + - v is a function object with a signature equivalent to: + v(size_t idx, tensor& t) + ensures + - Loops over all the computational layers (i.e. layers with parameters, as + opposed to loss, tag, or input layers) in net and passes their parameters to + v(). To be specific, this function essentially performs the following: + + size_t computational_layer_idx = 0; + for (size_t i = 0; i < net_type::num_layers; ++i) + { + if (layer(net) is a computational layer) + { + v(computational_layer_idx, layer(net).layer_details().get_layer_params()); + ++computational_layer_idx; + } + } + - When v() is called, the first argument is always < net_type::num_computational_layers. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename net_type, + typename visitor + > + void visit_layer_parameter_gradients( + net_type& net, + visitor v + ); + /*! + requires + - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or + add_tag_layer. + - v is a function object with a signature equivalent to: + v(size_t idx, tensor& t) + ensures + - Loops over all the computational layers (i.e. layers with parameters, as + opposed to loss, tag, or input layers) in net and passes their parameter + gradients to v(). To be specific, this function essentially performs the + following: + + size_t computational_layer_idx = 0; + for (size_t i = 0; i < net_type::num_layers; ++i) + { + if (layer(net) is a computational layer) + { + v(computational_layer_idx, layer(net).get_parameter_gradient()); + ++computational_layer_idx; + } + } + - When v() is called, the first argument is always < net_type::num_computational_layers. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename net_type, + typename visitor + > + void visit_layers( + net_type& net, + visitor v + ); + /*! + requires + - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or + add_tag_layer. + - v is a function object with a signature equivalent to: + v(size_t idx, any_net_type& t) + That is, it must take a size_t and then any of the network types such as + add_layer, add_loss_layer, etc. + ensures + - Loops over all the layers in net and calls v() on them. To be specific, this + function essentially performs the following: + + for (size_t i = 0; i < net_type::num_layers; ++i) + v(i, layer(net)); + !*/ + + template < + typename net_type, + typename visitor + > + void visit_layers_backwards( + net_type& net, + visitor v + ); + /*! + requires + - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or + add_tag_layer. + - v is a function object with a signature equivalent to: + v(size_t idx, any_net_type& t) + That is, it must take a size_t and then any of the network types such as + add_layer, add_loss_layer, etc. + ensures + - Loops over all the layers in net and calls v() on them. The loop happens in + the reverse order of visit_layers(). To be specific, this function + essentially performs the following: + + for (size_t i = net_type::num_layers; i != 0; --i) + v(i-1, layer(net)); + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + size_t begin, + size_t end, + typename net_type, + typename visitor + > + void visit_layers_range( + net_type& net, + visitor v + ); + /*! + requires + - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or + add_tag_layer. + - v is a function object with a signature equivalent to: + v(size_t idx, any_net_type& t) + That is, it must take a size_t and then any of the network types such as + add_layer, add_loss_layer, etc. + - begin <= end <= net_type::num_layers + ensures + - Loops over the layers in the range [begin,end) in net and calls v() on them. + The loop happens in the reverse order of visit_layers(). To be specific, + this function essentially performs the following: + + for (size_t i = begin; i < end; ++i) + v(i, layer(net)); + !*/ + + template < + size_t begin, + size_t end, + typename net_type, + typename visitor + > + void visit_layers_backwards_range( + net_type& net, + visitor v + ); + /*! + requires + - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or + add_tag_layer. + - v is a function object with a signature equivalent to: + v(size_t idx, any_net_type& t) + That is, it must take a size_t and then any of the network types such as + add_layer, add_loss_layer, etc. + - begin <= end <= net_type::num_layers + ensures + - Loops over the layers in the range [begin,end) in net and calls v() on them. + The loop happens in the reverse order of visit_layers_range(). To be specific, + this function essentially performs the following: + + for (size_t i = end; i != begin; --i) + v(i-1, layer(net)); + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long tag_id, + typename net_type, + typename visitor + > + void visit_layers_until_tag( + net_type& net, + visitor v + ); + /*! + requires + - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or + add_tag_layer. + - v is a function object with a signature equivalent to: + v(any_net_type& t) + That is, it must take any of the network types such as add_layer, + add_loss_layer, etc. + ensures + - Loops over all the layers in net beginning with layer<0>(net) and going until + a tag layer with an ID of tag_id is encountered. To be specific, this + function essentially performs the following: + + size_t i = 0; + while(layer(net) isn't an add_tag_layer with ID == tag_id) { + v(layer(net)); + ++i; + } + v(layer(net)); // also visits the tag layer itself at the very end. + !*/ + +// ---------------------------------------------------------------------------------------- + + struct layer_test_results + { + std::string log; + bool was_good; + + operator bool() const { return was_good; } + }; + + inline std::ostream& operator<< (std::ostream& out, const layer_test_results& item) + { + out << item.log; + return out; + } + + template < + typename layer_details_type + > + layer_test_results test_layer ( + layer_details_type l + ); + /*! + ensures + - Checks if l correctly implements the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined in layers_abstract.h. Importantly, it computes numerical approximations + to the gradients and compares them to the outputs of the layer. + - The results of the testing are returned. In particular, if the returned object + is RESULT then we will have: + - RESULT.was_good == false if and only if the layer failed the testing. + - RESULT.log == a string describing why the testing failed if was_good==false. + - Note that this function is only capable of checking layers that take + arbitrary subnetworks as input. So if you have designed a layer that expects + only a certain restricted type of subnetwork then you might get a compile or + runtime error when you call this function. + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DNn_CORE_ABSTRACT_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/dnn/input.h b/lib/3rdParty/dlib/include/dlib/dnn/input.h new file mode 100644 index 00000000..700dbd3e --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/dnn/input.h @@ -0,0 +1,808 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DNn_INPUT_H_ +#define DLIB_DNn_INPUT_H_ + +#include "input_abstract.h" +#include "../matrix.h" +#include "../array2d.h" +#include "../pixel.h" +#include "../image_processing.h" +#include +#include +#include "../cuda/tensor_tools.h" + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template + class input + { + const static bool always_false = sizeof(T)!=sizeof(T); + static_assert(always_false, "Unsupported type given to input<>. input<> only supports " + "dlib::matrix and dlib::array2d objects."); + }; + +// ---------------------------------------------------------------------------------------- + + template + class input_rgb_image_sized; + + class input_rgb_image + { + public: + typedef matrix input_type; + + input_rgb_image ( + ) : + avg_red(122.782), + avg_green(117.001), + avg_blue(104.298) + { + } + + input_rgb_image ( + float avg_red_, + float avg_green_, + float avg_blue_ + ) : avg_red(avg_red_), avg_green(avg_green_), avg_blue(avg_blue_) + {} + + template + inline input_rgb_image ( + const input_rgb_image_sized& item + ); + + float get_avg_red() const { return avg_red; } + float get_avg_green() const { return avg_green; } + float get_avg_blue() const { return avg_blue; } + + bool image_contained_point ( const tensor& data, const point& p) const { return get_rect(data).contains(p); } + drectangle tensor_space_to_image_space ( const tensor& /*data*/, drectangle r) const { return r; } + drectangle image_space_to_tensor_space ( const tensor& /*data*/, double /*scale*/, drectangle r ) const { return r; } + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const + { + DLIB_CASSERT(std::distance(ibegin,iend) > 0); + const auto nr = ibegin->nr(); + const auto nc = ibegin->nc(); + // make sure all the input matrices have the same dimensions + for (auto i = ibegin; i != iend; ++i) + { + DLIB_CASSERT(i->nr()==nr && i->nc()==nc, + "\t input_rgb_image::to_tensor()" + << "\n\t All matrices given to to_tensor() must have the same dimensions." + << "\n\t nr: " << nr + << "\n\t nc: " << nc + << "\n\t i->nr(): " << i->nr() + << "\n\t i->nc(): " << i->nc() + ); + } + + + // initialize data to the right size to contain the stuff in the iterator range. + data.set_size(std::distance(ibegin,iend), 3, nr, nc); + + + const size_t offset = nr*nc; + auto ptr = data.host(); + for (auto i = ibegin; i != iend; ++i) + { + for (long r = 0; r < nr; ++r) + { + for (long c = 0; c < nc; ++c) + { + rgb_pixel temp = (*i)(r,c); + auto p = ptr++; + *p = (temp.red-avg_red)/256.0; + p += offset; + *p = (temp.green-avg_green)/256.0; + p += offset; + *p = (temp.blue-avg_blue)/256.0; + p += offset; + } + } + ptr += offset*(data.k()-1); + } + + } + + friend void serialize(const input_rgb_image& item, std::ostream& out) + { + serialize("input_rgb_image", out); + serialize(item.avg_red, out); + serialize(item.avg_green, out); + serialize(item.avg_blue, out); + } + + friend void deserialize(input_rgb_image& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "input_rgb_image" && version != "input_rgb_image_sized") + throw serialization_error("Unexpected version found while deserializing dlib::input_rgb_image."); + deserialize(item.avg_red, in); + deserialize(item.avg_green, in); + deserialize(item.avg_blue, in); + + // read and discard the sizes if this was really a sized input layer. + if (version == "input_rgb_image_sized") + { + size_t nr, nc; + deserialize(nr, in); + deserialize(nc, in); + } + } + + friend std::ostream& operator<<(std::ostream& out, const input_rgb_image& item) + { + out << "input_rgb_image("<"; + } + + private: + float avg_red; + float avg_green; + float avg_blue; + }; + +// ---------------------------------------------------------------------------------------- + + template + class input_rgb_image_sized + { + public: + static_assert(NR != 0 && NC != 0, "The input image can't be empty."); + + typedef matrix input_type; + + input_rgb_image_sized ( + ) : + avg_red(122.782), + avg_green(117.001), + avg_blue(104.298) + { + } + + input_rgb_image_sized ( + const input_rgb_image& item + ) : avg_red(item.get_avg_red()), + avg_green(item.get_avg_green()), + avg_blue(item.get_avg_blue()) + {} + + input_rgb_image_sized ( + float avg_red_, + float avg_green_, + float avg_blue_ + ) : avg_red(avg_red_), avg_green(avg_green_), avg_blue(avg_blue_) + {} + + float get_avg_red() const { return avg_red; } + float get_avg_green() const { return avg_green; } + float get_avg_blue() const { return avg_blue; } + + bool image_contained_point ( const tensor& data, const point& p) const { return get_rect(data).contains(p); } + drectangle tensor_space_to_image_space ( const tensor& /*data*/, drectangle r) const { return r; } + drectangle image_space_to_tensor_space ( const tensor& /*data*/, double /*scale*/, drectangle r ) const { return r; } + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const + { + DLIB_CASSERT(std::distance(ibegin,iend) > 0); + // make sure all input images have the correct size + for (auto i = ibegin; i != iend; ++i) + { + DLIB_CASSERT(i->nr()==NR && i->nc()==NC, + "\t input_rgb_image_sized::to_tensor()" + << "\n\t All input images must have "<nr()<<" rows and "<nc()<<" columns." + ); + } + + + // initialize data to the right size to contain the stuff in the iterator range. + data.set_size(std::distance(ibegin,iend), 3, NR, NC); + + + const size_t offset = NR*NC; + auto ptr = data.host(); + for (auto i = ibegin; i != iend; ++i) + { + for (size_t r = 0; r < NR; ++r) + { + for (size_t c = 0; c < NC; ++c) + { + rgb_pixel temp = (*i)(r,c); + auto p = ptr++; + *p = (temp.red-avg_red)/256.0; + p += offset; + *p = (temp.green-avg_green)/256.0; + p += offset; + *p = (temp.blue-avg_blue)/256.0; + p += offset; + } + } + ptr += offset*(data.k()-1); + } + + } + + friend void serialize(const input_rgb_image_sized& item, std::ostream& out) + { + serialize("input_rgb_image_sized", out); + serialize(item.avg_red, out); + serialize(item.avg_green, out); + serialize(item.avg_blue, out); + serialize(NR, out); + serialize(NC, out); + } + + friend void deserialize(input_rgb_image_sized& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "input_rgb_image_sized") + throw serialization_error("Unexpected version found while deserializing dlib::input_rgb_image_sized."); + deserialize(item.avg_red, in); + deserialize(item.avg_green, in); + deserialize(item.avg_blue, in); + size_t nr, nc; + deserialize(nr, in); + deserialize(nc, in); + if (nr != NR || nc != NC) + { + std::ostringstream sout; + sout << "Wrong image dimensions found while deserializing dlib::input_rgb_image_sized.\n"; + sout << "Expected "<"; + } + + private: + float avg_red; + float avg_green; + float avg_blue; + }; + +// ---------------------------------------------------------------------------------------- + + template + input_rgb_image:: + input_rgb_image ( + const input_rgb_image_sized& item + ) : avg_red(item.get_avg_red()), + avg_green(item.get_avg_green()), + avg_blue(item.get_avg_blue()) + {} + +// ---------------------------------------------------------------------------------------- + + template + class input> + { + public: + typedef matrix input_type; + + input() {} + input(const input&) {} + + template + input(const input>&) {} + + bool image_contained_point ( const tensor& data, const point& p) const { return get_rect(data).contains(p); } + drectangle tensor_space_to_image_space ( const tensor& /*data*/, drectangle r) const { return r; } + drectangle image_space_to_tensor_space ( const tensor& /*data*/, double /*scale*/, drectangle r ) const { return r; } + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const + { + DLIB_CASSERT(std::distance(ibegin,iend) > 0); + const auto nr = ibegin->nr(); + const auto nc = ibegin->nc(); + // make sure all the input matrices have the same dimensions + for (auto i = ibegin; i != iend; ++i) + { + DLIB_CASSERT(i->nr()==nr && i->nc()==nc, + "\t input::to_tensor()" + << "\n\t All matrices given to to_tensor() must have the same dimensions." + << "\n\t nr: " << nr + << "\n\t nc: " << nc + << "\n\t i->nr(): " << i->nr() + << "\n\t i->nc(): " << i->nc() + ); + } + + + // initialize data to the right size to contain the stuff in the iterator range. + data.set_size(std::distance(ibegin,iend), pixel_traits::num, nr, nc); + + typedef typename pixel_traits::basic_pixel_type bptype; + + const size_t offset = nr*nc; + auto ptr = data.host(); + for (auto i = ibegin; i != iend; ++i) + { + for (long r = 0; r < nr; ++r) + { + for (long c = 0; c < nc; ++c) + { + auto temp = pixel_to_vector((*i)(r,c)); + auto p = ptr++; + for (long j = 0; j < temp.size(); ++j) + { + if (is_same_type::value) + *p = temp(j)/256.0; + else + *p = temp(j); + p += offset; + } + } + } + ptr += offset*(data.k()-1); + } + + } + + friend void serialize(const input& /*item*/, std::ostream& out) + { + serialize("input", out); + } + + friend void deserialize(input& /*item*/, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "input") + throw serialization_error("Unexpected version found while deserializing dlib::input."); + } + + friend std::ostream& operator<<(std::ostream& out, const input& /*item*/) + { + out << "input"; + return out; + } + + friend void to_xml(const input& /*item*/, std::ostream& out) + { + out << ""; + } + }; + +// ---------------------------------------------------------------------------------------- + + template + class input,K>> + { + public: + typedef std::array,K> input_type; + + input() {} + input(const input&) {} + + bool image_contained_point ( const tensor& data, const point& p) const { return get_rect(data).contains(p); } + drectangle tensor_space_to_image_space ( const tensor& /*data*/, drectangle r) const { return r; } + drectangle image_space_to_tensor_space ( const tensor& /*data*/, double /*scale*/, drectangle r ) const { return r; } + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const + { + DLIB_CASSERT(std::distance(ibegin,iend) > 0); + DLIB_CASSERT(ibegin->size() != 0, "When using std::array inputs you can't give 0 sized arrays."); + const auto nr = (*ibegin)[0].nr(); + const auto nc = (*ibegin)[0].nc(); + // make sure all the input matrices have the same dimensions + for (auto i = ibegin; i != iend; ++i) + { + for (size_t k = 0; k < K; ++k) + { + const auto& arr = *i; + DLIB_CASSERT(arr[k].nr()==nr && arr[k].nc()==nc, + "\t input::to_tensor()" + << "\n\t When using std::array as input, all matrices in a batch must have the same dimensions." + << "\n\t nr: " << nr + << "\n\t nc: " << nc + << "\n\t k: " << k + << "\n\t arr[k].nr(): " << arr[k].nr() + << "\n\t arr[k].nc(): " << arr[k].nc() + ); + } + } + + + // initialize data to the right size to contain the stuff in the iterator range. + data.set_size(std::distance(ibegin,iend), K, nr, nc); + + auto ptr = data.host(); + for (auto i = ibegin; i != iend; ++i) + { + for (size_t k = 0; k < K; ++k) + { + for (long r = 0; r < nr; ++r) + { + for (long c = 0; c < nc; ++c) + { + if (is_same_type::value) + *ptr++ = (*i)[k](r,c)/256.0; + else + *ptr++ = (*i)[k](r,c); + } + } + } + } + + } + + friend void serialize(const input& /*item*/, std::ostream& out) + { + serialize("input>", out); + } + + friend void deserialize(input& /*item*/, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "input>") + throw serialization_error("Unexpected version found while deserializing dlib::input>."); + } + + friend std::ostream& operator<<(std::ostream& out, const input& /*item*/) + { + out << "input>"; + return out; + } + + friend void to_xml(const input& /*item*/, std::ostream& out) + { + out << ""; + } + }; + +// ---------------------------------------------------------------------------------------- + + template + class input> + { + public: + typedef array2d input_type; + + input() {} + input(const input&) {} + + template + input(const input>&) {} + + bool image_contained_point ( const tensor& data, const point& p) const { return get_rect(data).contains(p); } + drectangle tensor_space_to_image_space ( const tensor& /*data*/, drectangle r) const { return r; } + drectangle image_space_to_tensor_space ( const tensor& /*data*/, double /*scale*/, drectangle r ) const { return r; } + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const + { + DLIB_CASSERT(std::distance(ibegin,iend) > 0); + const auto nr = ibegin->nr(); + const auto nc = ibegin->nc(); + // make sure all the input matrices have the same dimensions + for (auto i = ibegin; i != iend; ++i) + { + DLIB_CASSERT(i->nr()==nr && i->nc()==nc, + "\t input::to_tensor()" + << "\n\t All array2d objects given to to_tensor() must have the same dimensions." + << "\n\t nr: " << nr + << "\n\t nc: " << nc + << "\n\t i->nr(): " << i->nr() + << "\n\t i->nc(): " << i->nc() + ); + } + + + // initialize data to the right size to contain the stuff in the iterator range. + data.set_size(std::distance(ibegin,iend), pixel_traits::num, nr, nc); + typedef typename pixel_traits::basic_pixel_type bptype; + + const size_t offset = nr*nc; + auto ptr = data.host(); + for (auto i = ibegin; i != iend; ++i) + { + for (long r = 0; r < nr; ++r) + { + for (long c = 0; c < nc; ++c) + { + auto temp = pixel_to_vector((*i)[r][c]); + auto p = ptr++; + for (long j = 0; j < temp.size(); ++j) + { + if (is_same_type::value) + *p = temp(j)/256.0; + else + *p = temp(j); + p += offset; + } + } + } + ptr += offset*(data.k()-1); + } + + } + + friend void serialize(const input& item, std::ostream& out) + { + serialize("input", out); + } + + friend void deserialize(input& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "input") + throw serialization_error("Unexpected version found while deserializing dlib::input."); + } + friend std::ostream& operator<<(std::ostream& out, const input& item) + { + out << "input"; + return out; + } + + friend void to_xml(const input& item, std::ostream& out) + { + out << ""; + } + }; + +// ---------------------------------------------------------------------------------------- + + template + class input_rgb_image_pyramid + { + public: + typedef matrix input_type; + typedef PYRAMID_TYPE pyramid_type; + + input_rgb_image_pyramid ( + ) : + avg_red(122.782), + avg_green(117.001), + avg_blue(104.298) + { + } + + input_rgb_image_pyramid ( + float avg_red_, + float avg_green_, + float avg_blue_ + ) : avg_red(avg_red_), avg_green(avg_green_), avg_blue(avg_blue_) + {} + + float get_avg_red() const { return avg_red; } + float get_avg_green() const { return avg_green; } + float get_avg_blue() const { return avg_blue; } + + unsigned long get_pyramid_padding () const { return pyramid_padding; } + void set_pyramid_padding (unsigned long value) { pyramid_padding = value; } + + unsigned long get_pyramid_outer_padding () const { return pyramid_outer_padding; } + void set_pyramid_outer_padding (unsigned long value) { pyramid_outer_padding = value; } + + bool image_contained_point ( + const tensor& data, + const point& p + ) const + { + auto&& rects = any_cast>(data.annotation()); + DLIB_CASSERT(rects.size() > 0); + return rects[0].contains(p+rects[0].tl_corner()); + } + + drectangle tensor_space_to_image_space ( + const tensor& data, + drectangle r + ) const + { + auto&& rects = any_cast>(data.annotation()); + return tiled_pyramid_to_image(rects, r); + } + + drectangle image_space_to_tensor_space ( + const tensor& data, + double scale, + drectangle r + ) const + { + DLIB_CASSERT(0 < scale && scale <= 1 , "scale: "<< scale); + auto&& rects = any_cast>(data.annotation()); + return image_to_tiled_pyramid(rects, scale, r); + } + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const + { + DLIB_CASSERT(std::distance(ibegin,iend) > 0); + auto nr = ibegin->nr(); + auto nc = ibegin->nc(); + // make sure all the input matrices have the same dimensions + for (auto i = ibegin; i != iend; ++i) + { + DLIB_CASSERT(i->nr()==nr && i->nc()==nc, + "\t input_rgb_image_pyramid::to_tensor()" + << "\n\t All matrices given to to_tensor() must have the same dimensions." + << "\n\t nr: " << nr + << "\n\t nc: " << nc + << "\n\t i->nr(): " << i->nr() + << "\n\t i->nc(): " << i->nc() + ); + } + + long NR, NC; + pyramid_type pyr; + auto& rects = data.annotation().get>(); + impl::compute_tiled_image_pyramid_details(pyr, nr, nc, pyramid_padding, pyramid_outer_padding, rects, NR, NC); + + // initialize data to the right size to contain the stuff in the iterator range. + data.set_size(std::distance(ibegin,iend), 3, NR, NC); + + // We need to zero the image before doing the pyramid, since the pyramid + // creation code doesn't write to all parts of the image. We also take + // care to avoid triggering any device to hosts copies. + auto ptr = data.host_write_only(); + for (size_t i = 0; i < data.size(); ++i) + ptr[i] = 0; + + if (rects.size() == 0) + return; + + // copy the first raw image into the top part of the tiled pyramid. We need to + // do this for each of the input images/samples in the tensor. + for (auto i = ibegin; i != iend; ++i) + { + auto& img = *i; + ptr += rects[0].top()*data.nc(); + for (long r = 0; r < img.nr(); ++r) + { + auto p = ptr+rects[0].left(); + for (long c = 0; c < img.nc(); ++c) + p[c] = (img(r,c).red-avg_red)/256.0; + ptr += data.nc(); + } + ptr += data.nc()*(data.nr()-rects[0].bottom()-1); + + ptr += rects[0].top()*data.nc(); + for (long r = 0; r < img.nr(); ++r) + { + auto p = ptr+rects[0].left(); + for (long c = 0; c < img.nc(); ++c) + p[c] = (img(r,c).green-avg_green)/256.0; + ptr += data.nc(); + } + ptr += data.nc()*(data.nr()-rects[0].bottom()-1); + + ptr += rects[0].top()*data.nc(); + for (long r = 0; r < img.nr(); ++r) + { + auto p = ptr+rects[0].left(); + for (long c = 0; c < img.nc(); ++c) + p[c] = (img(r,c).blue-avg_blue)/256.0; + ptr += data.nc(); + } + ptr += data.nc()*(data.nr()-rects[0].bottom()-1); + } + + // now build the image pyramid into data. This does the same thing as + // create_tiled_pyramid(), except we use the GPU if one is available. + for (size_t i = 1; i < rects.size(); ++i) + { + alias_tensor src(data.num_samples(),data.k(),rects[i-1].height(),rects[i-1].width()); + alias_tensor dest(data.num_samples(),data.k(),rects[i].height(),rects[i].width()); + + auto asrc = src(data, data.nc()*rects[i-1].top() + rects[i-1].left()); + auto adest = dest(data, data.nc()*rects[i].top() + rects[i].left()); + + tt::resize_bilinear(adest, data.nc(), data.nr()*data.nc(), + asrc, data.nc(), data.nr()*data.nc()); + } + } + + friend void serialize(const input_rgb_image_pyramid& item, std::ostream& out) + { + serialize("input_rgb_image_pyramid2", out); + serialize(item.avg_red, out); + serialize(item.avg_green, out); + serialize(item.avg_blue, out); + serialize(item.pyramid_padding, out); + serialize(item.pyramid_outer_padding, out); + } + + friend void deserialize(input_rgb_image_pyramid& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "input_rgb_image_pyramid" && version != "input_rgb_image_pyramid2") + throw serialization_error("Unexpected version found while deserializing dlib::input_rgb_image_pyramid."); + deserialize(item.avg_red, in); + deserialize(item.avg_green, in); + deserialize(item.avg_blue, in); + if (version == "input_rgb_image_pyramid2") + { + deserialize(item.pyramid_padding, in); + deserialize(item.pyramid_outer_padding, in); + } + else + { + item.pyramid_padding = 10; + item.pyramid_outer_padding = 11; + } + } + + friend std::ostream& operator<<(std::ostream& out, const input_rgb_image_pyramid& item) + { + out << "input_rgb_image_pyramid("<"; + } + + private: + float avg_red; + float avg_green; + float avg_blue; + unsigned long pyramid_padding = 10; + unsigned long pyramid_outer_padding = 11; + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DNn_INPUT_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/dnn/input_abstract.h b/lib/3rdParty/dlib/include/dlib/dnn/input_abstract.h new file mode 100644 index 00000000..7130efb1 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/dnn/input_abstract.h @@ -0,0 +1,467 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_DNn_INPUT_ABSTRACT_H_ +#ifdef DLIB_DNn_INPUT_ABSTRACT_H_ + +#include "../matrix.h" +#include "../pixel.h" + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class EXAMPLE_INPUT_LAYER + { + /*! + WHAT THIS OBJECT REPRESENTS + Each deep neural network model in dlib begins with an input layer. The job + of the input layer is to convert an input_type into a tensor. Nothing more + and nothing less. + + Note that there is no dlib::EXAMPLE_INPUT_LAYER type. It is shown here + purely to document the interface that an input layer object must implement. + If you are using some kind of image or matrix object as your input_type + then you can use the provided dlib::input layer defined below. Otherwise, + you need to define your own custom input layer. + + THREAD SAFETY + to_tensor() must be thread safe. That is, multiple threads must be able to + make calls to to_tensor() on a single instance of this object at the same + time. + !*/ + public: + + EXAMPLE_INPUT_LAYER( + ); + /*! + ensures + - Default constructs this object. This function is not required to do + anything in particular but it must exist, that is, it is required that + layer objects be default constructable. + !*/ + + EXAMPLE_INPUT_LAYER ( + const EXAMPLE_INPUT_LAYER& item + ); + /*! + ensures + - EXAMPLE_INPUT_LAYER objects are copy constructable + !*/ + + EXAMPLE_INPUT_LAYER( + const some_other_input_layer_type& item + ); + /*! + ensures + - Constructs this object from item. This form of constructor is optional + but it allows you to provide a conversion from one input layer type to + another. For example, the following code is valid only if my_input_layer2 can + be constructed from my_input_layer1: + relu>>> my_dnn1; + relu>>> my_dnn2(my_dnn1); + This kind of pattern is useful if you want to use one type of input layer + during training but a different type of layer during testing since it + allows you to easily convert between related deep neural network types. + !*/ + + typedef whatever_type_to_tensor_expects input_type; + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const; + /*! + requires + - [ibegin, iend) is an iterator range over input_type objects. + - std::distance(ibegin,iend) > 0 + ensures + - Converts the iterator range into a tensor and stores it into #data. + - #data.num_samples()%distance(ibegin,iend) == 0. + Normally you would have #data.num_samples() == distance(ibegin,iend) but + you can also expand the output by some integer factor so long as the loss + you use can deal with it correctly. + - The data in the ith sample of #data corresponds to the input_type object + *(ibegin+i/sample_expansion_factor). + where sample_expansion_factor==#data.num_samples()/distance(ibegin,iend). + !*/ + }; + + std::ostream& operator<<(std::ostream& out, const EXAMPLE_INPUT_LAYER& item); + /*! + print a string describing this layer. + !*/ + + void to_xml(const EXAMPLE_INPUT_LAYER& item, std::ostream& out); + /*! + This function is optional, but required if you want to print your networks with + net_to_xml(). Therefore, to_xml() prints a layer as XML. + !*/ + + void serialize(const EXAMPLE_INPUT_LAYER& item, std::ostream& out); + void deserialize(EXAMPLE_INPUT_LAYER& item, std::istream& in); + /*! + provides serialization support + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + class input + { + /*! + REQUIREMENTS ON T + One of the following must be true: + - T is a matrix or array2d object and it must contain some kind of + pixel type. I.e. pixel_traits must be defined. + - T is a std::array> where U is any built in scalar type like + float, double, or unsigned char. + + WHAT THIS OBJECT REPRESENTS + This is a basic input layer that simply copies images into a tensor. + !*/ + + public: + typedef T input_type; + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const; + /*! + requires + - [ibegin, iend) is an iterator range over input_type objects. + - std::distance(ibegin,iend) > 0 + - The input range should contain image objects that all have the same + dimensions. + ensures + - Converts the iterator range into a tensor and stores it into #data. In + particular, if the input images have R rows, C columns, and K channels + (where K is given by pixel_traits::num or std::array::size() if + std::array inputs are used) then we will have: + - #data.num_samples() == std::distance(ibegin,iend) + - #data.nr() == R + - #data.nc() == C + - #data.k() == K + For example, a matrix would turn into a tensor with 3 rows, 3 + columns, and k()==1. Or a matrix would turn into a tensor + with 4 rows, 5 columns, and k()==3 (since rgb_pixels have 3 channels). + Or a std::array,5> would turn into a tensor with 3 rows + and columns, and k()==5 channels. + - If the input data contains pixels of type unsigned char, rgb_pixel, or + other pixel types with a basic_pixel_type of unsigned char then each + value written to the output tensor is first divided by 256.0 so that the + resulting outputs are all in the range [0,1]. + !*/ + + // Provided for compatibility with input_rgb_image_pyramid's interface + bool image_contained_point ( const tensor& data, const point& p) const { return get_rect(data).contains(p); } + drectangle tensor_space_to_image_space ( const tensor& /*data*/, drectangle r) const { return r; } + drectangle image_space_to_tensor_space ( const tensor& /*data*/, double /*scale*/, drectangle r ) const { return r; } + }; + +// ---------------------------------------------------------------------------------------- + + class input_rgb_image + { + /*! + WHAT THIS OBJECT REPRESENTS + This input layer works with RGB images of type matrix. It is + very similar to the dlib::input layer except that it allows you to subtract + the average color value from each color channel when converting an image to + a tensor. + !*/ + public: + typedef matrix input_type; + + input_rgb_image ( + ); + /*! + ensures + - #get_avg_red() == 122.782 + - #get_avg_green() == 117.001 + - #get_avg_blue() == 104.298 + !*/ + + input_rgb_image ( + float avg_red, + float avg_green, + float avg_blue + ); + /*! + ensures + - #get_avg_red() == avg_red + - #get_avg_green() == avg_green + - #get_avg_blue() == avg_blue + !*/ + + float get_avg_red( + ) const; + /*! + ensures + - returns the value subtracted from the red color channel. + !*/ + + float get_avg_green( + ) const; + /*! + ensures + - returns the value subtracted from the green color channel. + !*/ + + float get_avg_blue( + ) const; + /*! + ensures + - returns the value subtracted from the blue color channel. + !*/ + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const; + /*! + requires + - [ibegin, iend) is an iterator range over input_type objects. + - std::distance(ibegin,iend) > 0 + - The input range should contain images that all have the same + dimensions. + ensures + - Converts the iterator range into a tensor and stores it into #data. In + particular, if the input images have R rows, C columns then we will have: + - #data.num_samples() == std::distance(ibegin,iend) + - #data.nr() == R + - #data.nc() == C + - #data.k() == 3 + Moreover, each color channel is normalized by having its average value + subtracted (according to get_avg_red(), get_avg_green(), or + get_avg_blue()) and then is divided by 256.0. + !*/ + + + // Provided for compatibility with input_rgb_image_pyramid's interface + bool image_contained_point ( const tensor& data, const point& p) const { return get_rect(data).contains(p); } + drectangle tensor_space_to_image_space ( const tensor& /*data*/, drectangle r) const { return r; } + drectangle image_space_to_tensor_space ( const tensor& /*data*/, double /*scale*/, drectangle r ) const { return r; } + }; + +// ---------------------------------------------------------------------------------------- + + template + class input_rgb_image_sized + { + /*! + WHAT THIS OBJECT REPRESENTS + This layer has an interface and behavior identical to input_rgb_image + except that it requires input images to have NR rows and NC columns. This + is checked by a DLIB_CASSERT inside to_tensor(). + + You can also convert between input_rgb_image and input_rgb_image_sized by + copy construction or assignment. + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename PYRAMID_TYPE + > + class input_rgb_image_pyramid + { + /*! + REQUIREMENTS ON PYRAMID_TYPE + PYRAMID_TYPE must be an instance of the dlib::pyramid_down template. + + WHAT THIS OBJECT REPRESENTS + This input layer works with RGB images of type matrix. It is + identical to input_rgb_image except that it outputs a tensor containing a + tiled image pyramid of each input image rather than a simple copy of each + image. The tiled image pyramid is created using create_tiled_pyramid(). + !*/ + + public: + + typedef matrix input_type; + typedef PYRAMID_TYPE pyramid_type; + + input_rgb_image_pyramid ( + ); + /*! + ensures + - #get_avg_red() == 122.782 + - #get_avg_green() == 117.001 + - #get_avg_blue() == 104.298 + - #get_pyramid_padding() == 10 + - #get_pyramid_outer_padding() == 11 + !*/ + + input_rgb_image_pyramid ( + float avg_red, + float avg_green, + float avg_blue + ); + /*! + ensures + - #get_avg_red() == avg_red + - #get_avg_green() == avg_green + - #get_avg_blue() == avg_blue + - #get_pyramid_padding() == 10 + - #get_pyramid_outer_padding() == 11 + !*/ + + float get_avg_red( + ) const; + /*! + ensures + - returns the value subtracted from the red color channel. + !*/ + + float get_avg_green( + ) const; + /*! + ensures + - returns the value subtracted from the green color channel. + !*/ + + float get_avg_blue( + ) const; + /*! + ensures + - returns the value subtracted from the blue color channel. + !*/ + + unsigned long get_pyramid_padding ( + ) const; + /*! + ensures + - When this object creates a pyramid it will call create_tiled_pyramid() and + set create_tiled_pyramid's pyramid_padding parameter to get_pyramid_padding(). + !*/ + void set_pyramid_padding ( + unsigned long value + ); + /*! + ensures + - #get_pyramid_padding() == value + !*/ + + unsigned long get_pyramid_outer_padding ( + ) const; + /*! + ensures + - When this object creates a pyramid it will call create_tiled_pyramid() + and set create_tiled_pyramid's pyramid_outer_padding parameter to + get_pyramid_outer_padding(). + !*/ + void set_pyramid_outer_padding ( + unsigned long value + ); + /*! + ensures + - #get_pyramid_outer_padding() == value + !*/ + + template + void to_tensor ( + forward_iterator ibegin, + forward_iterator iend, + resizable_tensor& data + ) const; + /*! + requires + - [ibegin, iend) is an iterator range over input_type objects. + - std::distance(ibegin,iend) > 0 + - The input range should contain images that all have the same + dimensions. + ensures + - Converts the iterator range into a tensor and stores it into #data. In + particular, we will have: + - #data.num_samples() == std::distance(ibegin,iend) + - #data.k() == 3 + - Each sample in #data contains a tiled image pyramid of the + corresponding input image. The tiled pyramid is created by + create_tiled_pyramid(). + Moreover, each color channel is normalized by having its average value + subtracted (according to get_avg_red(), get_avg_green(), or + get_avg_blue()) and then is divided by 256.0. + !*/ + + bool image_contained_point ( + const tensor& data, + const point& p + ) const; + /*! + requires + - data is a tensor that was produced by this->to_tensor() + ensures + - Since data is a tensor that is built from a bunch of identically sized + images, we can ask if those images were big enough to contain the point + p. This function returns the answer to that question. + !*/ + + drectangle image_space_to_tensor_space ( + const tensor& data, + double scale, + drectangle r + ) const; + /*! + requires + - data is a tensor that was produced by this->to_tensor() + - 0 < scale <= 1 + ensures + - This function maps from to_tensor()'s input image space to its output + tensor space. Therefore, given that data is a tensor produced by + to_tensor(), image_space_to_tensor_space() allows you to ask for the + rectangle in data that corresponds to a rectangle in the original image + space. + + Note that since the output tensor contains an image pyramid, there are + multiple points in the output tensor that correspond to any input + location. So you must also specify a scale so we know what level of the + pyramid is needed. So given a rectangle r in an input image, you can + ask, what rectangle in data corresponds to r when things are scale times + smaller? That rectangle is returned by this function. + - A scale of 1 means we don't move anywhere in the pyramid scale space relative + to the input image while smaller values of scale mean we move down the + pyramid. + !*/ + + drectangle tensor_space_to_image_space ( + const tensor& data, + drectangle r + ) const; + /*! + requires + - data is a tensor that was produced by this->to_tensor() + ensures + - This function maps from to_tensor()'s output tensor space to its input + image space. Therefore, given that data is a tensor produced by + to_tensor(), tensor_space_to_image_space() allows you to ask for the + rectangle in the input image that corresponds to a rectangle in data. + - It should be noted that this function isn't always an inverse of + image_space_to_tensor_space(). This is because you can ask + image_space_to_tensor_space() for the coordinates of points outside the input + image and they will be mapped to somewhere that doesn't have an inverse. + But for points actually inside the input image this function performs an + approximate inverse mapping. I.e. when image_contained_point(data,center(r))==true + there is an approximate inverse. + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DNn_INPUT_ABSTRACT_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/dnn/layers.h b/lib/3rdParty/dlib/include/dlib/dnn/layers.h new file mode 100644 index 00000000..9f3e9300 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/dnn/layers.h @@ -0,0 +1,3358 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DNn_LAYERS_H_ +#define DLIB_DNn_LAYERS_H_ + +#include "layers_abstract.h" +#include "../cuda/tensor.h" +#include "core.h" +#include +#include +#include "../rand.h" +#include "../string.h" +#include "../cuda/tensor_tools.h" +#include "../vectorstream.h" +#include "utilities.h" +#include + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + struct num_con_outputs + { + num_con_outputs(unsigned long n) : num_outputs(n) {} + unsigned long num_outputs; + }; + + template < + long _num_filters, + long _nr, + long _nc, + int _stride_y, + int _stride_x, + int _padding_y = _stride_y!=1? 0 : _nr/2, + int _padding_x = _stride_x!=1? 0 : _nc/2 + > + class con_ + { + public: + + static_assert(_num_filters > 0, "The number of filters must be > 0"); + static_assert(_nr >= 0, "The number of rows in a filter must be >= 0"); + static_assert(_nc >= 0, "The number of columns in a filter must be >= 0"); + static_assert(_stride_y > 0, "The filter stride must be > 0"); + static_assert(_stride_x > 0, "The filter stride must be > 0"); + static_assert(_nr==0 || (0 <= _padding_y && _padding_y < _nr), "The padding must be smaller than the filter size."); + static_assert(_nc==0 || (0 <= _padding_x && _padding_x < _nc), "The padding must be smaller than the filter size."); + static_assert(_nr!=0 || 0 == _padding_y, "If _nr==0 then the padding must be set to 0 as well."); + static_assert(_nc!=0 || 0 == _padding_x, "If _nr==0 then the padding must be set to 0 as well."); + + con_( + num_con_outputs o + ) : + learning_rate_multiplier(1), + weight_decay_multiplier(1), + bias_learning_rate_multiplier(1), + bias_weight_decay_multiplier(0), + num_filters_(o.num_outputs), + padding_y_(_padding_y), + padding_x_(_padding_x) + { + DLIB_CASSERT(num_filters_ > 0); + } + + con_() : con_(num_con_outputs(_num_filters)) {} + + long num_filters() const { return num_filters_; } + long nr() const + { + if (_nr==0) + return filters.nr(); + else + return _nr; + } + long nc() const + { + if (_nc==0) + return filters.nc(); + else + return _nc; + } + long stride_y() const { return _stride_y; } + long stride_x() const { return _stride_x; } + long padding_y() const { return padding_y_; } + long padding_x() const { return padding_x_; } + + void set_num_filters(long num) + { + DLIB_CASSERT(num > 0); + if (num != num_filters_) + { + DLIB_CASSERT(get_layer_params().size() == 0, + "You can't change the number of filters in con_ if the parameter tensor has already been allocated."); + num_filters_ = num; + } + } + + double get_learning_rate_multiplier () const { return learning_rate_multiplier; } + double get_weight_decay_multiplier () const { return weight_decay_multiplier; } + void set_learning_rate_multiplier(double val) { learning_rate_multiplier = val; } + void set_weight_decay_multiplier(double val) { weight_decay_multiplier = val; } + + double get_bias_learning_rate_multiplier () const { return bias_learning_rate_multiplier; } + double get_bias_weight_decay_multiplier () const { return bias_weight_decay_multiplier; } + void set_bias_learning_rate_multiplier(double val) { bias_learning_rate_multiplier = val; } + void set_bias_weight_decay_multiplier(double val) { bias_weight_decay_multiplier = val; } + + inline dpoint map_input_to_output ( + dpoint p + ) const + { + p.x() = (p.x()+padding_x()-nc()/2)/stride_x(); + p.y() = (p.y()+padding_y()-nr()/2)/stride_y(); + return p; + } + + inline dpoint map_output_to_input ( + dpoint p + ) const + { + p.x() = p.x()*stride_x() - padding_x() + nc()/2; + p.y() = p.y()*stride_y() - padding_y() + nr()/2; + return p; + } + + con_ ( + const con_& item + ) : + params(item.params), + filters(item.filters), + biases(item.biases), + learning_rate_multiplier(item.learning_rate_multiplier), + weight_decay_multiplier(item.weight_decay_multiplier), + bias_learning_rate_multiplier(item.bias_learning_rate_multiplier), + bias_weight_decay_multiplier(item.bias_weight_decay_multiplier), + num_filters_(item.num_filters_), + padding_y_(item.padding_y_), + padding_x_(item.padding_x_) + { + // this->conv is non-copyable and basically stateless, so we have to write our + // own copy to avoid trying to copy it and getting an error. + } + + con_& operator= ( + const con_& item + ) + { + if (this == &item) + return *this; + + // this->conv is non-copyable and basically stateless, so we have to write our + // own copy to avoid trying to copy it and getting an error. + params = item.params; + filters = item.filters; + biases = item.biases; + padding_y_ = item.padding_y_; + padding_x_ = item.padding_x_; + learning_rate_multiplier = item.learning_rate_multiplier; + weight_decay_multiplier = item.weight_decay_multiplier; + bias_learning_rate_multiplier = item.bias_learning_rate_multiplier; + bias_weight_decay_multiplier = item.bias_weight_decay_multiplier; + num_filters_ = item.num_filters_; + return *this; + } + + template + void setup (const SUBNET& sub) + { + const long filt_nr = _nr!=0 ? _nr : sub.get_output().nr(); + const long filt_nc = _nc!=0 ? _nc : sub.get_output().nc(); + + long num_inputs = filt_nr*filt_nc*sub.get_output().k(); + long num_outputs = num_filters_; + // allocate params for the filters and also for the filter bias values. + params.set_size(num_inputs*num_filters_ + num_filters_); + + dlib::rand rnd(std::rand()); + randomize_parameters(params, num_inputs+num_outputs, rnd); + + filters = alias_tensor(num_filters_, sub.get_output().k(), filt_nr, filt_nc); + biases = alias_tensor(1,num_filters_); + + // set the initial bias values to zero + biases(params,filters.size()) = 0; + } + + template + void forward(const SUBNET& sub, resizable_tensor& output) + { + conv.setup(sub.get_output(), + filters(params,0), + _stride_y, + _stride_x, + padding_y_, + padding_x_); + conv(false, output, + sub.get_output(), + filters(params,0)); + + tt::add(1,output,1,biases(params,filters.size())); + } + + template + void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad) + { + conv.get_gradient_for_data (true, gradient_input, filters(params,0), sub.get_gradient_input()); + // no dpoint computing the parameter gradients if they won't be used. + if (learning_rate_multiplier != 0) + { + auto filt = filters(params_grad,0); + conv.get_gradient_for_filters (false, gradient_input, sub.get_output(), filt); + auto b = biases(params_grad, filters.size()); + tt::assign_conv_bias_gradient(b, gradient_input); + } + } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const con_& item, std::ostream& out) + { + serialize("con_4", out); + serialize(item.params, out); + serialize(item.num_filters_, out); + serialize(_nr, out); + serialize(_nc, out); + serialize(_stride_y, out); + serialize(_stride_x, out); + serialize(item.padding_y_, out); + serialize(item.padding_x_, out); + serialize(item.filters, out); + serialize(item.biases, out); + serialize(item.learning_rate_multiplier, out); + serialize(item.weight_decay_multiplier, out); + serialize(item.bias_learning_rate_multiplier, out); + serialize(item.bias_weight_decay_multiplier, out); + } + + friend void deserialize(con_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + long nr; + long nc; + int stride_y; + int stride_x; + if (version == "con_4") + { + deserialize(item.params, in); + deserialize(item.num_filters_, in); + deserialize(nr, in); + deserialize(nc, in); + deserialize(stride_y, in); + deserialize(stride_x, in); + deserialize(item.padding_y_, in); + deserialize(item.padding_x_, in); + deserialize(item.filters, in); + deserialize(item.biases, in); + deserialize(item.learning_rate_multiplier, in); + deserialize(item.weight_decay_multiplier, in); + deserialize(item.bias_learning_rate_multiplier, in); + deserialize(item.bias_weight_decay_multiplier, in); + if (item.padding_y_ != _padding_y) throw serialization_error("Wrong padding_y found while deserializing dlib::con_"); + if (item.padding_x_ != _padding_x) throw serialization_error("Wrong padding_x found while deserializing dlib::con_"); + if (nr != _nr) throw serialization_error("Wrong nr found while deserializing dlib::con_"); + if (nc != _nc) throw serialization_error("Wrong nc found while deserializing dlib::con_"); + if (stride_y != _stride_y) throw serialization_error("Wrong stride_y found while deserializing dlib::con_"); + if (stride_x != _stride_x) throw serialization_error("Wrong stride_x found while deserializing dlib::con_"); + } + else + { + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::con_."); + } + } + + + friend std::ostream& operator<<(std::ostream& out, const con_& item) + { + out << "con\t (" + << "num_filters="<\n"; + out << mat(item.params); + out << ""; + } + + private: + + resizable_tensor params; + alias_tensor filters, biases; + + tt::tensor_conv conv; + double learning_rate_multiplier; + double weight_decay_multiplier; + double bias_learning_rate_multiplier; + double bias_weight_decay_multiplier; + long num_filters_; + + // These are here only because older versions of con (which you might encounter + // serialized to disk) used different padding settings. + int padding_y_; + int padding_x_; + + }; + + template < + long num_filters, + long nr, + long nc, + int stride_y, + int stride_x, + typename SUBNET + > + using con = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + + template < + long _num_filters, + long _nr, + long _nc, + int _stride_y, + int _stride_x, + int _padding_y = _stride_y!=1? 0 : _nr/2, + int _padding_x = _stride_x!=1? 0 : _nc/2 + > + class cont_ + { + public: + + static_assert(_num_filters > 0, "The number of filters must be > 0"); + static_assert(_nr > 0, "The number of rows in a filter must be > 0"); + static_assert(_nc > 0, "The number of columns in a filter must be > 0"); + static_assert(_stride_y > 0, "The filter stride must be > 0"); + static_assert(_stride_x > 0, "The filter stride must be > 0"); + static_assert(0 <= _padding_y && _padding_y < _nr, "The padding must be smaller than the filter size."); + static_assert(0 <= _padding_x && _padding_x < _nc, "The padding must be smaller than the filter size."); + + cont_( + num_con_outputs o + ) : + learning_rate_multiplier(1), + weight_decay_multiplier(1), + bias_learning_rate_multiplier(1), + bias_weight_decay_multiplier(0), + num_filters_(o.num_outputs), + padding_y_(_padding_y), + padding_x_(_padding_x) + { + DLIB_CASSERT(num_filters_ > 0); + } + + cont_() : cont_(num_con_outputs(_num_filters)) {} + + long num_filters() const { return num_filters_; } + long nr() const { return _nr; } + long nc() const { return _nc; } + long stride_y() const { return _stride_y; } + long stride_x() const { return _stride_x; } + long padding_y() const { return padding_y_; } + long padding_x() const { return padding_x_; } + + void set_num_filters(long num) + { + DLIB_CASSERT(num > 0); + if (num != num_filters_) + { + DLIB_CASSERT(get_layer_params().size() == 0, + "You can't change the number of filters in cont_ if the parameter tensor has already been allocated."); + num_filters_ = num; + } + } + + double get_learning_rate_multiplier () const { return learning_rate_multiplier; } + double get_weight_decay_multiplier () const { return weight_decay_multiplier; } + void set_learning_rate_multiplier(double val) { learning_rate_multiplier = val; } + void set_weight_decay_multiplier(double val) { weight_decay_multiplier = val; } + + double get_bias_learning_rate_multiplier () const { return bias_learning_rate_multiplier; } + double get_bias_weight_decay_multiplier () const { return bias_weight_decay_multiplier; } + void set_bias_learning_rate_multiplier(double val) { bias_learning_rate_multiplier = val; } + void set_bias_weight_decay_multiplier(double val) { bias_weight_decay_multiplier = val; } + + inline dpoint map_output_to_input ( + dpoint p + ) const + { + p.x() = (p.x()+padding_x()-nc()/2)/stride_x(); + p.y() = (p.y()+padding_y()-nr()/2)/stride_y(); + return p; + } + + inline dpoint map_input_to_output ( + dpoint p + ) const + { + p.x() = p.x()*stride_x() - padding_x() + nc()/2; + p.y() = p.y()*stride_y() - padding_y() + nr()/2; + return p; + } + + cont_ ( + const cont_& item + ) : + params(item.params), + filters(item.filters), + biases(item.biases), + learning_rate_multiplier(item.learning_rate_multiplier), + weight_decay_multiplier(item.weight_decay_multiplier), + bias_learning_rate_multiplier(item.bias_learning_rate_multiplier), + bias_weight_decay_multiplier(item.bias_weight_decay_multiplier), + num_filters_(item.num_filters_), + padding_y_(item.padding_y_), + padding_x_(item.padding_x_) + { + // this->conv is non-copyable and basically stateless, so we have to write our + // own copy to avoid trying to copy it and getting an error. + } + + cont_& operator= ( + const cont_& item + ) + { + if (this == &item) + return *this; + + // this->conv is non-copyable and basically stateless, so we have to write our + // own copy to avoid trying to copy it and getting an error. + params = item.params; + filters = item.filters; + biases = item.biases; + padding_y_ = item.padding_y_; + padding_x_ = item.padding_x_; + learning_rate_multiplier = item.learning_rate_multiplier; + weight_decay_multiplier = item.weight_decay_multiplier; + bias_learning_rate_multiplier = item.bias_learning_rate_multiplier; + bias_weight_decay_multiplier = item.bias_weight_decay_multiplier; + num_filters_ = item.num_filters_; + return *this; + } + + template + void setup (const SUBNET& sub) + { + long num_inputs = _nr*_nc*sub.get_output().k(); + long num_outputs = num_filters_; + // allocate params for the filters and also for the filter bias values. + params.set_size(num_inputs*num_filters_ + num_filters_); + + dlib::rand rnd(std::rand()); + randomize_parameters(params, num_inputs+num_outputs, rnd); + + filters = alias_tensor(sub.get_output().k(), num_filters_, _nr, _nc); + biases = alias_tensor(1,num_filters_); + + // set the initial bias values to zero + biases(params,filters.size()) = 0; + } + + template + void forward(const SUBNET& sub, resizable_tensor& output) + { + auto filt = filters(params,0); + unsigned int gnr = _stride_y * (sub.get_output().nr() - 1) + filt.nr() - 2 * padding_y_; + unsigned int gnc = _stride_x * (sub.get_output().nc() - 1) + filt.nc() - 2 * padding_x_; + unsigned int gnsamps = sub.get_output().num_samples(); + unsigned int gk = filt.k(); + output.set_size(gnsamps,gk,gnr,gnc); + conv.setup(output,filt,_stride_y,_stride_x,padding_y_,padding_x_); + conv.get_gradient_for_data(false, sub.get_output(),filt,output); + tt::add(1,output,1,biases(params,filters.size())); + } + + template + void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad) + { + auto filt = filters(params,0); + conv(true, sub.get_gradient_input(),gradient_input, filt); + // no point computing the parameter gradients if they won't be used. + if (learning_rate_multiplier != 0) + { + auto filt = filters(params_grad,0); + conv.get_gradient_for_filters (false, sub.get_output(),gradient_input, filt); + auto b = biases(params_grad, filters.size()); + tt::assign_conv_bias_gradient(b, gradient_input); + } + } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const cont_& item, std::ostream& out) + { + serialize("cont_1", out); + serialize(item.params, out); + serialize(item.num_filters_, out); + serialize(_nr, out); + serialize(_nc, out); + serialize(_stride_y, out); + serialize(_stride_x, out); + serialize(item.padding_y_, out); + serialize(item.padding_x_, out); + serialize(item.filters, out); + serialize(item.biases, out); + serialize(item.learning_rate_multiplier, out); + serialize(item.weight_decay_multiplier, out); + serialize(item.bias_learning_rate_multiplier, out); + serialize(item.bias_weight_decay_multiplier, out); + } + + friend void deserialize(cont_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + long nr; + long nc; + int stride_y; + int stride_x; + if (version == "cont_1") + { + deserialize(item.params, in); + deserialize(item.num_filters_, in); + deserialize(nr, in); + deserialize(nc, in); + deserialize(stride_y, in); + deserialize(stride_x, in); + deserialize(item.padding_y_, in); + deserialize(item.padding_x_, in); + deserialize(item.filters, in); + deserialize(item.biases, in); + deserialize(item.learning_rate_multiplier, in); + deserialize(item.weight_decay_multiplier, in); + deserialize(item.bias_learning_rate_multiplier, in); + deserialize(item.bias_weight_decay_multiplier, in); + if (item.padding_y_ != _padding_y) throw serialization_error("Wrong padding_y found while deserializing dlib::con_"); + if (item.padding_x_ != _padding_x) throw serialization_error("Wrong padding_x found while deserializing dlib::con_"); + if (nr != _nr) throw serialization_error("Wrong nr found while deserializing dlib::con_"); + if (nc != _nc) throw serialization_error("Wrong nc found while deserializing dlib::con_"); + if (stride_y != _stride_y) throw serialization_error("Wrong stride_y found while deserializing dlib::con_"); + if (stride_x != _stride_x) throw serialization_error("Wrong stride_x found while deserializing dlib::con_"); + } + else + { + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::con_."); + } + } + + + friend std::ostream& operator<<(std::ostream& out, const cont_& item) + { + out << "cont\t (" + << "num_filters="<\n"; + out << mat(item.params); + out << ""; + } + + private: + + resizable_tensor params; + alias_tensor filters, biases; + + tt::tensor_conv conv; + double learning_rate_multiplier; + double weight_decay_multiplier; + double bias_learning_rate_multiplier; + double bias_weight_decay_multiplier; + long num_filters_; + + int padding_y_; + int padding_x_; + + }; + + template < + long num_filters, + long nr, + long nc, + int stride_y, + int stride_x, + typename SUBNET + > + using cont = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + + template < + int scale_y, + int scale_x + > + class upsample_ + { + public: + static_assert(scale_y >= 1, "upsampling scale factor can't be less than 1."); + static_assert(scale_x >= 1, "upsampling scale factor can't be less than 1."); + + upsample_() + { + } + + template + void setup (const SUBNET& /*sub*/) + { + } + + template + void forward(const SUBNET& sub, resizable_tensor& output) + { + output.set_size( + sub.get_output().num_samples(), + sub.get_output().k(), + scale_y*sub.get_output().nr(), + scale_x*sub.get_output().nc()); + tt::resize_bilinear(output, sub.get_output()); + } + + template + void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/) + { + tt::resize_bilinear_gradient(sub.get_gradient_input(), gradient_input); + } + + inline dpoint map_input_to_output (dpoint p) const + { + p.x() = p.x()*scale_x; + p.y() = p.y()*scale_y; + return p; + } + inline dpoint map_output_to_input (dpoint p) const + { + p.x() = p.x()/scale_x; + p.y() = p.y()/scale_y; + return p; + } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const upsample_& , std::ostream& out) + { + serialize("upsample_", out); + serialize(scale_y, out); + serialize(scale_x, out); + } + + friend void deserialize(upsample_& , std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "upsample_") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::upsample_."); + + int _scale_y; + int _scale_x; + deserialize(_scale_y, in); + deserialize(_scale_x, in); + if (_scale_y != scale_y || _scale_x != scale_x) + throw serialization_error("Wrong scale found while deserializing dlib::upsample_"); + } + + friend std::ostream& operator<<(std::ostream& out, const upsample_& ) + { + out << "upsample\t (" + << "scale_y="<\n"; + } + + private: + resizable_tensor params; + }; + + template < + int scale, + typename SUBNET + > + using upsample = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + + template < + long NR_, + long NC_ + > + class resize_to_ + { + public: + static_assert(NR_ >= 1, "NR resize parameter can't be less than 1."); + static_assert(NC_ >= 1, "NC resize parameter can't be less than 1."); + + resize_to_() + { + } + + template + void setup (const SUBNET& /*sub*/) + { + } + + template + void forward(const SUBNET& sub, resizable_tensor& output) + { + scale_y = (double)NR_/(double)sub.get_output().nr(); + scale_x = (double)NC_/(double)sub.get_output().nc(); + + output.set_size( + sub.get_output().num_samples(), + sub.get_output().k(), + NR_, + NC_); + tt::resize_bilinear(output, sub.get_output()); + } + + template + void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/) + { + tt::resize_bilinear_gradient(sub.get_gradient_input(), gradient_input); + } + + inline dpoint map_input_to_output (dpoint p) const + { + p.x() = p.x()*scale_x; + p.y() = p.y()*scale_y; + return p; + } + + inline dpoint map_output_to_input (dpoint p) const + { + p.x() = p.x()/scale_x; + p.y() = p.y()/scale_y; + return p; + } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const resize_to_& item, std::ostream& out) + { + serialize("resize_to_", out); + serialize(NR_, out); + serialize(NC_, out); + serialize(item.scale_y, out); + serialize(item.scale_x, out); + } + + friend void deserialize(resize_to_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "resize_to_") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::resize_to_."); + + long _nr; + long _nc; + deserialize(_nr, in); + deserialize(_nc, in); + deserialize(item.scale_y, in); + deserialize(item.scale_x, in); + if (_nr != NR_ || _nc != NC_) + throw serialization_error("Wrong size found while deserializing dlib::resize_to_"); + } + + friend std::ostream& operator<<(std::ostream& out, const resize_to_& item) + { + out << "resize_to (" + << "nr=" << NR_ + << ", nc=" << NC_ + << ")"; + return out; + } + + friend void to_xml(const resize_to_& item, std::ostream& out) + { + out << "\n"; + } + private: + resizable_tensor params; + double scale_y; + double scale_x; + + }; // end of class resize_to_ + + + template < + long NR, + long NC, + typename SUBNET + > + using resize_to = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + + template < + long _nr, + long _nc, + int _stride_y, + int _stride_x, + int _padding_y = _stride_y!=1? 0 : _nr/2, + int _padding_x = _stride_x!=1? 0 : _nc/2 + > + class max_pool_ + { + static_assert(_nr >= 0, "The number of rows in a filter must be >= 0"); + static_assert(_nc >= 0, "The number of columns in a filter must be >= 0"); + static_assert(_stride_y > 0, "The filter stride must be > 0"); + static_assert(_stride_x > 0, "The filter stride must be > 0"); + static_assert(0 <= _padding_y && ((_nr==0 && _padding_y == 0) || (_nr!=0 && _padding_y < _nr)), + "The padding must be smaller than the filter size, unless the filters size is 0."); + static_assert(0 <= _padding_x && ((_nc==0 && _padding_x == 0) || (_nc!=0 && _padding_x < _nc)), + "The padding must be smaller than the filter size, unless the filters size is 0."); + public: + + + max_pool_( + ) : + padding_y_(_padding_y), + padding_x_(_padding_x) + {} + + long nr() const { return _nr; } + long nc() const { return _nc; } + long stride_y() const { return _stride_y; } + long stride_x() const { return _stride_x; } + long padding_y() const { return padding_y_; } + long padding_x() const { return padding_x_; } + + inline dpoint map_input_to_output ( + dpoint p + ) const + { + p.x() = (p.x()+padding_x()-nc()/2)/stride_x(); + p.y() = (p.y()+padding_y()-nr()/2)/stride_y(); + return p; + } + + inline dpoint map_output_to_input ( + dpoint p + ) const + { + p.x() = p.x()*stride_x() - padding_x() + nc()/2; + p.y() = p.y()*stride_y() - padding_y() + nr()/2; + return p; + } + + max_pool_ ( + const max_pool_& item + ) : + padding_y_(item.padding_y_), + padding_x_(item.padding_x_) + { + // this->mp is non-copyable so we have to write our own copy to avoid trying to + // copy it and getting an error. + } + + max_pool_& operator= ( + const max_pool_& item + ) + { + if (this == &item) + return *this; + + padding_y_ = item.padding_y_; + padding_x_ = item.padding_x_; + + // this->mp is non-copyable so we have to write our own copy to avoid trying to + // copy it and getting an error. + return *this; + } + + template + void setup (const SUBNET& /*sub*/) + { + } + + template + void forward(const SUBNET& sub, resizable_tensor& output) + { + mp.setup_max_pooling(_nr!=0?_nr:sub.get_output().nr(), + _nc!=0?_nc:sub.get_output().nc(), + _stride_y, _stride_x, padding_y_, padding_x_); + + mp(output, sub.get_output()); + } + + template + void backward(const tensor& computed_output, const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/) + { + mp.setup_max_pooling(_nr!=0?_nr:sub.get_output().nr(), + _nc!=0?_nc:sub.get_output().nc(), + _stride_y, _stride_x, padding_y_, padding_x_); + + mp.get_gradient(gradient_input, computed_output, sub.get_output(), sub.get_gradient_input()); + } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const max_pool_& item, std::ostream& out) + { + serialize("max_pool_2", out); + serialize(_nr, out); + serialize(_nc, out); + serialize(_stride_y, out); + serialize(_stride_x, out); + serialize(item.padding_y_, out); + serialize(item.padding_x_, out); + } + + friend void deserialize(max_pool_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + long nr; + long nc; + int stride_y; + int stride_x; + if (version == "max_pool_2") + { + deserialize(nr, in); + deserialize(nc, in); + deserialize(stride_y, in); + deserialize(stride_x, in); + deserialize(item.padding_y_, in); + deserialize(item.padding_x_, in); + } + else + { + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::max_pool_."); + } + + if (item.padding_y_ != _padding_y) throw serialization_error("Wrong padding_y found while deserializing dlib::max_pool_"); + if (item.padding_x_ != _padding_x) throw serialization_error("Wrong padding_x found while deserializing dlib::max_pool_"); + if (_nr != nr) throw serialization_error("Wrong nr found while deserializing dlib::max_pool_"); + if (_nc != nc) throw serialization_error("Wrong nc found while deserializing dlib::max_pool_"); + if (_stride_y != stride_y) throw serialization_error("Wrong stride_y found while deserializing dlib::max_pool_"); + if (_stride_x != stride_x) throw serialization_error("Wrong stride_x found while deserializing dlib::max_pool_"); + } + + friend std::ostream& operator<<(std::ostream& out, const max_pool_& item) + { + out << "max_pool (" + << "nr="<<_nr + << ", nc="<<_nc + << ", stride_y="<<_stride_y + << ", stride_x="<<_stride_x + << ", padding_y="<\n"; + } + + + private: + + + tt::pooling mp; + resizable_tensor params; + + int padding_y_; + int padding_x_; + }; + + template < + long nr, + long nc, + int stride_y, + int stride_x, + typename SUBNET + > + using max_pool = add_layer, SUBNET>; + + template < + typename SUBNET + > + using max_pool_everything = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + + template < + long _nr, + long _nc, + int _stride_y, + int _stride_x, + int _padding_y = _stride_y!=1? 0 : _nr/2, + int _padding_x = _stride_x!=1? 0 : _nc/2 + > + class avg_pool_ + { + public: + static_assert(_nr >= 0, "The number of rows in a filter must be >= 0"); + static_assert(_nc >= 0, "The number of columns in a filter must be >= 0"); + static_assert(_stride_y > 0, "The filter stride must be > 0"); + static_assert(_stride_x > 0, "The filter stride must be > 0"); + static_assert(0 <= _padding_y && ((_nr==0 && _padding_y == 0) || (_nr!=0 && _padding_y < _nr)), + "The padding must be smaller than the filter size, unless the filters size is 0."); + static_assert(0 <= _padding_x && ((_nc==0 && _padding_x == 0) || (_nc!=0 && _padding_x < _nc)), + "The padding must be smaller than the filter size, unless the filters size is 0."); + + avg_pool_( + ) : + padding_y_(_padding_y), + padding_x_(_padding_x) + {} + + long nr() const { return _nr; } + long nc() const { return _nc; } + long stride_y() const { return _stride_y; } + long stride_x() const { return _stride_x; } + long padding_y() const { return padding_y_; } + long padding_x() const { return padding_x_; } + + inline dpoint map_input_to_output ( + dpoint p + ) const + { + p.x() = (p.x()+padding_x()-nc()/2)/stride_x(); + p.y() = (p.y()+padding_y()-nr()/2)/stride_y(); + return p; + } + + inline dpoint map_output_to_input ( + dpoint p + ) const + { + p.x() = p.x()*stride_x() - padding_x() + nc()/2; + p.y() = p.y()*stride_y() - padding_y() + nr()/2; + return p; + } + + avg_pool_ ( + const avg_pool_& item + ) : + padding_y_(item.padding_y_), + padding_x_(item.padding_x_) + { + // this->ap is non-copyable so we have to write our own copy to avoid trying to + // copy it and getting an error. + } + + avg_pool_& operator= ( + const avg_pool_& item + ) + { + if (this == &item) + return *this; + + padding_y_ = item.padding_y_; + padding_x_ = item.padding_x_; + + // this->ap is non-copyable so we have to write our own copy to avoid trying to + // copy it and getting an error. + return *this; + } + + template + void setup (const SUBNET& /*sub*/) + { + } + + template + void forward(const SUBNET& sub, resizable_tensor& output) + { + ap.setup_avg_pooling(_nr!=0?_nr:sub.get_output().nr(), + _nc!=0?_nc:sub.get_output().nc(), + _stride_y, _stride_x, padding_y_, padding_x_); + + ap(output, sub.get_output()); + } + + template + void backward(const tensor& computed_output, const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/) + { + ap.setup_avg_pooling(_nr!=0?_nr:sub.get_output().nr(), + _nc!=0?_nc:sub.get_output().nc(), + _stride_y, _stride_x, padding_y_, padding_x_); + + ap.get_gradient(gradient_input, computed_output, sub.get_output(), sub.get_gradient_input()); + } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const avg_pool_& item, std::ostream& out) + { + serialize("avg_pool_2", out); + serialize(_nr, out); + serialize(_nc, out); + serialize(_stride_y, out); + serialize(_stride_x, out); + serialize(item.padding_y_, out); + serialize(item.padding_x_, out); + } + + friend void deserialize(avg_pool_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + + long nr; + long nc; + int stride_y; + int stride_x; + if (version == "avg_pool_2") + { + deserialize(nr, in); + deserialize(nc, in); + deserialize(stride_y, in); + deserialize(stride_x, in); + deserialize(item.padding_y_, in); + deserialize(item.padding_x_, in); + } + else + { + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::avg_pool_."); + } + + if (item.padding_y_ != _padding_y) throw serialization_error("Wrong padding_y found while deserializing dlib::avg_pool_"); + if (item.padding_x_ != _padding_x) throw serialization_error("Wrong padding_x found while deserializing dlib::avg_pool_"); + if (_nr != nr) throw serialization_error("Wrong nr found while deserializing dlib::avg_pool_"); + if (_nc != nc) throw serialization_error("Wrong nc found while deserializing dlib::avg_pool_"); + if (_stride_y != stride_y) throw serialization_error("Wrong stride_y found while deserializing dlib::avg_pool_"); + if (_stride_x != stride_x) throw serialization_error("Wrong stride_x found while deserializing dlib::avg_pool_"); + } + + friend std::ostream& operator<<(std::ostream& out, const avg_pool_& item) + { + out << "avg_pool (" + << "nr="<<_nr + << ", nc="<<_nc + << ", stride_y="<<_stride_y + << ", stride_x="<<_stride_x + << ", padding_y="<\n"; + } + private: + + tt::pooling ap; + resizable_tensor params; + + int padding_y_; + int padding_x_; + }; + + template < + long nr, + long nc, + int stride_y, + int stride_x, + typename SUBNET + > + using avg_pool = add_layer, SUBNET>; + + template < + typename SUBNET + > + using avg_pool_everything = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + + enum layer_mode + { + CONV_MODE = 0, + FC_MODE = 1 + }; + + const double DEFAULT_BATCH_NORM_EPS = 0.0001; + + template < + layer_mode mode + > + class bn_ + { + public: + explicit bn_( + unsigned long window_size, + double eps_ = DEFAULT_BATCH_NORM_EPS + ) : + num_updates(0), + running_stats_window_size(window_size), + learning_rate_multiplier(1), + weight_decay_multiplier(0), + bias_learning_rate_multiplier(1), + bias_weight_decay_multiplier(1), + eps(eps_) + { + DLIB_CASSERT(window_size > 0, "The batch normalization running stats window size can't be 0."); + } + + bn_() : bn_(100) {} + + layer_mode get_mode() const { return mode; } + unsigned long get_running_stats_window_size () const { return running_stats_window_size; } + void set_running_stats_window_size (unsigned long new_window_size ) + { + DLIB_CASSERT(new_window_size > 0, "The batch normalization running stats window size can't be 0."); + running_stats_window_size = new_window_size; + } + double get_eps() const { return eps; } + + double get_learning_rate_multiplier () const { return learning_rate_multiplier; } + double get_weight_decay_multiplier () const { return weight_decay_multiplier; } + void set_learning_rate_multiplier(double val) { learning_rate_multiplier = val; } + void set_weight_decay_multiplier(double val) { weight_decay_multiplier = val; } + + double get_bias_learning_rate_multiplier () const { return bias_learning_rate_multiplier; } + double get_bias_weight_decay_multiplier () const { return bias_weight_decay_multiplier; } + void set_bias_learning_rate_multiplier(double val) { bias_learning_rate_multiplier = val; } + void set_bias_weight_decay_multiplier(double val) { bias_weight_decay_multiplier = val; } + + inline dpoint map_input_to_output (const dpoint& p) const { return p; } + inline dpoint map_output_to_input (const dpoint& p) const { return p; } + + + template + void setup (const SUBNET& sub) + { + if (mode == FC_MODE) + { + gamma = alias_tensor(1, + sub.get_output().k(), + sub.get_output().nr(), + sub.get_output().nc()); + } + else + { + gamma = alias_tensor(1, sub.get_output().k()); + } + beta = gamma; + + params.set_size(gamma.size()+beta.size()); + + gamma(params,0) = 1; + beta(params,gamma.size()) = 0; + + running_means.copy_size(gamma(params,0)); + running_variances.copy_size(gamma(params,0)); + running_means = 0; + running_variances = 1; + num_updates = 0; + } + + template + void forward(const SUBNET& sub, resizable_tensor& output) + { + auto g = gamma(params,0); + auto b = beta(params,gamma.size()); + if (sub.get_output().num_samples() > 1) + { + const double decay = 1.0 - num_updates/(num_updates+1.0); + ++num_updates; + if (num_updates > running_stats_window_size) + num_updates = running_stats_window_size; + + if (mode == FC_MODE) + tt::batch_normalize(eps, output, means, invstds, decay, running_means, running_variances, sub.get_output(), g, b); + else + tt::batch_normalize_conv(eps, output, means, invstds, decay, running_means, running_variances, sub.get_output(), g, b); + } + else // we are running in testing mode so we just linearly scale the input tensor. + { + if (mode == FC_MODE) + tt::batch_normalize_inference(eps, output, sub.get_output(), g, b, running_means, running_variances); + else + tt::batch_normalize_conv_inference(eps, output, sub.get_output(), g, b, running_means, running_variances); + } + } + + template + void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad) + { + auto g = gamma(params,0); + auto g_grad = gamma(params_grad, 0); + auto b_grad = beta(params_grad, gamma.size()); + if (mode == FC_MODE) + tt::batch_normalize_gradient(eps, gradient_input, means, invstds, sub.get_output(), g, sub.get_gradient_input(), g_grad, b_grad ); + else + tt::batch_normalize_conv_gradient(eps, gradient_input, means, invstds, sub.get_output(), g, sub.get_gradient_input(), g_grad, b_grad ); + } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const bn_& item, std::ostream& out) + { + if (mode == CONV_MODE) + serialize("bn_con2", out); + else // if FC_MODE + serialize("bn_fc2", out); + serialize(item.params, out); + serialize(item.gamma, out); + serialize(item.beta, out); + serialize(item.means, out); + serialize(item.invstds, out); + serialize(item.running_means, out); + serialize(item.running_variances, out); + serialize(item.num_updates, out); + serialize(item.running_stats_window_size, out); + serialize(item.learning_rate_multiplier, out); + serialize(item.weight_decay_multiplier, out); + serialize(item.bias_learning_rate_multiplier, out); + serialize(item.bias_weight_decay_multiplier, out); + serialize(item.eps, out); + } + + friend void deserialize(bn_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (mode == CONV_MODE) + { + if (version != "bn_con2") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::bn_."); + } + else // must be in FC_MODE + { + if (version != "bn_fc2") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::bn_."); + } + + deserialize(item.params, in); + deserialize(item.gamma, in); + deserialize(item.beta, in); + deserialize(item.means, in); + deserialize(item.invstds, in); + deserialize(item.running_means, in); + deserialize(item.running_variances, in); + deserialize(item.num_updates, in); + deserialize(item.running_stats_window_size, in); + deserialize(item.learning_rate_multiplier, in); + deserialize(item.weight_decay_multiplier, in); + deserialize(item.bias_learning_rate_multiplier, in); + deserialize(item.bias_weight_decay_multiplier, in); + deserialize(item.eps, in); + } + + friend std::ostream& operator<<(std::ostream& out, const bn_& item) + { + if (mode == CONV_MODE) + out << "bn_con "; + else + out << "bn_fc "; + out << " eps="<\n"; + + out << mat(item.params); + + if (mode==CONV_MODE) + out << "\n"; + else + out << "\n"; + } + + private: + + friend class affine_; + + resizable_tensor params; + alias_tensor gamma, beta; + resizable_tensor means, running_means; + resizable_tensor invstds, running_variances; + unsigned long num_updates; + unsigned long running_stats_window_size; + double learning_rate_multiplier; + double weight_decay_multiplier; + double bias_learning_rate_multiplier; + double bias_weight_decay_multiplier; + double eps; + }; + + template + using bn_con = add_layer, SUBNET>; + template + using bn_fc = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + class visitor_bn_running_stats_window_size + { + public: + + visitor_bn_running_stats_window_size(unsigned long new_window_size_) : new_window_size(new_window_size_) {} + + template + void set_window_size(T&) const + { + // ignore other layer detail types + } + + template < layer_mode mode > + void set_window_size(bn_& l) const + { + l.set_running_stats_window_size(new_window_size); + } + + template + void operator()(size_t , input_layer_type& ) const + { + // ignore other layers + } + + template + void operator()(size_t , add_layer& l) const + { + set_window_size(l.layer_details()); + } + + private: + + unsigned long new_window_size; + }; + } + + template + void set_all_bn_running_stats_window_sizes ( + net_type& net, + unsigned long new_window_size + ) + { + visit_layers(net, impl::visitor_bn_running_stats_window_size(new_window_size)); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + enum fc_bias_mode + { + FC_HAS_BIAS = 0, + FC_NO_BIAS = 1 + }; + + struct num_fc_outputs + { + num_fc_outputs(unsigned long n) : num_outputs(n) {} + unsigned long num_outputs; + }; + + template < + unsigned long num_outputs_, + fc_bias_mode bias_mode + > + class fc_ + { + static_assert(num_outputs_ > 0, "The number of outputs from a fc_ layer must be > 0"); + + public: + fc_(num_fc_outputs o) : num_outputs(o.num_outputs), num_inputs(0), + learning_rate_multiplier(1), + weight_decay_multiplier(1), + bias_learning_rate_multiplier(1), + bias_weight_decay_multiplier(0) + {} + + fc_() : fc_(num_fc_outputs(num_outputs_)) {} + + double get_learning_rate_multiplier () const { return learning_rate_multiplier; } + double get_weight_decay_multiplier () const { return weight_decay_multiplier; } + void set_learning_rate_multiplier(double val) { learning_rate_multiplier = val; } + void set_weight_decay_multiplier(double val) { weight_decay_multiplier = val; } + + double get_bias_learning_rate_multiplier () const { return bias_learning_rate_multiplier; } + double get_bias_weight_decay_multiplier () const { return bias_weight_decay_multiplier; } + void set_bias_learning_rate_multiplier(double val) { bias_learning_rate_multiplier = val; } + void set_bias_weight_decay_multiplier(double val) { bias_weight_decay_multiplier = val; } + + unsigned long get_num_outputs ( + ) const { return num_outputs; } + + void set_num_outputs(long num) + { + DLIB_CASSERT(num > 0); + if (num != (long)num_outputs) + { + DLIB_CASSERT(get_layer_params().size() == 0, + "You can't change the number of filters in fc_ if the parameter tensor has already been allocated."); + num_outputs = num; + } + } + + fc_bias_mode get_bias_mode ( + ) const { return bias_mode; } + + template + void setup (const SUBNET& sub) + { + num_inputs = sub.get_output().nr()*sub.get_output().nc()*sub.get_output().k(); + if (bias_mode == FC_HAS_BIAS) + params.set_size(num_inputs+1, num_outputs); + else + params.set_size(num_inputs, num_outputs); + + dlib::rand rnd(std::rand()); + randomize_parameters(params, num_inputs+num_outputs, rnd); + + weights = alias_tensor(num_inputs, num_outputs); + + if (bias_mode == FC_HAS_BIAS) + { + biases = alias_tensor(1,num_outputs); + // set the initial bias values to zero + biases(params,weights.size()) = 0; + } + } + + template + void forward(const SUBNET& sub, resizable_tensor& output) + { + DLIB_CASSERT((long)num_inputs == sub.get_output().nr()*sub.get_output().nc()*sub.get_output().k(), + "The size of the input tensor to this fc layer doesn't match the size the fc layer was trained with."); + output.set_size(sub.get_output().num_samples(), num_outputs); + + auto w = weights(params, 0); + tt::gemm(0,output, 1,sub.get_output(),false, w,false); + if (bias_mode == FC_HAS_BIAS) + { + auto b = biases(params, weights.size()); + tt::add(1,output,1,b); + } + } + + template + void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad) + { + // no point computing the parameter gradients if they won't be used. + if (learning_rate_multiplier != 0) + { + // compute the gradient of the weight parameters. + auto pw = weights(params_grad, 0); + tt::gemm(0,pw, 1,sub.get_output(),true, gradient_input,false); + + if (bias_mode == FC_HAS_BIAS) + { + // compute the gradient of the bias parameters. + auto pb = biases(params_grad, weights.size()); + tt::assign_bias_gradient(pb, gradient_input); + } + } + + // compute the gradient for the data + auto w = weights(params, 0); + tt::gemm(1,sub.get_gradient_input(), 1,gradient_input,false, w,true); + } + + alias_tensor_instance get_weights() + { + return weights(params, 0); + } + + alias_tensor_const_instance get_weights() const + { + return weights(params, 0); + } + + alias_tensor_instance get_biases() + { + static_assert(bias_mode == FC_HAS_BIAS, "This fc_ layer doesn't have a bias vector " + "to be retrieved, as per template parameter 'bias_mode'."); + return biases(params, weights.size()); + } + + alias_tensor_const_instance get_biases() const + { + static_assert(bias_mode == FC_HAS_BIAS, "This fc_ layer doesn't have a bias vector " + "to be retrieved, as per template parameter 'bias_mode'."); + return biases(params, weights.size()); + } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const fc_& item, std::ostream& out) + { + serialize("fc_2", out); + serialize(item.num_outputs, out); + serialize(item.num_inputs, out); + serialize(item.params, out); + serialize(item.weights, out); + serialize(item.biases, out); + serialize((int)bias_mode, out); + serialize(item.learning_rate_multiplier, out); + serialize(item.weight_decay_multiplier, out); + serialize(item.bias_learning_rate_multiplier, out); + serialize(item.bias_weight_decay_multiplier, out); + } + + friend void deserialize(fc_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "fc_2") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::fc_."); + + deserialize(item.num_outputs, in); + deserialize(item.num_inputs, in); + deserialize(item.params, in); + deserialize(item.weights, in); + deserialize(item.biases, in); + int bmode = 0; + deserialize(bmode, in); + if (bias_mode != (fc_bias_mode)bmode) throw serialization_error("Wrong fc_bias_mode found while deserializing dlib::fc_"); + deserialize(item.learning_rate_multiplier, in); + deserialize(item.weight_decay_multiplier, in); + deserialize(item.bias_learning_rate_multiplier, in); + deserialize(item.bias_weight_decay_multiplier, in); + } + + friend std::ostream& operator<<(std::ostream& out, const fc_& item) + { + if (bias_mode == FC_HAS_BIAS) + { + out << "fc\t (" + << "num_outputs="<\n"; + out << mat(item.params); + out << "\n"; + } + else + { + out << "\n"; + out << mat(item.params); + out << "\n"; + } + } + + private: + + unsigned long num_outputs; + unsigned long num_inputs; + resizable_tensor params; + alias_tensor weights, biases; + double learning_rate_multiplier; + double weight_decay_multiplier; + double bias_learning_rate_multiplier; + double bias_weight_decay_multiplier; + }; + + template < + unsigned long num_outputs, + typename SUBNET + > + using fc = add_layer, SUBNET>; + + template < + unsigned long num_outputs, + typename SUBNET + > + using fc_no_bias = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + + class dropout_ + { + public: + explicit dropout_( + float drop_rate_ = 0.5 + ) : + drop_rate(drop_rate_), + rnd(std::rand()) + { + DLIB_CASSERT(0 <= drop_rate && drop_rate <= 1); + } + + // We have to add a copy constructor and assignment operator because the rnd object + // is non-copyable. + dropout_( + const dropout_& item + ) : drop_rate(item.drop_rate), mask(item.mask), rnd(std::rand()) + {} + + dropout_& operator= ( + const dropout_& item + ) + { + if (this == &item) + return *this; + + drop_rate = item.drop_rate; + mask = item.mask; + return *this; + } + + float get_drop_rate ( + ) const { return drop_rate; } + + template + void setup (const SUBNET& /*sub*/) + { + } + + void forward_inplace(const tensor& input, tensor& output) + { + // create a random mask and use it to filter the data + mask.copy_size(input); + rnd.fill_uniform(mask); + tt::threshold(mask, drop_rate); + tt::multiply(false, output, input, mask); + } + + void backward_inplace( + const tensor& gradient_input, + tensor& data_grad, + tensor& /*params_grad*/ + ) + { + if (is_same_object(gradient_input, data_grad)) + tt::multiply(false, data_grad, mask, gradient_input); + else + tt::multiply(true, data_grad, mask, gradient_input); + } + + inline dpoint map_input_to_output (const dpoint& p) const { return p; } + inline dpoint map_output_to_input (const dpoint& p) const { return p; } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const dropout_& item, std::ostream& out) + { + serialize("dropout_", out); + serialize(item.drop_rate, out); + serialize(item.mask, out); + } + + friend void deserialize(dropout_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "dropout_") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::dropout_."); + deserialize(item.drop_rate, in); + deserialize(item.mask, in); + } + + void clean( + ) + { + mask.clear(); + } + + friend std::ostream& operator<<(std::ostream& out, const dropout_& item) + { + out << "dropout\t (" + << "drop_rate="<\n"; + } + + private: + float drop_rate; + resizable_tensor mask; + + tt::tensor_rand rnd; + resizable_tensor params; // unused + }; + + + template + using dropout = add_layer; + +// ---------------------------------------------------------------------------------------- + + class multiply_ + { + public: + explicit multiply_( + float val_ = 0.5 + ) : + val(val_) + { + } + + multiply_ ( + const dropout_& item + ) : val(1-item.get_drop_rate()) {} + + float get_multiply_value ( + ) const { return val; } + + template + void setup (const SUBNET& /*sub*/) + { + } + + void forward_inplace(const tensor& input, tensor& output) + { + tt::affine_transform(output, input, val); + } + + inline dpoint map_input_to_output (const dpoint& p) const { return p; } + inline dpoint map_output_to_input (const dpoint& p) const { return p; } + + void backward_inplace( + const tensor& gradient_input, + tensor& data_grad, + tensor& /*params_grad*/ + ) + { + if (is_same_object(gradient_input, data_grad)) + tt::affine_transform(data_grad, gradient_input, val); + else + tt::affine_transform(data_grad, data_grad, gradient_input, 1, val); + } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const multiply_& item, std::ostream& out) + { + serialize("multiply_", out); + serialize(item.val, out); + } + + friend void deserialize(multiply_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version == "dropout_") + { + // Since we can build a multiply_ from a dropout_ we check if that's what + // is in the stream and if so then just convert it right here. + unserialize sin(version, in); + dropout_ temp; + deserialize(temp, sin); + item = temp; + return; + } + + if (version != "multiply_") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::multiply_."); + deserialize(item.val, in); + } + + friend std::ostream& operator<<(std::ostream& out, const multiply_& item) + { + out << "multiply (" + << "val="<\n"; + } + private: + float val; + resizable_tensor params; // unused + }; + + template + using multiply = add_layer; + +// ---------------------------------------------------------------------------------------- + + class affine_ + { + public: + affine_( + ) : mode(FC_MODE) + { + } + + affine_( + layer_mode mode_ + ) : mode(mode_) + { + } + + template < + layer_mode bnmode + > + affine_( + const bn_& item + ) + { + gamma = item.gamma; + beta = item.beta; + mode = bnmode; + + params.copy_size(item.params); + + auto g = gamma(params,0); + auto b = beta(params,gamma.size()); + + resizable_tensor temp(item.params); + auto sg = gamma(temp,0); + auto sb = beta(temp,gamma.size()); + + g = pointwise_multiply(mat(sg), 1.0f/sqrt(mat(item.running_variances)+item.get_eps())); + b = mat(sb) - pointwise_multiply(mat(g), mat(item.running_means)); + } + + layer_mode get_mode() const { return mode; } + + inline dpoint map_input_to_output (const dpoint& p) const { return p; } + inline dpoint map_output_to_input (const dpoint& p) const { return p; } + + template + void setup (const SUBNET& sub) + { + if (mode == FC_MODE) + { + gamma = alias_tensor(1, + sub.get_output().k(), + sub.get_output().nr(), + sub.get_output().nc()); + } + else + { + gamma = alias_tensor(1, sub.get_output().k()); + } + beta = gamma; + + params.set_size(gamma.size()+beta.size()); + + gamma(params,0) = 1; + beta(params,gamma.size()) = 0; + } + + void forward_inplace(const tensor& input, tensor& output) + { + auto g = gamma(params,0); + auto b = beta(params,gamma.size()); + if (mode == FC_MODE) + tt::affine_transform(output, input, g, b); + else + tt::affine_transform_conv(output, input, g, b); + } + + void backward_inplace( + const tensor& gradient_input, + tensor& data_grad, + tensor& /*params_grad*/ + ) + { + auto g = gamma(params,0); + auto b = beta(params,gamma.size()); + + // We are computing the gradient of dot(gradient_input, computed_output*g + b) + if (mode == FC_MODE) + { + if (is_same_object(gradient_input, data_grad)) + tt::multiply(false, data_grad, gradient_input, g); + else + tt::multiply(true, data_grad, gradient_input, g); + } + else + { + if (is_same_object(gradient_input, data_grad)) + tt::multiply_conv(false, data_grad, gradient_input, g); + else + tt::multiply_conv(true, data_grad, gradient_input, g); + } + } + + const tensor& get_layer_params() const { return empty_params; } + tensor& get_layer_params() { return empty_params; } + + friend void serialize(const affine_& item, std::ostream& out) + { + serialize("affine_", out); + serialize(item.params, out); + serialize(item.gamma, out); + serialize(item.beta, out); + serialize((int)item.mode, out); + } + + friend void deserialize(affine_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version == "bn_con2") + { + // Since we can build an affine_ from a bn_ we check if that's what is in + // the stream and if so then just convert it right here. + unserialize sin(version, in); + bn_ temp; + deserialize(temp, sin); + item = temp; + return; + } + else if (version == "bn_fc2") + { + // Since we can build an affine_ from a bn_ we check if that's what is in + // the stream and if so then just convert it right here. + unserialize sin(version, in); + bn_ temp; + deserialize(temp, sin); + item = temp; + return; + } + + if (version != "affine_") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::affine_."); + deserialize(item.params, in); + deserialize(item.gamma, in); + deserialize(item.beta, in); + int mode; + deserialize(mode, in); + item.mode = (layer_mode)mode; + } + + friend std::ostream& operator<<(std::ostream& out, const affine_& ) + { + out << "affine"; + return out; + } + + friend void to_xml(const affine_& item, std::ostream& out) + { + if (item.mode==CONV_MODE) + out << "\n"; + else + out << "\n"; + + out << mat(item.params); + + if (item.mode==CONV_MODE) + out << "\n"; + else + out << "\n"; + } + + private: + resizable_tensor params, empty_params; + alias_tensor gamma, beta; + layer_mode mode; + }; + + template + using affine = add_layer; + +// ---------------------------------------------------------------------------------------- + + template < + template class tag + > + class add_prev_ + { + public: + const static unsigned long id = tag_id::id; + + add_prev_() + { + } + + template + void setup (const SUBNET& /*sub*/) + { + } + + template + void forward(const SUBNET& sub, resizable_tensor& output) + { + auto&& t1 = sub.get_output(); + auto&& t2 = layer(sub).get_output(); + output.set_size(std::max(t1.num_samples(),t2.num_samples()), + std::max(t1.k(),t2.k()), + std::max(t1.nr(),t2.nr()), + std::max(t1.nc(),t2.nc())); + tt::add(output, t1, t2); + } + + template + void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/) + { + // The gradient just flows backwards to the two layers that forward() added + // together. + tt::add(sub.get_gradient_input(), sub.get_gradient_input(), gradient_input); + tt::add(layer(sub).get_gradient_input(), layer(sub).get_gradient_input(), gradient_input); + } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + inline dpoint map_input_to_output (const dpoint& p) const { return p; } + inline dpoint map_output_to_input (const dpoint& p) const { return p; } + + friend void serialize(const add_prev_& , std::ostream& out) + { + serialize("add_prev_", out); + } + + friend void deserialize(add_prev_& , std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "add_prev_") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::add_prev_."); + } + + friend std::ostream& operator<<(std::ostream& out, const add_prev_& item) + { + out << "add_prev"<\n"; + } + + private: + resizable_tensor params; + }; + + template < + template class tag, + typename SUBNET + > + using add_prev = add_layer, SUBNET>; + + template using add_prev1 = add_prev; + template using add_prev2 = add_prev; + template using add_prev3 = add_prev; + template using add_prev4 = add_prev; + template using add_prev5 = add_prev; + template using add_prev6 = add_prev; + template using add_prev7 = add_prev; + template using add_prev8 = add_prev; + template using add_prev9 = add_prev; + template using add_prev10 = add_prev; + + using add_prev1_ = add_prev_; + using add_prev2_ = add_prev_; + using add_prev3_ = add_prev_; + using add_prev4_ = add_prev_; + using add_prev5_ = add_prev_; + using add_prev6_ = add_prev_; + using add_prev7_ = add_prev_; + using add_prev8_ = add_prev_; + using add_prev9_ = add_prev_; + using add_prev10_ = add_prev_; + +// ---------------------------------------------------------------------------------------- + + template < + template class tag + > + class mult_prev_ + { + public: + const static unsigned long id = tag_id::id; + + mult_prev_() + { + } + + template + void setup (const SUBNET& /*sub*/) + { + } + + template + void forward(const SUBNET& sub, resizable_tensor& output) + { + auto&& t1 = sub.get_output(); + auto&& t2 = layer(sub).get_output(); + output.set_size(std::max(t1.num_samples(),t2.num_samples()), + std::max(t1.k(),t2.k()), + std::max(t1.nr(),t2.nr()), + std::max(t1.nc(),t2.nc())); + tt::multiply_zero_padded(false, output, t1, t2); + } + + template + void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/) + { + auto&& t1 = sub.get_output(); + auto&& t2 = layer(sub).get_output(); + // The gradient just flows backwards to the two layers that forward() + // multiplied together. + tt::multiply_zero_padded(true, sub.get_gradient_input(), t2, gradient_input); + tt::multiply_zero_padded(true, layer(sub).get_gradient_input(), t1, gradient_input); + } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const mult_prev_& , std::ostream& out) + { + serialize("mult_prev_", out); + } + + friend void deserialize(mult_prev_& , std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "mult_prev_") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::mult_prev_."); + } + + friend std::ostream& operator<<(std::ostream& out, const mult_prev_& item) + { + out << "mult_prev"<\n"; + } + + private: + resizable_tensor params; + }; + + template < + template class tag, + typename SUBNET + > + using mult_prev = add_layer, SUBNET>; + + template using mult_prev1 = mult_prev; + template using mult_prev2 = mult_prev; + template using mult_prev3 = mult_prev; + template using mult_prev4 = mult_prev; + template using mult_prev5 = mult_prev; + template using mult_prev6 = mult_prev; + template using mult_prev7 = mult_prev; + template using mult_prev8 = mult_prev; + template using mult_prev9 = mult_prev; + template using mult_prev10 = mult_prev; + + using mult_prev1_ = mult_prev_; + using mult_prev2_ = mult_prev_; + using mult_prev3_ = mult_prev_; + using mult_prev4_ = mult_prev_; + using mult_prev5_ = mult_prev_; + using mult_prev6_ = mult_prev_; + using mult_prev7_ = mult_prev_; + using mult_prev8_ = mult_prev_; + using mult_prev9_ = mult_prev_; + using mult_prev10_ = mult_prev_; + +// ---------------------------------------------------------------------------------------- + + template < + template class tag + > + class scale_ + { + public: + const static unsigned long id = tag_id::id; + + scale_() + { + } + + template + void setup (const SUBNET& /*sub*/) + { + } + + template + void forward(const SUBNET& sub, resizable_tensor& output) + { + auto&& scales = sub.get_output(); + auto&& src = layer(sub).get_output(); + DLIB_CASSERT(scales.num_samples() == src.num_samples() && + scales.k() == src.k() && + scales.nr() == 1 && + scales.nc() == 1, + "scales.k(): " << scales.k() << + "\nsrc.k(): " << src.k() + ); + + output.copy_size(src); + tt::scale_channels(false, output, src, scales); + } + + template + void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/) + { + auto&& scales = sub.get_output(); + auto&& src = layer(sub).get_output(); + // The gradient just flows backwards to the two layers that forward() + // read from. + tt::scale_channels(true, layer(sub).get_gradient_input(), gradient_input, scales); + + if (reshape_src.num_samples() != src.num_samples()) + { + reshape_scales = alias_tensor(src.num_samples()*src.k()); + reshape_src = alias_tensor(src.num_samples()*src.k(),src.nr()*src.nc()); + } + + auto&& scales_grad = sub.get_gradient_input(); + auto sgrad = reshape_scales(scales_grad); + tt::dot_prods(true, sgrad, reshape_src(src), reshape_src(gradient_input)); + } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const scale_& item, std::ostream& out) + { + serialize("scale_", out); + serialize(item.reshape_scales, out); + serialize(item.reshape_src, out); + } + + friend void deserialize(scale_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "scale_") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::scale_."); + deserialize(item.reshape_scales, in); + deserialize(item.reshape_src, in); + } + + friend std::ostream& operator<<(std::ostream& out, const scale_& item) + { + out << "scale"<\n"; + } + + private: + alias_tensor reshape_scales; + alias_tensor reshape_src; + resizable_tensor params; + }; + + template < + template class tag, + typename SUBNET + > + using scale = add_layer, SUBNET>; + + template using scale1 = scale; + template using scale2 = scale; + template using scale3 = scale; + template using scale4 = scale; + template using scale5 = scale; + template using scale6 = scale; + template using scale7 = scale; + template using scale8 = scale; + template using scale9 = scale; + template using scale10 = scale; + + using scale1_ = scale_; + using scale2_ = scale_; + using scale3_ = scale_; + using scale4_ = scale_; + using scale5_ = scale_; + using scale6_ = scale_; + using scale7_ = scale_; + using scale8_ = scale_; + using scale9_ = scale_; + using scale10_ = scale_; + +// ---------------------------------------------------------------------------------------- + + class relu_ + { + public: + relu_() + { + } + + template + void setup (const SUBNET& /*sub*/) + { + } + + void forward_inplace(const tensor& input, tensor& output) + { + tt::relu(output, input); + } + + void backward_inplace( + const tensor& computed_output, + const tensor& gradient_input, + tensor& data_grad, + tensor& + ) + { + tt::relu_gradient(data_grad, computed_output, gradient_input); + } + + inline dpoint map_input_to_output (const dpoint& p) const { return p; } + inline dpoint map_output_to_input (const dpoint& p) const { return p; } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const relu_& , std::ostream& out) + { + serialize("relu_", out); + } + + friend void deserialize(relu_& , std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "relu_") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::relu_."); + } + + friend std::ostream& operator<<(std::ostream& out, const relu_& ) + { + out << "relu"; + return out; + } + + friend void to_xml(const relu_& /*item*/, std::ostream& out) + { + out << "\n"; + } + + private: + resizable_tensor params; + }; + + + template + using relu = add_layer; + +// ---------------------------------------------------------------------------------------- + + class prelu_ + { + public: + explicit prelu_( + float initial_param_value_ = 0.25 + ) : initial_param_value(initial_param_value_) + { + } + + float get_initial_param_value ( + ) const { return initial_param_value; } + + template + void setup (const SUBNET& /*sub*/) + { + params.set_size(1); + params = initial_param_value; + } + + template + void forward( + const SUBNET& sub, + resizable_tensor& data_output + ) + { + data_output.copy_size(sub.get_output()); + tt::prelu(data_output, sub.get_output(), params); + } + + template + void backward( + const tensor& gradient_input, + SUBNET& sub, + tensor& params_grad + ) + { + tt::prelu_gradient(sub.get_gradient_input(), sub.get_output(), + gradient_input, params, params_grad); + } + + inline dpoint map_input_to_output (const dpoint& p) const { return p; } + inline dpoint map_output_to_input (const dpoint& p) const { return p; } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const prelu_& item, std::ostream& out) + { + serialize("prelu_", out); + serialize(item.params, out); + serialize(item.initial_param_value, out); + } + + friend void deserialize(prelu_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "prelu_") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::prelu_."); + deserialize(item.params, in); + deserialize(item.initial_param_value, in); + } + + friend std::ostream& operator<<(std::ostream& out, const prelu_& item) + { + out << "prelu\t (" + << "initial_param_value="<\n"; + out << mat(item.params); + out << "\n"; + } + + private: + resizable_tensor params; + float initial_param_value; + }; + + template + using prelu = add_layer; + +// ---------------------------------------------------------------------------------------- + + class sig_ + { + public: + sig_() + { + } + + template + void setup (const SUBNET& /*sub*/) + { + } + + void forward_inplace(const tensor& input, tensor& output) + { + tt::sigmoid(output, input); + } + + void backward_inplace( + const tensor& computed_output, + const tensor& gradient_input, + tensor& data_grad, + tensor& + ) + { + tt::sigmoid_gradient(data_grad, computed_output, gradient_input); + } + + inline dpoint map_input_to_output (const dpoint& p) const { return p; } + inline dpoint map_output_to_input (const dpoint& p) const { return p; } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const sig_& , std::ostream& out) + { + serialize("sig_", out); + } + + friend void deserialize(sig_& , std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "sig_") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::sig_."); + } + + friend std::ostream& operator<<(std::ostream& out, const sig_& ) + { + out << "sig"; + return out; + } + + friend void to_xml(const sig_& /*item*/, std::ostream& out) + { + out << "\n"; + } + + + private: + resizable_tensor params; + }; + + + template + using sig = add_layer; + +// ---------------------------------------------------------------------------------------- + + class htan_ + { + public: + htan_() + { + } + + template + void setup (const SUBNET& /*sub*/) + { + } + + inline dpoint map_input_to_output (const dpoint& p) const { return p; } + inline dpoint map_output_to_input (const dpoint& p) const { return p; } + + void forward_inplace(const tensor& input, tensor& output) + { + tt::tanh(output, input); + } + + void backward_inplace( + const tensor& computed_output, + const tensor& gradient_input, + tensor& data_grad, + tensor& + ) + { + tt::tanh_gradient(data_grad, computed_output, gradient_input); + } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const htan_& , std::ostream& out) + { + serialize("htan_", out); + } + + friend void deserialize(htan_& , std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "htan_") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::htan_."); + } + + friend std::ostream& operator<<(std::ostream& out, const htan_& ) + { + out << "htan"; + return out; + } + + friend void to_xml(const htan_& /*item*/, std::ostream& out) + { + out << "\n"; + } + + + private: + resizable_tensor params; + }; + + + template + using htan = add_layer; + +// ---------------------------------------------------------------------------------------- + + class softmax_ + { + public: + softmax_() + { + } + + template + void setup (const SUBNET& /*sub*/) + { + } + + void forward_inplace(const tensor& input, tensor& output) + { + tt::softmax(output, input); + } + + void backward_inplace( + const tensor& computed_output, + const tensor& gradient_input, + tensor& data_grad, + tensor& + ) + { + tt::softmax_gradient(data_grad, computed_output, gradient_input); + } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const softmax_& , std::ostream& out) + { + serialize("softmax_", out); + } + + friend void deserialize(softmax_& , std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "softmax_") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::softmax_."); + } + + friend std::ostream& operator<<(std::ostream& out, const softmax_& ) + { + out << "softmax"; + return out; + } + + friend void to_xml(const softmax_& /*item*/, std::ostream& out) + { + out << "\n"; + } + + private: + resizable_tensor params; + }; + + template + using softmax = add_layer; + +// ---------------------------------------------------------------------------------------- + + class softmax_all_ + { + public: + softmax_all_() + { + } + + template + void setup (const SUBNET& /*sub*/) + { + } + + void forward_inplace(const tensor& input, tensor& output) + { + tt::softmax_all(output, input); + } + + void backward_inplace( + const tensor& computed_output, + const tensor& gradient_input, + tensor& data_grad, + tensor& + ) + { + tt::softmax_all_gradient(data_grad, computed_output, gradient_input); + } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const softmax_all_& , std::ostream& out) + { + serialize("softmax_all_", out); + } + + friend void deserialize(softmax_all_& , std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "softmax_all_") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::softmax_all_."); + } + + friend std::ostream& operator<<(std::ostream& out, const softmax_all_& ) + { + out << "softmax_all"; + return out; + } + + friend void to_xml(const softmax_all_& /*item*/, std::ostream& out) + { + out << "\n"; + } + + private: + resizable_tensor params; + }; + + template + using softmax_all = add_layer; + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template class TAG_TYPE, template class... TAG_TYPES> + struct concat_helper_impl{ + + constexpr static size_t tag_count() {return 1 + concat_helper_impl::tag_count();} + static void list_tags(std::ostream& out) + { + out << tag_id::id << (tag_count() > 1 ? "," : ""); + concat_helper_impl::list_tags(out); + } + + template + static void resize_out(resizable_tensor& out, const SUBNET& sub, long sum_k) + { + auto& t = layer(sub).get_output(); + concat_helper_impl::resize_out(out, sub, sum_k + t.k()); + } + template + static void concat(tensor& out, const SUBNET& sub, size_t k_offset) + { + auto& t = layer(sub).get_output(); + tt::copy_tensor(false, out, k_offset, t, 0, t.k()); + k_offset += t.k(); + concat_helper_impl::concat(out, sub, k_offset); + } + template + static void split(const tensor& input, SUBNET& sub, size_t k_offset) + { + auto& t = layer(sub).get_gradient_input(); + tt::copy_tensor(true, t, 0, input, k_offset, t.k()); + k_offset += t.k(); + concat_helper_impl::split(input, sub, k_offset); + } + }; + template class TAG_TYPE> + struct concat_helper_impl{ + constexpr static size_t tag_count() {return 1;} + static void list_tags(std::ostream& out) + { + out << tag_id::id; + } + + template + static void resize_out(resizable_tensor& out, const SUBNET& sub, long sum_k) + { + auto& t = layer(sub).get_output(); + out.set_size(t.num_samples(), t.k() + sum_k, t.nr(), t.nc()); + } + template + static void concat(tensor& out, const SUBNET& sub, size_t k_offset) + { + auto& t = layer(sub).get_output(); + tt::copy_tensor(false, out, k_offset, t, 0, t.k()); + } + template + static void split(const tensor& input, SUBNET& sub, size_t k_offset) + { + auto& t = layer(sub).get_gradient_input(); + tt::copy_tensor(true, t, 0, input, k_offset, t.k()); + } + }; + } + // concat layer + template< + template class... TAG_TYPES + > + class concat_ + { + static void list_tags(std::ostream& out) { impl::concat_helper_impl::list_tags(out);}; + + public: + constexpr static size_t tag_count() {return impl::concat_helper_impl::tag_count();}; + + template + void setup (const SUBNET&) + { + // do nothing + } + template + void forward(const SUBNET& sub, resizable_tensor& output) + { + // the total depth of result is the sum of depths from all tags + impl::concat_helper_impl::resize_out(output, sub, 0); + + // copy output from each tag into different part result + impl::concat_helper_impl::concat(output, sub, 0); + } + + template + void backward(const tensor& gradient_input, SUBNET& sub, tensor&) + { + // Gradient is split into parts for each tag layer + impl::concat_helper_impl::split(gradient_input, sub, 0); + } + + dpoint map_input_to_output(dpoint p) const { return p; } + dpoint map_output_to_input(dpoint p) const { return p; } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const concat_& item, std::ostream& out) + { + serialize("concat_", out); + size_t count = tag_count(); + serialize(count, out); + } + + friend void deserialize(concat_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "concat_") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::concat_."); + size_t count_tags; + deserialize(count_tags, in); + if (count_tags != tag_count()) + throw serialization_error("Invalid count of tags "+ std::to_string(count_tags) +", expecting " + + std::to_string(tag_count()) + + " found while deserializing dlib::concat_."); + } + + friend std::ostream& operator<<(std::ostream& out, const concat_& item) + { + out << "concat\t ("; + list_tags(out); + out << ")"; + return out; + } + + friend void to_xml(const concat_& item, std::ostream& out) + { + out << "\n"; + } + + private: + resizable_tensor params; // unused + }; + + + // concat layer definitions + template class TAG1, + template class TAG2, + typename SUBNET> + using concat2 = add_layer, SUBNET>; + + template class TAG1, + template class TAG2, + template class TAG3, + typename SUBNET> + using concat3 = add_layer, SUBNET>; + + template class TAG1, + template class TAG2, + template class TAG3, + template class TAG4, + typename SUBNET> + using concat4 = add_layer, SUBNET>; + + template class TAG1, + template class TAG2, + template class TAG3, + template class TAG4, + template class TAG5, + typename SUBNET> + using concat5 = add_layer, SUBNET>; + + // inception layer will use tags internally. If user will use tags too, some conflicts + // possible to exclude them, here are new tags specially for inceptions + template using itag0 = add_tag_layer< 1000 + 0, SUBNET>; + template using itag1 = add_tag_layer< 1000 + 1, SUBNET>; + template using itag2 = add_tag_layer< 1000 + 2, SUBNET>; + template using itag3 = add_tag_layer< 1000 + 3, SUBNET>; + template using itag4 = add_tag_layer< 1000 + 4, SUBNET>; + template using itag5 = add_tag_layer< 1000 + 5, SUBNET>; + // skip to inception input + template using iskip = add_skip_layer< itag0, SUBNET>; + + // here are some templates to be used for creating inception layer groups + template class B1, + templateclass B2, + typename SUBNET> + using inception2 = concat2>>>>>>; + + template class B1, + templateclass B2, + templateclass B3, + typename SUBNET> + using inception3 = concat3>>>>>>>>>; + + template class B1, + templateclass B2, + templateclass B3, + templateclass B4, + typename SUBNET> + using inception4 = concat4>>>>>>>>>>>>; + + template class B1, + templateclass B2, + templateclass B3, + templateclass B4, + templateclass B5, + typename SUBNET> + using inception5 = concat5>>>>>>>>>>>>>>>; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + const double DEFAULT_L2_NORM_EPS = 1e-5; + + class l2normalize_ + { + public: + explicit l2normalize_( + double eps_ = DEFAULT_L2_NORM_EPS + ) : + eps(eps_) + { + } + + double get_eps() const { return eps; } + + template + void setup (const SUBNET& /*sub*/) + { + } + + void forward_inplace(const tensor& input, tensor& output) + { + tt::inverse_norms(norm, input, eps); + tt::scale_rows(output, input, norm); + } + + void backward_inplace( + const tensor& computed_output, + const tensor& gradient_input, + tensor& data_grad, + tensor& /*params_grad*/ + ) + { + if (is_same_object(gradient_input, data_grad)) + { + tt::dot_prods(temp, gradient_input, computed_output); + tt::scale_rows2(0, data_grad, gradient_input, computed_output, temp, norm); + } + else + { + tt::dot_prods(temp, gradient_input, computed_output); + tt::scale_rows2(1, data_grad, gradient_input, computed_output, temp, norm); + } + } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const l2normalize_& item, std::ostream& out) + { + serialize("l2normalize_", out); + serialize(item.eps, out); + } + + friend void deserialize(l2normalize_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "l2normalize_") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::l2normalize_."); + deserialize(item.eps, in); + } + + friend std::ostream& operator<<(std::ostream& out, const l2normalize_& item) + { + out << "l2normalize"; + out << " eps="<\n"; + } + private: + double eps; + + resizable_tensor params; // unused + // Here only to avoid reallocation and as a cache between forward/backward + // functions. + resizable_tensor norm; + resizable_tensor temp; + }; + + template + using l2normalize = add_layer; + +// ---------------------------------------------------------------------------------------- + + template < + long _offset, + long _k, + long _nr, + long _nc + > + class extract_ + { + static_assert(_offset >= 0, "The offset must be >= 0."); + static_assert(_k > 0, "The number of channels must be > 0."); + static_assert(_nr > 0, "The number of rows must be > 0."); + static_assert(_nc > 0, "The number of columns must be > 0."); + public: + extract_( + ) + { + } + + template + void setup (const SUBNET& sub) + { + DLIB_CASSERT((long)sub.get_output().size() >= sub.get_output().num_samples()*(_offset+_k*_nr*_nc), + "The tensor we are trying to extract from the input tensor is too big to fit into the input tensor."); + + aout = alias_tensor(sub.get_output().num_samples(), _k*_nr*_nc); + ain = alias_tensor(sub.get_output().num_samples(), sub.get_output().size()/sub.get_output().num_samples()); + } + + template + void forward(const SUBNET& sub, resizable_tensor& output) + { + if (aout.num_samples() != sub.get_output().num_samples()) + { + aout = alias_tensor(sub.get_output().num_samples(), _k*_nr*_nc); + ain = alias_tensor(sub.get_output().num_samples(), sub.get_output().size()/sub.get_output().num_samples()); + } + + output.set_size(sub.get_output().num_samples(), _k, _nr, _nc); + auto out = aout(output,0); + auto in = ain(sub.get_output(),0); + tt::copy_tensor(false, out, 0, in, _offset, _k*_nr*_nc); + } + + template + void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/) + { + auto out = ain(sub.get_gradient_input(),0); + auto in = aout(gradient_input,0); + tt::copy_tensor(true, out, _offset, in, 0, _k*_nr*_nc); + } + + const tensor& get_layer_params() const { return params; } + tensor& get_layer_params() { return params; } + + friend void serialize(const extract_& item, std::ostream& out) + { + serialize("extract_", out); + serialize(_offset, out); + serialize(_k, out); + serialize(_nr, out); + serialize(_nc, out); + } + + friend void deserialize(extract_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "extract_") + throw serialization_error("Unexpected version '"+version+"' found while deserializing dlib::extract_."); + + long offset; + long k; + long nr; + long nc; + deserialize(offset, in); + deserialize(k, in); + deserialize(nr, in); + deserialize(nc, in); + + if (offset != _offset) throw serialization_error("Wrong offset found while deserializing dlib::extract_"); + if (k != _k) throw serialization_error("Wrong k found while deserializing dlib::extract_"); + if (nr != _nr) throw serialization_error("Wrong nr found while deserializing dlib::extract_"); + if (nc != _nc) throw serialization_error("Wrong nc found while deserializing dlib::extract_"); + } + + friend std::ostream& operator<<(std::ostream& out, const extract_& item) + { + out << "extract\t (" + << "offset="<<_offset + << ", k="<<_k + << ", nr="<<_nr + << ", nc="<<_nc + << ")"; + return out; + } + + friend void to_xml(const extract_& item, std::ostream& out) + { + out << "\n"; + } + private: + alias_tensor aout, ain; + + resizable_tensor params; // unused + }; + + template < + long offset, + long k, + long nr, + long nc, + typename SUBNET + > + using extract = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DNn_LAYERS_H_ + + diff --git a/lib/3rdParty/dlib/include/dlib/dnn/layers_abstract.h b/lib/3rdParty/dlib/include/dlib/dnn/layers_abstract.h new file mode 100644 index 00000000..9a11724a --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/dnn/layers_abstract.h @@ -0,0 +1,2687 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_DNn_LAYERS_ABSTRACT_H_ +#ifdef DLIB_DNn_LAYERS_ABSTRACT_H_ + +#include "../cuda/tensor_abstract.h" +#include "core_abstract.h" + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class SUBNET + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a deep neural network. In particular, it is + the simplified interface through which layer objects interact with their + subnetworks. A layer's two important tasks are to (1) take outputs from its + subnetwork and forward propagate them through itself and (2) to backwards + propagate an error gradient through itself and onto its subnetwork. + The idea of a subnetwork is illustrated in the following diagram: + + +---------------------------------------------------------+ + | loss <-- layer1 <-- layer2 <-- ... <-- layern <-- input | + +---------------------------------------------------------+ + ^ ^ + \__ subnetwork for layer1 __/ + + Therefore, by "subnetwork" we mean the part of the network closer to the + input. + + Note that there is no dlib::SUBNET type. It is shown here purely to + document the interface layer objects expect to see when they interact + with a network. + !*/ + + public: + // You aren't allowed to copy subnetworks from inside a layer. + SUBNET(const SUBNET&) = delete; + SUBNET& operator=(const SUBNET&) = delete; + + const tensor& get_output( + ) const; + /*! + ensures + - returns the output of this subnetwork. This is the data that the next + layer in the network will take as input. + - have_same_dimensions(#get_gradient_input(), get_output()) == true + !*/ + + tensor& get_gradient_input( + ); + /*! + ensures + - returns the error gradient for this subnetwork. That is, this is the + error gradient that this network will use to update itself. Therefore, + when performing back propagation, layers that sit on top of this + subnetwork write their back propagated error gradients into + get_gradient_input(). Or to put it another way, during back propagation, + layers take the contents of their get_gradient_input() and back propagate + it through themselves and store the results into their subnetwork's + get_gradient_input(). + !*/ + + const NEXT_SUBNET& subnet( + ) const; + /*! + ensures + - returns the subnetwork of *this network. With respect to the diagram + above, if *this was layer1 then subnet() would return the network that + begins with layer2. + !*/ + + NEXT_SUBNET& subnet( + ); + /*! + ensures + - returns the subnetwork of *this network. With respect to the diagram + above, if *this was layer1 then subnet() would return the network that + begins with layer2. + !*/ + + const layer_details_type& layer_details( + ) const; + /*! + ensures + - returns the layer_details_type instance that defines the behavior of the + layer at the top of this network. I.e. returns the layer details that + defines the behavior of the layer nearest to the network output rather + than the input layer. For computational layers, this is the object + implementing the EXAMPLE_COMPUTATIONAL_LAYER_ interface that defines the + layer's behavior. + !*/ + + unsigned int sample_expansion_factor ( + ) const; + /*! + ensures + - When to_tensor() is invoked on this network's input layer it converts N + input objects into M samples, all stored inside a resizable_tensor. It + is always the case that M is some integer multiple of N. + sample_expansion_factor() returns the value of this multiplier. To be + very specific, it is always true that M==I*N where I is some integer. + This integer I is what is returned by sample_expansion_factor(). + + It should be noted that computational layers likely do not care about the + sample expansion factor. It is only really of concern inside a loss + layer where you need to know its value so that tensor samples can be + matched against truth objects. Moreover, in most cases the sample + expansion factor is 1. + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + + class EXAMPLE_COMPUTATIONAL_LAYER_ + { + /*! + WHAT THIS OBJECT REPRESENTS + Each computational layer in a deep neural network can be thought of as a + function, f(data,parameters), that takes in a data tensor, some parameters, + and produces an output tensor. You create an entire deep network by + composing these functions. Importantly, you are able to use a wide range + of different functions to accommodate the task you are trying to + accomplish. Therefore, dlib includes a number of common layer types but if + you want to define your own then you simply implement a class with the same + interface as EXAMPLE_COMPUTATIONAL_LAYER_. + + Note that there is no dlib::EXAMPLE_COMPUTATIONAL_LAYER_ type. It is shown + here purely to document the interface that a layer object must implement. + + The central work of defining a layer is implementing the forward and backward + methods. When you do this you have four options: + - Implement the forward() and backward() methods according to the + specification shown below. Do not implement forward_inplace() and + backward_inplace(). + - Implement the forward() and backward() methods according to the + specification shown below, except exclude the computed_output + parameter from backward(). Doing this will allow dlib to make some + layers execute in-place and therefore run a little faster and use + less memory. Do not implement forward_inplace() and + backward_inplace(). + - Implement the forward_inplace() and backward_inplace() methods + according to the specification shown below. Do not implement + forward() and backward(). These in-place methods allow some types of + layers to be implemented more efficiently. + - Implement the forward_inplace() and backward_inplace() methods + according to the specification shown below, except exclude the + computed_output parameter from backward_inplace(). Doing this will + allow dlib to make some layers execute in-place and therefore run a + little faster and use less memory. Do not implement forward() and + backward(). + + + It should also be noted that layers may define additional layer specific + fields and the solvers can use these fields as they see fit. For example, + some layers define get_learning_rate_multiplier() and + get_weight_decay_multiplier() methods. The solvers that come with dlib + look at these methods, if they exist, and adjust the learning rate or + weight decay for that layer according to the multiplier. Therefore, you + can add these methods to your layer types if you want, or even define new + fields and new solvers that use those fields in some way. + !*/ + + public: + + EXAMPLE_COMPUTATIONAL_LAYER_( + ); + /*! + ensures + - Default constructs this object. This function is not required to do + anything in particular but it must exist, that is, it is required that + layer objects be default constructable. + !*/ + + EXAMPLE_COMPUTATIONAL_LAYER_ ( + const EXAMPLE_COMPUTATIONAL_LAYER_& item + ); + /*! + ensures + - EXAMPLE_COMPUTATIONAL_LAYER_ objects are copy constructable + !*/ + + EXAMPLE_COMPUTATIONAL_LAYER_( + const some_other_layer_type& item + ); + /*! + ensures + - Constructs this object from item. This form of constructor is optional + but it allows you to provide a conversion from one layer type to another. + For example, the following code is valid only if my_layer2 can be + constructed from my_layer1: + relu>>>>> my_dnn1; + relu>>>>> my_dnn2(my_dnn1); + This kind of pattern is useful if you want to use one type of layer + during training but a different type of layer during testing since it + allows you to easily convert between related deep neural network types. + + Additionally, if you provide a constructor to build a layer from another + layer type you should also write your layer's deserialize() routine such + that it can read that other layer's serialized data in addition to your + own serialized data. + !*/ + + template + void setup ( + const SUBNET& sub + ); + /*! + requires + - SUBNET implements the SUBNET interface defined at the top of this file. + ensures + - performs any necessary initial memory allocations and/or sets parameters + to their initial values prior to learning. Therefore, calling setup + destroys any previously learned parameters. Also, typically setup() + would look at the dimensions of the outputs of sub and configure the + number of parameters in *this accordingly. + !*/ + + template + void forward( + const SUBNET& sub, + resizable_tensor& data_output + ); + /*! + requires + - SUBNET implements the SUBNET interface defined at the top of this file. + - setup() has been called. + ensures + - Runs the output of the subnetwork through this layer and stores the + results into #data_output. In particular, forward() can use any of the + outputs in sub (e.g. sub.get_output(), sub.subnet().get_output(), etc.) + to compute whatever it wants. + !*/ + + template + void backward( + const tensor& computed_output, // this parameter is optional + const tensor& gradient_input, + SUBNET& sub, + tensor& params_grad + ); + /*! + requires + - SUBNET implements the SUBNET interface defined at the top of this file. + - setup() has been called. + - computed_output is the tensor resulting from calling forward(sub,computed_output). + Moreover, this was the most recent call to forward(). This means that + forward() is allowed to cache intermediate results so they can be used + during the backward computation. + - have_same_dimensions(gradient_input, computed_output) == true + - have_same_dimensions(sub.get_gradient_input(), sub.get_output()) == true + - have_same_dimensions(params_grad, get_layer_params()) == true + ensures + - This function outputs the gradients of this layer with respect to the + input data from sub and also with respect to this layer's parameters. + These gradients are stored into #sub and #params_grad, respectively. To be + precise, the gradients are taken of a function f(sub,get_layer_params()) + which is defined thusly: + - Recalling that computed_output is a function of both sub and get_layer_params(), + since it is the result of calling forward(sub,computed_output): + let f(sub,get_layer_params()) == dot(computed_output, gradient_input) + Then we define the following gradient vectors: + - PARAMETER_GRADIENT == gradient of f(sub,get_layer_params()) with + respect to get_layer_params(). + - for all valid I: + - DATA_GRADIENT_I == gradient of f(sub,get_layer_params()) with + respect to layer(sub).get_output() (recall that forward() can + draw inputs from the immediate sub layer, sub.subnet(), or + any earlier layer. So you must consider the gradients with + respect to all inputs drawn from sub) + Finally, backward() outputs these gradients by performing: + - params_grad = PARAMETER_GRADIENT + - for all valid I: + - layer(sub).get_gradient_input() += DATA_GRADIENT_I + !*/ + + void forward_inplace( + const tensor& data_input, + tensor& data_output + ); + /*! + requires + - have_same_dimensions(data_input,data_output) == true + - setup() has been called. + ensures + - Runs the data_input tensor through this layer and stores the output into + #data_output. + - This function supports in-place operation, i.e. having + is_same_object(data_input, data_output)==true + !*/ + + void backward_inplace( + const tensor& computed_output, // this parameter is optional + const tensor& gradient_input, + tensor& data_grad, + tensor& params_grad + ); + /*! + requires + - setup() has been called. + - computed_output is the tensor resulting from the most recent call to + forward_inplace(). This means that forward_inplace() is allowed to cache + intermediate results so they can be used during the backward computation. + - have_same_dimensions(gradient_input, data_grad) == true + - have_same_dimensions(gradient_input, computed_output) == true + - have_same_dimensions(params_grad, get_layer_params()) == true + ensures + - This function supports in-place operation, i.e. having + is_same_object(gradient_input, data_grad)==true + - This function outputs the gradients of this layer with respect to the + input data from a sublayer and also with respect to this layer's parameters. + These gradients are stored into #data_grad and #params_grad, respectively. To be + precise, the gradients are taken of a function f(data_input,get_layer_params()) + which is defined thusly: + - Recalling that computed_output is a function of both the input to + forward_inplace() and get_layer_params(), since it is the result of + calling forward_inplace(data_input,computed_output): + let f(data_input,get_layer_params()) == dot(computed_output, gradient_input) + Then we define the following gradient vectors: + - PARAMETER_GRADIENT == gradient of f(data_input,get_layer_params()) with + respect to get_layer_params(). + - DATA_GRADIENT == gradient of f(data_input,get_layer_params()) with respect + to data_input. + Finally, backward_inplace() outputs these gradients by performing: + - params_grad = PARAMETER_GRADIENT + - if (is_same_object(gradient_input, data_grad)) then + - data_grad = DATA_GRADIENT + - else + - data_grad += DATA_GRADIENT + !*/ + + const tensor& get_layer_params( + ) const; + /*! + ensures + - returns the parameters that define the behavior of forward(). + !*/ + + tensor& get_layer_params( + ); + /*! + ensures + - returns the parameters that define the behavior of forward(). + !*/ + + + dpoint map_input_to_output(dpoint p) const; + dpoint map_output_to_input(dpoint p) const; + /*! + These two functions are optional. If provided, they should map between + (column,row) coordinates in input and output tensors of forward(). Providing + these functions allows you to use global utility functions like + input_tensor_to_output_tensor(). + !*/ + + void clean ( + ); + /*! + Implementing this function is optional. If you don't need it then you don't + have to provide a clean(). But if you do provide it then it must behave as + follows: + + ensures + - calling clean() causes this object to forget about everything except its + parameters. This is useful if your layer caches information between + forward and backward passes and you want to clean out that cache + information before saving the network to disk. + !*/ + + }; + + std::ostream& operator<<(std::ostream& out, const EXAMPLE_COMPUTATIONAL_LAYER_& item); + /*! + print a string describing this layer. + !*/ + + void to_xml(const EXAMPLE_COMPUTATIONAL_LAYER_& item, std::ostream& out); + /*! + This function is optional, but required if you want to print your networks with + net_to_xml(). Therefore, to_xml() prints a layer as XML. + !*/ + + void serialize(const EXAMPLE_COMPUTATIONAL_LAYER_& item, std::ostream& out); + void deserialize(EXAMPLE_COMPUTATIONAL_LAYER_& item, std::istream& in); + /*! + provides serialization support + !*/ + + // For each layer you define, always define an add_layer template so that layers can be + // easily composed. Moreover, the convention is that the layer class ends with an _ + // while the add_layer template has the same name but without the trailing _. + template + using EXAMPLE_COMPUTATIONAL_LAYER = add_layer; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + enum fc_bias_mode + { + FC_HAS_BIAS = 0, + FC_NO_BIAS = 1 + }; + + struct num_fc_outputs + { + num_fc_outputs(unsigned long n) : num_outputs(n) {} + unsigned long num_outputs; + }; + + template < + unsigned long num_outputs, + fc_bias_mode bias_mode + > + class fc_ + { + /*! + REQUIREMENTS ON num_outputs + num_outputs > 0 + + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. In particular, it defines a fully connected layer that + takes an input tensor and multiplies it by a weight matrix and outputs the + results. + + The dimensions of the tensors output by this layer are as follows (letting + IN be the input tensor and OUT the output tensor): + - OUT.num_samples() == IN.num_samples() + - OUT.k() == get_num_outputs() + - OUT.nr() == 1 + - OUT.nc() == 1 + !*/ + + public: + + fc_( + ); + /*! + ensures + - #get_num_outputs() == num_outputs + - #get_bias_mode() == bias_mode + - #get_learning_rate_multiplier() == 1 + - #get_weight_decay_multiplier() == 1 + - #get_bias_learning_rate_multiplier() == 1 + - #get_bias_weight_decay_multiplier() == 0 + !*/ + + fc_( + num_fc_outputs o + ); + /*! + ensures + - #get_num_outputs() == o.num_outputs + - #get_bias_mode() == bias_mode + - #get_learning_rate_multiplier() == 1 + - #get_weight_decay_multiplier() == 1 + - #get_bias_learning_rate_multiplier() == 1 + - #get_bias_weight_decay_multiplier() == 0 + !*/ + + unsigned long get_num_outputs ( + ) const; + /*! + ensures + - This layer outputs column vectors that contain get_num_outputs() + elements. That is, the output tensor T from forward() will be such that: + - T.num_samples() == however many samples were given to forward(). + - T.k() == get_num_outputs() + - The rest of the dimensions of T will be 1. + !*/ + + void set_num_outputs( + long num + ); + /*! + requires + - num > 0 + - get_layer_params().size() == 0 || get_num_outputs() == num + (i.e. You can't change the number of outputs in fc_ if the parameter + tensor has already been allocated.) + ensures + - #get_num_outputs() == num + !*/ + + fc_bias_mode get_bias_mode ( + ) const; + /*! + ensures + - returns the bias mode which determines if this layer includes bias terms. + That is, if the bias mode is FC_HAS_BIAS then a different constant scalar + is added to each of the outputs of this layer. + !*/ + + double get_learning_rate_multiplier( + ) const; + /*! + ensures + - returns a multiplier number. The interpretation is that this object is + requesting that the learning rate used to optimize its parameters be + multiplied by get_learning_rate_multiplier(). + !*/ + + double get_weight_decay_multiplier( + ) const; + /*! + ensures + - returns a multiplier number. The interpretation is that this object is + requesting that the weight decay used to optimize its parameters be + multiplied by get_weight_decay_multiplier(). + !*/ + + void set_learning_rate_multiplier( + double val + ); + /*! + requires + - val >= 0 + ensures + - #get_learning_rate_multiplier() == val + !*/ + + void set_weight_decay_multiplier( + double val + ); + /*! + requires + - val >= 0 + ensures + - #get_weight_decay_multiplier() == val + !*/ + + double get_bias_learning_rate_multiplier( + ) const; + /*! + ensures + - returns a multiplier number. The interpretation is that this object is + requesting that the learning rate used to optimize its bias parameters be + multiplied by get_learning_rate_multiplier()*get_bias_learning_rate_multiplier(). + !*/ + + double get_bias_weight_decay_multiplier( + ) const; + /*! + ensures + - returns a multiplier number. The interpretation is that this object is + requesting that the weight decay used to optimize its bias parameters be + multiplied by get_weight_decay_multiplier()*get_bias_weight_decay_multiplier(). + !*/ + + void set_bias_learning_rate_multiplier( + double val + ); + /*! + requires + - val >= 0 + ensures + - #get_bias_learning_rate_multiplier() == val + !*/ + + void set_bias_weight_decay_multiplier( + double val + ); + /*! + requires + - val >= 0 + ensures + - #get_bias_weight_decay_multiplier() == val + !*/ + + alias_tensor_const_instance get_weights( + ) const; + /*! + ensures + - returns an alias of get_layer_params(), containing the weights matrix of + the fully connected layer. + - #get_weights().num_samples() is the number of elements in input sample, + i.e. sublayer's output's k * nc * nr. + - #get_bias().k() == #get_num_outputs() + - if get_bias_mode() == FC_HAS_BIAS: + - #get_layer_params().size() == (#get_weights().size() + #get_biases().size()) + - else: + - #get_layer_params().size() == #get_weights().size() + !*/ + + alias_tensor_instance get_weights( + ); + /*! + ensures + - returns an alias of get_layer_params(), containing the weights matrix of + the fully connected layer. + - #get_weights().num_samples() is the number of elements in input sample, + i.e. sublayer's output's k * nc * nr. + - #get_bias().k() == #get_num_outputs() + - if get_bias_mode() == FC_HAS_BIAS: + - #get_layer_params().size() == (#get_weights().size() + #get_biases().size()) + - else: + - #get_layer_params().size() == #get_weights().size() + !*/ + + alias_tensor_const_instance get_biases( + ) const; + /*! + requires + - #get_bias_mode() == FC_HAS_BIAS + ensures + - returns an alias of get_layer_params(), containing the bias vector of + the fully connected layer. + - #get_bias().num_samples() == 1 + - #get_bias().k() == #get_num_outputs() + - #get_layer_params().size() == (#get_weights().size() + #get_biases().size()) + !*/ + + alias_tensor_instance get_biases( + ); + /*! + requires + - #get_bias_mode() == FC_HAS_BIAS + ensures + - returns an alias of get_layer_params(), containing the bias vector of + the fully connected layer. + - #get_bias().num_samples() == 1 + - #get_bias().k() == #get_num_outputs() + - #get_layer_params().size() == (#get_weights().size() + #get_biases().size()) + !*/ + + template void setup (const SUBNET& sub); + template void forward(const SUBNET& sub, resizable_tensor& output); + template void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad); + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface. + !*/ + + }; + + template < + unsigned long num_outputs, + typename SUBNET + > + using fc = add_layer, SUBNET>; + + template < + unsigned long num_outputs, + typename SUBNET + > + using fc_no_bias = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + + struct num_con_outputs + { + num_con_outputs(unsigned long n) : num_outputs(n) {} + unsigned long num_outputs; + }; + + template < + long _num_filters, + long _nr, + long _nc, + int _stride_y, + int _stride_x, + int _padding_y = _stride_y!=1? 0 : _nr/2, + int _padding_x = _stride_x!=1? 0 : _nc/2 + > + class con_ + { + /*! + REQUIREMENTS ON TEMPLATE ARGUMENTS + - _num_filters > 0 + - _nr >= 0 + - _nc >= 0 + - _stride_y > 0 + - _stride_x > 0 + - _padding_y >= 0 + - _padding_x >= 0 + - Also, we require that: + - if (_nr == 0) then + - _padding_y == 0 + - else + - _padding_y < _nr + - if (_nc == 0) then + - _padding_x == 0 + - else + - _padding_x < _nc + + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. In particular, it defines a convolution layer that takes an + input tensor (nominally representing an image) and convolves it with a set + of filters and then outputs the results. + + The dimensions of the tensors output by this layer are as follows (letting + IN be the input tensor and OUT the output tensor): + - OUT.num_samples() == IN.num_samples() + - OUT.k() == num_filters() + - OUT.nr() == 1+(IN.nr() + 2*padding_y() - nr())/stride_y() + - OUT.nc() == 1+(IN.nc() + 2*padding_x() - nc())/stride_x() + + Note also that setting _nr or _nc to 0 has a special meaning of "set the + filter size equal to the input image size". Specifically, it means: + - if (_nr == 0) then + - nr() == IN.nr() + - OUT.nr() == 1 + - if (_nc == 0) then + - nc() == IN.nc() + - OUT.nc() == 1 + !*/ + + public: + con_( + ); + /*! + ensures + - #num_filters() == _num_filters + - #nr() == _nr + - #nc() == _nc + - #stride_y() == _stride_y + - #stride_x() == _stride_x + - #padding_y() == _padding_y + - #padding_x() == _padding_x + - #get_learning_rate_multiplier() == 1 + - #get_weight_decay_multiplier() == 1 + - #get_bias_learning_rate_multiplier() == 1 + - #get_bias_weight_decay_multiplier() == 0 + !*/ + + con_( + num_con_outputs o + ); + /*! + ensures + - #num_filters() == o.num_outputs + - #nr() == _nr + - #nc() == _nc + - #stride_y() == _stride_y + - #stride_x() == _stride_x + - #padding_y() == _padding_y + - #padding_x() == _padding_x + - #get_learning_rate_multiplier() == 1 + - #get_weight_decay_multiplier() == 1 + - #get_bias_learning_rate_multiplier() == 1 + - #get_bias_weight_decay_multiplier() == 0 + !*/ + + long num_filters( + ) const; + /*! + ensures + - returns the number of filters contained in this layer. The k dimension + of the output tensors produced by this layer will be equal to the number + of filters. + !*/ + + void set_num_filters( + long num + ); + /*! + requires + - num > 0 + - get_layer_params().size() == 0 || num_filters() == num + (i.e. You can't change the number of filters in con_ if the parameter + tensor has already been allocated.) + ensures + - #num_filters() == num + !*/ + + long nr( + ) const; + /*! + ensures + - returns the number of rows in the filters in this layer. Note that if + nr()==0 then it means the size of the filter is not yet assigned, but + once setup() is called nr() will be set to the input tensor's nr(). + Therefore, nr()==0 has the special interpretation of "be the same size as + the input tensor". + !*/ + + long nc( + ) const; + /*! + ensures + - returns the number of columns in the filters in this layer. Note that if + nc()==0 then it means the size of the filter is not yet assigned, but + once setup() is called nc() will be set to the input tensor's nc(). + Therefore, nc()==0 has the special interpretation of "be the same size as + the input tensor". + !*/ + + long stride_y( + ) const; + /*! + ensures + - returns the vertical stride used when convolving the filters over an + image. That is, each filter will be moved stride_y() pixels down at a + time when it moves over the image. + !*/ + + long stride_x( + ) const; + /*! + ensures + - returns the horizontal stride used when convolving the filters over an + image. That is, each filter will be moved stride_x() pixels right at a + time when it moves over the image. + !*/ + + long padding_y( + ) const; + /*! + ensures + - returns the number of pixels of zero padding added to the top and bottom + sides of the image. + !*/ + + long padding_x( + ) const; + /*! + ensures + - returns the number of pixels of zero padding added to the left and right + sides of the image. + !*/ + + double get_learning_rate_multiplier( + ) const; + /*! + ensures + - returns a multiplier number. The interpretation is that this object is + requesting that the learning rate used to optimize its parameters be + multiplied by get_learning_rate_multiplier(). + !*/ + + double get_weight_decay_multiplier( + ) const; + /*! + ensures + - returns a multiplier number. The interpretation is that this object is + requesting that the weight decay used to optimize its parameters be + multiplied by get_weight_decay_multiplier(). + !*/ + + void set_learning_rate_multiplier( + double val + ); + /*! + requires + - val >= 0 + ensures + - #get_learning_rate_multiplier() == val + !*/ + + void set_weight_decay_multiplier( + double val + ); + /*! + requires + - val >= 0 + ensures + - #get_weight_decay_multiplier() == val + !*/ + + double get_bias_learning_rate_multiplier( + ) const; + /*! + ensures + - returns a multiplier number. The interpretation is that this object is + requesting that the learning rate used to optimize its bias parameters be + multiplied by get_learning_rate_multiplier()*get_bias_learning_rate_multiplier(). + !*/ + + double get_bias_weight_decay_multiplier( + ) const; + /*! + ensures + - returns a multiplier number. The interpretation is that this object is + requesting that the weight decay used to optimize its bias parameters be + multiplied by get_weight_decay_multiplier()*get_bias_weight_decay_multiplier(). + !*/ + + void set_bias_learning_rate_multiplier( + double val + ); + /*! + requires + - val >= 0 + ensures + - #get_bias_learning_rate_multiplier() == val + !*/ + + void set_bias_weight_decay_multiplier( + double val + ); + /*! + requires + - val >= 0 + ensures + - #get_bias_weight_decay_multiplier() == val + !*/ + + template void setup (const SUBNET& sub); + template void forward(const SUBNET& sub, resizable_tensor& output); + template void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad); + dpoint map_input_to_output(dpoint p) const; + dpoint map_output_to_input(dpoint p) const; + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface. + !*/ + + }; + + template < + long num_filters, + long nr, + long nc, + int stride_y, + int stride_x, + typename SUBNET + > + using con = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + + template < + long _num_filters, + long _nr, + long _nc, + int _stride_y, + int _stride_x, + int _padding_y = _stride_y!=1? 0 : _nr/2, + int _padding_x = _stride_x!=1? 0 : _nc/2 + > + class cont_ + { + /*! + REQUIREMENTS ON TEMPLATE ARGUMENTS + All of them must be > 0. + Also, we require that: + - 0 <= _padding_y && _padding_y < _nr + - 0 <= _padding_x && _padding_x < _nc + + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. In particular, it defines a transposed convolution layer + that takes an input tensor and transpose convolves (sometimes called + "deconvolution") it with a set of filters and then outputs the results. + + This is essentially a convolutional layer that allows fractional strides. + Therefore, you can make output tensors that are larger than the input + tensors using this layer type. + + + The dimensions of the tensors output by this layer are as follows (letting + IN be the input tensor and OUT the output tensor): + - OUT.num_samples() == IN.num_samples() + - OUT.k() == num_filters() + - OUT.nr() == stride_y()*(IN.nr()-1) + nr() - 2*padding_y() + - OUT.nc() == stride_x()*(IN.nc()-1) + nc() - 2*padding_x() + !*/ + + public: + cont_( + ); + /*! + ensures + - #num_filters() == _num_filters + - #nr() == _nr + - #nc() == _nc + - #stride_y() == _stride_y + - #stride_x() == _stride_x + - #padding_y() == _padding_y + - #padding_x() == _padding_x + - #get_learning_rate_multiplier() == 1 + - #get_weight_decay_multiplier() == 1 + - #get_bias_learning_rate_multiplier() == 1 + - #get_bias_weight_decay_multiplier() == 0 + !*/ + + cont_( + num_con_outputs o + ); + /*! + ensures + - #num_filters() == o.num_outputs + - #nr() == _nr + - #nc() == _nc + - #stride_y() == _stride_y + - #stride_x() == _stride_x + - #padding_y() == _padding_y + - #padding_x() == _padding_x + - #get_learning_rate_multiplier() == 1 + - #get_weight_decay_multiplier() == 1 + - #get_bias_learning_rate_multiplier() == 1 + - #get_bias_weight_decay_multiplier() == 0 + !*/ + + long num_filters( + ) const; + /*! + ensures + - returns the number of filters contained in this layer. The k dimension + of the output tensors produced by this layer will be equal to the number + of filters. + !*/ + + void set_num_filters( + long num + ); + /*! + requires + - num > 0 + - get_layer_params().size() == 0 || num_filters() == num + (i.e. You can't change the number of filters in cont_ if the parameter + tensor has already been allocated.) + ensures + - #num_filters() == num + !*/ + + long nr( + ) const; + /*! + ensures + - returns the number of rows in the filters in this layer. + !*/ + + long nc( + ) const; + /*! + ensures + - returns the number of columns in the filters in this layer. + !*/ + + long stride_y( + ) const; + /*! + ensures + - returns the vertical stride used when convolving the filters over an + image. That is, each filter will be moved 1.0/stride_y() pixels down at + a time when it moves over the image. + !*/ + + long stride_x( + ) const; + /*! + ensures + - returns the horizontal stride used when convolving the filters over an + image. That is, each filter will be moved 1.0/stride_x() pixels right at + a time when it moves over the image. + !*/ + + long padding_y( + ) const; + /*! + ensures + - returns the number of pixels of zero padding added to the top and bottom + sides of the image. + !*/ + + long padding_x( + ) const; + /*! + ensures + - returns the number of pixels of zero padding added to the left and right + sides of the image. + !*/ + + double get_learning_rate_multiplier( + ) const; + /*! + ensures + - returns a multiplier number. The interpretation is that this object is + requesting that the learning rate used to optimize its parameters be + multiplied by get_learning_rate_multiplier(). + !*/ + + double get_weight_decay_multiplier( + ) const; + /*! + ensures + - returns a multiplier number. The interpretation is that this object is + requesting that the weight decay used to optimize its parameters be + multiplied by get_weight_decay_multiplier(). + !*/ + + void set_learning_rate_multiplier( + double val + ); + /*! + requires + - val >= 0 + ensures + - #get_learning_rate_multiplier() == val + !*/ + + void set_weight_decay_multiplier( + double val + ); + /*! + requires + - val >= 0 + ensures + - #get_weight_decay_multiplier() == val + !*/ + + double get_bias_learning_rate_multiplier( + ) const; + /*! + ensures + - returns a multiplier number. The interpretation is that this object is + requesting that the learning rate used to optimize its bias parameters be + multiplied by get_learning_rate_multiplier()*get_bias_learning_rate_multiplier(). + !*/ + + double get_bias_weight_decay_multiplier( + ) const; + /*! + ensures + - returns a multiplier number. The interpretation is that this object is + requesting that the weight decay used to optimize its bias parameters be + multiplied by get_weight_decay_multiplier()*get_bias_weight_decay_multiplier(). + !*/ + + void set_bias_learning_rate_multiplier( + double val + ); + /*! + requires + - val >= 0 + ensures + - #get_bias_learning_rate_multiplier() == val + !*/ + + void set_bias_weight_decay_multiplier( + double val + ); + /*! + requires + - val >= 0 + ensures + - #get_bias_weight_decay_multiplier() == val + !*/ + + template void setup (const SUBNET& sub); + template void forward(const SUBNET& sub, resizable_tensor& output); + template void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad); + dpoint map_input_to_output(dpoint p) const; + dpoint map_output_to_input(dpoint p) const; + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface. + !*/ + + }; + + template < + long num_filters, + long nr, + long nc, + int stride_y, + int stride_x, + typename SUBNET + > + using cont = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + + template < + int scale_y, + int scale_x + > + class upsample_ + { + /*! + REQUIREMENTS ON TEMPLATE ARGUMENTS + All of them must be >= 1. + + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. In particular, it allows you to upsample a layer using + bilinear interpolation. To be very specific, it upsamples each of the + channels in an input tensor. Therefore, if IN is the input tensor to this + layer and OUT the output tensor, then we will have: + - OUT.num_samples() == IN.num_samples() + - OUT.k() == IN.k() + - OUT.nr() == IN.nr()*scale_y + - OUT.nc() == IN.nc()*scale_x + - for all valid i,k: image_plane(OUT,i,k) is a copy of + image_plane(IN,i,k) that has been bilinearly interpolated to fit into + the shape of image_plane(OUT,i,k). + !*/ + public: + + upsample_( + ); + /*! + ensures + - This object has no state, so the constructor does nothing, aside from + providing default constructability. + !*/ + + template void setup (const SUBNET& sub); + template void forward(const SUBNET& sub, resizable_tensor& output); + template void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad); + dpoint map_input_to_output(dpoint p) const; + dpoint map_output_to_input(dpoint p) const; + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface. + !*/ + }; + + template < + int scale, + typename SUBNET + > + using upsample = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + + template < + long NR_, + long NC_ + > + class resize_to_ + { + /*! + REQUIREMENTS ON THE INPUT ARGUMENTS + - NR_ >= 1 + - NC_ >= 1 + + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. In particular, it allows you to resize a layer using + bilinear interpolation. To be very specific, it resizes each of the + channels in an input tensor. Therefore, if IN is the input tensor to this + layer and OUT the output tensor, then we will have: + - OUT.num_samples() == IN.num_samples() + - OUT.k() == IN.k() + - OUT.nr() == NR_ + - OUT.nc() == NC_ + - for all valid i,k: image_plane(OUT,i,k) is a copy of + image_plane(IN,i,k) that has been bilinearly interpolated to fit into + the shape of image_plane(OUT,i,k). + !*/ + public: + + resize_to_( + ); + /*! + ensures + - This object has no state, so the constructor does nothing, aside from + providing default constructability. + !*/ + + template void setup (const SUBNET& sub); + template void forward(const SUBNET& sub, resizable_tensor& output); + template void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad); + dpoint map_input_to_output(dpoint p) const; + dpoint map_output_to_input(dpoint p) const; + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface. + !*/ + }; + + template < + long NR, + long NC, + typename SUBNET + > + using resize_to = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + + class dropout_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. In particular, it defines a dropout layer. Therefore, it + passes its inputs through the stochastic function f(x) which outputs either + 0 or x. The probability of 0 being output is given by the drop_rate + argument to this object's constructor. + + Note that, after you finish training a network with dropout, it is a good + idea to replace each dropout_ layer with a multiply_ layer because the + multiply_ layer is faster and deterministic. + !*/ + + public: + + explicit dropout_( + float drop_rate = 0.5 + ); + /*! + requires + - 0 <= drop_rate <= 1 + ensures + - #get_drop_rate() == drop_rate + !*/ + + float get_drop_rate ( + ) const; + /*! + ensures + - returns the probability that an individual input value to this layer will + be replaced with 0. + !*/ + + template void setup (const SUBNET& sub); + void forward_inplace(const tensor& input, tensor& output); + void backward_inplace(const tensor& gradient_input, tensor& data_grad, tensor& params_grad); + dpoint map_input_to_output(dpoint p) const; + dpoint map_output_to_input(dpoint p) const; + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface. + !*/ + }; + + template + using dropout = add_layer; + +// ---------------------------------------------------------------------------------------- + + class multiply_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. In particular, it defines a basic layer that just + multiplies its input tensor with a constant value and returns the result. + It therefore has no learnable parameters. + !*/ + + public: + explicit multiply_( + float val = 0.5 + ); + /*! + ensures + - #get_multiply_value() == val + !*/ + + multiply_ ( + const dropout_& item + ); + /*! + ensures + - #get_multiply_value() == 1-item.get_drop_rate() + (i.e. We construct the multiply_ layer so that it is essentially a + deterministic version of the given dropout_ layer) + !*/ + + float get_multiply_value ( + ) const; + /*! + ensures + - this layer simply multiplies its input tensor by get_multiply_value() and + produces the result as output. + !*/ + + template void setup (const SUBNET& sub); + void forward_inplace(const tensor& input, tensor& output); + void backward_inplace(const tensor& gradient_input, tensor& data_grad, tensor& params_grad); + dpoint map_input_to_output(dpoint p) const; + dpoint map_output_to_input(dpoint p) const; + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface. + !*/ + }; + + template + using multiply = add_layer; + +// ---------------------------------------------------------------------------------------- + + enum layer_mode + { + CONV_MODE = 0, // convolutional mode + FC_MODE = 1 // fully connected mode + }; + + const double DEFAULT_BATCH_NORM_EPS = 0.0001; + + template < + layer_mode mode + > + class bn_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. In particular, it defines a batch normalization layer that + implements the method described in the paper: + Batch Normalization: Accelerating Deep Network Training by Reducing + Internal Covariate Shift by Sergey Ioffe and Christian Szegedy + + In particular, this layer produces output tensors with the same + dimensionality as the input tensors, except that the mean and variances of + the elements have been standardized to 0 and 1 respectively. + + It should also be noted that when tensors with a num_samples() dimension of + 1 are passed to this layer it doesn't perform batch normalization. + Instead, it runs in "inference mode" where the learned linear normalizing + transformation is used to transform the tensor. + + Finally, after you finish training a batch normalized network, it is a good + idea to replace each bn_ layer with an affine_ layer because the affine_ + layer is faster and will never surprise you by performing batch + normalization on tensors that have a num_samples() dimension > 1. This allows + you to run large mini-batches of samples through your final network without + batch normalization executing at all. + !*/ + + public: + bn_( + ); + /*! + ensures + - #get_mode() == mode + - #get_running_stats_window_size() == 100 + - #get_learning_rate_multiplier() == 1 + - #get_weight_decay_multiplier() == 0 + - #get_bias_learning_rate_multiplier() == 1 + - #get_bias_weight_decay_multiplier() == 1 + - #get_eps() == tt::DEFAULT_BATCH_NORM_EPS + !*/ + + explicit bn_( + unsigned long window_size, + double eps = tt::DEFAULT_BATCH_NORM_EPS + ); + /*! + requires + - eps > 0 + - window_size > 0 + ensures + - #get_mode() == mode + - #get_running_stats_window_size() == window_size + - #get_learning_rate_multiplier() == 1 + - #get_weight_decay_multiplier() == 0 + - #get_bias_learning_rate_multiplier() == 1 + - #get_bias_weight_decay_multiplier() == 1 + - #get_eps() == eps + !*/ + + layer_mode get_mode( + ) const; + /*! + ensures + - returns the mode of this layer, either CONV_MODE or FC_MODE. + If the mode is FC_MODE then the normalization is applied across the + samples in a tensor (i.e. k()*nr()*nc() different things will be + normalized). Otherwise, normalization is applied across everything + except for the k() dimension, resulting in there being only k() + normalization equations that are applied spatially over the tensor. + + Therefore, if you are putting batch normalization after a fully connected + layer you should use FC_MODE. Otherwise, if you are putting batch + normalization after a convolutional layer you should use CONV_MODE. + !*/ + + double get_eps( + ) const; + /*! + ensures + - When doing batch normalization, we are dividing by the standard + deviation. This epsilon value returned by this function is added to the + variance to prevent the division from dividing by zero. + !*/ + + unsigned long get_running_stats_window_size ( + ) const; + /*! + ensures + - Just as recommended in the batch normalization paper, this object keeps a + running average of the mean and standard deviations of the features. + These averages are used during "inference mode" so you can run a single + object through a batch normalized network. They are also what is used to + initialize an affine_ layer that is constructed from a bn_ layer. This + function returns the effective number of recent samples used to compute + the running average. + !*/ + + void set_running_stats_window_size ( + unsigned long new_window_size + ); + /*! + requires + - new_window_size > 0 + ensures + - #get_running_stats_window_size() == new_window_size + !*/ + + double get_learning_rate_multiplier( + ) const; + /*! + ensures + - returns a multiplier number. The interpretation is that this object is + requesting that the learning rate used to optimize its parameters be + multiplied by get_learning_rate_multiplier(). + !*/ + + double get_weight_decay_multiplier( + ) const; + /*! + ensures + - returns a multiplier number. The interpretation is that this object is + requesting that the weight decay used to optimize its parameters be + multiplied by get_weight_decay_multiplier(). + !*/ + + void set_learning_rate_multiplier( + double val + ); + /*! + requires + - val >= 0 + ensures + - #get_learning_rate_multiplier() == val + !*/ + + void set_weight_decay_multiplier( + double val + ); + /*! + requires + - val >= 0 + ensures + - #get_weight_decay_multiplier() == val + !*/ + + double get_bias_learning_rate_multiplier( + ) const; + /*! + ensures + - returns a multiplier number. The interpretation is that this object is + requesting that the learning rate used to optimize its bias parameters be + multiplied by get_learning_rate_multiplier()*get_bias_learning_rate_multiplier(). + !*/ + + double get_bias_weight_decay_multiplier( + ) const; + /*! + ensures + - returns a multiplier number. The interpretation is that this object is + requesting that the weight decay used to optimize its bias parameters be + multiplied by get_weight_decay_multiplier()*get_bias_weight_decay_multiplier(). + !*/ + + void set_bias_learning_rate_multiplier( + double val + ); + /*! + requires + - val >= 0 + ensures + - #get_bias_learning_rate_multiplier() == val + !*/ + + void set_bias_weight_decay_multiplier( + double val + ); + /*! + requires + - val >= 0 + ensures + - #get_bias_weight_decay_multiplier() == val + !*/ + + template void setup (const SUBNET& sub); + template void forward(const SUBNET& sub, resizable_tensor& output); + template void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad); + dpoint map_input_to_output(dpoint p) const; + dpoint map_output_to_input(dpoint p) const; + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface. + !*/ + }; + + template + using bn_con = add_layer, SUBNET>; + template + using bn_fc = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + + template + void set_all_bn_running_stats_window_sizes ( + const net_type& net, + unsigned long new_window_size + ); + /*! + requires + - new_window_size > 0 + - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or + add_tag_layer. + ensures + - Sets the get_running_stats_window_size() field of all bn_ layers in net to + new_window_size. + !*/ + +// ---------------------------------------------------------------------------------------- + + class affine_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. In particular, it applies a simple pointwise linear + transformation to an input tensor. You can think of it as having two + parameter tensors, A and B. If the input tensor is called INPUT then the + output of this layer is: + A*INPUT+B + where all operations are performed element wise and each sample in the + INPUT tensor is processed separately. + + Moreover, this object has two modes that effect the dimensionalities of A + and B and how they are applied to compute A*INPUT+B. If + get_mode()==FC_MODE then A and B each have the same dimensionality as the + input tensor, except their num_samples() dimensions are 1. If + get_mode()==CONV_MODE then A and B have all their dimensions set to 1 + except for k(), which is equal to INPUT.k(). + + In either case, the computation of A*INPUT+B is performed pointwise over all + the elements of INPUT using either: + OUTPUT(n,k,r,c) == A(1,k,r,c)*INPUT(n,k,r,c)+B(1,k,r,c) + or + OUTPUT(n,k,r,c) == A(1,k,1,1)*INPUT(n,k,r,c)+B(1,k,1,1) + as appropriate. + + + Finally, note that the parameters of this layer are not learnable and + therefore not modified during network updates. Instead, the layer will + perform the identity transformation unless it is initialized with a bn_ + layer, in which case it will perform whatever transformation the bn_ layer + has learned. + !*/ + + public: + + affine_( + ); + /*! + ensures + - #get_mode() == FC_MODE + !*/ + + affine_( + layer_mode mode + ); + /*! + ensures + - #get_mode() == mode + !*/ + + template < + layer_mode mode + > + affine_( + const bn_& layer + ); + /*! + ensures + - Constructs affine_ so that it performs the same transformation as the + supplied batch normalization layer. You would want to do this after you + finish training a network with bn_ layers because the affine_ layer will + execute faster. + - #get_mode() == layer.get_mode() + !*/ + + layer_mode get_mode( + ) const; + /*! + ensures + - returns the mode of this layer, either CONV_MODE or FC_MODE. + !*/ + + template void setup (const SUBNET& sub); + void forward_inplace(const tensor& input, tensor& output); + void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad); + dpoint map_input_to_output(dpoint p) const; + dpoint map_output_to_input(dpoint p) const; + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the + EXAMPLE_COMPUTATIONAL_LAYER_ interface. Also note that get_layer_params() + always returns an empty tensor since there are no learnable parameters in this + object. + !*/ + + }; + + template + using affine = add_layer; + +// ---------------------------------------------------------------------------------------- + + template < + long _nr, + long _nc, + int _stride_y, + int _stride_x, + int _padding_y = _stride_y!=1? 0 : _nr/2, + int _padding_x = _stride_x!=1? 0 : _nc/2 + > + class max_pool_ + { + /*! + REQUIREMENTS ON TEMPLATE ARGUMENTS + - _nr >= 0 + - _nc >= 0 + - _stride_y > 0 + - _stride_x > 0 + - _padding_y >= 0 + - _padding_x >= 0 + - if (_nr != 0) then + - _padding_y < _nr + - else + - _padding_y == 0 + - if (_nc != 0) then + - _padding_x < _nr + - else + - _padding_x == 0 + + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. In particular, it defines a max pooling layer that takes an + input tensor and downsamples it. It does this by sliding a window over the + images in an input tensor and outputting, for each channel, the maximum + element within the window. + + If _nr == 0 then it means the filter size covers all the rows in the input + tensor, similarly for the _nc parameter. To be precise, if we call the + input tensor IN and the output tensor OUT, then OUT is defined as follows: + - let FILT_NR == (nr()==0) ? IN.nr() : nr() + - let FILT_NC == (nc()==0) ? IN.nc() : nc() + - OUT.num_samples() == IN.num_samples() + - OUT.k() == IN.k() + - OUT.nr() == 1+(IN.nr() + 2*padding_y() - FILT_NR)/stride_y() + - OUT.nc() == 1+(IN.nc() + 2*padding_x() - FILT_NC)/stride_x() + - for all valid s, k, r, and c: + - image_plane(OUT,s,k)(r,c) == max(subm_clipped(image_plane(IN,s,k), + centered_rect(x*stride_x() + FILT_NC/2 - padding_x(), + y*stride_y() + FILT_NR/2 - padding_y(), + FILT_NC, + FILT_NR))) + !*/ + + public: + + max_pool_ ( + ); + /*! + ensures + - #nr() == _nr + - #nc() == _nc + - #stride_y() == _stride_y + - #stride_x() == _stride_x + - #padding_y() == _padding_y + - #padding_x() == _padding_x + !*/ + + long nr( + ) const; + /*! + ensures + - returns the number of rows in the pooling window or 0 if the window size + is "the entire input tensor". + !*/ + + long nc( + ) const; + /*! + ensures + - returns the number of rows in the pooling window or 0 if the window size + is "the entire input tensor". + !*/ + + long stride_y( + ) const; + /*! + ensures + - returns the vertical stride used when scanning the max pooling window + over an image. That is, each window will be moved stride_y() pixels down + at a time when it moves over the image. + !*/ + + long stride_x( + ) const; + /*! + ensures + - returns the horizontal stride used when scanning the max pooling window + over an image. That is, each window will be moved stride_x() pixels down + at a time when it moves over the image. + !*/ + + long padding_y( + ) const; + /*! + ensures + - returns the number of pixels of zero padding added to the top and bottom + sides of the image. + !*/ + + long padding_x( + ) const; + /*! + ensures + - returns the number of pixels of zero padding added to the left and right + sides of the image. + !*/ + + template void setup (const SUBNET& sub); + template void forward(const SUBNET& sub, resizable_tensor& output); + template void backward(const tensor& computed_output, const tensor& gradient_input, SUBNET& sub, tensor& params_grad); + dpoint map_input_to_output(dpoint p) const; + dpoint map_output_to_input(dpoint p) const; + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ + interface. Note that this layer doesn't have any parameters, so the tensor + returned by get_layer_params() is always empty. + !*/ + }; + + template < + long nr, + long nc, + int stride_y, + int stride_x, + typename SUBNET + > + using max_pool = add_layer, SUBNET>; + + template < + typename SUBNET + > + using max_pool_everything = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + + template < + long _nr, + long _nc, + int _stride_y, + int _stride_x, + int _padding_y = _stride_y!=1? 0 : _nr/2, + int _padding_x = _stride_x!=1? 0 : _nc/2 + > + class avg_pool_ + { + /*! + REQUIREMENTS ON TEMPLATE ARGUMENTS + - _nr >= 0 + - _nc >= 0 + - _stride_y > 0 + - _stride_x > 0 + - _padding_y >= 0 + - _padding_x >= 0 + - if (_nr != 0) then + - _padding_y < _nr + - else + - _padding_y == 0 + - if (_nc != 0) then + - _padding_x < _nr + - else + - _padding_x == 0 + + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. In particular, it defines an average pooling layer that + takes an input tensor and downsamples it. It does this by sliding a window + over the images in an input tensor and outputting, for each channel, the + average element within the window. + + If _nr == 0 then it means the filter size covers all the rows in the input + tensor, similarly for the _nc parameter. To be precise, if we call the + input tensor IN and the output tensor OUT, then OUT is defined as follows: + - let FILT_NR == (nr()==0) ? IN.nr() : nr() + - let FILT_NC == (nc()==0) ? IN.nc() : nc() + - OUT.num_samples() == IN.num_samples() + - OUT.k() == IN.k() + - OUT.nr() == 1+(IN.nr() + 2*padding_y() - FILT_NR)/stride_y() + - OUT.nc() == 1+(IN.nc() + 2*padding_x() - FILT_NC)/stride_x() + - for all valid s, k, r, and c: + - image_plane(OUT,s,k)(r,c) == mean(subm_clipped(image_plane(IN,s,k), + centered_rect(x*stride_x() + FILT_NC/2 - padding_x(), + y*stride_y() + FILT_NR/2 - padding_y(), + FILT_NC, + FILT_NR))) + !*/ + + public: + + avg_pool_ ( + ); + /*! + ensures + - #nr() == _nr + - #nc() == _nc + - #stride_y() == _stride_y + - #stride_x() == _stride_x + - #padding_y() == _padding_y + - #padding_x() == _padding_x + !*/ + + long nr( + ) const; + /*! + ensures + - returns the number of rows in the pooling window or 0 if the window size + is "the entire input tensor". + !*/ + + long nc( + ) const; + /*! + ensures + - returns the number of rows in the pooling window or 0 if the window size + is "the entire input tensor". + !*/ + + long stride_y( + ) const; + /*! + ensures + - returns the vertical stride used when scanning the pooling window + over an image. That is, each window will be moved stride_y() pixels down + at a time when it moves over the image. + !*/ + + long stride_x( + ) const; + /*! + ensures + - returns the horizontal stride used when scanning the pooling window + over an image. That is, each window will be moved stride_x() pixels down + at a time when it moves over the image. + !*/ + + long padding_y( + ) const; + /*! + ensures + - returns the number of pixels of zero padding added to the top and bottom + sides of the image. + !*/ + + long padding_x( + ) const; + /*! + ensures + - returns the number of pixels of zero padding added to the left and right + sides of the image. + !*/ + + template void setup (const SUBNET& sub); + template void forward(const SUBNET& sub, resizable_tensor& output); + template void backward(const tensor& computed_output, const tensor& gradient_input, SUBNET& sub, tensor& params_grad); + dpoint map_input_to_output(dpoint p) const; + dpoint map_output_to_input(dpoint p) const; + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ + interface. Note that this layer doesn't have any parameters, so the tensor + returned by get_layer_params() is always empty. + !*/ + + }; + + template < + long nr, + long nc, + int stride_y, + int stride_x, + typename SUBNET + > + using avg_pool = add_layer, SUBNET>; + + template < + typename SUBNET + > + using avg_pool_everything = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + + class relu_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. In particular, it defines a rectified linear layer. + Therefore, it passes its inputs through the function + f(x)=max(x,0) + where f() is applied pointwise across the input tensor. + !*/ + + public: + + relu_( + ); + + template void setup (const SUBNET& sub); + void forward_inplace(const tensor& input, tensor& output); + void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad); + dpoint map_input_to_output(dpoint p) const; + dpoint map_output_to_input(dpoint p) const; + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ + interface. Note that this layer doesn't have any parameters, so the tensor + returned by get_layer_params() is always empty. + !*/ + }; + + template + using relu = add_layer; + +// ---------------------------------------------------------------------------------------- + + class prelu_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. In particular, it defines a parametric rectified linear + layer. Therefore, it passes its inputs through the function + f(x) = x>0 ? x : p*x + where f() is applied pointwise across the input tensor and p is a scalar + parameter learned by this layer. + + + This is the layer type introduced in the paper: + He, Kaiming, et al. "Delving deep into rectifiers: Surpassing + human-level performance on imagenet classification." Proceedings of the + IEEE International Conference on Computer Vision. 2015. + !*/ + + public: + + explicit prelu_( + float initial_param_value = 0.25 + ); + /*! + ensures + - The p parameter will be initialized with initial_param_value. + - #get_initial_param_value() == initial_param_value. + !*/ + + float get_initial_param_value ( + ) const; + /*! + ensures + - returns the initial value of the prelu parameter. + !*/ + + template void setup (const SUBNET& sub); + void forward_inplace(const tensor& input, tensor& output); + void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad); + dpoint map_input_to_output(dpoint p) const; + dpoint map_output_to_input(dpoint p) const; + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface. + !*/ + }; + + template + using prelu = add_layer; + +// ---------------------------------------------------------------------------------------- + + class sig_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. In particular, it defines a sigmoid layer. Therefore, it + passes its inputs through the function + f(x)=1/(1+exp(-x)) + where f() is applied pointwise across the input tensor. + !*/ + + public: + + sig_( + ); + + template void setup (const SUBNET& sub); + void forward_inplace(const tensor& input, tensor& output); + void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad); + dpoint map_input_to_output(dpoint p) const; + dpoint map_output_to_input(dpoint p) const; + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ + interface. Note that this layer doesn't have any parameters, so the tensor + returned by get_layer_params() is always empty. + !*/ + }; + + template + using sig = add_layer; + +// ---------------------------------------------------------------------------------------- + + class htan_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. In particular, it defines a hyperbolic tangent layer. + Therefore, it passes its inputs through the function + f(x)=std::tanh(x) + where f() is applied pointwise across the input tensor. + !*/ + + public: + + htan_( + ); + + template void setup (const SUBNET& sub); + void forward_inplace(const tensor& input, tensor& output); + void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad); + dpoint map_input_to_output(dpoint p) const; + dpoint map_output_to_input(dpoint p) const; + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ + interface. Note that this layer doesn't have any parameters, so the tensor + returned by get_layer_params() is always empty. + !*/ + }; + + template + using htan = add_layer; + +// ---------------------------------------------------------------------------------------- + + class softmax_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. In particular, it defines a softmax layer. To be precise, + we define the softmax function s(x) as: + s(x) == exp(x)/sum(exp(x)) + where x is a vector. Then this layer treats its input tensor as a + collection of multi-channel images and applies s() to each spatial location + in each image. In each application, the tensor::k() channel elements at + each position are input to s() and then replaced by the outputs of s(). + + This means that, for example, if you collapsed each output image to a 1 + channel image by adding the channels then you would end up with images + where each pixel value was 1. This is because the sum of the outputs of + s() will always be equal to 1. + !*/ + + public: + + softmax_( + ); + + template void setup (const SUBNET& sub); + void forward_inplace(const tensor& input, tensor& output); + void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad); + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ + interface. Note that this layer doesn't have any parameters, so the tensor + returned by get_layer_params() is always empty. + !*/ + }; + + template + using softmax = add_layer; + +// ---------------------------------------------------------------------------------------- + + class softmax_all_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. In particular, it defines a softmax layer. To be precise, + we define the softmax function s(x) as: + s(x) == exp(x)/sum(exp(x)) + where x is a vector. Then this layer treats its input tensor as a + collection of tensor::num_samples() vectors and applies s() to each vector + in the tensor. Therefore, there are logically tensor::num_samples() + invocations of s(). + !*/ + + public: + + softmax_all_( + ); + + template void setup (const SUBNET& sub); + void forward_inplace(const tensor& input, tensor& output); + void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad); + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ + interface. Note that this layer doesn't have any parameters, so the tensor + returned by get_layer_params() is always empty. + !*/ + }; + + template + using softmax_all = add_layer; + +// ---------------------------------------------------------------------------------------- + + template < + template class tag + > + class add_prev_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. This layer simply adds the output of two previous layers. + In particular, it adds the tensor from its immediate predecessor layer, + sub.get_output(), with the tensor from a deeper layer, + layer(sub).get_output(). + + Therefore, you supply a tag via add_prev_'s template argument that tells it + what layer to add to the output of the previous layer. The result of this + addition is output by add_prev_. Finally, the addition happens pointwise + according to 4D tensor arithmetic. If the dimensions don't match then + missing elements are presumed to be equal to 0. Moreover, each dimension + of the output tensor is equal to the maximum dimension of either of the + inputs. That is, if the tensors A and B are being added to produce C then: + - C.num_samples() == max(A.num_samples(), B.num_samples()) + - C.k() == max(A.k(), B.k()) + - C.nr() == max(A.nr(), B.nr()) + - C.nc() == max(A.nc(), B.nc()) + !*/ + + public: + add_prev_( + ); + + template void setup (const SUBNET& sub); + template void forward(const SUBNET& sub, resizable_tensor& output); + template void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad); + dpoint map_input_to_output(dpoint p) const; + dpoint map_output_to_input(dpoint p) const; + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface. + !*/ + }; + + + template < + template class tag, + typename SUBNET + > + using add_prev = add_layer, SUBNET>; + + // Here we add some convenient aliases for using add_prev_ with the tag layers. + template using add_prev1 = add_prev; + template using add_prev2 = add_prev; + template using add_prev3 = add_prev; + template using add_prev4 = add_prev; + template using add_prev5 = add_prev; + template using add_prev6 = add_prev; + template using add_prev7 = add_prev; + template using add_prev8 = add_prev; + template using add_prev9 = add_prev; + template using add_prev10 = add_prev; + using add_prev1_ = add_prev_; + using add_prev2_ = add_prev_; + using add_prev3_ = add_prev_; + using add_prev4_ = add_prev_; + using add_prev5_ = add_prev_; + using add_prev6_ = add_prev_; + using add_prev7_ = add_prev_; + using add_prev8_ = add_prev_; + using add_prev9_ = add_prev_; + using add_prev10_ = add_prev_; + +// ---------------------------------------------------------------------------------------- + + template < + template class tag + > + class mult_prev_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. This layer simply multiplies the output of two previous + layers. In particular, it multiplies the tensor from its immediate + predecessor layer, sub.get_output(), with the tensor from a deeper layer, + layer(sub).get_output(). + + Therefore, you supply a tag via mult_prev_'s template argument that tells + it what layer to multiply with the output of the previous layer. The + result of this multiplication is output by mult_prev_. Finally, the + multiplication happens pointwise according to 4D tensor arithmetic. If the + dimensions don't match then missing elements are presumed to be equal to 0. + Moreover, each dimension of the output tensor is equal to the maximum + dimension of either of the inputs. That is, if the tensors A and B are + being multiplied to produce C then: + - C.num_samples() == max(A.num_samples(), B.num_samples()) + - C.k() == max(A.k(), B.k()) + - C.nr() == max(A.nr(), B.nr()) + - C.nc() == max(A.nc(), B.nc()) + !*/ + + public: + mult_prev_( + ); + + template void setup (const SUBNET& sub); + template void forward(const SUBNET& sub, resizable_tensor& output); + template void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad); + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface. + !*/ + }; + + + template < + template class tag, + typename SUBNET + > + using mult_prev = add_layer, SUBNET>; + + // Here we add some convenient aliases for using mult_prev_ with the tag layers. + template using mult_prev1 = mult_prev; + template using mult_prev2 = mult_prev; + template using mult_prev3 = mult_prev; + template using mult_prev4 = mult_prev; + template using mult_prev5 = mult_prev; + template using mult_prev6 = mult_prev; + template using mult_prev7 = mult_prev; + template using mult_prev8 = mult_prev; + template using mult_prev9 = mult_prev; + template using mult_prev10 = mult_prev; + using mult_prev1_ = mult_prev_; + using mult_prev2_ = mult_prev_; + using mult_prev3_ = mult_prev_; + using mult_prev4_ = mult_prev_; + using mult_prev5_ = mult_prev_; + using mult_prev6_ = mult_prev_; + using mult_prev7_ = mult_prev_; + using mult_prev8_ = mult_prev_; + using mult_prev9_ = mult_prev_; + using mult_prev10_ = mult_prev_; + +// ---------------------------------------------------------------------------------------- + + template < + template class tag + > + class scale_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. This layer scales the output channels of the tagged layer + by multiplying it with the output of the previous layer. To be specific: + - Let INPUT == layer(sub).get_output() + - Let SCALES == sub.get_output() + - This layer takes INPUT and SCALES as input. + - The output of this layer has the same dimensions as INPUT. + - This layer requires: + - SCALES.num_samples() == INPUT.num_samples() + - SCALES.k() == INPUT.k() + - SCALES.nr() == 1 + - SCALES.nc() == 1 + - The output tensor is produced by pointwise multiplying SCALES with + INPUT at each spatial location. Therefore, if OUT is the output of + this layer then we would have: + OUT(n,k,r,c) == INPUT(n,k,r,c)*SCALES(n,k) + !*/ + + public: + scale_( + ); + + template void setup (const SUBNET& sub); + template void forward(const SUBNET& sub, resizable_tensor& output); + template void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad); + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface. + !*/ + }; + + + template < + template class tag, + typename SUBNET + > + using scale = add_layer, SUBNET>; + + // Here we add some convenient aliases for using scale_ with the tag layers. + template using scale1 = scale; + template using scale2 = scale; + template using scale3 = scale; + template using scale4 = scale; + template using scale5 = scale; + template using scale6 = scale; + template using scale7 = scale; + template using scale8 = scale; + template using scale9 = scale; + template using scale10 = scale; + using scale1_ = scale_; + using scale2_ = scale_; + using scale3_ = scale_; + using scale4_ = scale_; + using scale5_ = scale_; + using scale6_ = scale_; + using scale7_ = scale_; + using scale8_ = scale_; + using scale9_ = scale_; + using scale10_ = scale_; + +// ---------------------------------------------------------------------------------------- + + template< + template class... TAG_TYPES + > + class concat_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. This layer simply concatenates the output of tagged layers. + Importantly, each input layer must have the same dimensions (i.e. + num_samples, nr, and nc) except for the k channel, which may vary. This is + because the concatenation happens along the k dimension. That is, the + output of this network is a tensor, OUT, that is the concatenation of the + tensors: + for each (tag in TAG_TYPES) + layer(subnet).get_output() + Therefore, out.num_samples(), out.nr(), and out.nc() match the dimensions + of the input tensors while OUT.k() is the sum of the input layer's k() + dimensions. + !*/ + + public: + template void setup (const SUBNET& sub); + template void forward(const SUBNET& sub, resizable_tensor& output); + template void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad); + dpoint map_input_to_output(dpoint p) const; + dpoint map_output_to_input(dpoint p) const; + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface. + !*/ + }; + + + // concat layer definitions + template class TAG1, + template class TAG2, + typename SUBNET> + using concat2 = add_layer, SUBNET>; + + template class TAG1, + template class TAG2, + template class TAG3, + typename SUBNET> + using concat3 = add_layer, SUBNET>; + + template class TAG1, + template class TAG2, + template class TAG3, + template class TAG4, + typename SUBNET> + using concat4 = add_layer, SUBNET>; + + template class TAG1, + template class TAG2, + template class TAG3, + template class TAG4, + template class TAG5, + typename SUBNET> + using concat5 = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + + /*!A inception layer definitions !*/ + + // Now define inception layer tag types. These layer aliases allow creating + // the networks described in the paper: + // Szegedy, Christian, et al. "Going deeper with convolutions." Proceedings of + // the IEEE Conference on Computer Vision and Pattern Recognition. 2015. + // See the dnn_inception_ex.cpp example for a complete example of their use. Note also + // that we use tag ID numbers >= 1000 to avoid conflict with user's tag layers. + template using itag0 = add_tag_layer< 1000 + 0, SUBNET>; + template using itag1 = add_tag_layer< 1000 + 1, SUBNET>; + template using itag2 = add_tag_layer< 1000 + 2, SUBNET>; + template using itag3 = add_tag_layer< 1000 + 3, SUBNET>; + template using itag4 = add_tag_layer< 1000 + 4, SUBNET>; + template using itag5 = add_tag_layer< 1000 + 5, SUBNET>; + // skip to inception input + template using iskip = add_skip_layer< itag0, SUBNET>; + + // here are some templates to be used for creating inception layer groups + template class B1, + templateclass B2, + typename SUBNET> + using inception2 = concat2>>>>>>; + + template class B1, + templateclass B2, + templateclass B3, + typename SUBNET> + using inception3 = concat3>>>>>>>>>; + + template class B1, + templateclass B2, + templateclass B3, + templateclass B4, + typename SUBNET> + using inception4 = concat4>>>>>>>>>>>>; + + template class B1, + templateclass B2, + templateclass B3, + templateclass B4, + templateclass B5, + typename SUBNET> + using inception5 = concat5>>>>>>>>>>>>>>>; + +// ---------------------------------------------------------------------------------------- + + const double DEFAULT_L2_NORM_EPS = 1e-5; + + class l2normalize_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. It takes tensors as input and L2 normalizes them. In particular, + it has the following properties: + - The output tensors from this layer have the same dimensions as the + input tensors. + - If you think of each input tensor as a set of tensor::num_samples() + vectors, then the output tensor contains the same vectors except they + have been length normalized so that their L2 norms are all 1. I.e. + for each vector v we will have ||v||==1. + !*/ + + public: + + explicit l2normalize_( + double eps = tt::DEFAULT_L2_NORM_EPS + ); + /*! + requires + - eps > 0 + ensures + - #get_eps() == eps + !*/ + + double get_eps( + ) const; + /*! + ensures + - When we normalize a vector we divide it by its L2 norm. However, the + get_eps() value is added to the squared norm prior to division to avoid + ever dividing by zero. + !*/ + + template void setup (const SUBNET& sub); + void forward_inplace(const tensor& input, tensor& output); + void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad); + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface. + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + template < + long _offset, + long _k, + long _nr, + long _nc + > + class extract_ + { + /*! + REQUIREMENTS ON TEMPLATE ARGUMENTS + - 0 <= _offset + - 0 < _k + - 0 < _nr + - 0 < _nc + + WHAT THIS OBJECT REPRESENTS + This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface + defined above. In particular, the output of this layer is simply a copy of + the input tensor. However, you can configure the extract layer to output + only some subset of the input tensor and also to reshape it. Therefore, + the dimensions of the tensor output by this layer are as follows (letting + IN be the input tensor and OUT the output tensor): + - OUT.num_samples() == IN.num_samples() + - OUT.k() == _k + - OUT.nr() == _nr + - OUT.nc() == _nc + + So the output will always have the same number of samples as the input, but + within each sample (the k,nr,nc part) we will copy only a subset of the + values. Moreover, the _offset parameter controls which part of each sample + we take. To be very precise, we will have: + - let IN_SIZE = IN.k()*IN.nr()*IN.nc() + - let OUT_SIZE = _k*_nr*_nc + - for i in range[0,IN.num_samples()) and j in range[0,OUT_SIZE): + - OUT.host()[i*OUT_SIZE+j] == IN.host()[i*IN_SIZE+_offset+j] + + + Finally, all this means that the input tensor to this layer must have a big + enough size to accommodate taking a _k*_nr*_nc slice from each of its + samples. + !*/ + + public: + + template void setup (const SUBNET& sub); + template void forward(const SUBNET& sub, resizable_tensor& output); + template void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad); + const tensor& get_layer_params() const; + tensor& get_layer_params(); + /*! + These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface. + !*/ + }; + + template < + long offset, + long k, + long nr, + long nc, + typename SUBNET + > + using extract = add_layer, SUBNET>; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DNn_LAYERS_ABSTRACT_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/dnn/loss.h b/lib/3rdParty/dlib/include/dlib/dnn/loss.h new file mode 100644 index 00000000..f30cec5c --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/dnn/loss.h @@ -0,0 +1,2882 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DNn_LOSS_H_ +#define DLIB_DNn_LOSS_H_ + +#include "loss_abstract.h" +#include "core.h" +#include "../matrix.h" +#include "../cuda/tensor_tools.h" +#include "../geometry.h" +#include "../image_processing/box_overlap_testing.h" +#include "../image_processing/full_object_detection.h" +#include "../svm/ranking_tools.h" +#include +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class loss_binary_hinge_ + { + public: + + typedef float training_label_type; + typedef float output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const + { + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + + const tensor& output_tensor = sub.get_output(); + DLIB_CASSERT(output_tensor.nr() == 1 && + output_tensor.nc() == 1 && + output_tensor.k() == 1); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + + const float* out_data = output_tensor.host(); + for (long i = 0; i < output_tensor.num_samples(); ++i) + { + *iter++ = out_data[i]; + } + } + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const + { + const tensor& output_tensor = sub.get_output(); + tensor& grad = sub.get_gradient_input(); + + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + DLIB_CASSERT(input_tensor.num_samples() != 0); + DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0); + DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples()); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + DLIB_CASSERT(output_tensor.nr() == 1 && + output_tensor.nc() == 1 && + output_tensor.k() == 1); + + // The loss we output is the average loss over the mini-batch. + const double scale = 1.0/output_tensor.num_samples(); + double loss = 0; + const float* out_data = output_tensor.host(); + float* g = grad.host_write_only(); + for (long i = 0; i < output_tensor.num_samples(); ++i) + { + const float y = *truth++; + DLIB_CASSERT(y == +1 || y == -1, "y: " << y); + const float temp = 1-y*out_data[i]; + if (temp > 0) + { + loss += scale*temp; + g[i] = -scale*y; + } + else + { + g[i] = 0; + } + } + return loss; + } + + friend void serialize(const loss_binary_hinge_& , std::ostream& out) + { + serialize("loss_binary_hinge_", out); + } + + friend void deserialize(loss_binary_hinge_& , std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "loss_binary_hinge_") + throw serialization_error("Unexpected version found while deserializing dlib::loss_binary_hinge_."); + } + + friend std::ostream& operator<<(std::ostream& out, const loss_binary_hinge_& ) + { + out << "loss_binary_hinge"; + return out; + } + + friend void to_xml(const loss_binary_hinge_& /*item*/, std::ostream& out) + { + out << ""; + } + + }; + + template + using loss_binary_hinge = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_binary_log_ + { + public: + + typedef float training_label_type; + typedef float output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const + { + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + + const tensor& output_tensor = sub.get_output(); + DLIB_CASSERT(output_tensor.nr() == 1 && + output_tensor.nc() == 1 && + output_tensor.k() == 1); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + + const float* out_data = output_tensor.host(); + for (long i = 0; i < output_tensor.num_samples(); ++i) + { + *iter++ = out_data[i]; + } + } + + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const + { + const tensor& output_tensor = sub.get_output(); + tensor& grad = sub.get_gradient_input(); + + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + DLIB_CASSERT(input_tensor.num_samples() != 0); + DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0); + DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples()); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + DLIB_CASSERT(output_tensor.nr() == 1 && + output_tensor.nc() == 1 && + output_tensor.k() == 1); + DLIB_CASSERT(grad.nr() == 1 && + grad.nc() == 1 && + grad.k() == 1); + + tt::sigmoid(grad, output_tensor); + + // The loss we output is the average loss over the mini-batch. + const double scale = 1.0/output_tensor.num_samples(); + double loss = 0; + float* g = grad.host(); + const float* out_data = output_tensor.host(); + for (long i = 0; i < output_tensor.num_samples(); ++i) + { + const float y = *truth++; + DLIB_CASSERT(y == +1 || y == -1, "y: " << y); + float temp; + if (y > 0) + { + temp = log1pexp(-out_data[i]); + loss += scale*temp; + g[i] = scale*(g[i]-1); + } + else + { + temp = -(-out_data[i]-log1pexp(-out_data[i])); + loss += scale*temp; + g[i] = scale*g[i]; + } + } + return loss; + } + + friend void serialize(const loss_binary_log_& , std::ostream& out) + { + serialize("loss_binary_log_", out); + } + + friend void deserialize(loss_binary_log_& , std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "loss_binary_log_") + throw serialization_error("Unexpected version found while deserializing dlib::loss_binary_log_."); + } + + friend std::ostream& operator<<(std::ostream& out, const loss_binary_log_& ) + { + out << "loss_binary_log"; + return out; + } + + friend void to_xml(const loss_binary_log_& /*item*/, std::ostream& out) + { + out << ""; + } + + }; + + template + T safe_log(T input, T epsilon = 1e-10) + { + // Prevent trying to calculate the logarithm of a very small number (let alone zero) + return std::log(std::max(input, epsilon)); + } + + template + using loss_binary_log = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_multiclass_log_ + { + public: + + typedef unsigned long training_label_type; + typedef unsigned long output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const + { + const tensor& output_tensor = sub.get_output(); + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + DLIB_CASSERT(output_tensor.nr() == 1 && + output_tensor.nc() == 1 ); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + + + // Note that output_tensor.k() should match the number of labels. + + for (long i = 0; i < output_tensor.num_samples(); ++i) + { + // The index of the largest output for this sample is the label. + *iter++ = index_of_max(rowm(mat(output_tensor),i)); + } + } + + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const + { + const tensor& output_tensor = sub.get_output(); + tensor& grad = sub.get_gradient_input(); + + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + DLIB_CASSERT(input_tensor.num_samples() != 0); + DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0); + DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples()); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + DLIB_CASSERT(output_tensor.nr() == 1 && + output_tensor.nc() == 1); + DLIB_CASSERT(grad.nr() == 1 && + grad.nc() == 1); + + tt::softmax(grad, output_tensor); + + // The loss we output is the average loss over the mini-batch. + const double scale = 1.0/output_tensor.num_samples(); + double loss = 0; + float* g = grad.host(); + for (long i = 0; i < output_tensor.num_samples(); ++i) + { + const long y = (long)*truth++; + // The network must produce a number of outputs that is equal to the number + // of labels when using this type of loss. + DLIB_CASSERT(y < output_tensor.k(), "y: " << y << ", output_tensor.k(): " << output_tensor.k()); + for (long k = 0; k < output_tensor.k(); ++k) + { + const unsigned long idx = i*output_tensor.k()+k; + if (k == y) + { + loss += scale*-safe_log(g[idx]); + g[idx] = scale*(g[idx]-1); + } + else + { + g[idx] = scale*g[idx]; + } + } + } + return loss; + } + + friend void serialize(const loss_multiclass_log_& , std::ostream& out) + { + serialize("loss_multiclass_log_", out); + } + + friend void deserialize(loss_multiclass_log_& , std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "loss_multiclass_log_") + throw serialization_error("Unexpected version found while deserializing dlib::loss_multiclass_log_."); + } + + friend std::ostream& operator<<(std::ostream& out, const loss_multiclass_log_& ) + { + out << "loss_multiclass_log"; + return out; + } + + friend void to_xml(const loss_multiclass_log_& /*item*/, std::ostream& out) + { + out << ""; + } + + }; + + template + using loss_multiclass_log = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_multimulticlass_log_ + { + + public: + + loss_multimulticlass_log_ () = default; + + loss_multimulticlass_log_ ( + const std::map>& labels + ) + { + for (auto& l : labels) + { + possible_labels[l.first] = std::make_shared(l.second); + DLIB_CASSERT(l.second.size() >= 2, "Each classifier must have at least two possible labels."); + + for (size_t i = 0; i < l.second.size(); ++i) + { + label_idx_lookup[l.first][l.second[i]] = i; + ++total_num_labels; + } + } + } + + unsigned long number_of_labels() const { return total_num_labels; } + + unsigned long number_of_classifiers() const { return possible_labels.size(); } + + std::map> get_labels ( + ) const + { + std::map> info; + for (auto& i : possible_labels) + { + for (auto& label : *i.second) + info[i.first].emplace_back(label); + } + return info; + } + + class classifier_output + { + + public: + classifier_output() = default; + + size_t num_classes() const { return class_probs.size(); } + + double probability_of_class ( + size_t i + ) const + { + DLIB_CASSERT(i < num_classes()); + return class_probs(i); + } + + const std::string& label( + size_t i + ) const + { + DLIB_CASSERT(i < num_classes()); + return (*_labels)[i]; + } + + operator std::string( + ) const + { + DLIB_CASSERT(num_classes() != 0); + return (*_labels)[index_of_max(class_probs)]; + } + + friend std::ostream& operator<< (std::ostream& out, const classifier_output& item) + { + DLIB_ASSERT(item.num_classes() != 0); + out << static_cast(item); + return out; + } + + private: + + friend class loss_multimulticlass_log_; + + template + classifier_output( + const matrix_exp& class_probs, + const std::shared_ptr>& _labels + ) : + class_probs(class_probs), + _labels(_labels) + { + } + + matrix class_probs; + std::shared_ptr> _labels; + }; + + typedef std::map training_label_type; + typedef std::map output_label_type; + + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter_begin + ) const + { + const tensor& output_tensor = sub.get_output(); + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + DLIB_CASSERT(output_tensor.nr() == 1 && + output_tensor.nc() == 1 ); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + + DLIB_CASSERT(number_of_labels() != 0, "You must give the loss_multimulticlass_log_'s constructor label data before you can use it!"); + DLIB_CASSERT(output_tensor.k() == (long)number_of_labels(), "The output tensor must have " << number_of_labels() << " channels."); + + + long k_offset = 0; + for (auto& l : possible_labels) + { + auto iter = iter_begin; + const std::string& classifier_name = l.first; + const auto& labels = (*l.second); + scratch.set_size(output_tensor.num_samples(), labels.size()); + tt::copy_tensor(false, scratch, 0, output_tensor, k_offset, labels.size()); + + tt::softmax(scratch, scratch); + + for (long i = 0; i < scratch.num_samples(); ++i) + (*iter++)[classifier_name] = classifier_output(rowm(mat(scratch),i), l.second); + + k_offset += labels.size(); + } + } + + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth_begin, + SUBNET& sub + ) const + { + const tensor& output_tensor = sub.get_output(); + tensor& grad = sub.get_gradient_input(); + + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + DLIB_CASSERT(input_tensor.num_samples() != 0); + DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0); + DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples()); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + DLIB_CASSERT(output_tensor.nr() == 1 && + output_tensor.nc() == 1); + DLIB_CASSERT(grad.nr() == 1 && + grad.nc() == 1); + DLIB_CASSERT(number_of_labels() != 0, "You must give the loss_multimulticlass_log_'s constructor label data before you can use it!"); + DLIB_CASSERT(output_tensor.k() == (long)number_of_labels(), "The output tensor must have " << number_of_labels() << " channels."); + + // The loss we output is the average loss over the mini-batch. + const double scale = 1.0/output_tensor.num_samples(); + double loss = 0; + long k_offset = 0; + for (auto& l : label_idx_lookup) + { + const std::string& classifier_name = l.first; + const auto& int_labels = l.second; + scratch.set_size(output_tensor.num_samples(), int_labels.size()); + tt::copy_tensor(false, scratch, 0, output_tensor, k_offset, int_labels.size()); + + tt::softmax(scratch, scratch); + + + auto truth = truth_begin; + float* g = scratch.host(); + for (long i = 0; i < scratch.num_samples(); ++i) + { + const long y = int_labels.at(truth->at(classifier_name)); + ++truth; + + for (long k = 0; k < scratch.k(); ++k) + { + const unsigned long idx = i*scratch.k()+k; + if (k == y) + { + loss += scale*-std::log(g[idx]); + g[idx] = scale*(g[idx]-1); + } + else + { + g[idx] = scale*g[idx]; + } + } + } + + tt::copy_tensor(false, grad, k_offset, scratch, 0, int_labels.size()); + + k_offset += int_labels.size(); + } + return loss; + } + + + friend void serialize(const loss_multimulticlass_log_& item, std::ostream& out) + { + serialize("loss_multimulticlass_log_", out); + serialize(item.get_labels(), out); + } + + friend void deserialize(loss_multimulticlass_log_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "loss_multimulticlass_log_") + throw serialization_error("Unexpected version found while deserializing dlib::loss_multimulticlass_log_."); + + std::map> info; + deserialize(info, in); + item = loss_multimulticlass_log_(info); + } + + friend std::ostream& operator<<(std::ostream& out, const loss_multimulticlass_log_& item) + { + out << "loss_multimulticlass_log, labels={"; + for (auto i = item.possible_labels.begin(); i != item.possible_labels.end(); ) + { + auto& category = i->first; + auto& labels = *(i->second); + out << category << ":("; + for (size_t j = 0; j < labels.size(); ++j) + { + out << labels[j]; + if (j+1 < labels.size()) + out << ","; + } + + out << ")"; + if (++i != item.possible_labels.end()) + out << ", "; + } + out << "}"; + return out; + } + + friend void to_xml(const loss_multimulticlass_log_& item, std::ostream& out) + { + out << "\n"; + out << item; + out << "\n"; + } + + private: + + std::map>> possible_labels; + unsigned long total_num_labels = 0; + + // We make it true that: possible_labels[classifier][label_idx_lookup[classifier][label]] == label + std::map> label_idx_lookup; + + + // Scratch doesn't logically contribute to the state of this object. It's just + // temporary scratch space used by this class. + mutable resizable_tensor scratch; + + + }; + + template + using loss_multimulticlass_log = add_loss_layer; + + inline bool operator== (const std::string& lhs, const loss_multimulticlass_log_::classifier_output& rhs) + { return lhs == static_cast(rhs); } + inline bool operator== (const loss_multimulticlass_log_::classifier_output& lhs, const std::string& rhs) + { return rhs == static_cast(lhs); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + enum class use_image_pyramid : uint8_t + { + no, + yes + }; + + struct mmod_options + { + public: + + struct detector_window_details + { + detector_window_details() = default; + detector_window_details(unsigned long w, unsigned long h) : width(w), height(h) {} + detector_window_details(unsigned long w, unsigned long h, const std::string& l) : width(w), height(h), label(l) {} + + unsigned long width = 0; + unsigned long height = 0; + std::string label; + + friend inline void serialize(const detector_window_details& item, std::ostream& out) + { + int version = 2; + serialize(version, out); + serialize(item.width, out); + serialize(item.height, out); + serialize(item.label, out); + } + + friend inline void deserialize(detector_window_details& item, std::istream& in) + { + int version = 0; + deserialize(version, in); + if (version != 1 && version != 2) + throw serialization_error("Unexpected version found while deserializing dlib::mmod_options::detector_window_details"); + deserialize(item.width, in); + deserialize(item.height, in); + if (version == 2) + deserialize(item.label, in); + } + + }; + + mmod_options() = default; + + std::vector detector_windows; + double loss_per_false_alarm = 1; + double loss_per_missed_target = 1; + double truth_match_iou_threshold = 0.5; + test_box_overlap overlaps_nms = test_box_overlap(0.4); + test_box_overlap overlaps_ignore; + + use_image_pyramid assume_image_pyramid = use_image_pyramid::yes; + + mmod_options ( + const std::vector>& boxes, + const unsigned long target_size, // We want the length of the longest dimension of the detector window to be this. + const unsigned long min_target_size, // But we require that the smallest dimension of the detector window be at least this big. + const double min_detector_window_overlap_iou = 0.75 + ) + { + DLIB_CASSERT(0 < min_target_size && min_target_size <= target_size); + DLIB_CASSERT(0.5 < min_detector_window_overlap_iou && min_detector_window_overlap_iou < 1); + + // Figure out what detector windows we will need. + for (auto& label : get_labels(boxes)) + { + for (auto ratio : find_covering_aspect_ratios(boxes, test_box_overlap(min_detector_window_overlap_iou), label)) + { + double detector_width; + double detector_height; + if (ratio < 1) + { + detector_height = target_size; + detector_width = ratio*target_size; + if (detector_width < min_target_size) + { + detector_height = min_target_size/ratio; + detector_width = min_target_size; + } + } + else + { + detector_width = target_size; + detector_height = target_size/ratio; + if (detector_height < min_target_size) + { + detector_width = min_target_size*ratio; + detector_height = min_target_size; + } + } + + detector_window_details p((unsigned long)std::round(detector_width), (unsigned long)std::round(detector_height), label); + detector_windows.push_back(p); + } + } + + DLIB_CASSERT(detector_windows.size() != 0, "You can't call mmod_options's constructor with a set of boxes that is empty (or only contains ignored boxes)."); + + set_overlap_nms(boxes); + } + + mmod_options( + use_image_pyramid assume_image_pyramid, + const std::vector>& boxes, + const double min_detector_window_overlap_iou = 0.75 + ) + : assume_image_pyramid(assume_image_pyramid) + { + DLIB_CASSERT(assume_image_pyramid == use_image_pyramid::no); + DLIB_CASSERT(0.5 < min_detector_window_overlap_iou && min_detector_window_overlap_iou < 1); + + // Figure out what detector windows we will need. + for (auto& label : get_labels(boxes)) + { + for (auto rectangle : find_covering_rectangles(boxes, test_box_overlap(min_detector_window_overlap_iou), label)) + { + detector_windows.push_back(detector_window_details(rectangle.width(), rectangle.height(), label)); + } + } + + DLIB_CASSERT(detector_windows.size() != 0, "You can't call mmod_options's constructor with a set of boxes that is empty (or only contains ignored boxes)."); + + set_overlap_nms(boxes); + } + + private: + + void set_overlap_nms(const std::vector>& boxes) + { + // Convert from mmod_rect to rectangle so we can call + // find_tight_overlap_tester(). + std::vector> temp; + for (auto&& bi : boxes) + { + std::vector rtemp; + for (auto&& b : bi) + { + if (b.ignore) + continue; + rtemp.push_back(b.rect); + } + temp.push_back(std::move(rtemp)); + } + overlaps_nms = find_tight_overlap_tester(temp); + // Relax the non-max-suppression a little so that it doesn't accidentally make + // it impossible for the detector to output boxes matching the training data. + // This could be a problem with the tightest possible nms test since there is + // some small variability in how boxes get positioned between the training data + // and the coordinate system used by the detector when it runs. So relaxing it + // here takes care of that. + auto iou_thresh = advance_toward_1(overlaps_nms.get_iou_thresh()); + auto percent_covered_thresh = advance_toward_1(overlaps_nms.get_percent_covered_thresh()); + overlaps_nms = test_box_overlap(iou_thresh, percent_covered_thresh); + } + + static double advance_toward_1 ( + double val + ) + { + if (val < 1) + val += (1-val)*0.1; + return val; + } + + static size_t count_overlaps ( + const std::vector& rects, + const test_box_overlap& overlaps, + const rectangle& ref_box + ) + { + size_t cnt = 0; + for (auto& b : rects) + { + if (overlaps(b, ref_box)) + ++cnt; + } + return cnt; + } + + static std::vector find_rectangles_overlapping_all_others ( + std::vector rects, + const test_box_overlap& overlaps + ) + { + std::vector exemplars; + dlib::rand rnd; + + while(rects.size() > 0) + { + // Pick boxes at random and see if they overlap a lot of other boxes. We will try + // 500 different boxes each iteration and select whichever hits the most others to + // add to our exemplar set. + rectangle best_ref_box; + size_t best_cnt = 0; + for (int iter = 0; iter < 500; ++iter) + { + rectangle ref_box = rects[rnd.get_random_64bit_number()%rects.size()]; + size_t cnt = count_overlaps(rects, overlaps, ref_box); + if (cnt >= best_cnt) + { + best_cnt = cnt; + best_ref_box = ref_box; + } + } + + // Now mark all the boxes the new ref box hit as hit. + for (size_t i = 0; i < rects.size(); ++i) + { + if (overlaps(rects[i], best_ref_box)) + { + // remove box from rects so we don't hit it again later + swap(rects[i], rects.back()); + rects.pop_back(); + --i; + } + } + + exemplars.push_back(best_ref_box); + } + + return exemplars; + } + + static std::set get_labels ( + const std::vector>& rects + ) + { + std::set labels; + for (auto& rr : rects) + { + for (auto& r : rr) + labels.insert(r.label); + } + return labels; + } + + static std::vector find_covering_aspect_ratios ( + const std::vector>& rects, + const test_box_overlap& overlaps, + const std::string& label + ) + { + std::vector boxes; + // Make sure all the boxes have the same size and position, so that the only thing our + // checks for overlap will care about is aspect ratio (i.e. scale and x,y position are + // ignored). + for (auto& bb : rects) + { + for (auto&& b : bb) + { + if (!b.ignore && b.label == label) + boxes.push_back(move_rect(set_rect_area(b.rect,400*400), point(0,0))); + } + } + + std::vector ratios; + for (auto r : find_rectangles_overlapping_all_others(boxes, overlaps)) + ratios.push_back(r.width()/(double)r.height()); + return ratios; + } + + static std::vector find_covering_rectangles ( + const std::vector>& rects, + const test_box_overlap& overlaps, + const std::string& label + ) + { + std::vector boxes; + // Make sure all the boxes have the same position, so that the we only check for + // width and height. + for (auto& bb : rects) + { + for (auto&& b : bb) + { + if (!b.ignore && b.label == label) + boxes.push_back(rectangle(b.rect.width(), b.rect.height())); + } + } + + return find_rectangles_overlapping_all_others(boxes, overlaps); + } + }; + + inline void serialize(const mmod_options& item, std::ostream& out) + { + int version = 3; + + serialize(version, out); + serialize(item.detector_windows, out); + serialize(item.loss_per_false_alarm, out); + serialize(item.loss_per_missed_target, out); + serialize(item.truth_match_iou_threshold, out); + serialize(item.overlaps_nms, out); + serialize(item.overlaps_ignore, out); + serialize(static_cast(item.assume_image_pyramid), out); + } + + inline void deserialize(mmod_options& item, std::istream& in) + { + int version = 0; + deserialize(version, in); + if (version != 3 && version != 2 && version != 1) + throw serialization_error("Unexpected version found while deserializing dlib::mmod_options"); + if (version == 1) + { + unsigned long width; + unsigned long height; + deserialize(width, in); + deserialize(height, in); + item.detector_windows = {mmod_options::detector_window_details(width, height)}; + } + else + { + deserialize(item.detector_windows, in); + } + deserialize(item.loss_per_false_alarm, in); + deserialize(item.loss_per_missed_target, in); + deserialize(item.truth_match_iou_threshold, in); + deserialize(item.overlaps_nms, in); + deserialize(item.overlaps_ignore, in); + item.assume_image_pyramid = use_image_pyramid::yes; + if (version >= 3) + { + uint8_t assume_image_pyramid = 0; + deserialize(assume_image_pyramid, in); + item.assume_image_pyramid = static_cast(assume_image_pyramid); + } + } + +// ---------------------------------------------------------------------------------------- + + class loss_mmod_ + { + struct intermediate_detection + { + intermediate_detection() = default; + + intermediate_detection( + rectangle rect_ + ) : rect(rect_) {} + + intermediate_detection( + rectangle rect_, + double detection_confidence_, + size_t tensor_offset_, + long channel + ) : rect(rect_), detection_confidence(detection_confidence_), tensor_offset(tensor_offset_), tensor_channel(channel) {} + + rectangle rect; + double detection_confidence = 0; + size_t tensor_offset = 0; + long tensor_channel = 0; + + bool operator<(const intermediate_detection& item) const { return detection_confidence < item.detection_confidence; } + }; + + public: + + typedef std::vector training_label_type; + typedef std::vector output_label_type; + + loss_mmod_() {} + + loss_mmod_(mmod_options options_) : options(options_) {} + + const mmod_options& get_options ( + ) const { return options; } + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter, + double adjust_threshold = 0 + ) const + { + const tensor& output_tensor = sub.get_output(); + DLIB_CASSERT(output_tensor.k() == (long)options.detector_windows.size()); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + DLIB_CASSERT(sub.sample_expansion_factor() == 1, sub.sample_expansion_factor()); + + std::vector dets_accum; + output_label_type final_dets; + for (long i = 0; i < output_tensor.num_samples(); ++i) + { + tensor_to_dets(input_tensor, output_tensor, i, dets_accum, adjust_threshold, sub); + + // Do non-max suppression + final_dets.clear(); + for (unsigned long i = 0; i < dets_accum.size(); ++i) + { + if (overlaps_any_box_nms(final_dets, dets_accum[i].rect)) + continue; + + final_dets.push_back(mmod_rect(dets_accum[i].rect, + dets_accum[i].detection_confidence, + options.detector_windows[dets_accum[i].tensor_channel].label)); + } + + *iter++ = std::move(final_dets); + } + } + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const + { + const tensor& output_tensor = sub.get_output(); + tensor& grad = sub.get_gradient_input(); + + DLIB_CASSERT(input_tensor.num_samples() != 0); + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples()); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + DLIB_CASSERT(output_tensor.k() == (long)options.detector_windows.size()); + + double det_thresh_speed_adjust = 0; + + + // we will scale the loss so that it doesn't get really huge + const double scale = 1.0/output_tensor.size(); + double loss = 0; + + float* g = grad.host_write_only(); + for (size_t i = 0; i < grad.size(); ++i) + g[i] = 0; + + const float* out_data = output_tensor.host(); + + std::vector truth_idxs; truth_idxs.reserve(truth->size()); + std::vector dets; + for (long i = 0; i < output_tensor.num_samples(); ++i) + { + tensor_to_dets(input_tensor, output_tensor, i, dets, -options.loss_per_false_alarm + det_thresh_speed_adjust, sub); + + const unsigned long max_num_dets = 50 + truth->size()*5; + // Prevent calls to tensor_to_dets() from running for a really long time + // due to the production of an obscene number of detections. + const unsigned long max_num_initial_dets = max_num_dets*100; + if (dets.size() >= max_num_initial_dets) + { + det_thresh_speed_adjust = std::max(det_thresh_speed_adjust,dets[max_num_initial_dets].detection_confidence + options.loss_per_false_alarm); + } + + + // The loss will measure the number of incorrect detections. A detection is + // incorrect if it doesn't hit a truth rectangle or if it is a duplicate detection + // on a truth rectangle. + loss += truth->size()*options.loss_per_missed_target; + for (auto&& x : *truth) + { + if (!x.ignore) + { + size_t k; + point p; + if(image_rect_to_feat_coord(p, input_tensor, x, x.label, sub, k, options.assume_image_pyramid)) + { + // Ignore boxes that can't be detected by the CNN. + loss -= options.loss_per_missed_target; + continue; + } + const size_t idx = (k*output_tensor.nr() + p.y())*output_tensor.nc() + p.x(); + loss -= out_data[idx]; + // compute gradient + g[idx] = -scale; + truth_idxs.push_back(idx); + } + else + { + // This box was ignored so shouldn't have been counted in the loss. + loss -= options.loss_per_missed_target; + truth_idxs.push_back(0); + } + } + + // Measure the loss augmented score for the detections which hit a truth rect. + std::vector truth_score_hits(truth->size(), 0); + + // keep track of which truth boxes we have hit so far. + std::vector hit_truth_table(truth->size(), false); + + std::vector final_dets; + // The point of this loop is to fill out the truth_score_hits array. + for (unsigned long i = 0; i < dets.size() && final_dets.size() < max_num_dets; ++i) + { + if (overlaps_any_box_nms(final_dets, dets[i].rect)) + continue; + + const auto& det_label = options.detector_windows[dets[i].tensor_channel].label; + + const std::pair hittruth = find_best_match(*truth, dets[i].rect, det_label); + + final_dets.push_back(dets[i].rect); + + const double truth_match = hittruth.first; + // if hit truth rect + if (truth_match > options.truth_match_iou_threshold) + { + // if this is the first time we have seen a detect which hit (*truth)[hittruth.second] + const double score = dets[i].detection_confidence; + if (hit_truth_table[hittruth.second] == false) + { + hit_truth_table[hittruth.second] = true; + truth_score_hits[hittruth.second] += score; + } + else + { + truth_score_hits[hittruth.second] += score + options.loss_per_false_alarm; + } + } + } + + // Check if any of the truth boxes are unobtainable because the NMS is + // killing them. If so, automatically set those unobtainable boxes to + // ignore and print a warning message to the user. + for (size_t i = 0; i < hit_truth_table.size(); ++i) + { + if (!hit_truth_table[i] && !(*truth)[i].ignore) + { + // So we didn't hit this truth box. Is that because there is + // another, different truth box, that overlaps it according to NMS? + const std::pair hittruth = find_best_match(*truth, (*truth)[i], i); + if (hittruth.second == i || (*truth)[hittruth.second].ignore) + continue; + rectangle best_matching_truth_box = (*truth)[hittruth.second]; + if (options.overlaps_nms(best_matching_truth_box, (*truth)[i])) + { + const size_t idx = truth_idxs[i]; + // We are ignoring this box so we shouldn't have counted it in the + // loss in the first place. So we subtract out the loss values we + // added for it in the code above. + loss -= options.loss_per_missed_target-out_data[idx]; + g[idx] = 0; + std::cout << "Warning, ignoring object. We encountered a truth rectangle located at " << (*truth)[i].rect; + std::cout << " that is suppressed by non-max-suppression "; + std::cout << "because it is overlapped by another truth rectangle located at " << best_matching_truth_box + << " (IoU:"<< box_intersection_over_union(best_matching_truth_box,(*truth)[i]) <<", Percent covered:" + << box_percent_covered(best_matching_truth_box,(*truth)[i]) << ")." << std::endl; + } + } + } + + hit_truth_table.assign(hit_truth_table.size(), false); + final_dets.clear(); + + + // Now figure out which detections jointly maximize the loss and detection score sum. We + // need to take into account the fact that allowing a true detection in the output, while + // initially reducing the loss, may allow us to increase the loss later with many duplicate + // detections. + for (unsigned long i = 0; i < dets.size() && final_dets.size() < max_num_dets; ++i) + { + if (overlaps_any_box_nms(final_dets, dets[i].rect)) + continue; + + const auto& det_label = options.detector_windows[dets[i].tensor_channel].label; + + const std::pair hittruth = find_best_match(*truth, dets[i].rect, det_label); + + const double truth_match = hittruth.first; + if (truth_match > options.truth_match_iou_threshold) + { + if (truth_score_hits[hittruth.second] > options.loss_per_missed_target) + { + if (!hit_truth_table[hittruth.second]) + { + hit_truth_table[hittruth.second] = true; + final_dets.push_back(dets[i]); + loss -= options.loss_per_missed_target; + } + else + { + final_dets.push_back(dets[i]); + loss += options.loss_per_false_alarm; + } + } + } + else if (!overlaps_ignore_box(*truth, dets[i].rect)) + { + // didn't hit anything + final_dets.push_back(dets[i]); + loss += options.loss_per_false_alarm; + } + } + + for (auto&& x : final_dets) + { + loss += out_data[x.tensor_offset]; + g[x.tensor_offset] += scale; + } + + ++truth; + g += output_tensor.k()*output_tensor.nr()*output_tensor.nc(); + out_data += output_tensor.k()*output_tensor.nr()*output_tensor.nc(); + } // END for (long i = 0; i < output_tensor.num_samples(); ++i) + + + // Here we scale the loss so that it's roughly equal to the number of mistakes + // in an image. Note that this scaling is different than the scaling we + // applied to the gradient but it doesn't matter since the loss value isn't + // used to update parameters. It's used only for display and to check if we + // have converged. So it doesn't matter that they are scaled differently and + // this way the loss that is displayed is readily interpretable to the user. + return loss/output_tensor.num_samples(); + } + + + friend void serialize(const loss_mmod_& item, std::ostream& out) + { + serialize("loss_mmod_", out); + serialize(item.options, out); + } + + friend void deserialize(loss_mmod_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "loss_mmod_") + throw serialization_error("Unexpected version found while deserializing dlib::loss_mmod_."); + deserialize(item.options, in); + } + + friend std::ostream& operator<<(std::ostream& out, const loss_mmod_& item) + { + out << "loss_mmod\t ("; + + out << "detector_windows:("; + auto& opts = item.options; + for (size_t i = 0; i < opts.detector_windows.size(); ++i) + { + out << opts.detector_windows[i].width << "x" << opts.detector_windows[i].height; + if (i+1 < opts.detector_windows.size()) + out << ","; + } + out << ")"; + out << ", loss per FA:" << opts.loss_per_false_alarm; + out << ", loss per miss:" << opts.loss_per_missed_target; + out << ", truth match IOU thresh:" << opts.truth_match_iou_threshold; + out << ", overlaps_nms:("<"; + } + + private: + + template + void tensor_to_dets ( + const tensor& input_tensor, + const tensor& output_tensor, + long i, + std::vector& dets_accum, + double adjust_threshold, + const net_type& net + ) const + { + DLIB_CASSERT(net.sample_expansion_factor() == 1,net.sample_expansion_factor()); + DLIB_CASSERT(output_tensor.k() == (long)options.detector_windows.size()); + const float* out_data = output_tensor.host() + output_tensor.k()*output_tensor.nr()*output_tensor.nc()*i; + // scan the final layer and output the positive scoring locations + dets_accum.clear(); + for (long k = 0; k < output_tensor.k(); ++k) + { + for (long r = 0; r < output_tensor.nr(); ++r) + { + for (long c = 0; c < output_tensor.nc(); ++c) + { + double score = out_data[(k*output_tensor.nr() + r)*output_tensor.nc() + c]; + if (score > adjust_threshold) + { + dpoint p = output_tensor_to_input_tensor(net, point(c,r)); + drectangle rect = centered_drect(p, options.detector_windows[k].width, options.detector_windows[k].height); + rect = input_layer(net).tensor_space_to_image_space(input_tensor,rect); + + dets_accum.push_back(intermediate_detection(rect, score, (k*output_tensor.nr() + r)*output_tensor.nc() + c, k)); + } + } + } + } + std::sort(dets_accum.rbegin(), dets_accum.rend()); + } + + size_t find_best_detection_window ( + rectangle rect, + const std::string& label, + use_image_pyramid assume_image_pyramid + ) const + { + if (assume_image_pyramid == use_image_pyramid::yes) + { + rect = move_rect(set_rect_area(rect, 400*400), point(0,0)); + } + else + { + rect = rectangle(rect.width(), rect.height()); + } + + // Figure out which detection window in options.detector_windows is most similar to rect + // (in terms of aspect ratio, if assume_image_pyramid == use_image_pyramid::yes). + size_t best_i = 0; + double best_ratio_diff = -std::numeric_limits::infinity(); + for (size_t i = 0; i < options.detector_windows.size(); ++i) + { + if (options.detector_windows[i].label != label) + continue; + + rectangle det_window; + + if (options.assume_image_pyramid == use_image_pyramid::yes) + { + det_window = centered_rect(point(0,0), options.detector_windows[i].width, options.detector_windows[i].height); + det_window = move_rect(set_rect_area(det_window, 400*400), point(0,0)); + } + else + { + det_window = rectangle(options.detector_windows[i].width, options.detector_windows[i].height); + } + + double iou = box_intersection_over_union(rect, det_window); + if (iou > best_ratio_diff) + { + best_ratio_diff = iou; + best_i = i; + } + } + return best_i; + } + + template + bool image_rect_to_feat_coord ( + point& tensor_p, + const tensor& input_tensor, + const rectangle& rect, + const std::string& label, + const net_type& net, + size_t& det_idx, + use_image_pyramid assume_image_pyramid + ) const + { + using namespace std; + if (!input_layer(net).image_contained_point(input_tensor,center(rect))) + { + std::ostringstream sout; + sout << "Encountered a truth rectangle located at " << rect << " that is outside the image." << endl; + sout << "The center of each truth rectangle must be within the image." << endl; + throw impossible_labeling_error(sout.str()); + } + + det_idx = find_best_detection_window(rect,label,assume_image_pyramid); + + double scale = 1.0; + if (options.assume_image_pyramid == use_image_pyramid::yes) + { + // Compute the scale we need to be at to get from rect to our detection window. + // Note that we compute the scale as the max of two numbers. It doesn't + // actually matter which one we pick, because if they are very different then + // it means the box can't be matched by the sliding window. But picking the + // max causes the right error message to be selected in the logic below. + scale = std::max(options.detector_windows[det_idx].width/(double)rect.width(), options.detector_windows[det_idx].height/(double)rect.height()); + } + else + { + // We don't want invariance to scale. + scale = 1.0; + } + + const rectangle mapped_rect = input_layer(net).image_space_to_tensor_space(input_tensor, std::min(1.0,scale), rect); + + // compute the detection window that we would use at this position. + tensor_p = center(mapped_rect); + rectangle det_window = centered_rect(tensor_p, options.detector_windows[det_idx].width,options.detector_windows[det_idx].height); + det_window = input_layer(net).tensor_space_to_image_space(input_tensor, det_window); + + // make sure the rect can actually be represented by the image pyramid we are + // using. + if (box_intersection_over_union(rect, det_window) <= options.truth_match_iou_threshold) + { + std::cout << "Warning, ignoring object. We encountered a truth rectangle with a width and height of " << rect.width() << " and " << rect.height() << ". "; + std::cout << "The image pyramid and sliding windows can't output a rectangle of this shape. "; + const double detector_area = options.detector_windows[det_idx].width*options.detector_windows[det_idx].height; + if (mapped_rect.area()/detector_area <= options.truth_match_iou_threshold) + { + std::cout << "This is because the rectangle is smaller than the best matching detection window, which has a width "; + std::cout << "and height of " << options.detector_windows[det_idx].width << " and " << options.detector_windows[det_idx].height << "." << std::endl; + } + else + { + std::cout << "This is either because (1) the final layer's features have too large of a stride across the image, limiting the possible locations the sliding window can search "; + std::cout << "or (2) because the rectangle's aspect ratio is too different from the best matching detection window, "; + std::cout << "which has a width and height of " << options.detector_windows[det_idx].width << " and " << options.detector_windows[det_idx].height << "." << std::endl; + } + return true; + } + + // now map through the CNN to the output layer. + tensor_p = input_tensor_to_output_tensor(net,tensor_p); + + const tensor& output_tensor = net.get_output(); + if (!get_rect(output_tensor).contains(tensor_p)) + { + std::cout << "Warning, ignoring object. We encountered a truth rectangle located at " << rect << " that is too close to the edge "; + std::cout << "of the image to be captured by the CNN features." << std::endl; + return true; + } + + return false; + } + + + bool overlaps_ignore_box ( + const std::vector& boxes, + const rectangle& rect + ) const + { + for (auto&& b : boxes) + { + if (b.ignore && options.overlaps_ignore(b, rect)) + return true; + } + return false; + } + + std::pair find_best_match( + const std::vector& boxes, + const rectangle& rect, + const std::string& label + ) const + { + double match = 0; + unsigned int best_idx = 0; + for (unsigned long i = 0; i < boxes.size(); ++i) + { + if (boxes[i].ignore || boxes[i].label != label) + continue; + + const double new_match = box_intersection_over_union(rect, boxes[i]); + if (new_match > match) + { + match = new_match; + best_idx = i; + } + } + + return std::make_pair(match,best_idx); + } + + std::pair find_best_match( + const std::vector& boxes, + const rectangle& rect, + const size_t excluded_idx + ) const + { + double match = 0; + unsigned int best_idx = 0; + for (unsigned long i = 0; i < boxes.size(); ++i) + { + if (boxes[i].ignore || excluded_idx == i) + continue; + + const double new_match = box_intersection_over_union(rect, boxes[i]); + if (new_match > match) + { + match = new_match; + best_idx = i; + } + } + + return std::make_pair(match,best_idx); + } + + template + inline bool overlaps_any_box_nms ( + const std::vector& rects, + const rectangle& rect + ) const + { + for (auto&& r : rects) + { + if (options.overlaps_nms(r.rect, rect)) + return true; + } + return false; + } + + + mmod_options options; + + }; + + template + using loss_mmod = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_metric_ + { + public: + + typedef unsigned long training_label_type; + typedef matrix output_label_type; + + loss_metric_() = default; + + loss_metric_( + float margin_, + float dist_thresh_ + ) : margin(margin_), dist_thresh(dist_thresh_) + { + DLIB_CASSERT(margin_ > 0); + DLIB_CASSERT(dist_thresh_ > 0); + } + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const + { + const tensor& output_tensor = sub.get_output(); + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + DLIB_CASSERT(input_tensor.num_samples() != 0); + DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + DLIB_CASSERT(output_tensor.nr() == 1 && + output_tensor.nc() == 1); + + const float* p = output_tensor.host(); + for (long i = 0; i < output_tensor.num_samples(); ++i) + { + *iter = mat(p,output_tensor.k(),1); + + ++iter; + p += output_tensor.k(); + } + } + + + float get_margin() const { return margin; } + float get_distance_threshold() const { return dist_thresh; } + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const + { + const tensor& output_tensor = sub.get_output(); + tensor& grad = sub.get_gradient_input(); + + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + DLIB_CASSERT(input_tensor.num_samples() != 0); + DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0); + DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples()); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + DLIB_CASSERT(output_tensor.nr() == 1 && + output_tensor.nc() == 1); + DLIB_CASSERT(grad.nr() == 1 && + grad.nc() == 1); + + + + temp.set_size(output_tensor.num_samples(), output_tensor.num_samples()); + grad_mul.copy_size(temp); + + tt::gemm(0, temp, 1, output_tensor, false, output_tensor, true); + + + std::vector temp_threshs; + const float* d = temp.host(); + double loss = 0; + double num_pos_samps = 0.0001; + double num_neg_samps = 0.0001; + for (long r = 0; r < temp.num_samples(); ++r) + { + auto xx = d[r*temp.num_samples() + r]; + const auto x_label = *(truth + r); + for (long c = r+1; c < temp.num_samples(); ++c) + { + const auto y_label = *(truth + c); + if (x_label == y_label) + { + ++num_pos_samps; + } + else + { + ++num_neg_samps; + + // Figure out what distance threshold, when applied to the negative pairs, + // causes there to be an equal number of positive and negative pairs. + auto yy = d[c*temp.num_samples() + c]; + auto xy = d[r*temp.num_samples() + c]; + // compute the distance between x and y samples. + auto d2 = xx + yy - 2*xy; + if (d2 < 0) + d2 = 0; + temp_threshs.push_back(d2); + } + } + } + // The whole objective function is multiplied by this to scale the loss + // relative to the number of things in the mini-batch. + const double scale = 0.5/num_pos_samps; + DLIB_CASSERT(num_pos_samps>=1, "Make sure each mini-batch contains both positive pairs and negative pairs"); + DLIB_CASSERT(num_neg_samps>=1, "Make sure each mini-batch contains both positive pairs and negative pairs"); + + std::sort(temp_threshs.begin(), temp_threshs.end()); + const float neg_thresh = std::sqrt(temp_threshs[std::min(num_pos_samps,num_neg_samps)-1]); + + // loop over all the pairs of training samples and compute the loss and + // gradients. Note that we only use the hardest negative pairs and that in + // particular we pick the number of negative pairs equal to the number of + // positive pairs so everything is balanced. + float* gm = grad_mul.host(); + for (long r = 0; r < temp.num_samples(); ++r) + { + gm[r*temp.num_samples() + r] = 0; + const auto x_label = *(truth + r); + auto xx = d[r*temp.num_samples() + r]; + for (long c = 0; c < temp.num_samples(); ++c) + { + if (r==c) + continue; + const auto y_label = *(truth + c); + auto yy = d[c*temp.num_samples() + c]; + auto xy = d[r*temp.num_samples() + c]; + + // compute the distance between x and y samples. + auto d2 = xx + yy - 2*xy; + if (d2 <= 0) + d2 = 0; + else + d2 = std::sqrt(d2); + + // It should be noted that the derivative of length(x-y) with respect + // to the x vector is the unit vector (x-y)/length(x-y). If you stare + // at the code below long enough you will see that it's just an + // application of this formula. + + if (x_label == y_label) + { + // Things with the same label should have distances < dist_thresh between + // them. If not then we experience non-zero loss. + if (d2 < dist_thresh-margin) + { + gm[r*temp.num_samples() + c] = 0; + } + else + { + loss += scale*(d2 - (dist_thresh-margin)); + gm[r*temp.num_samples() + r] += scale/d2; + gm[r*temp.num_samples() + c] = -scale/d2; + } + } + else + { + // Things with different labels should have distances > dist_thresh between + // them. If not then we experience non-zero loss. + if (d2 > dist_thresh+margin || d2 > neg_thresh) + { + gm[r*temp.num_samples() + c] = 0; + } + else + { + loss += scale*((dist_thresh+margin) - d2); + // don't divide by zero (or a really small number) + d2 = std::max(d2, 0.001f); + gm[r*temp.num_samples() + r] -= scale/d2; + gm[r*temp.num_samples() + c] = scale/d2; + } + } + } + } + + + tt::gemm(0, grad, 1, grad_mul, false, output_tensor, false); + + return loss; + } + + friend void serialize(const loss_metric_& item, std::ostream& out) + { + serialize("loss_metric_2", out); + serialize(item.margin, out); + serialize(item.dist_thresh, out); + } + + friend void deserialize(loss_metric_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version == "loss_metric_") + { + // These values used to be hard coded, so for this version of the metric + // learning loss we just use these values. + item.margin = 0.1; + item.dist_thresh = 0.75; + return; + } + else if (version == "loss_metric_2") + { + deserialize(item.margin, in); + deserialize(item.dist_thresh, in); + } + else + { + throw serialization_error("Unexpected version found while deserializing dlib::loss_metric_. Instead found " + version); + } + } + + friend std::ostream& operator<<(std::ostream& out, const loss_metric_& item ) + { + out << "loss_metric (margin="<"; + } + + private: + float margin = 0.04; + float dist_thresh = 0.6; + + + // These variables are only here to avoid being reallocated over and over in + // compute_loss_value_and_gradient() + mutable resizable_tensor temp, grad_mul; + + }; + + template + using loss_metric = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_ranking_ + { + public: + + typedef float training_label_type; // nominally +1/-1 + typedef float output_label_type; // ranking score + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const + { + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + + const tensor& output_tensor = sub.get_output(); + + DLIB_CASSERT(output_tensor.nr() == 1 && + output_tensor.nc() == 1 && + output_tensor.k() == 1); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + + const float* out_data = output_tensor.host(); + for (long i = 0; i < output_tensor.num_samples(); ++i) + { + *iter++ = out_data[i]; + } + } + + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const + { + const tensor& output_tensor = sub.get_output(); + tensor& grad = sub.get_gradient_input(); + + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + DLIB_CASSERT(input_tensor.num_samples() != 0); + DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0); + DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples()); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + DLIB_CASSERT(output_tensor.nr() == 1 && + output_tensor.nc() == 1 && + output_tensor.k() == 1); + DLIB_CASSERT(grad.nr() == 1 && + grad.nc() == 1 && + grad.k() == 1); + + + std::vector rel_scores; + std::vector nonrel_scores; + std::vector rel_idx, nonrel_idx; + + const float* out_data = output_tensor.host(); + float* g = grad.host_write_only(); + for (long i = 0; i < output_tensor.num_samples(); ++i) + { + const float y = *truth++; + if (y > 0) + { + rel_scores.push_back(out_data[i]-y); + rel_idx.push_back(i); + } + else if (y < 0) + { + nonrel_scores.push_back(out_data[i]-y); + nonrel_idx.push_back(i); + } + else + { + g[i] = 0; + } + } + + + std::vector rel_counts; + std::vector nonrel_counts; + count_ranking_inversions(rel_scores, nonrel_scores, rel_counts, nonrel_counts); + const unsigned long total_pairs = rel_scores.size()*nonrel_scores.size(); + DLIB_CASSERT(total_pairs > 0, "You can't give a ranking mini-batch that contains only one class. Both classes must be represented."); + const double scale = 1.0/total_pairs; + + + double loss = 0; + for (unsigned long k = 0; k < rel_counts.size(); ++k) + { + loss -= rel_counts[k]*rel_scores[k]; + g[rel_idx[k]] = -1.0*rel_counts[k]*scale; + } + + for (unsigned long k = 0; k < nonrel_counts.size(); ++k) + { + loss += nonrel_counts[k]*nonrel_scores[k]; + g[nonrel_idx[k]] = nonrel_counts[k]*scale; + } + + return loss*scale; + } + + friend void serialize(const loss_ranking_& , std::ostream& out) + { + serialize("loss_ranking_", out); + } + + friend void deserialize(loss_ranking_& , std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "loss_ranking_") + throw serialization_error("Unexpected version found while deserializing dlib::loss_ranking_."); + } + + friend std::ostream& operator<<(std::ostream& out, const loss_ranking_& ) + { + out << "loss_ranking"; + return out; + } + + friend void to_xml(const loss_ranking_& /*item*/, std::ostream& out) + { + out << ""; + } + + }; + + template + using loss_ranking = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_mean_squared_ + { + public: + + typedef float training_label_type; + typedef float output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const + { + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + + const tensor& output_tensor = sub.get_output(); + + DLIB_CASSERT(output_tensor.nr() == 1 && + output_tensor.nc() == 1 && + output_tensor.k() == 1); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + + const float* out_data = output_tensor.host(); + for (long i = 0; i < output_tensor.num_samples(); ++i) + { + *iter++ = out_data[i]; + } + } + + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const + { + const tensor& output_tensor = sub.get_output(); + tensor& grad = sub.get_gradient_input(); + + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + DLIB_CASSERT(input_tensor.num_samples() != 0); + DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0); + DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples()); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + DLIB_CASSERT(output_tensor.nr() == 1 && + output_tensor.nc() == 1 && + output_tensor.k() == 1); + DLIB_CASSERT(grad.nr() == 1 && + grad.nc() == 1 && + grad.k() == 1); + + // The loss we output is the average loss over the mini-batch. + const double scale = 1.0/output_tensor.num_samples(); + double loss = 0; + float* g = grad.host_write_only(); + const float* out_data = output_tensor.host(); + for (long i = 0; i < output_tensor.num_samples(); ++i) + { + const float y = *truth++; + const float temp1 = y - out_data[i]; + const float temp2 = scale*temp1; + loss += temp2*temp1; + g[i] = -temp2; + + } + return loss; + } + + friend void serialize(const loss_mean_squared_& , std::ostream& out) + { + serialize("loss_mean_squared_", out); + } + + friend void deserialize(loss_mean_squared_& , std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "loss_mean_squared_") + throw serialization_error("Unexpected version found while deserializing dlib::loss_mean_squared_."); + } + + friend std::ostream& operator<<(std::ostream& out, const loss_mean_squared_& ) + { + out << "loss_mean_squared"; + return out; + } + + friend void to_xml(const loss_mean_squared_& /*item*/, std::ostream& out) + { + out << ""; + } + + }; + + template + using loss_mean_squared = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_epsilon_insensitive_ + { + public: + + typedef float training_label_type; + typedef float output_label_type; + + loss_epsilon_insensitive_() = default; + loss_epsilon_insensitive_(double eps) : eps(eps) + { + DLIB_CASSERT(eps >= 0, "You can't set a negative error epsilon."); + } + + double get_epsilon () const { return eps; } + void set_epsilon(double e) + { + DLIB_CASSERT(e >= 0, "You can't set a negative error epsilon."); + eps = e; + } + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const + { + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + + const tensor& output_tensor = sub.get_output(); + + DLIB_CASSERT(output_tensor.nr() == 1 && + output_tensor.nc() == 1 && + output_tensor.k() == 1); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + + const float* out_data = output_tensor.host(); + for (long i = 0; i < output_tensor.num_samples(); ++i) + { + *iter++ = out_data[i]; + } + } + + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const + { + const tensor& output_tensor = sub.get_output(); + tensor& grad = sub.get_gradient_input(); + + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + DLIB_CASSERT(input_tensor.num_samples() != 0); + DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0); + DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples()); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + DLIB_CASSERT(output_tensor.nr() == 1 && + output_tensor.nc() == 1 && + output_tensor.k() == 1); + DLIB_CASSERT(grad.nr() == 1 && + grad.nc() == 1 && + grad.k() == 1); + + // The loss we output is the average loss over the mini-batch. + const double scale = 1.0/output_tensor.num_samples(); + double loss = 0; + float* g = grad.host_write_only(); + const float* out_data = output_tensor.host(); + for (long i = 0; i < output_tensor.num_samples(); ++i) + { + const float y = *truth++; + const float err = out_data[i]-y; + if (err > eps) + { + loss += scale*(err-eps); + g[i] = scale; + } + else if (err < -eps) + { + loss += scale*(eps-err); + g[i] = -scale; + } + } + return loss; + } + + friend void serialize(const loss_epsilon_insensitive_& item, std::ostream& out) + { + serialize("loss_epsilon_insensitive_", out); + serialize(item.eps, out); + } + + friend void deserialize(loss_epsilon_insensitive_& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "loss_epsilon_insensitive_") + throw serialization_error("Unexpected version found while deserializing dlib::loss_epsilon_insensitive_."); + deserialize(item.eps, in); + } + + friend std::ostream& operator<<(std::ostream& out, const loss_epsilon_insensitive_& item) + { + out << "loss_epsilon_insensitive epsilon: " << item.eps; + return out; + } + + friend void to_xml(const loss_epsilon_insensitive_& item, std::ostream& out) + { + out << ""; + } + + private: + double eps = 1; + + }; + + template + using loss_epsilon_insensitive = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_mean_squared_multioutput_ + { + public: + + typedef matrix training_label_type; + typedef matrix output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const + { + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + + const tensor& output_tensor = sub.get_output(); + + DLIB_CASSERT(output_tensor.nr() == 1 && + output_tensor.nc() == 1) + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + + const float* out_data = output_tensor.host(); + for (long i = 0; i < output_tensor.num_samples(); ++i) + { + *iter++ = mat(out_data, output_tensor.k(), 1); + out_data += output_tensor.k(); + } + } + + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const + { + const tensor& output_tensor = sub.get_output(); + tensor& grad = sub.get_gradient_input(); + + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + DLIB_CASSERT(input_tensor.num_samples() != 0); + DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0); + DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples()); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + DLIB_CASSERT(output_tensor.nr() == 1 && + output_tensor.nc() == 1); + DLIB_CASSERT(grad.nr() == 1 && + grad.nc() == 1); + DLIB_CASSERT(grad.k() == output_tensor.k()); + const long k = output_tensor.k(); + for (long idx = 0; idx < output_tensor.num_samples(); ++idx) + { + const_label_iterator truth_matrix_ptr = (truth + idx); + DLIB_CASSERT((*truth_matrix_ptr).nr() == k && + (*truth_matrix_ptr).nc() == 1); + } + + // The loss we output is the average loss over the mini-batch. + const double scale = 1.0/output_tensor.num_samples(); + double loss = 0; + float* g = grad.host_write_only(); + const float* out_data = output_tensor.host(); + matrix ytrue; + for (long i = 0; i < output_tensor.num_samples(); ++i) + { + ytrue = *truth++; + for (long j = 0; j < output_tensor.k(); ++j) + { + const float y = ytrue(j, 0); + const float temp1 = y - *out_data++; + const float temp2 = scale*temp1; + loss += temp2*temp1; + *g = -temp2; + ++g; + } + + } + return loss; + } + + friend void serialize(const loss_mean_squared_multioutput_& , std::ostream& out) + { + serialize("loss_mean_squared_multioutput_", out); + } + + friend void deserialize(loss_mean_squared_multioutput_& , std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "loss_mean_squared_multioutput_") + throw serialization_error("Unexpected version found while deserializing dlib::loss_mean_squared_."); + } + + friend std::ostream& operator<<(std::ostream& out, const loss_mean_squared_multioutput_& ) + { + out << "loss_mean_squared_multioutput"; + return out; + } + + friend void to_xml(const loss_mean_squared_multioutput_& /*item*/, std::ostream& out) + { + out << ""; + } + + }; + + template + using loss_mean_squared_multioutput = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_multiclass_log_per_pixel_ + { + public: + + // In semantic segmentation, if you don't know the ground-truth of some pixel, + // set the label of that pixel to this value. When you do so, the pixel will be + // ignored when computing gradients. + static const uint16_t label_to_ignore = std::numeric_limits::max(); + + + // In semantic segmentation, 65535 classes ought to be enough for anybody. + typedef matrix training_label_type; + typedef matrix output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + static void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) + { + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + + const tensor& output_tensor = sub.get_output(); + + DLIB_CASSERT(output_tensor.k() >= 1); // Note that output_tensor.k() should match the number of labels. + DLIB_CASSERT(output_tensor.k() < std::numeric_limits::max()); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + + const float* const out_data = output_tensor.host(); + + // The index of the largest output for each element is the label. + const auto find_label = [&](long sample, long r, long c) + { + uint16_t label = 0; + float max_value = out_data[tensor_index(output_tensor, sample, 0, r, c)]; + for (long k = 1; k < output_tensor.k(); ++k) + { + const float value = out_data[tensor_index(output_tensor, sample, k, r, c)]; + if (value > max_value) + { + label = static_cast(k); + max_value = value; + } + } + return label; + }; + + for (long i = 0; i < output_tensor.num_samples(); ++i, ++iter) + { + iter->set_size(output_tensor.nr(), output_tensor.nc()); + for (long r = 0; r < output_tensor.nr(); ++r) + { + for (long c = 0; c < output_tensor.nc(); ++c) + { + // The index of the largest output for this element is the label. + iter->operator()(r, c) = find_label(i, r, c); + } + } + } + } + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const + { + const tensor& output_tensor = sub.get_output(); + tensor& grad = sub.get_gradient_input(); + + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + DLIB_CASSERT(input_tensor.num_samples() != 0); + DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0); + DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples()); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + DLIB_CASSERT(output_tensor.k() >= 1); + DLIB_CASSERT(output_tensor.k() < std::numeric_limits::max()); + DLIB_CASSERT(output_tensor.nr() == grad.nr() && + output_tensor.nc() == grad.nc() && + output_tensor.k() == grad.k()); + for (long idx = 0; idx < output_tensor.num_samples(); ++idx) + { + const_label_iterator truth_matrix_ptr = (truth + idx); + DLIB_CASSERT(truth_matrix_ptr->nr() == output_tensor.nr() && + truth_matrix_ptr->nc() == output_tensor.nc(), + "truth size = " << truth_matrix_ptr->nr() << " x " << truth_matrix_ptr->nc() << ", " + "output size = " << output_tensor.nr() << " x " << output_tensor.nc()); + } + + +#ifdef DLIB_USE_CUDA + double loss; + cuda_compute(truth, output_tensor, grad, loss); + return loss; +#else + + tt::softmax(grad, output_tensor); + + // The loss we output is the average loss over the mini-batch, and also over each element of the matrix output. + const double scale = 1.0 / (output_tensor.num_samples() * output_tensor.nr() * output_tensor.nc()); + double loss = 0; + float* const g = grad.host(); + for (long i = 0; i < output_tensor.num_samples(); ++i, ++truth) + { + for (long r = 0; r < output_tensor.nr(); ++r) + { + for (long c = 0; c < output_tensor.nc(); ++c) + { + const uint16_t y = truth->operator()(r, c); + // The network must produce a number of outputs that is equal to the number + // of labels when using this type of loss. + DLIB_CASSERT(static_cast(y) < output_tensor.k() || y == label_to_ignore, + "y: " << y << ", output_tensor.k(): " << output_tensor.k()); + for (long k = 0; k < output_tensor.k(); ++k) + { + const size_t idx = tensor_index(output_tensor, i, k, r, c); + if (k == y) + { + loss += scale*-safe_log(g[idx]); + g[idx] = scale*(g[idx] - 1); + } + else if (y == label_to_ignore) + { + g[idx] = 0.f; + } + else + { + g[idx] = scale*g[idx]; + } + } + } + } + } + return loss; +#endif + } + + friend void serialize(const loss_multiclass_log_per_pixel_& , std::ostream& out) + { + serialize("loss_multiclass_log_per_pixel_", out); + } + + friend void deserialize(loss_multiclass_log_per_pixel_& , std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "loss_multiclass_log_per_pixel_") + throw serialization_error("Unexpected version found while deserializing dlib::loss_multiclass_log_per_pixel_."); + } + + friend std::ostream& operator<<(std::ostream& out, const loss_multiclass_log_per_pixel_& ) + { + out << "loss_multiclass_log_per_pixel"; + return out; + } + + friend void to_xml(const loss_multiclass_log_per_pixel_& /*item*/, std::ostream& out) + { + out << ""; + } + + private: + static size_t tensor_index(const tensor& t, long sample, long k, long row, long column) + { + // See: https://github.com/davisking/dlib/blob/4dfeb7e186dd1bf6ac91273509f687293bd4230a/dlib/dnn/tensor_abstract.h#L38 + return ((sample * t.k() + k) * t.nr() + row) * t.nc() + column; + } + + +#ifdef DLIB_USE_CUDA + cuda::compute_loss_multiclass_log_per_pixel cuda_compute; +#endif + }; + + template + using loss_multiclass_log_per_pixel = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_multiclass_log_per_pixel_weighted_ + { + public: + + struct weighted_label + { + weighted_label() + {} + + weighted_label(uint16_t label, float weight = 1.f) + : label(label), weight(weight) + {} + + // In semantic segmentation, 65536 classes ought to be enough for anybody. + uint16_t label = 0; + float weight = 1.f; + }; + + typedef matrix training_label_type; + typedef matrix output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + static void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) + { + loss_multiclass_log_per_pixel_::to_label(input_tensor, sub, iter); + } + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const + { + const tensor& output_tensor = sub.get_output(); + tensor& grad = sub.get_gradient_input(); + + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + DLIB_CASSERT(input_tensor.num_samples() != 0); + DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0); + DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples()); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + DLIB_CASSERT(output_tensor.k() >= 1); + DLIB_CASSERT(output_tensor.k() < std::numeric_limits::max()); + DLIB_CASSERT(output_tensor.nr() == grad.nr() && + output_tensor.nc() == grad.nc() && + output_tensor.k() == grad.k()); + for (long idx = 0; idx < output_tensor.num_samples(); ++idx) + { + const_label_iterator truth_matrix_ptr = (truth + idx); + DLIB_CASSERT(truth_matrix_ptr->nr() == output_tensor.nr() && + truth_matrix_ptr->nc() == output_tensor.nc(), + "truth size = " << truth_matrix_ptr->nr() << " x " << truth_matrix_ptr->nc() << ", " + "output size = " << output_tensor.nr() << " x " << output_tensor.nc()); + } + + tt::softmax(grad, output_tensor); + + // The loss we output is the weighted average loss over the mini-batch, and also over each element of the matrix output. + const double scale = 1.0 / (output_tensor.num_samples() * output_tensor.nr() * output_tensor.nc()); + double loss = 0; + float* const g = grad.host(); + for (long i = 0; i < output_tensor.num_samples(); ++i, ++truth) + { + for (long r = 0; r < output_tensor.nr(); ++r) + { + for (long c = 0; c < output_tensor.nc(); ++c) + { + const weighted_label& weighted_label = truth->operator()(r, c); + const uint16_t y = weighted_label.label; + const float weight = weighted_label.weight; + // The network must produce a number of outputs that is equal to the number + // of labels when using this type of loss. + DLIB_CASSERT(static_cast(y) < output_tensor.k() || weight == 0.f, + "y: " << y << ", output_tensor.k(): " << output_tensor.k()); + for (long k = 0; k < output_tensor.k(); ++k) + { + const size_t idx = tensor_index(output_tensor, i, k, r, c); + if (k == y) + { + loss += weight*scale*-safe_log(g[idx]); + g[idx] = weight*scale*(g[idx] - 1); + } + else + { + g[idx] = weight*scale*g[idx]; + } + } + } + } + } + return loss; + } + + friend void serialize(const loss_multiclass_log_per_pixel_weighted_& , std::ostream& out) + { + serialize("loss_multiclass_log_per_pixel_weighted_", out); + } + + friend void deserialize(loss_multiclass_log_per_pixel_weighted_& , std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "loss_multiclass_log_per_pixel_weighted_") + throw serialization_error("Unexpected version found while deserializing dlib::loss_multiclass_log_per_pixel_weighted_."); + } + + friend std::ostream& operator<<(std::ostream& out, const loss_multiclass_log_per_pixel_weighted_& ) + { + out << "loss_multiclass_log_per_pixel_weighted"; + return out; + } + + friend void to_xml(const loss_multiclass_log_per_pixel_weighted_& /*item*/, std::ostream& out) + { + out << ""; + } + + private: + static size_t tensor_index(const tensor& t, long sample, long k, long row, long column) + { + // See: https://github.com/davisking/dlib/blob/4dfeb7e186dd1bf6ac91273509f687293bd4230a/dlib/dnn/tensor_abstract.h#L38 + return ((sample * t.k() + k) * t.nr() + row) * t.nc() + column; + } + + }; + + template + using loss_multiclass_log_per_pixel_weighted = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_mean_squared_per_pixel_ + { + public: + + typedef matrix training_label_type; + typedef matrix output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const + { + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + + const tensor& output_tensor = sub.get_output(); + + DLIB_CASSERT(output_tensor.k() == 1, "output k = " << output_tensor.k()); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + + const float* out_data = output_tensor.host(); + for (long i = 0; i < output_tensor.num_samples(); ++i, ++iter) + { + iter->set_size(output_tensor.nr(), output_tensor.nc()); + for (long r = 0; r < output_tensor.nr(); ++r) + { + for (long c = 0; c < output_tensor.nc(); ++c) + { + iter->operator()(r, c) = out_data[tensor_index(output_tensor, i, 0, r, c)]; + } + } + } + } + + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const + { + const tensor& output_tensor = sub.get_output(); + tensor& grad = sub.get_gradient_input(); + + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + DLIB_CASSERT(input_tensor.num_samples() != 0); + DLIB_CASSERT(input_tensor.num_samples() % sub.sample_expansion_factor() == 0); + DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples()); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + DLIB_CASSERT(output_tensor.k() >= 1); + DLIB_CASSERT(output_tensor.k() < std::numeric_limits::max()); + DLIB_CASSERT(output_tensor.nr() == grad.nr() && + output_tensor.nc() == grad.nc() && + output_tensor.k() == grad.k()); + for (long idx = 0; idx < output_tensor.num_samples(); ++idx) + { + const_label_iterator truth_matrix_ptr = (truth + idx); + DLIB_CASSERT(truth_matrix_ptr->nr() == output_tensor.nr() && + truth_matrix_ptr->nc() == output_tensor.nc(), + "truth size = " << truth_matrix_ptr->nr() << " x " << truth_matrix_ptr->nc() << ", " + "output size = " << output_tensor.nr() << " x " << output_tensor.nc()); + } + + // The loss we output is the average loss over the mini-batch, and also over each element of the matrix output. + const double scale = 1.0 / (output_tensor.num_samples() * output_tensor.nr() * output_tensor.nc()); + double loss = 0; + float* const g = grad.host(); + const float* out_data = output_tensor.host(); + for (long i = 0; i < output_tensor.num_samples(); ++i, ++truth) + { + for (long r = 0; r < output_tensor.nr(); ++r) + { + for (long c = 0; c < output_tensor.nc(); ++c) + { + const float y = truth->operator()(r, c); + const size_t idx = tensor_index(output_tensor, i, 0, r, c); + const float temp1 = y - out_data[idx]; + const float temp2 = scale*temp1; + loss += temp2*temp1; + g[idx] = -temp2; + } + } + } + return loss; + } + + friend void serialize(const loss_mean_squared_per_pixel_& , std::ostream& out) + { + serialize("loss_mean_squared_per_pixel_", out); + } + + friend void deserialize(loss_mean_squared_per_pixel_& , std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "loss_mean_squared_per_pixel_") + throw serialization_error("Unexpected version found while deserializing dlib::loss_mean_squared_per_pixel_."); + } + + friend std::ostream& operator<<(std::ostream& out, const loss_mean_squared_per_pixel_& ) + { + out << "loss_mean_squared_per_pixel"; + return out; + } + + friend void to_xml(const loss_mean_squared_per_pixel_& /*item*/, std::ostream& out) + { + out << ""; + } + + private: + static size_t tensor_index(const tensor& t, long sample, long k, long row, long column) + { + // See: https://github.com/davisking/dlib/blob/4dfeb7e186dd1bf6ac91273509f687293bd4230a/dlib/dnn/tensor_abstract.h#L38 + return ((sample * t.k() + k) * t.nr() + row) * t.nc() + column; + } + }; + + template + using loss_mean_squared_per_pixel = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_dot_ + { + public: + + typedef matrix training_label_type; + typedef matrix output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const + { + const tensor& output_tensor = sub.get_output(); + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + DLIB_CASSERT(input_tensor.num_samples() != 0); + DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + + for (long i = 0; i < output_tensor.num_samples(); ++i) + *iter++ = trans(rowm(mat(output_tensor),i)); + } + + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const + { + const tensor& output_tensor = sub.get_output(); + tensor& grad = sub.get_gradient_input(); + + DLIB_CASSERT(sub.sample_expansion_factor() == 1); + DLIB_CASSERT(input_tensor.num_samples() != 0); + DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0); + DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples()); + DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples()); + + const long network_output_dims = output_tensor.size()/output_tensor.num_samples(); + + + // The loss we output is the average loss over the mini-batch. + const double scale = 1.0/output_tensor.num_samples(); + double loss = 0; + float* g = grad.host(); + const float* out_data = output_tensor.host(); + for (long i = 0; i < output_tensor.num_samples(); ++i) + { + DLIB_CASSERT(truth->size() == network_output_dims, "The network must output a vector with the same dimensionality as the training labels. " + << "\ntruth->size(): " << truth->size() + << "\nnetwork_output_dims: " << network_output_dims); + + const float* t = &(*truth++)(0); + + for (long j = 0; j < network_output_dims; ++j) + { + g[j] = -t[j]*scale; + loss -= out_data[j]*t[j]; + } + + g += network_output_dims; + out_data += network_output_dims; + } + return loss*scale; + } + + friend void serialize(const loss_dot_& , std::ostream& out) + { + serialize("loss_dot_", out); + } + + friend void deserialize(loss_dot_& , std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "loss_dot_") + throw serialization_error("Unexpected version found while deserializing dlib::loss_dot_."); + } + + friend std::ostream& operator<<(std::ostream& out, const loss_dot_& ) + { + out << "loss_dot"; + return out; + } + + friend void to_xml(const loss_dot_& /*item*/, std::ostream& out) + { + out << ""; + } + + }; + + template + using loss_dot = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DNn_LOSS_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/dnn/loss_abstract.h b/lib/3rdParty/dlib/include/dlib/dnn/loss_abstract.h new file mode 100644 index 00000000..0dd04367 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/dnn/loss_abstract.h @@ -0,0 +1,1542 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_DNn_LOSS_ABSTRACT_H_ +#ifdef DLIB_DNn_LOSS_ABSTRACT_H_ + +#include "core_abstract.h" +#include "../image_processing/full_object_detection_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class EXAMPLE_LOSS_LAYER_ + { + /*! + WHAT THIS OBJECT REPRESENTS + A loss layer is the final layer in a deep neural network. It computes the + task loss. That is, it computes a number that tells us how well the + network is performing on some task, such as predicting a binary label. + + You can use one of the loss layers that comes with dlib (defined below). + But importantly, you are able to define your own loss layers to suit your + needs. You do this by creating a class that defines an interface matching + the one described by this EXAMPLE_LOSS_LAYER_ class. Note that there is no + dlib::EXAMPLE_LOSS_LAYER_ type. It is shown here purely to document the + interface that a loss layer must implement. + + A loss layer can optionally provide a to_label() method that converts the + output of a network into a user defined type. If to_label() is not + provided then the operator() methods of add_loss_layer will not be + available, but otherwise everything will function as normal. + + Finally, note that there are two broad flavors of loss layer, supervised + and unsupervised. The EXAMPLE_LOSS_LAYER_ as shown here is a supervised + layer. To make an unsupervised loss you simply leave out the + training_label_type typedef and the truth iterator argument to + compute_loss_value_and_gradient(). + !*/ + + public: + + // In most cases training_label_type and output_label_type will be the same type. + typedef whatever_type_you_use_for_training_labels training_label_type; + typedef whatever_type_you_use_for_outout_labels output_label_type; + + EXAMPLE_LOSS_LAYER_ ( + ); + /*! + ensures + - EXAMPLE_LOSS_LAYER_ objects are default constructable. + !*/ + + EXAMPLE_LOSS_LAYER_ ( + const EXAMPLE_LOSS_LAYER_& item + ); + /*! + ensures + - EXAMPLE_LOSS_LAYER_ objects are copy constructable. + !*/ + + // Implementing to_label() is optional. + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const; + /*! + requires + - SUBNET implements the SUBNET interface defined at the top of + layers_abstract.h. + - input_tensor was given as input to the network sub and the outputs are + now visible in layer(sub).get_output(), for all valid i. + - input_tensor.num_samples() > 0 + - input_tensor.num_samples()%sub.sample_expansion_factor() == 0. + - iter == an iterator pointing to the beginning of a range of + input_tensor.num_samples()/sub.sample_expansion_factor() elements. Moreover, + they must be output_label_type elements. + ensures + - Converts the output of the provided network to output_label_type objects and + stores the results into the range indicated by iter. In particular, for + all valid i, it will be the case that: + *(iter+i/sub.sample_expansion_factor()) is populated based on the output of + sub and corresponds to the ith sample in input_tensor. + !*/ + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const; + /*! + requires + - SUBNET implements the SUBNET interface defined at the top of + layers_abstract.h. + - input_tensor was given as input to the network sub and the outputs are + now visible in layer(sub).get_output(), for all valid i. + - input_tensor.num_samples() > 0 + - input_tensor.num_samples()%sub.sample_expansion_factor() == 0. + - for all valid i: + - layer(sub).get_gradient_input() has the same dimensions as + layer(sub).get_output(). + - layer(sub).get_gradient_input() contains all zeros (i.e. + initially, all input gradients are 0). + - truth == an iterator pointing to the beginning of a range of + input_tensor.num_samples()/sub.sample_expansion_factor() elements. Moreover, + they must be training_label_type elements. + - for all valid i: + - *(truth+i/sub.sample_expansion_factor()) is the label of the ith sample in + input_tensor. + ensures + - This function computes a loss function that describes how well the output + of sub matches the expected labels given by truth. Let's write the loss + function as L(input_tensor, truth, sub). + - Then compute_loss_value_and_gradient() computes the gradient of L() with + respect to the outputs in sub. Specifically, compute_loss_value_and_gradient() + assigns the gradients into sub by performing the following tensor + assignments, for all valid i: + - layer(sub).get_gradient_input() = the gradient of + L(input_tensor,truth,sub) with respect to layer(sub).get_output(). + Note that, since get_gradient_input() is zero initialized, you don't + have to write gradient information to layers that have a zero + loss gradient. + - returns L(input_tensor,truth,sub) + !*/ + }; + + std::ostream& operator<<(std::ostream& out, const EXAMPLE_LOSS_LAYER_& item); + /*! + print a string describing this layer. + !*/ + + void to_xml(const EXAMPLE_LOSS_LAYER_& item, std::ostream& out); + /*! + This function is optional, but required if you want to print your networks with + net_to_xml(). Therefore, to_xml() prints a layer as XML. + !*/ + + void serialize(const EXAMPLE_LOSS_LAYER_& item, std::ostream& out); + void deserialize(EXAMPLE_LOSS_LAYER_& item, std::istream& in); + /*! + provides serialization support + !*/ + + // For each loss layer you define, always define an add_loss_layer template so that + // layers can be easily composed. Moreover, the convention is that the layer class + // ends with an _ while the add_loss_layer template has the same name but without the + // trailing _. + template + using EXAMPLE_LOSS_LAYER = add_loss_layer; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class loss_binary_hinge_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This object implements the loss layer interface defined above by + EXAMPLE_LOSS_LAYER_. In particular, it implements the hinge loss, which is + appropriate for binary classification problems. Therefore, the possible + labels when using this loss are +1 and -1. Moreover, it will cause the + network to produce outputs > 0 when predicting a member of the +1 class and + values < 0 otherwise. + !*/ + public: + + typedef float training_label_type; + typedef float output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except + it has the additional calling requirements that: + - sub.get_output().nr() == 1 + - sub.get_output().nc() == 1 + - sub.get_output().k() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + and the output label is the raw score for each classified object. If the score + is > 0 then the classifier is predicting the +1 class, otherwise it is + predicting the -1 class. + !*/ + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() + except it has the additional calling requirements that: + - sub.get_output().nr() == 1 + - sub.get_output().nc() == 1 + - sub.get_output().k() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + - all values pointed to by truth are +1 or -1. + !*/ + + }; + + template + using loss_binary_hinge = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_binary_log_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This object implements the loss layer interface defined above by + EXAMPLE_LOSS_LAYER_. In particular, it implements the log loss, which is + appropriate for binary classification problems. Therefore, the possible + labels when using this loss are +1 and -1. Moreover, it will cause the + network to produce outputs > 0 when predicting a member of the +1 class and + values < 0 otherwise. + + To be more specific, this object contains a sigmoid layer followed by a + cross-entropy layer. + !*/ + public: + + typedef float training_label_type; + typedef float output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except + it has the additional calling requirements that: + - sub.get_output().nr() == 1 + - sub.get_output().nc() == 1 + - sub.get_output().k() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + and the output label is the raw score for each classified object. If the score + is > 0 then the classifier is predicting the +1 class, otherwise it is + predicting the -1 class. + !*/ + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() + except it has the additional calling requirements that: + - sub.get_output().nr() == 1 + - sub.get_output().nc() == 1 + - sub.get_output().k() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + - all values pointed to by truth are +1 or -1. + !*/ + + }; + + template + using loss_binary_log = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_multiclass_log_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This object implements the loss layer interface defined above by + EXAMPLE_LOSS_LAYER_. In particular, it implements the multiclass logistic + regression loss (e.g. negative log-likelihood loss), which is appropriate + for multiclass classification problems. This means that the possible + labels when using this loss are integers >= 0. + + Moreover, if after training you were to replace the loss layer of the + network with a softmax layer, the network outputs would give the + probabilities of each class assignment. That is, if you have K classes + then the network should output tensors with the tensor::k()'th dimension + equal to K. Applying softmax to these K values gives the probabilities of + each class. The index into that K dimensional vector with the highest + probability is the predicted class label. + !*/ + + public: + + typedef unsigned long training_label_type; + typedef unsigned long output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except + it has the additional calling requirements that: + - sub.get_output().nr() == 1 + - sub.get_output().nc() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + and the output label is the predicted class for each classified object. The number + of possible output classes is sub.get_output().k(). + !*/ + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() + except it has the additional calling requirements that: + - sub.get_output().nr() == 1 + - sub.get_output().nc() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + - all values pointed to by truth are < sub.get_output().k() + !*/ + + }; + + template + using loss_multiclass_log = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_multimulticlass_log_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This object implements the loss layer interface defined above by + EXAMPLE_LOSS_LAYER_. In particular, it implements a collection of + multiclass classifiers. An example will make its use clear. So suppose, + for example, that you want to make something that takes a picture of a + vehicle and answers the following questions: + - What type of vehicle is it? A sedan or a truck? + - What color is it? red, green, blue, gray, or black? + You need two separate multi-class classifiers to do this. One to decide + the type of vehicle, and another to decide the color. The + loss_multimulticlass_log_ allows you to pack these two classifiers into one + neural network. This means that when you use the network to process an + image it will output 2 labels for each image, the type label and the color + label. + + To create a loss_multimulticlass_log_ for the above case you would + construct it as follows: + std::map> labels; + labels["type"] = {"sedan", "truck"}; + labels["color"] = {"red", "green", "blue", "gray", "black"}; + loss_multimulticlass_log_ myloss(labels); + Then you could use myloss with a network object and train it to do this + task. More generally, you can use any number of classifiers and labels + when using this object. Finally, each of the classifiers uses a standard + multi-class logistic regression loss. + !*/ + + public: + + loss_multimulticlass_log_( + ); + /*! + ensures + - #number_of_labels() == 0 + - #get_labels().size() == 0 + !*/ + + loss_multimulticlass_log_ ( + const std::map>& labels + ); + /*! + requires + - Each vector in labels must contain at least 2 strings. I.e. each + classifier must have at least two possible labels. + ensures + - #number_of_labels() == the total number of strings in all the + std::vectors in labels. + - #number_of_classifiers() == labels.size() + - #get_labels() == labels + !*/ + + unsigned long number_of_labels( + ) const; + /*! + ensures + - returns the total number of labels known to this loss. This is the count of + all the labels in each classifier. + !*/ + + unsigned long number_of_classifiers( + ) const; + /*! + ensures + - returns the number of classifiers defined by this loss. + !*/ + + std::map> get_labels ( + ) const; + /*! + ensures + - returns the names of the classifiers and labels used by this loss. In + particular, if the returned object is L then: + - L[CLASS] == the set of labels used by the classifier CLASS. + - L.size() == number_of_classifiers() + - The count of strings in the vectors in L == number_of_labels() + !*/ + + class classifier_output + { + /*! + WHAT THIS OBJECT REPRESENTS + This object stores the predictions from one of the classifiers in + loss_multimulticlass_log_. It allows you to find out the most likely + string label predicted by that classifier, as well as get the class + conditional probability of any of the classes in the classifier. + !*/ + + public: + + classifier_output( + ); + /*! + ensures + - #num_classes() == 0 + !*/ + + size_t num_classes( + ) const; + /*! + ensures + - returns the number of possible classes output by this classifier. + !*/ + + double probability_of_class ( + size_t i + ) const; + /*! + requires + - i < num_classes() + ensures + - returns the probability that the true class has a label of label(i). + - The sum of probability_of_class(j) for j in the range [0, num_classes()) is always 1. + !*/ + + const std::string& label( + size_t i + ) const; + /*! + requires + - i < num_classes() + ensures + - returns the string label for the ith class. + !*/ + + operator std::string( + ) const; + /*! + requires + - num_classes() != 0 + ensures + - returns the string label for the most probable class. + !*/ + + friend std::ostream& operator<< (std::ostream& out, const classifier_output& item); + /*! + requires + - num_classes() != 0 + ensures + - prints the most probable class label to out. + !*/ + + }; + + // Both training_label_type and output_label_type should always have sizes equal to + // number_of_classifiers(). That is, the std::map should have an entry for every + // classifier known to this loss. + typedef std::map training_label_type; + typedef std::map output_label_type; + + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except + it has the additional calling requirements that: + - number_of_labels() != 0 + - sub.get_output().k() == number_of_labels() + - sub.get_output().nr() == 1 + - sub.get_output().nc() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + !*/ + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() + except it has the additional calling requirements that: + - number_of_labels() != 0 + - sub.get_output().k() == number_of_labels() + It should be noted that the last layer in your network should usually + be an fc layer. If so, you can satisfy this requirement of k() being + number_of_labels() by calling set_num_outputs() prior to training your + network like so: + your_network.subnet().layer_details().set_num_outputs(your_network.loss_details().number_of_labels()); + - sub.get_output().nr() == 1 + - sub.get_output().nc() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + - All the std::maps pointed to by truth contain entries for all the + classifiers known to this loss. That is, it must be valid to call + truth[i][classifier] for any of the classifiers known to this loss. To + say this another way, all the training samples must contain labels for + each of the classifiers defined by this loss. + + To really belabor this, this also means that truth[i].size() == + get_labels().size() and that both truth[i] and get_labels() have the same + set of key strings. It also means that the value strings in truth[i] + must be strings known to the loss, i.e. they are valid labels according + to get_labels(). + !*/ + }; + + template + using loss_multimulticlass_log = add_loss_layer; + + // Allow comparison between classifier_outputs and std::string to check if the + // predicted class is a particular string. + inline bool operator== (const std::string& lhs, const loss_multimulticlass_log_::classifier_output& rhs) + { return lhs == static_cast(rhs); } + inline bool operator== (const loss_multimulticlass_log_::classifier_output& lhs, const std::string& rhs) + { return rhs == static_cast(lhs); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + enum class use_image_pyramid : uint8_t + { + no, + yes + }; + + struct mmod_options + { + /*! + WHAT THIS OBJECT REPRESENTS + This object contains all the parameters that control the behavior of loss_mmod_. + !*/ + + public: + + struct detector_window_details + { + detector_window_details() = default; + detector_window_details(unsigned long w, unsigned long h) : width(w), height(h) {} + detector_window_details(unsigned long w, unsigned long h, const std::string& l) : width(w), height(h), label(l) {} + + unsigned long width = 0; + unsigned long height = 0; + std::string label; + + friend inline void serialize(const detector_window_details& item, std::ostream& out); + friend inline void deserialize(detector_window_details& item, std::istream& in); + }; + + mmod_options() = default; + + // This kind of object detector is a sliding window detector. The detector_windows + // field determines how many sliding windows we will use and what the shape of each + // window is. It also determines the output label applied to each detection + // identified by each window. Since you will usually use the MMOD loss with an + // image pyramid, the detector sizes also determine the size of the smallest object + // you can detect. + std::vector detector_windows; + + // These parameters control how we penalize different kinds of mistakes. See + // Max-Margin Object Detection by Davis E. King (http://arxiv.org/abs/1502.00046) + // for further details. + double loss_per_false_alarm = 1; + double loss_per_missed_target = 1; + + // A detection must have an intersection-over-union value greater than this for us + // to consider it a match against a ground truth box. + double truth_match_iou_threshold = 0.5; + + // When doing non-max suppression, we use overlaps_nms to decide if a box overlaps + // an already output detection and should therefore be thrown out. + test_box_overlap overlaps_nms = test_box_overlap(0.4); + + // Any mmod_rect in the training data that has its ignore field set to true defines + // an "ignore zone" in an image. Any detection from that area is totally ignored + // by the optimizer. Therefore, this overlaps_ignore field defines how we decide + // if a box falls into an ignore zone. You use these ignore zones if there are + // objects in your dataset that you are unsure if you want to detect or otherwise + // don't care if the detector gets them or not. + test_box_overlap overlaps_ignore; + + // Usually the detector would be scale-invariant, and used with an image pyramid. + // However, sometimes scale-invariance may not be desired. + use_image_pyramid assume_image_pyramid = use_image_pyramid::yes; + + mmod_options ( + const std::vector>& boxes, + const unsigned long target_size, + const unsigned long min_target_size, + const double min_detector_window_overlap_iou = 0.75 + ); + /*! + requires + - 0 < min_target_size <= target_size + - 0.5 < min_detector_window_overlap_iou < 1 + ensures + - use_image_pyramid_ == use_image_pyramid::yes + - This function should be used when scale-invariance is desired, and + input_rgb_image_pyramid is therefore used as the input layer. + - This function tries to automatically set the MMOD options to reasonable + values, assuming you have a training dataset of boxes.size() images, where + the ith image contains objects boxes[i] you want to detect. + - The most important thing this function does is decide what detector + windows should be used. This is done by finding a set of detector + windows that are sized such that: + - When slid over an image pyramid, each box in boxes will have an + intersection-over-union with one of the detector windows of at least + min_detector_window_overlap_iou. That is, we will make sure that + each box in boxes could potentially be detected by one of the + detector windows. This essentially comes down to picking detector + windows with aspect ratios similar to the aspect ratios in boxes. + Note that we also make sure that each box can be detected by a window + with the same label. For example, if all the boxes had the same + aspect ratio but there were 4 different labels used in boxes then + there would be 4 resulting detector windows, one for each label. + - The longest edge of each detector window is target_size pixels in + length, unless the window's shortest side would be less than + min_target_size pixels in length. In this case the shortest side + will be set to min_target_size length, and the other side sized to + preserve the aspect ratio of the window. + This means that target_size and min_target_size control the size of the + detector windows, while the aspect ratios of the detector windows are + automatically determined by the contents of boxes. It should also be + emphasized that the detector isn't going to be able to detect objects + smaller than any of the detector windows. So consider that when setting + these sizes. + - This function will also set the overlaps_nms tester to the most + restrictive tester that doesn't reject anything in boxes. + !*/ + + mmod_options ( + use_image_pyramid use_image_pyramid, + const std::vector>& boxes, + const double min_detector_window_overlap_iou = 0.75 + ); + /*! + requires + - use_image_pyramid == use_image_pyramid::no + - 0.5 < min_detector_window_overlap_iou < 1 + ensures + - This function should be used when scale-invariance is not desired, and + there is no intention to apply an image pyramid. + - This function tries to automatically set the MMOD options to reasonable + values, assuming you have a training dataset of boxes.size() images, where + the ith image contains objects boxes[i] you want to detect. + - The most important thing this function does is decide what detector + windows should be used. This is done by finding a set of detector + windows that are sized such that: + - When slid over an image, each box in boxes will have an + intersection-over-union with one of the detector windows of at least + min_detector_window_overlap_iou. That is, we will make sure that + each box in boxes could potentially be detected by one of the + detector windows. + - This function will also set the overlaps_nms tester to the most + restrictive tester that doesn't reject anything in boxes. + !*/ + }; + + void serialize(const mmod_options& item, std::ostream& out); + void deserialize(mmod_options& item, std::istream& in); + +// ---------------------------------------------------------------------------------------- + + class loss_mmod_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This object implements the loss layer interface defined above by + EXAMPLE_LOSS_LAYER_. In particular, it implements the Max Margin Object + Detection loss defined in the paper: + Max-Margin Object Detection by Davis E. King (http://arxiv.org/abs/1502.00046). + + This means you use this loss if you want to detect the locations of objects + in images. + + It should also be noted that this loss layer requires an input layer that + defines the following functions: + - image_contained_point() + - tensor_space_to_image_space() + - image_space_to_tensor_space() + A reference implementation of them and their definitions can be found in + the input_rgb_image_pyramid object, which is the recommended input layer to + be used with loss_mmod_. + !*/ + + public: + + typedef std::vector training_label_type; + typedef std::vector output_label_type; + + loss_mmod_( + ); + /*! + ensures + - #get_options() == mmod_options() + !*/ + + loss_mmod_( + mmod_options options_ + ); + /*! + ensures + - #get_options() == options_ + !*/ + + const mmod_options& get_options ( + ) const; + /*! + ensures + - returns the options object that defines the general behavior of this loss layer. + !*/ + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter, + double adjust_threshold = 0 + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except + it has the additional calling requirements that: + - sub.get_output().k() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + Also, the output labels are std::vectors of mmod_rects where, for each mmod_rect R, + we have the following interpretations: + - R.rect == the location of an object in the image. + - R.detection_confidence the score for the object, the bigger the score the + more confident the detector is that an object is really there. Only + objects with a detection_confidence > adjust_threshold are output. So if + you want to output more objects (that are also of less confidence) you + can call to_label() with a smaller value of adjust_threshold. + - R.ignore == false (this value is unused by to_label()). + !*/ + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() + except it has the additional calling requirements that: + - sub.get_output().k() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + Also, the loss value returned is roughly equal to the average number of + mistakes made per image. This is the sum of false alarms and missed + detections, weighted by the loss weights for these types of mistakes specified + in the mmod_options. + !*/ + }; + + template + using loss_mmod = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_metric_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This object implements the loss layer interface defined above by + EXAMPLE_LOSS_LAYER_. In particular, it allows you to learn to map objects + into a vector space where objects sharing the same class label are close to + each other, while objects with different labels are far apart. + + To be specific, it optimizes the following loss function which considers + all pairs of objects in a mini-batch and computes a different loss depending + on their respective class labels. So if objects A1 and A2 in a mini-batch + share the same class label then their contribution to the loss is: + max(0, length(A1-A2)-get_distance_threshold() + get_margin()) + + While if A1 and B1 have different class labels then their contribution to + the loss function is: + max(0, get_distance_threshold()-length(A1-B1) + get_margin()) + + Therefore, this loss layer optimizes a version of the hinge loss. + Moreover, the loss is trying to make sure that all objects with the same + label are within get_distance_threshold() distance of each other. + Conversely, if two objects have different labels then they should be more + than get_distance_threshold() distance from each other in the learned + embedding. So this loss function gives you a natural decision boundary for + deciding if two objects are from the same class. + + Finally, the loss balances the number of negative pairs relative to the + number of positive pairs. Therefore, if there are N pairs that share the + same identity in a mini-batch then the algorithm will only include the N + worst non-matching pairs in the loss. That is, the algorithm performs hard + negative mining on the non-matching pairs. This is important since there + are in general way more non-matching pairs than matching pairs. So to + avoid imbalance in the loss this kind of hard negative mining is useful. + !*/ + public: + + typedef unsigned long training_label_type; + typedef matrix output_label_type; + + loss_metric_( + ); + /*! + ensures + - #get_margin() == 0.04 + - #get_distance_threshold() == 0.6 + !*/ + + loss_metric_( + float margin, + float dist_thresh + ); + /*! + requires + - margin > 0 + - dist_thresh > 0 + ensures + - #get_margin() == margin + - #get_distance_threshold() == dist_thresh + !*/ + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except + it has the additional calling requirements that: + - sub.get_output().nr() == 1 + - sub.get_output().nc() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + This loss expects the network to produce a single vector (per sample) as + output. This vector is the learned embedding. Therefore, to_label() just + copies these output vectors from the network into the output label_iterators + given to this function, one for each sample in the input_tensor. + !*/ + + float get_margin() const; + /*! + ensures + - returns the margin value used by the loss function. See the discussion + in WHAT THIS OBJECT REPRESENTS for details. + !*/ + + float get_distance_threshold() const; + /*! + ensures + - returns the distance threshold value used by the loss function. See the discussion + in WHAT THIS OBJECT REPRESENTS for details. + !*/ + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() + except it has the additional calling requirements that: + - sub.get_output().nr() == 1 + - sub.get_output().nc() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + !*/ + + }; + + template + using loss_metric = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_ranking_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This object implements the loss layer interface defined above by + EXAMPLE_LOSS_LAYER_. In particular, it implements the pairwise ranking + loss described in the paper: + Optimizing Search Engines using Clickthrough Data by Thorsten Joachims + + This is the same loss function used by the dlib::svm_rank_trainer object. + Therefore, it is generally appropriate when you have a two class problem + and you want to learn a function that ranks one class before the other. + + So for example, suppose you have two classes of data. Objects of type A + and objects of type B. Moreover, suppose that you want to sort the objects + so that A objects always come before B objects. This loss will help you + learn a function that assigns a real number to each object such that A + objects get a larger number assigned to them than B objects. This lets you + then sort the objects according to the output of the neural network and + obtain the desired result of having A objects come before B objects. + + The training labels should be positive values for objects you want to get + high scores and negative for objects that should get small scores. So + relative to our A/B example, you would give A objects labels of +1 and B + objects labels of -1. This should cause the learned network to give A + objects large positive values and B objects negative values. + + + Finally, the specific loss function is: + For all pairs of positive vs negative training examples A_i and B_j respectively: + sum_ij: max(0, B_i - A_j + margin_ij) + where margin_ij = the label for A_j minus the label for B_i. If you + always use +1 and -1 labels then the margin is always 2. However, this + formulation allows you to give certain training samples different weight by + adjusting the training labels appropriately. + !*/ + + public: + + typedef float training_label_type; + typedef float output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except + it has the additional calling requirements that: + - sub.get_output().nr() == 1 + - sub.get_output().nc() == 1 + - sub.get_output().k() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + and the output label is the predicted ranking score. + !*/ + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() + except it has the additional calling requirements that: + - sub.get_output().nr() == 1 + - sub.get_output().nc() == 1 + - sub.get_output().k() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + !*/ + + }; + + template + using loss_ranking = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_epsilon_insensitive_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This object implements the loss layer interface defined above by + EXAMPLE_LOSS_LAYER_. In particular, it implements the epsilon insensitive + loss, which is appropriate for regression problems. In particular, this + loss function is; + loss(y1,y2) = abs(y1-y2)= 0 + ensures + - #get_epsilon() == eps + !*/ + + double get_epsilon ( + ) const; + /*! + ensures + - returns the epsilon value used in the loss function. Mistakes in the + regressor smaller than get_epsilon() are ignored by the loss function. + !*/ + + void set_epsilon( + double eps + ); + /*! + requires + - eps >= 0 + ensures + - #get_epsilon() == eps + !*/ + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except + it has the additional calling requirements that: + - sub.get_output().nr() == 1 + - sub.get_output().nc() == 1 + - sub.get_output().k() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + and the output label is the predicted continuous variable. + !*/ + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() + except it has the additional calling requirements that: + - sub.get_output().nr() == 1 + - sub.get_output().nc() == 1 + - sub.get_output().k() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + !*/ + + }; + + template + using loss_epsilon_insensitive = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_mean_squared_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This object implements the loss layer interface defined above by + EXAMPLE_LOSS_LAYER_. In particular, it implements the mean squared loss, which is + appropriate for regression problems. + !*/ + public: + + typedef float training_label_type; + typedef float output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except + it has the additional calling requirements that: + - sub.get_output().nr() == 1 + - sub.get_output().nc() == 1 + - sub.get_output().k() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + and the output label is the predicted continuous variable. + !*/ + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() + except it has the additional calling requirements that: + - sub.get_output().nr() == 1 + - sub.get_output().nc() == 1 + - sub.get_output().k() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + !*/ + + }; + + template + using loss_mean_squared = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_mean_squared_multioutput_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This object implements the loss layer interface defined above by + EXAMPLE_LOSS_LAYER_. In particular, it implements the mean squared loss, + which is appropriate for regression problems. It is basically just like + loss_mean_squared_ except that it lets you define multiple outputs instead + of just 1. + !*/ + public: + + typedef matrix training_label_type; + typedef matrix output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except + it has the additional calling requirements that: + - sub.get_output().nr() == 1 + - sub.get_output().nc() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + and the output label is the predicted continuous variable. + !*/ + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() + except it has the additional calling requirements that: + - sub.get_output().nr() == 1 + - sub.get_output().nc() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + - (*(truth + idx)).nc() == 1 for all idx such that 0 <= idx < sub.get_output().num_samples() + - (*(truth + idx)).nr() == sub.get_output().k() for all idx such that 0 <= idx < sub.get_output().num_samples() + !*/ + + }; + + template + using loss_mean_squared_multioutput = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_multiclass_log_per_pixel_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This object implements the loss layer interface defined above by + EXAMPLE_LOSS_LAYER_. In particular, it implements the multiclass logistic + regression loss (e.g. negative log-likelihood loss), which is appropriate + for multiclass classification problems. It is basically just like + loss_multiclass_log_ except that it lets you define matrix outputs instead + of scalar outputs. It should be useful, for example, in semantic + segmentation where we want to classify each pixel of an image. + !*/ + public: + + // In semantic segmentation, if you don't know the ground-truth of some pixel, + // set the label of that pixel to this value. When you do so, the pixel will be + // ignored when computing gradients. + static const uint16_t label_to_ignore = std::numeric_limits::max(); + + // In semantic segmentation, 65535 classes ought to be enough for anybody. + typedef matrix training_label_type; + typedef matrix output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except + it has the additional calling requirements that: + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + and the output label is the predicted class for each classified element. The number + of possible output classes is sub.get_output().k(). + !*/ + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() + except it has the additional calling requirements that: + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + - all values pointed to by truth are < sub.get_output().k() or are equal to label_to_ignore. + !*/ + + }; + + template + using loss_multiclass_log_per_pixel = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_multiclass_log_per_pixel_weighted_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This object implements the loss layer interface defined above by + EXAMPLE_LOSS_LAYER_. In particular, it implements the multiclass logistic + regression loss (e.g. negative log-likelihood loss), which is appropriate + for multiclass classification problems. It is basically just like + loss_multiclass_log_per_pixel_ except that it lets you define per-pixel + weights, which may be useful e.g. if you want to emphasize rare classes + while training. (If the classification problem is difficult, a flat weight + structure may lead the network to always predict the most common label, in + particular if the degree of imbalance is high. To emphasize a certain + class or classes, simply increase the weights of the corresponding pixels, + relative to the weights of the other pixels.) + + Note that if you set the weight to 0 whenever a pixel's label is equal to + loss_multiclass_log_per_pixel_::label_to_ignore, and to 1 otherwise, then + you essentially get loss_multiclass_log_per_pixel_ as a special case. + !*/ + public: + + struct weighted_label + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents the truth label of a single pixel, together with + an associated weight (the higher the weight, the more emphasis the + corresponding pixel is given during the training). + !*/ + + weighted_label(); + weighted_label(uint16_t label, float weight = 1.f); + + // The ground-truth label. In semantic segmentation, 65536 classes ought to be + // enough for anybody. + uint16_t label = 0; + + // The weight of the corresponding pixel. + float weight = 1.f; + }; + + typedef matrix training_label_type; + typedef matrix output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except + it has the additional calling requirements that: + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + and the output label is the predicted class for each classified element. The number + of possible output classes is sub.get_output().k(). + !*/ + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() + except it has the additional calling requirements that: + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + - all labels pointed to by truth are < sub.get_output().k(), or the corresponding weight + is zero. + !*/ + + }; + + template + using loss_multiclass_log_per_pixel_weighted = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_mean_squared_per_pixel_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This object implements the loss layer interface defined above by + EXAMPLE_LOSS_LAYER_. In particular, it implements the mean squared loss, + which is appropriate for regression problems. It is basically just like + loss_mean_squared_multioutput_ except that it lets you define matrix or + image outputs, instead of vector. + !*/ + public: + + typedef matrix training_label_type; + typedef matrix output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except + it has the additional calling requirements that: + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + and the output labels are the predicted continuous variables. + !*/ + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() + except it has the additional calling requirements that: + - sub.get_output().k() == 1 + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + - for all idx such that 0 <= idx < sub.get_output().num_samples(): + - sub.get_output().nr() == (*(truth + idx)).nr() + - sub.get_output().nc() == (*(truth + idx)).nc() + !*/ + }; + + template + using loss_mean_squared_per_pixel = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + + class loss_dot_ + { + /*! + WHAT THIS OBJECT REPRESENTS + This object implements the loss layer interface defined above by + EXAMPLE_LOSS_LAYER_. In particular, selecting this loss means you want + maximize the dot product between the output of a network and a set of + training vectors. The loss is therefore the negative dot product. To be + very specific, if X is the output vector of a network and Y is a training + label (also a vector), then the loss for this training sample is: -dot(X,Y) + !*/ + + public: + + typedef matrix training_label_type; + typedef matrix output_label_type; + + template < + typename SUB_TYPE, + typename label_iterator + > + void to_label ( + const tensor& input_tensor, + const SUB_TYPE& sub, + label_iterator iter + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except + it has the additional calling requirements that: + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + and the output labels are simply the final network outputs stuffed into a + vector. To be very specific, the output is the following for all valid i: + *(iter+i) == trans(rowm(mat(sub.get_output()),i)) + !*/ + + + template < + typename const_label_iterator, + typename SUBNET + > + double compute_loss_value_and_gradient ( + const tensor& input_tensor, + const_label_iterator truth, + SUBNET& sub + ) const; + /*! + This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() + except it has the additional calling requirements that: + - sub.get_output().num_samples() == input_tensor.num_samples() + - sub.sample_expansion_factor() == 1 + - Let NETWORK_OUTPUT_DIMS == sub.get_output().size()/sub.get_output().num_samples() + - for all idx such that 0 <= idx < sub.get_output().num_samples(): + - NETWORK_OUTPUT_DIMS == (*(truth + idx)).size() + !*/ + }; + + template + using loss_dot = add_loss_layer; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DNn_LOSS_ABSTRACT_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/dnn/solvers.h b/lib/3rdParty/dlib/include/dlib/dnn/solvers.h new file mode 100644 index 00000000..1c17a51c --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/dnn/solvers.h @@ -0,0 +1,405 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DNn_SOLVERS_H_ +#define DLIB_DNn_SOLVERS_H_ + +#include "solvers_abstract.h" +#include "../cuda/tensor.h" +#include +#include "layers.h" + +namespace dlib +{ + class sgd + { + public: + + explicit sgd( + float weight_decay_, + float momentum_ = 0.9 + ) + { + weight_decay = weight_decay_; + momentum = momentum_; + } + + sgd( + ) : sgd(0.0005, 0.9) + { + } + + float get_momentum ( + ) const { return momentum; } + + float get_weight_decay ( + ) const { return weight_decay; } + + template + const tensor& operator() ( + const float learning_rate, + const layer_type& l, + const tensor& params_grad + ) + { + const tensor& params = l.get_layer_params(); + + DLIB_CASSERT(params.size() != 0); + if (v.size() == 0) + { + v.copy_size(params_grad); + v = 0; + } + + const double lr = learning_rate*get_learning_rate_multiplier(l); + const double wd = weight_decay*get_weight_decay_multiplier(l); + + //perform: v = momentum*mat(v) - wd*lr*mat(params) - lr*mat(params_grad); + tt::affine_transform(v, v, params, params_grad, momentum, -wd*lr, -lr); + + return v; + } + + template + const tensor& operator() ( + const float learning_rate, + const fc_& l, + const tensor& params_grad + ) + { + update_considering_bias(learning_rate, l, params_grad, params_grad.size()-l.get_num_outputs()); + return v; + } + + template < + long _num_filters, + long _nr, + long _nc, + int _stride_y, + int _stride_x, + int _padding_y, + int _padding_x + > + const tensor& operator() ( + const float learning_rate, + const con_<_num_filters,_nr,_nc,_stride_y,_stride_x,_padding_y,_padding_x>& l, + const tensor& params_grad + ) + { + update_considering_bias(learning_rate, l, params_grad, params_grad.size()-l.num_filters()); + return v; + } + + template < + long _num_filters, + long _nr, + long _nc, + int _stride_y, + int _stride_x, + int _padding_y, + int _padding_x + > + const tensor& operator() ( + const float learning_rate, + const cont_<_num_filters,_nr,_nc,_stride_y,_stride_x,_padding_y,_padding_x>& l, + const tensor& params_grad + ) + { + update_considering_bias(learning_rate, l, params_grad, params_grad.size()-l.num_filters()); + return v; + } + + template < layer_mode mode > + const tensor& operator() ( + const float learning_rate, + const bn_& l, + const tensor& params_grad + ) + { + update_considering_bias(learning_rate, l, params_grad, params_grad.size()/2); + return v; + } + + friend void serialize(const sgd& item, std::ostream& out) + { + serialize("sgd2", out); + serialize(item.v, out); + serialize(item.weight_decay, out); + serialize(item.momentum, out); + } + + friend void deserialize(sgd& item, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != "sgd2") + throw serialization_error("Unexpected version found while deserializing dlib::sgd."); + deserialize(item.v, in); + deserialize(item.weight_decay, in); + deserialize(item.momentum, in); + } + + friend std::ostream& operator<< (std::ostream& out, const sgd& item) + { + out << "sgd: weight_decay="< + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class EXAMPLE_SOLVER + { + /*! + WHAT THIS OBJECT REPRESENTS + A solver defines the parameter update rule for a single layer in a deep + neural network. It takes a parameter gradient vector and the layer's + parameters and tells you how the parameters should be updated. + Importantly, each solver instance is used with only one layer in a network. + This allows us to define solvers that have per layer state, for example, a + solver may keep a momentum term and apply it to its update rule. + + Note that there is no dlib::EXAMPLE_SOLVER type. It is shown here purely + to document the interface a solver object must implement. + !*/ + + public: + + EXAMPLE_SOLVER( + ); + + template + const tensor& operator() ( + const float learning_rate, + const layer_type& l, + const tensor& params_grad + ) + /*! + requires + - l.get_layer_params().size() != 0 + - have_same_dimensions(l.get_layer_params(), params_grad) == true. + - When this function is invoked on a particular solver instance, it is + always supplied with the same layer instance, l. That is, the solver is + allowed to remember things from one invocation to another and to assume + that it is being serially applied to optimize the same layer's + parameters. + ensures + - Returns a step vector V that is intended to be used to update the + parameters by adding V to l.get_layer_params(). + - This function will use the given "learning rate" to compute V. How the + learning rate is used is solver dependent. But in general the learning + rate should be used to select the step size, i.e. to somehow determine + the magnitude of V. + !*/ + }; + + void serialize(const EXAMPLE_SOLVER& item, std::ostream& out); + void deserialize(EXAMPLE_SOLVER& item, std::istream& in); + /*! + provides serialization support + !*/ + + std::ostream& operator<< (std::ostream& out, const EXAMPLE_SOLVER& item); + /*! + Prints the solver's name and parameters to out. + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class sgd + { + /*! + WHAT THIS OBJECT REPRESENTS + This object implements the EXAMPLE_SOLVER interface defined above. It is a + basic stochastic gradient descent solver which uses momentum and weight + decay. In particular, it computes the update vector V according to: + V = momentum*V - weight_decay*learning_rate*l.get_layer_params() - learning_rate*params_grad; + Here V is a momentum term that is remembered by the solver from one + invocation of operator() to the next. + + + Note that the actual learning rate and weight decay used by the solver are + multiplied by the per layer multipliers. That is, the solver will call + get_learning_rate_multiplier(l) and get_weight_decay_multiplier(l) and + multiply these values with the nominal learning rate and weight decay, + respectively, to determine the values it will use during each step. It is + also overloaded to allow additional learning rate multipliers to be applied + to fc_ and con_ bias parameters. + !*/ + public: + + sgd( + ); + /*! + ensures + - #get_weight_decay() == 0.0005 + - #get_momentum() == 0.9 + !*/ + + explicit sgd( + float weight_decay, + float momentum = 0.9 + ); + /*! + requires + - weight_decay >= 0 + - momentum >= 0 + ensures + - #get_weight_decay() == weight_decay + - #get_momentum() == momentum + !*/ + + float get_weight_decay () const; + float get_momentum () const; + }; + + void serialize(const sgd& item, std::ostream& out); + void deserialize(sgd& item, std::istream& in); + /*! + provides serialization support + !*/ + + std::ostream& operator<< (std::ostream& out, const sgd& item); + /*! + Prints the solver's name and parameters to out. + !*/ + +// ---------------------------------------------------------------------------------------- + + class adam + { + /*! + WHAT THIS OBJECT REPRESENTS + This object implements the EXAMPLE_SOLVER interface defined above. In + particular, it implements the ADAM parameter update method described in the + paper: + Kingma, Diederik P., and Jimmy Ba Adam. "A method for stochastic + optimization." International Conference on Learning Representation. 2015. + + + Note that the actual learning rate and weight decay used by the solver are + multiplied by the per layer multipliers. That is, the solver will call + get_learning_rate_multiplier(l) and get_weight_decay_multiplier(l) and + multiply these values with the nominal learning rate and weight decay, + respectively, to determine the values it will use during each step. It is + also overloaded to allow additional learning rate multipliers to be applied + to fc_ and con_ bias parameters. + !*/ + + public: + + adam( + ); + /*! + ensures + - #get_weight_decay() == 0.0005 + - #get_momentum1() == 0.9 + - #get_momentum2() == 0.999 + !*/ + + adam( + float weight_decay, + float momentum1, + float momentum2 + ); + /*! + requires + - weight_decay >= 0 + - 0 <= momentum1 < 1 + - 0 <= momentum2 < 1 + ensures + - #get_weight_decay() == weight_decay + - #get_momentum1() == momentum1 + - #get_momentum2() == momentum2 + !*/ + + float get_weight_decay () const; + float get_momentum1 () const; + float get_momentum2 () const; + }; + + void serialize(const adam& item, std::ostream& out); + void deserialize(adam& item, std::istream& in); + /*! + provides serialization support + !*/ + + std::ostream& operator<< (std::ostream& out, const adam& item); + /*! + Prints the solver's name and parameters to out. + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DNn_SOLVERS_ABSTRACT_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/dnn/trainer.h b/lib/3rdParty/dlib/include/dlib/dnn/trainer.h new file mode 100644 index 00000000..0ed18e66 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/dnn/trainer.h @@ -0,0 +1,1333 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DNn_TRAINER_H_ +#define DLIB_DNn_TRAINER_H_ + +#include "trainer_abstract.h" +#include "core.h" +#include "solvers.h" +#include "../statistics.h" +#include +#include +#include +#include "../serialize.h" + +#include "../pipe.h" +#include "../threads.h" +#include "../cuda/cuda_dlib.h" +#include "../statistics/running_gradient.h" +#include +#include +#include +#include +#include +#include +#include "../dir_nav.h" +#include "../md5.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template + struct dnn_job_t + { + dnn_job_t() = default; + dnn_job_t(const dnn_job_t&) = delete; + dnn_job_t& operator=(const dnn_job_t&) = delete; + + std::vector> labels; + std::vector t; + std::vector have_data; // have_data[i] is true if there is data in labels[i] and t[i]. + bool test_only = false; + }; + + template + void swap(dnn_job_t& a, dnn_job_t& b) + { + a.labels.swap(b.labels); + a.t.swap(b.t); + a.have_data.swap(b.have_data); + std::swap(a.test_only,b.test_only); + } + } + + enum class force_flush_to_disk { + no = 0, + yes = 1 + }; + + template < + typename net_type, + typename solver_type = sgd + > + class dnn_trainer : private threaded_object + { + public: + + static_assert(is_loss_layer_type::value, + "The last layer in a network must be a loss layer."); + + typedef typename net_type::training_label_type training_label_type; + typedef typename net_type::input_type input_type; + const static size_t num_computational_layers = net_type::num_computational_layers; + const static size_t num_layers = net_type::num_layers; + private: + typedef impl::dnn_job_t job_t; + public: + + dnn_trainer() = delete; + dnn_trainer(const dnn_trainer&) = delete; + dnn_trainer& operator=(const dnn_trainer&) = delete; + + explicit dnn_trainer(net_type& net_) : job_pipe(0), net(net_) + { + solver_type default_solver; + devices.push_back(std::make_shared(dlib::cuda::get_device(), net, default_solver)); + + init(); + } + + dnn_trainer( + net_type& net_, + const solver_type& solver_ + ) : job_pipe(0), net(net_) + { + devices.push_back(std::make_shared(dlib::cuda::get_device(), net, solver_)); + + init(); + } + + dnn_trainer( + net_type& net_, + const solver_type& solver_, + const std::vector& cuda_extra_devices + ) : job_pipe(0), net(net_) + { + devices.push_back(std::make_shared(dlib::cuda::get_device(), net, solver_)); + + const int total_devices = dlib::cuda::get_num_devices(); + + // Make device contexts for the extra device ids but be careful to avoid any + // duplicate ids. + std::set temp(cuda_extra_devices.begin(), cuda_extra_devices.end()); + temp.erase(devices[0]->device_id); + for (auto id : temp) + { + DLIB_CASSERT(0 <= id && id < total_devices, "Invalid CUDA device id given to dnn_trainer."); + // Switch to this device so that any tensor objects that get allocated when + // we create the device context happen on this device. + dlib::cuda::set_device(id); + devices.push_back(std::make_shared(id, net, solver_, clone_net())); + } + // Set the current device back to what it was before this constructor was + // called. + dlib::cuda::set_device(devices[0]->device_id); + + init(); + } + + ~dnn_trainer( + ) + { + job_pipe.disable(); + stop(); + wait(); + } + + net_type& get_net ( + force_flush_to_disk force_flush = force_flush_to_disk::yes + ) + { + wait_for_thread_to_pause(); + sync_to_disk(force_flush == force_flush_to_disk::yes); + propagate_exception(); + return net; + } + + + unsigned long get_mini_batch_size ( + ) const { return mini_batch_size; } + + void set_mini_batch_size ( + unsigned long batch_size + ) + { + DLIB_CASSERT(batch_size > 0); + mini_batch_size = batch_size; + } + + unsigned long get_max_num_epochs ( + ) const { return max_num_epochs; } + + void set_max_num_epochs ( + unsigned long num + ) + { + DLIB_CASSERT(num > 0); + max_num_epochs = num; + } + + void be_verbose ( + ) + { + verbose = true; + } + + void be_quiet ( + ) + { + verbose = false; + } + + + const std::vector& get_solvers ( + ) const + { + wait_for_thread_to_pause(); + propagate_exception(); + return devices[0]->solvers; + } + + void train_one_step ( + const std::vector& data, + const std::vector& labels + ) + { + DLIB_CASSERT(data.size() == labels.size()); + + train_one_step(data.begin(), data.end(), labels.begin()); + } + + template < + typename data_iterator, + typename label_iterator + > + void train_one_step ( + data_iterator dbegin, + data_iterator dend, + label_iterator lbegin + ) + { + DLIB_CASSERT(std::distance(dbegin, dend) > 0); + + print_periodic_verbose_status(); + sync_to_disk(); + send_job(false, dbegin, dend, lbegin); + + ++train_one_step_calls; + } + + void train_one_step ( + const std::vector& data + ) + { + train_one_step(data.begin(), data.end()); + } + + template < + typename data_iterator + > + void train_one_step ( + data_iterator dbegin, + data_iterator dend + ) + { + DLIB_CASSERT(std::distance(dbegin, dend) > 0); + print_periodic_verbose_status(); + sync_to_disk(); + send_job(false, dbegin, dend); + ++train_one_step_calls; + } + + void test_one_step ( + const std::vector& data, + const std::vector& labels + ) + { + DLIB_CASSERT(data.size() == labels.size()); + + test_one_step(data.begin(), data.end(), labels.begin()); + } + + template < + typename data_iterator, + typename label_iterator + > + void test_one_step ( + data_iterator dbegin, + data_iterator dend, + label_iterator lbegin + ) + { + DLIB_CASSERT(std::distance(dbegin, dend) > 0); + + print_periodic_verbose_status(); + sync_to_disk(); + send_job(true, dbegin, dend, lbegin); + + ++test_one_step_calls; + } + + void test_one_step ( + const std::vector& data + ) + { + test_one_step(data.begin(), data.end()); + } + + template < + typename data_iterator + > + void test_one_step ( + data_iterator dbegin, + data_iterator dend + ) + { + DLIB_CASSERT(std::distance(dbegin, dend) > 0); + print_periodic_verbose_status(); + sync_to_disk(); + send_job(true, dbegin, dend); + ++test_one_step_calls; + } + + void train ( + const std::vector& data, + const std::vector& labels + ) + { + DLIB_CASSERT(data.size() == labels.size() && data.size() > 0); + + // The reason these two loops don't initialize their counter variables but + // instead use class members is so we can include the state of the loops in the + // stuff written by sync_to_disk() + for (; + epoch_iteration < max_num_epochs && learning_rate >= min_learning_rate; + ++epoch_iteration) + { + using namespace std::chrono; + last_time = system_clock::now(); + clear_average_loss(); + for (; epoch_pos < data.size() && learning_rate >= min_learning_rate; epoch_pos += mini_batch_size) + { + if (verbose) + { + auto now_time = system_clock::now(); + if (now_time-last_time > seconds(20)) + { + last_time = now_time; + auto iter = epoch_iteration + epoch_pos/(double)data.size(); + std::cout << "epoch: " << rpad(cast_to_string(iter),epoch_string_pad) << " " + << "learning rate: " << rpad(cast_to_string(learning_rate),lr_string_pad) << " " + << "average loss: " << rpad(cast_to_string(get_average_loss()),string_pad) << " "; + print_progress(); + } + } + + sync_to_disk(); + send_job(false, data.begin()+epoch_pos, + data.begin()+std::min(epoch_pos+mini_batch_size,data.size()), + labels.begin()+epoch_pos); + } + epoch_pos = 0; + + if (verbose) + { + // Capitalize the E in Epoch so it's easy to grep out the lines that + // are for full epoch status statements. + std::cout << "Epoch: " << rpad(cast_to_string(epoch_iteration+1),epoch_string_pad) << " " + << "learning rate: " << rpad(cast_to_string(learning_rate),lr_string_pad) << " " + << "average loss: " << rpad(cast_to_string(get_average_loss()),string_pad) << " "; + print_progress(); + } + } + wait_for_thread_to_pause(); + // if we modified the network at all then be sure to sync the final result. + sync_to_disk(true); + } + + void train ( + const std::vector& data + ) + { + DLIB_CASSERT(data.size() > 0); + + const bool has_unsupervised_loss = std::is_same::value; + static_assert(has_unsupervised_loss, + "You can only call this version of train() when using an unsupervised loss."); + + // The reason these two loops don't initialize their counter variables but + // instead use class members is so we can include the state of the loops in the + // stuff written by sync_to_disk() + for (; + epoch_iteration < max_num_epochs && learning_rate >= min_learning_rate; + ++epoch_iteration) + { + using namespace std::chrono; + last_time = system_clock::now(); + clear_average_loss(); + for (; epoch_pos < data.size() && learning_rate >= min_learning_rate; epoch_pos += mini_batch_size) + { + if (verbose) + { + auto now_time = system_clock::now(); + if (now_time-last_time > seconds(20)) + { + last_time = now_time; + auto iter = epoch_iteration + epoch_pos/(double)data.size(); + std::cout << "epoch: " << rpad(cast_to_string(iter),epoch_string_pad) << " " + << "learning rate: " << rpad(cast_to_string(learning_rate),lr_string_pad) << " " + << "average loss: " << rpad(cast_to_string(get_average_loss()),string_pad) << " "; + print_progress(); + } + } + + sync_to_disk(); + send_job(false, data.begin()+epoch_pos, + data.begin()+std::min(epoch_pos+mini_batch_size,data.size())); + } + epoch_pos = 0; + + if (verbose) + { + // Capitalize the E in Epoch so it's easy to grep out the lines that + // are for full epoch status statements. + std::cout << "Epoch: " << rpad(cast_to_string(epoch_iteration+1),epoch_string_pad) << " " + << "learning rate: " << rpad(cast_to_string(learning_rate),lr_string_pad) << " " + << "average loss: " << rpad(cast_to_string(get_average_loss()),string_pad) << " "; + print_progress(); + } + } + wait_for_thread_to_pause(); + // if we modified the network at all then be sure to sync the final result. + sync_to_disk(true); + } + + void set_synchronization_file ( + const std::string& filename, + std::chrono::seconds time_between_syncs_ = std::chrono::minutes(15) + ) + { + last_sync_time = std::chrono::system_clock::now(); + sync_filename = filename; + time_between_syncs = time_between_syncs_; + + // check if the sync file already exists, if it does we should load it. + std::ifstream fin(newest_syncfile(), std::ios::binary); + if (fin) + deserialize(*this, fin); + } + + const std::string& get_synchronization_file ( + ) + { + return sync_filename; + } + + double get_average_loss ( + ) const + { + wait_for_thread_to_pause(); + return rs.mean(); + } + + double get_average_test_loss ( + ) const + { + wait_for_thread_to_pause(); + return rs_test.mean(); + } + + void clear_average_loss ( + ) + { + wait_for_thread_to_pause(); + rs.clear(); + } + + void set_learning_rate ( + double lr + ) + { + DLIB_CASSERT(lr > 0); + wait_for_thread_to_pause(); + if (learning_rate != lr) + { + steps_without_progress = 0; + test_steps_without_progress = 0; + previous_loss_values.clear(); + test_previous_loss_values.clear(); + } + learning_rate = lr; + lr_schedule.set_size(0); + } + + double get_learning_rate( + ) const + { + return learning_rate; + } + + void set_min_learning_rate ( + double lr + ) + { + DLIB_CASSERT(lr > 0); + wait_for_thread_to_pause(); + lr_schedule.set_size(0); + min_learning_rate = lr; + } + + double get_min_learning_rate ( + ) const + { + return min_learning_rate; + } + + template + void set_learning_rate_schedule ( + const matrix_exp& schedule + ) + { + DLIB_CASSERT(schedule.size() > 0); + DLIB_CASSERT(min(schedule) > 0); + set_learning_rate(schedule(0,0)); + set_min_learning_rate(min(schedule)); + set_learning_rate_shrink_factor(1); + lr_schedule = matrix_cast(reshape_to_column_vector(schedule)); + lr_schedule_pos = 0; + } + + const matrix& get_learning_rate_schedule ( + ) const + { + return lr_schedule; + } + + void set_iterations_without_progress_threshold ( + unsigned long thresh + ) + { + wait_for_thread_to_pause(); + lr_schedule.set_size(0); + iter_without_progress_thresh = thresh; + } + + unsigned long get_iterations_without_progress_threshold ( + ) const + { + return iter_without_progress_thresh; + } + + unsigned long get_steps_without_progress ( + ) const + { + return steps_without_progress; + } + + void set_test_iterations_without_progress_threshold ( + unsigned long thresh + ) + { + wait_for_thread_to_pause(); + lr_schedule.set_size(0); + test_iter_without_progress_thresh = thresh; + } + + unsigned long get_test_iterations_without_progress_threshold ( + ) const + { + return test_iter_without_progress_thresh; + } + + unsigned long get_test_steps_without_progress ( + ) const + { + return test_steps_without_progress; + } + + void set_learning_rate_shrink_factor ( + double shrink + ) + { + DLIB_CASSERT(0 < shrink && shrink <= 1); + wait_for_thread_to_pause(); + lr_schedule.set_size(0); + learning_rate_shrink = shrink; + steps_without_progress = 0; + test_steps_without_progress = 0; + } + + double get_learning_rate_shrink_factor ( + ) const + { + return learning_rate_shrink; + } + + unsigned long long get_train_one_step_calls ( + ) const + { + return train_one_step_calls; + } + + unsigned long long get_test_one_step_calls ( + ) const + { + return test_one_step_calls; + } + + private: + + void record_test_loss(double loss) + { + test_previous_loss_values.push_back(loss); + if (is_finite(loss)) + rs_test.add(loss); + // discard really old loss values. + while (test_previous_loss_values.size() > test_iter_without_progress_thresh) + test_previous_loss_values.pop_front(); + } + + void record_loss(double loss) + { + // This kind of budgeting causes our gradient checking to use a fixed amount of + // computational resources, regardless of the size of iter_without_progress_thresh. + gradient_check_budget += 200; + + rs.add(loss); + previous_loss_values.push_back(loss); + // discard really old loss values. + while (previous_loss_values.size() > iter_without_progress_thresh) + previous_loss_values.pop_front(); + } + + template + double compute_parameter_gradients(size_t device, job_t& next_job, const T&) + { + if (next_job.have_data[device]) + { + auto&& dev = *devices[device]; + dlib::cuda::set_device(dev.device_id); + if (next_job.test_only) + return dev.net.compute_loss(next_job.t[device], next_job.labels[device].begin()); + else + return dev.net.compute_parameter_gradients(next_job.t[device], next_job.labels[device].begin()); + } + else + { + return 0; + } + } + + double compute_parameter_gradients(size_t device, job_t& next_job, const no_label_type&) + { + if (next_job.have_data[device]) + { + auto&& dev = *devices[device]; + dlib::cuda::set_device(dev.device_id); + no_label_type pick_which_run_update; + if (next_job.test_only) + return dev.net.compute_loss(next_job.t[device]); + else + return dev.net.compute_parameter_gradients(next_job.t[device]); + } + else + { + return 0; + } + } + + void update_parameters(size_t device) + { + auto&& dev = *devices[device]; + dlib::cuda::set_device(dev.device_id); + dev.net.update_parameters(make_sstack(dev.solvers), learning_rate); + } + + void thread() try + { + training_label_type pick_which_run_update; + job_t next_job; + + std::vector> losses(devices.size()); + + std::vector averagers; + // An array of all the parameter tensors in the first network. We will + // periodically copy these tensors to all the other devices to make sure the + // different GPUs don't go out of sync. + std::vector reference_params; + visit_layer_parameters(devices[0]->net, [&](size_t, tensor& t) { reference_params.push_back(&t); }); + + // We make separate thread pools with just one thread in them because we want + // to make sure each device is always executed on the same thread. We care + // about this because there are thread_local context variables for some cuda + // components and they get allocated for each combination of thread and device. + // So if we make sure the same device always uses the same thread this will + // reduce the number of contexts we allocate from num_devices*num_devices to + // just num_devices. + std::vector> tp; + for (size_t i = 0; i < devices.size(); ++i) + tp.push_back(std::make_shared(1)); + + + main_iteration_counter = 0; + while(job_pipe.dequeue(next_job)) + { + if (next_job.test_only) + { + // compute the testing loss + for (size_t i = 0; i < devices.size(); ++i) + tp[i]->add_task_by_value([&,i](double& loss){ loss = compute_parameter_gradients(i, next_job, pick_which_run_update); }, losses[i]); + // aggregate loss values from all the network computations. + double theloss = 0; + for (auto&& loss : losses) + theloss += loss.get(); + record_test_loss(theloss/losses.size()); + + // Check if we should shrink the learning rate based on how the test + // error has been doing lately. + if (learning_rate_shrink != 1) + { + test_steps_without_progress = count_steps_without_decrease(test_previous_loss_values); + if (test_steps_without_progress >= test_iter_without_progress_thresh) + { + test_steps_without_progress = count_steps_without_decrease_robust(test_previous_loss_values); + if (test_steps_without_progress >= test_iter_without_progress_thresh) + { + // optimization has flattened out, so drop the learning rate. + learning_rate = learning_rate_shrink*learning_rate; + test_steps_without_progress = 0; + // Empty out some of the previous loss values so that test_steps_without_progress + // will decrease below test_iter_without_progress_thresh. + for (unsigned long cnt = 0; cnt < test_previous_loss_values_dump_amount+test_iter_without_progress_thresh/10 && test_previous_loss_values.size() > 0; ++cnt) + test_previous_loss_values.pop_front(); + } + } + } + continue; + } + + updated_net_since_last_sync = true; + ++main_iteration_counter; + // Call compute_parameter_gradients() and update_parameters() but pick the + // right version for unsupervised or supervised training based on the type + // of training_label_type. + for (size_t i = 0; i < devices.size(); ++i) + tp[i]->add_task_by_value([&,i](double& loss){ loss = compute_parameter_gradients(i, next_job, pick_which_run_update); }, losses[i]); + // aggregate loss values from all the network computations. + double theloss = 0; + for (auto&& loss : losses) + theloss += loss.get(); + record_loss(theloss/losses.size()); + + // Now, if there is more than one active device we need to synchronize the + // gradient updates between devices. So we do that now. + if (devices.size() > 1) + { + // if this is the first iteration then we need to setup the averagers. + // We can't do this outside the loop because the tensors that get + // averaged need to be allocated to their devices before we call set() + // so that the averagers can determine how best to average them. + if (averagers.size() == 0 || sync_file_reloaded) + { + averagers = std::vector(net_type::num_computational_layers); + // setup the averagers to point to the tensors in the networks. + std::vector> all_tensors(devices.size()); + for (size_t i = 0; i < all_tensors.size(); ++i) + { + all_tensors[i].resize(net_type::num_computational_layers); + visit_layer_parameter_gradients(devices[i]->net, [&](size_t j, tensor& t){ + all_tensors[i][j] = &t; + }); + } + // Now set each averager to average the tensors at the same layer in each + // network. + for (size_t i = 0; i < net_type::num_computational_layers; ++i) + { + std::vector temp(all_tensors.size()); + for (size_t j = 0; j < all_tensors.size(); ++j) + temp[j] = all_tensors[j][i]; + // ignore layers that don't have parameters + if (temp[0]->size() != 0) + averagers[i].set(temp); + } + + sync_file_reloaded = false; + } + + + for (auto&& d : devices) + cuda::device_synchronize(d->device_id); + + for (auto&& avg : averagers) + avg.average(); + } + + + // Now apply all the updates to each device. + for (size_t i = 0; i < devices.size(); ++i) + tp[i]->add_task_by_value([&,i](){ if (next_job.have_data[i]) update_parameters(i); }); + // and wait for the updates to all happen. + for (size_t i = 0; i < devices.size(); ++i) + tp[i]->wait_for_all_tasks(); + + + // Every now and then force all the parameters to be the same just to make + // sure they aren't drifting apart due to any non-deterministic behavior on + // the GPU. It's also important to do this on the first iteration because + // the different networks may be initialized differently when tensor data + // is first passed through them. So this code block deals with these + // issues. + if (devices.size() > 1 && main_iteration_counter%2000 == 1) + { + for (size_t i = 1; i < devices.size(); ++i) + { + visit_layer_parameters(devices[i]->net, [&](size_t j, tensor& t) + { + memcpy(t, *reference_params[j]); + }); + } + } + + // If we have been running for a while then check if the loss is still + // dropping. If it isn't then we will reduce the learning rate. Note that we + // have a "budget" that prevents us from calling + // count_steps_without_decrease() every iteration. We do this because + // it can be expensive to compute when previous_loss_values is large. + if (gradient_check_budget > iter_without_progress_thresh && learning_rate_shrink != 1) + { + gradient_check_budget = 0; + steps_without_progress = count_steps_without_decrease(previous_loss_values); + if (steps_without_progress >= iter_without_progress_thresh) + { + // Double check that we aren't seeing decrease. This second check + // discards the top 10% largest values and checks again. We do + // this because sometimes a mini-batch might be bad and cause the + // loss to suddenly jump up, making count_steps_without_decrease() + // return a large number. But if we discard the top 10% of the + // values in previous_loss_values then we are robust to that kind + // of noise. Another way of looking at it, if the reason + // count_steps_without_decrease() returns a large value is only + // because the most recent loss values have suddenly been large, + // then we shouldn't stop or lower the learning rate. We should + // keep going until whatever disturbance we hit is damped down. + steps_without_progress = count_steps_without_decrease_robust(previous_loss_values); + if (steps_without_progress >= iter_without_progress_thresh) + { + // optimization has flattened out, so drop the learning rate. + learning_rate = learning_rate_shrink*learning_rate; + steps_without_progress = 0; + // Empty out some of the previous loss values so that steps_without_progress + // will decrease below iter_without_progress_thresh. + for (unsigned long cnt = 0; cnt < previous_loss_values_dump_amount+iter_without_progress_thresh/10 && previous_loss_values.size() > 0; ++cnt) + previous_loss_values.pop_front(); + } + } + } + else if (lr_schedule.size() != 0) // or use the learning rate schedule if we have one. + { + if (lr_schedule_pos < lr_schedule.size()) + learning_rate = lr_schedule(lr_schedule_pos++); + else + learning_rate = lr_schedule(lr_schedule.size()-1)*0.99; + } + } + } + catch(...) + { + // If an exception happens then permanently disable the trainer object. + job_pipe.disable(); + std::lock_guard lock(eptr_mutex); + eptr = std::current_exception(); + } + + void wait_for_thread_to_pause() const + { + job_pipe.wait_for_num_blocked_dequeues(1); + } + + const static long string_pad = 11; + const static long epoch_string_pad = 4; + const static long lr_string_pad = 4; + + void init() + { + max_num_epochs = 10000; + mini_batch_size = 128; + verbose = false; + learning_rate = 1e-2; + min_learning_rate = 1e-5; + iter_without_progress_thresh = 2000; + steps_without_progress = 0; + test_iter_without_progress_thresh = 500; + test_steps_without_progress = 0; + + learning_rate_shrink = 0.1; + epoch_iteration = 0; + epoch_pos = 0; + train_one_step_calls = 0; + test_one_step_calls = 0; + gradient_check_budget = 0; + lr_schedule_pos = 0; + + main_iteration_counter = 0; + main_iteration_counter_at_last_disk_sync = 0; + prob_loss_increasing_thresh_default_value = 0.99; + prob_loss_increasing_thresh_max_value = 0.99999; + prob_loss_increasing_thresh = prob_loss_increasing_thresh_default_value; + updated_net_since_last_sync = false; + sync_file_reloaded = false; + previous_loss_values_dump_amount = 400; + test_previous_loss_values_dump_amount = 100; + + rs_test = running_stats_decayed(200); + + start(); + } + + // serialize and deserialize are private because we hold net by reference so + // allowing someone to serialize this training object is weird and will likely + // result in user errors. However, we use these functions as part of the automatic + // sync code in this object. + friend void serialize(const dnn_trainer& item, std::ostream& out) + { + item.wait_for_thread_to_pause(); + int version = 12; + serialize(version, out); + + size_t nl = dnn_trainer::num_layers; + serialize(nl, out); + serialize(item.rs, out); + serialize(item.rs_test, out); + serialize(item.previous_loss_values, out); + serialize(item.max_num_epochs, out); + serialize(item.mini_batch_size, out); + serialize(item.verbose, out); + serialize(item.net, out); + serialize(item.devices[0]->solvers, out); + serialize(item.learning_rate.load(), out); + serialize(item.min_learning_rate, out); + serialize(item.iter_without_progress_thresh.load(), out); + serialize(item.steps_without_progress.load(), out); + serialize(item.learning_rate_shrink.load(), out); + serialize(item.epoch_iteration, out); + serialize(item.epoch_pos, out); + serialize(item.train_one_step_calls, out); + serialize(item.test_one_step_calls, out); + serialize(item.lr_schedule, out); + serialize(item.lr_schedule_pos, out); + serialize(item.test_iter_without_progress_thresh.load(), out); + serialize(item.test_steps_without_progress.load(), out); + serialize(item.test_previous_loss_values, out); + serialize(item.previous_loss_values_dump_amount, out); + serialize(item.test_previous_loss_values_dump_amount, out); + + } + friend void deserialize(dnn_trainer& item, std::istream& in) + { + item.wait_for_thread_to_pause(); + int version = 0; + deserialize(version, in); + if (version != 12) + throw serialization_error("Unexpected version found while deserializing dlib::dnn_trainer."); + + size_t num_layers = 0; + deserialize(num_layers, in); + if (num_layers != dnn_trainer::num_layers) + { + std::ostringstream sout; + sout << "Error deserializing dlib::dnn_trainer. The saved sync file is for a network with " << std::endl; + sout << "a different number of layers. We expected the number of layers to be " << dnn_trainer::num_layers << " but" << std::endl; + sout << "instead the file contains " << num_layers << " layers." << std::endl; + throw serialization_error(sout.str()); + } + + double dtemp; long ltemp; + deserialize(item.rs, in); + deserialize(item.rs_test, in); + deserialize(item.previous_loss_values, in); + deserialize(item.max_num_epochs, in); + deserialize(item.mini_batch_size, in); + deserialize(item.verbose, in); + deserialize(item.net, in); + deserialize(item.devices[0]->solvers, in); + deserialize(dtemp, in); item.learning_rate = dtemp; + deserialize(item.min_learning_rate, in); + deserialize(ltemp, in); item.iter_without_progress_thresh = ltemp; + deserialize(ltemp, in); item.steps_without_progress = ltemp; + deserialize(dtemp, in); item.learning_rate_shrink = dtemp; + deserialize(item.epoch_iteration, in); + deserialize(item.epoch_pos, in); + deserialize(item.train_one_step_calls, in); + deserialize(item.test_one_step_calls, in); + deserialize(item.lr_schedule, in); + deserialize(item.lr_schedule_pos, in); + deserialize(ltemp, in); item.test_iter_without_progress_thresh = ltemp; + deserialize(ltemp, in); item.test_steps_without_progress = ltemp; + deserialize(item.test_previous_loss_values, in); + deserialize(item.previous_loss_values_dump_amount, in); + deserialize(item.test_previous_loss_values_dump_amount, in); + + if (item.devices.size() > 1) + { + const auto prev_dev = dlib::cuda::get_device(); + // initialize all the other device networks and solver objects + for (size_t i = 1; i < item.devices.size(); ++i) + { + // Switch to this device so that any tensor objects that get allocated when + // we copy this stuff happen on this device. + dlib::cuda::set_device(item.devices[i]->device_id); + item.devices[i]->solvers = item.devices[0]->solvers; + item.devices[i]->net = item.devices[0]->net; + } + dlib::cuda::set_device(prev_dev); + } + } + + void sync_to_disk ( + bool do_it_now = false + ) + { + // don't sync anything if we haven't updated the network since the last sync + if (!updated_net_since_last_sync) + return; + + // If the sync file isn't set then don't do anything. + if (sync_filename.size() == 0) + return; + + // Only sync if it has been long enough since the last sync or we are being + // explicitly forced to do it. + if (std::chrono::system_clock::now() - last_sync_time > time_between_syncs || + do_it_now) + { + wait_for_thread_to_pause(); + + // compact network before saving to disk. + this->net.clean(); + + // if the loss has actually been going up since the last time we saved our + // state to disk then something has probably gone wrong in the + // optimization. So in this case we do the opposite and recall the + // previously saved state in the hopes that the problem won't reoccur. + if (loss_increased_since_last_disk_sync()) + { + std::ifstream fin(newest_syncfile(), std::ios::binary); + deserialize(*this, fin); + sync_file_reloaded = true; + if (verbose) + std::cout << "Loss has been increasing, reloading saved state from " << newest_syncfile() << std::endl; + } + else + { + + const std::string filename = oldest_syncfile(); + serialize(filename) << *this; + + if (verbose) + std::cout << "Saved state to " << filename << std::endl; + } + + last_sync_time = std::chrono::system_clock::now(); + main_iteration_counter_at_last_disk_sync = main_iteration_counter; + updated_net_since_last_sync = false; + } + } + + std::string newest_syncfile ( + ) + { + return select_newest_file(sync_filename, sync_filename + "_"); + } + + std::string oldest_syncfile ( + ) + { + return select_oldest_file(sync_filename, sync_filename + "_"); + } + + bool loss_increased_since_last_disk_sync() + { + size_t gradient_updates_since_last_sync = main_iteration_counter - main_iteration_counter_at_last_disk_sync; + + // if we haven't synced anything to disk yet then return false. + if (!std::ifstream(newest_syncfile(), std::ios::binary)) + return false; + + for (auto x : previous_loss_values) + { + // If we get a NaN value of loss assume things have gone horribly wrong and + // we should reload the state of the trainer. + if (std::isnan(x)) + return true; + } + + // if we haven't seen much data yet then just say false. Or, alternatively, if + // it's been too long since the last sync then don't reload either. + if (gradient_updates_since_last_sync < 30 || previous_loss_values.size() < 2*gradient_updates_since_last_sync) + return false; + + // Now look at the data since a little before the last disk sync. We will + // check if the loss is getting bettor or worse. + running_gradient g; + for (size_t i = previous_loss_values.size() - 2*gradient_updates_since_last_sync; i < previous_loss_values.size(); ++i) + g.add(previous_loss_values[i]); + + // if the loss is very likely to be increasing then return true + const double prob = g.probability_gradient_greater_than(0); + if (prob > prob_loss_increasing_thresh && prob_loss_increasing_thresh <= prob_loss_increasing_thresh_max_value) + { + // Exponentially decay the threshold towards 1 so that if we keep finding + // the loss to be increasing over and over we will make the test + // progressively harder and harder until it fails, therefore ensuring we + // can't get stuck reloading from a previous state over and over. + prob_loss_increasing_thresh = 0.1*prob_loss_increasing_thresh + 0.9*1; + return true; + } + else + { + // decay back to the default threshold + prob_loss_increasing_thresh = std::pow(prob_loss_increasing_thresh, 10.0); + // but don't decay below the default value + prob_loss_increasing_thresh = std::max(prob_loss_increasing_thresh, prob_loss_increasing_thresh_default_value); + + return false; + } + } + + + struct clone_net{}; + + // per device state. All the containers have the same number of objects in them. + struct device_data + { + device_data( + int device_id_, + net_type& net_, + const solver_type& solver_ + ) : device_id(device_id_), net(net_), solvers(num_computational_layers, solver_) {} + + device_data( + int device_id_, + net_type& net_, + const solver_type& solver_, + clone_net + ) : device_id(device_id_), net_copy(std::make_shared(net_)), net(*net_copy), solvers(num_computational_layers, solver_) {} + + int device_id; + std::shared_ptr net_copy; + net_type& net; + std::vector solvers; + }; + + template < + typename data_iterator, + typename label_iterator + > + void send_job ( + bool test_only, + data_iterator dbegin, + data_iterator dend, + label_iterator lbegin + ) + { + propagate_exception(); + size_t num = std::distance(dbegin, dend); + size_t devs = devices.size(); + job.t.resize(devs); + job.labels.resize(devs); + job.have_data.resize(devs); + job.test_only = test_only; + + // chop the data into devs blocks, each of about block_size elements. + size_t block_size = (num+devs-1)/devs; + + const auto prev_dev = dlib::cuda::get_device(); + for (size_t i = 0; i < devs; ++i) + { + dlib::cuda::set_device(devices[i]->device_id); + + size_t start = i*block_size; + size_t stop = std::min(num, start+block_size); + + if (start < stop) + { + devices[i]->net.to_tensor(dbegin+start, dbegin+stop, job.t[i]); + job.labels[i].assign(lbegin+start, lbegin+stop); + job.have_data[i] = true; + } + else + { + job.have_data[i] = false; + } + } + + dlib::cuda::set_device(prev_dev); + job_pipe.enqueue(job); + } + + template < + typename data_iterator + > + void send_job ( + bool test_only, + data_iterator dbegin, + data_iterator dend + ) + { + typename std::vector::iterator nothing; + send_job(test_only, dbegin, dend, nothing); + } + + void print_progress() + { + if (lr_schedule.size() == 0) + { + if (test_previous_loss_values.size() == 0) + std::cout << "steps without apparent progress: " << steps_without_progress; + else + std::cout << "steps without apparent progress: train=" << steps_without_progress << ", test=" << test_steps_without_progress; + } + else + { + std::ostringstream sout; + sout << "percent complete: " << std::fixed << std::setprecision(2) << 100.0*lr_schedule_pos/(double)lr_schedule.size() << "%"; + std::cout << sout.str(); + } + std::cout << std::endl; + } + + void print_periodic_verbose_status() + { + if (verbose) + { + using namespace std::chrono; + auto now_time = system_clock::now(); + if (now_time-last_time > seconds(40)) + { + last_time = now_time; + std::cout << "step#: " << rpad(cast_to_string(train_one_step_calls),epoch_string_pad) << " " + << "learning rate: " << rpad(cast_to_string(learning_rate),lr_string_pad) << " "; + if (test_previous_loss_values.size() == 0) + { + std::cout << "average loss: " << rpad(cast_to_string(get_average_loss()),string_pad) << " "; + } + else + { + std::cout << "train loss: " << rpad(cast_to_string(get_average_loss()),string_pad) << " "; + std::cout << "test loss: " << rpad(cast_to_string(get_average_test_loss()),string_pad) << " "; + } + print_progress(); + clear_average_loss(); + } + } + } + + std::vector> devices; + dlib::pipe job_pipe; + job_t job; + + + running_stats rs; + running_stats_decayed rs_test; + std::deque previous_loss_values; + unsigned long max_num_epochs; + size_t mini_batch_size; + bool verbose; + net_type& net; + std::atomic learning_rate; + double min_learning_rate; + std::atomic iter_without_progress_thresh; + std::atomic steps_without_progress; + + std::atomic test_iter_without_progress_thresh; + std::atomic test_steps_without_progress; + std::deque test_previous_loss_values; + + std::atomic learning_rate_shrink; + std::chrono::time_point last_sync_time; + std::string sync_filename; + std::chrono::seconds time_between_syncs; + unsigned long epoch_iteration; + size_t epoch_pos; + std::chrono::time_point last_time; + unsigned long long train_one_step_calls; + unsigned long long test_one_step_calls; + matrix lr_schedule; + long lr_schedule_pos; + unsigned long gradient_check_budget; + + std::exception_ptr eptr = nullptr; + mutable std::mutex eptr_mutex; + void propagate_exception() const + { + std::lock_guard lock(eptr_mutex); + if (eptr) + std::rethrow_exception(eptr); + } + + // These 5 variables are not serialized + size_t main_iteration_counter; + size_t main_iteration_counter_at_last_disk_sync; + double prob_loss_increasing_thresh_default_value; + double prob_loss_increasing_thresh_max_value; + double prob_loss_increasing_thresh; + std::atomic updated_net_since_last_sync; + + bool sync_file_reloaded; + unsigned long previous_loss_values_dump_amount; + unsigned long test_previous_loss_values_dump_amount; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename net_type, + typename solver_type + > + std::ostream& operator<< ( + std::ostream& out, + dnn_trainer& trainer + ) + { + using std::endl; + out << "dnn_trainer details: \n"; + out << " net_type::num_layers: " << net_type::num_layers << endl; + // figure out how big the net is in MB. + std::ostringstream sout; + net_type temp = trainer.get_net(); // make a copy so that we can clean it without mutating the trainer's net. + temp.clean(); + serialize(temp, sout); + out << " net size: " << sout.str().size()/1024.0/1024.0 << "MB" << endl; + // Don't include the loss params in the hash since we print them on the next line. + // They also aren't really part of the "architecture" of the network. + out << " net architecture hash: " << md5(cast_to_string(trainer.get_net().subnet())) << endl; + out << " loss: " << trainer.get_net().loss_details() << endl; + + out << " synchronization file: " << trainer.get_synchronization_file() << endl; + out << " trainer.get_solvers()[0]: " << trainer.get_solvers()[0] << endl; + auto sched = trainer.get_learning_rate_schedule(); + if (sched.size() != 0) + { + out << " using explicit user-supplied learning rate schedule" << endl; + } + else + { + out << " learning rate: "<< trainer.get_learning_rate() << endl; + out << " learning rate shrink factor: "<< trainer.get_learning_rate_shrink_factor() << endl; + out << " min learning rate: "<< trainer.get_min_learning_rate() << endl; + out << " iterations without progress threshold: "<< trainer.get_iterations_without_progress_threshold() << endl; + out << " test iterations without progress threshold: "<< trainer.get_test_iterations_without_progress_threshold() << endl; + } + return out; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DNn_TRAINER_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/dnn/trainer_abstract.h b/lib/3rdParty/dlib/include/dlib/dnn/trainer_abstract.h new file mode 100644 index 00000000..3bfb6dc9 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/dnn/trainer_abstract.h @@ -0,0 +1,765 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_DNn_TRAINER_ABSTRACT_H_ +#ifdef DLIB_DNn_TRAINER_ABSTRACT_H_ + +#include "core_abstract.h" +#include "solvers_abstract.h" +#include +#include + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + enum class force_flush_to_disk { + no = 0, + yes = 1 + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename net_type, + typename solver_type = sgd + > + class dnn_trainer + { + /*! + REQUIREMENTS ON net_type + - net_type is an add_loss_layer object. + + REQUIREMENTS ON solver_type + - solver_type is an implementation of the EXAMPLE_SOLVER interface defined + in solvers_abstract.h + + WHAT THIS OBJECT REPRESENTS + This object is a tool training a deep neural network. To use it you supply + a neural network type and a solver, then you call train() with your + training data and it will output a new network instance that has hopefully + learned something useful from your training data. + + If you are compiling with CUDA then this object will use the GPU that is + currently selected (i.e. the one indicated by cudaGetDevice()) when + dnn_trainer is constructed. It will continue to use that device even if + you later change it by a call to cudaSetDevice(). + + EXCEPTIONS + If an exception is thrown by any part of the neural network during training + then the exception will be propagated out of the trainer to the user. + Moreover, the trainer instance will be unusable and should be destroyed. + !*/ + + public: + + typedef typename net_type::training_label_type training_label_type; + typedef typename net_type::input_type input_type; + const static size_t num_computational_layers = net_type::num_computational_layers; + + dnn_trainer() = delete; + dnn_trainer(const dnn_trainer&) = delete; + dnn_trainer& operator=(const dnn_trainer&) = delete; + + dnn_trainer( + net_type& net, + const solver_type& solver = solver_type(), + const std::vector& cuda_extra_devices = {} + ); + /*! + requires + - for all valid i: + - 0 <= cuda_extra_devices[i] < dlib::cuda::get_num_devices() + ensures + - &#get_net() == &net + (i.e. The dnn_trainer holds a reference to net, it does not copy it. + Therefore, you must ensure net has a lifetime at least as long as the + dnn_trainer). + - #get_solvers() == a set of solvers that are all initialized with the + provided solver instance. + - #get_max_num_epochs() == 10000 + - #get_mini_batch_size() == 128 + - #get_learning_rate() == 1e-2 + - #get_min_learning_rate() == 1e-5 + - #get_iterations_without_progress_threshold() == 2000 + - #get_test_iterations_without_progress_threshold() == 500 + - #get_learning_rate_shrink_factor() == 0.1 + - #get_learning_rate_schedule().size() == 0 + - #get_train_one_step_calls() == 0 + - #get_test_one_step_calls() == 0 + - #get_synchronization_file() == "" + - if (cuda_extra_devices.size() > 0) then + - This object will use multiple graphics cards to run the learning + algorithms. In particular, it will always use whatever device is + currently selected on the calling thread (the device indicated by + cudaGetDevice()). In addition, you can ask to use additional + devices, which you do by putting their device numbers into + cuda_extra_devices. + !*/ + + net_type& get_net ( + force_flush_to_disk force_flush = force_flush_to_disk::yes + ); + /*! + ensures + - returns the neural network object used by this trainer. This is the + network that is optimized when you call train() or train_one_step(). + Recall that the dnn_trainer doesn't contain the net_type object but + simply holds a reference to an external network which was provided to the + dnn_trainer's constructor. + - This function blocks until all threads inside the dnn_trainer have + stopped touching the net. + - If force_flush is yes, then this function will sync the trainer state to + disk if the current state hasn't already been synced to disk since the + last network modification. + !*/ + + const std::vector& get_solvers ( + ) const; + /*! + ensures + - returns the solvers used to optimize each layer of the neural network + get_net(). In particular, the first layer's solver is + get_solvers()[0], the second layer's solver is + get_solvers()[1], and so on. + - This function blocks until all threads inside the dnn_trainer have + stopped touching the net. + !*/ + + unsigned long get_mini_batch_size ( + ) const; + /*! + ensures + - During training, we call the network's update() routine over and over + with training data. The number of training samples we give to each call + to update is the "mini-batch size", which is defined by + get_mini_batch_size(). + !*/ + + void set_mini_batch_size ( + unsigned long batch_size + ); + /*! + requires + - batch_size > 0 + ensures + - #get_mini_batch_size() == batch_size + !*/ + + unsigned long get_max_num_epochs ( + ) const; + /*! + ensures + - train() will execute at most get_max_num_epochs() iterations over the + training data before returning. + !*/ + + void set_max_num_epochs ( + unsigned long num + ); + /*! + requires + - num > 0 + ensures + - #get_max_num_epochs() == num + !*/ + + void set_learning_rate ( + double lr + ); + /*! + requires + - lr > 0 + ensures + - #get_learning_rate() == lr + - #get_learning_rate_schedule().size() == 0 + - This function blocks until all threads inside the dnn_trainer have + stopped touching the net. + !*/ + + double get_learning_rate( + ) const; + /*! + ensures + - During each training step, a solver tells us how to modify the parameters + of each layer in the network. It does this by outputting a step vector + that, when added to the parameters, will hopefully result in improved + network performance. The learning rate is one of the inputs to the + solver and influences the size of this step vector. This function + returns the current learning rate, that is, the learning rate that will + be used during the next training step. + !*/ + + void set_min_learning_rate ( + double lr + ); + /*! + requires + - lr > 0 + ensures + - #get_min_learning_rate() == lr + - #get_learning_rate_schedule().size() == 0 + - This function blocks until all threads inside the dnn_trainer have + stopped touching the net. + !*/ + + double get_min_learning_rate ( + ) const; + /*! + ensures + - During training via this->train(), this object will test if progress is + still being made and if it isn't then it will reduce get_learning_rate() + by setting it to get_learning_rate()*get_learning_rate_shrink_factor(). + However, it will not reduce it below get_min_learning_rate(). Once this + minimum learning rate is crossed the training will terminate. + - get_min_learning_rate() doesn't apply if you are using train_one_step(). + You can keep calling train_one_step() as many times as you want and the + learning rate will drop infinitely close to 0 if you run long enough. + !*/ + + template + void set_learning_rate_schedule ( + const matrix_exp& schedule + ); + /*! + requires + - schedule.size() > 0 + - min(schedule) > 0 + ensures + - #get_learning_rate_schedule() == reshape_to_column_vector(schedule) + - #get_learning_rate() == schedule(0,0) + - #get_min_learning_rate() == min(schedule) + - #set_learning_rate_shrink_factor() == 1 + !*/ + + const matrix& get_learning_rate_schedule ( + ) const; + /*! + ensures + - if (this function returns a non-empty matrix) then + - This trainer will use an explicit learning rate schedule defined by + the learning rate values in get_learning_rate_schedule(). For + example, if get_learning_rate_schedule() returned {0.1, 0.09, 0.08, + 0.07, 0.06} then the first training mini-batch would use a learning + rate of 0.1, then the next training mini-batch uses 0.09, and then + 0.8, and so on until the end of the schedule is reached. + + If you continue to run training after the end of the schedule has + been reached then the learning rate will be fixed to 0.99 times the + final value. So in our example, eventually the learning rate would + be fixed to 0.99*0.06. This allows you to test if we have reached the + end of the schedule by checking if get_learning_rate() >= 0.06. + !*/ + + unsigned long get_steps_without_progress ( + ) const; + /*! + ensures + - if (get_learning_rate_shrink_factor() != 1) then + - returns an estimate of how many mini-batches have executed without us + observing a statistically significant decrease in the training error. + - else + - returns 0 + !*/ + + void set_iterations_without_progress_threshold ( + unsigned long thresh + ); + /*! + ensures + - #get_iterations_without_progress_threshold() == thresh + - #get_learning_rate_schedule().size() == 0 + - This function blocks until all threads inside the dnn_trainer have + stopped touching the net. + !*/ + + unsigned long get_iterations_without_progress_threshold ( + ) const; + /*! + ensures + - This object monitors the progress of training and estimates if the + training error is being reduced. It does this by looking at the previous + get_iterations_without_progress_threshold() mini-batch results and + applying the statistical test defined by the running_gradient object to + see if the training error is getting smaller. If it isn't being reduced + then get_learning_rate() is made smaller by a factor of get_learning_rate_shrink_factor(). + + Therefore, get_iterations_without_progress_threshold() should always be + set to something sensibly large so that this test can be done with + reasonably high confidence. Think of this test as saying "if the loss + hasn't decreased for the previous get_iterations_without_progress_threshold() + then shrink the learning rate". + !*/ + + void set_learning_rate_shrink_factor ( + double shrink + ); + /*! + requires + - 0 < shrink && shrink <= 1 + ensures + - #get_learning_rate_shrink_factor() == shrink + - #get_learning_rate_schedule().size() == 0 + - This function blocks until all threads inside the dnn_trainer have + stopped touching the net. + !*/ + + double get_learning_rate_shrink_factor ( + ) const; + /*! + ensures + - Whenever the training routine thinks it isn't making progress anymore it + will reduce get_learning_rate() by multiplying it by get_learning_rate_shrink_factor(). + - You can disable the automatic learning rate reduction by setting + get_learning_rate_shrink_factor() to 1. + !*/ + + unsigned long long get_train_one_step_calls ( + ) const; + /*! + ensures + - returns the number of times train_one_step() has been called. + !*/ + + unsigned long long get_test_one_step_calls ( + ) const; + /*! + ensures + - returns the number of times test_one_step() has been called. + !*/ + + void be_verbose ( + ); + /*! + ensures + - This object will print status messages to standard out so that a + user can observe the progress of the algorithm. + !*/ + + void be_quiet ( + ); + /*! + ensures + - This object will not print anything to standard out + !*/ + + void set_synchronization_file ( + const std::string& filename, + std::chrono::seconds time_between_syncs = std::chrono::minutes(15) + ); + /*! + ensures + - #get_synchronization_file() == filename + - While training is running, either via train() or repeated calls to + train_one_step(), this object will save its entire state, including the + state of get_net(), to disk in the file named filename every + time_between_syncs seconds. + - If the filename file already exists then the state of this trainer will + be loaded from that file by this call to set_synchronization_file(). + This allows you to resume a training session which was previously + interrupted. + - It should be noted that when saving, the trainer will alternate between + saving to a file called filename and another file called filename+"_". + We do this because it's possible that your computer might crash (not + because of dlib, just in general) before the data is safely saved to + disk. This way, you will always have a backup file if the write to disk + gets corrupted or is incomplete. Moreover, when loading, we will always + load from the newest of the two possible files. + !*/ + + const std::string& get_synchronization_file ( + ); + /*! + ensures + - Returns the name of the file the dnn_trainer will periodically save it's + state to. If the return value is "" then synchronization is disabled. + !*/ + + void train ( + const std::vector& data, + const std::vector& labels + ); + /*! + requires + - data.size() == labels.size() + - data.size() > 0 + - net_type uses a supervised loss. + i.e. net_type::training_label_type != no_label_type. + ensures + - Trains a supervised neural network based on the given training data. + The goal of training is to find the network parameters that minimize + get_net().compute_loss(data.begin(), data.end(), labels.begin()). + - The optimizer will run until get_learning_rate() < get_min_learning_rate() + or get_max_num_epochs() training epochs have been executed. + - Each layer in the network will be optimized by its corresponding solver + in get_solvers(). + - Each call to train DOES NOT reinitialize the state of get_net() or + get_solvers(). That is, the existing state of the solvers and network is + the starting point for the optimization each time train() is called. In + particular, if you use the set_synchronization_file() method you can + resume an interrupted train() call by simply calling train() again and it + will pick up from the last synchronization point. + - You can obtain the average loss value during the final training epoch by + calling get_average_loss(). + - This function blocks until all threads inside the dnn_trainer have + stopped touching the net. + !*/ + + void train ( + const std::vector& data + ); + /*! + requires + - data.size() > 0 + - net_type uses an unsupervised loss. + i.e. net_type::training_label_type == no_label_type. + ensures + - Trains an unsupervised neural network based on the given training data. + The goal of training is to find the network parameters that minimize + get_net().compute_loss(data.begin(), data.end()). + - The optimizer will run until get_learning_rate() < get_min_learning_rate() + or get_max_num_epochs() training epochs have been executed. + - Each layer in the network will be optimized by its corresponding solver + in get_solvers(). + - Each call to train DOES NOT reinitialize the state of get_net() or + get_solvers(). That is, the existing state of the solvers and network is + the starting point for the optimization each time train() is called. In + particular, if you use the set_synchronization_file() method you can + resume an interrupted train() call by simply calling train() again and it + will pick up from the last synchronization point. + - You can obtain the average loss value during the final training epoch by + calling get_average_loss(). + - This function blocks until all threads inside the dnn_trainer have + stopped touching the net. + !*/ + + void train_one_step ( + const std::vector& data, + const std::vector& labels + ); + /*! + requires + - data.size() == labels.size() + - data.size() > 0 + - net_type uses a supervised loss. + i.e. net_type::training_label_type != no_label_type. + ensures + - Performs one stochastic gradient update step based on the mini-batch of + data and labels supplied to this function. In particular, calling + train_one_step() in a loop is equivalent to calling the train() method + defined above. However, train_one_step() allows you to stream data from + disk into the training process while train() requires you to first load + all the training data into RAM. Otherwise, these training methods are + equivalent. + - You can observe the current average loss value by calling get_average_loss(). + - The network training will happen in another thread. Therefore, after + calling this function you should call get_net() before you touch the net + object from the calling thread to ensure no other threads are still + accessing the network. + - #get_train_one_step_calls() == get_train_one_step_calls() + 1. + !*/ + + template < + typename data_iterator, + typename label_iterator + > + void train_one_step ( + data_iterator dbegin, + data_iterator dend, + label_iterator lbegin + ); + /*! + requires + - std::advance(lbegin, std::distance(dbegin, dend) - 1) is dereferencable + - std::distance(dbegin, dend) > 0 + - net_type uses a supervised loss. + i.e. net_type::training_label_type != no_label_type. + ensures + - Performs one stochastic gradient update step based on the mini-batch of + data and labels supplied to this function. In particular, calling + train_one_step() in a loop is equivalent to calling the train() method + defined above. However, train_one_step() allows you to stream data from + disk into the training process while train() requires you to first load + all the training data into RAM. Otherwise, these training methods are + equivalent. + - You can observe the current average loss value by calling get_average_loss(). + - The network training will happen in another thread. Therefore, after + calling this function you should call get_net() before you touch the net + object from the calling thread to ensure no other threads are still + accessing the network. + - #get_train_one_step_calls() == get_train_one_step_calls() + 1. + !*/ + + void train_one_step ( + const std::vector& data + ); + /*! + requires + - data.size() > 0 + - net_type uses an unsupervised loss. + i.e. net_type::training_label_type == no_label_type. + ensures + - Performs one stochastic gradient update step based on the mini-batch of + data supplied to this function. In particular, calling train_one_step() + in a loop is equivalent to calling the train() method defined above. + However, train_one_step() allows you to stream data from disk into the + training process while train() requires you to first load all the + training data into RAM. Otherwise, these training methods are + equivalent. + - You can observe the current average loss value by calling get_average_loss(). + - The network training will happen in another thread. Therefore, after + calling this function you should call get_net() before you touch the net + object from the calling thread to ensure no other threads are still + accessing the network. + - #get_train_one_step_calls() == get_train_one_step_calls() + 1. + !*/ + + template < + typename data_iterator + > + void train_one_step ( + data_iterator dbegin, + data_iterator dend + ); + /*! + requires + - std::distance(dbegin, dend) > 0 + - net_type uses an unsupervised loss. + i.e. net_type::training_label_type == no_label_type. + ensures + - Performs one stochastic gradient update step based on the mini-batch of + data supplied to this function. In particular, calling train_one_step() + in a loop is equivalent to calling the train() method defined above. + However, train_one_step() allows you to stream data from disk into the + training process while train() requires you to first load all the + training data into RAM. Otherwise, these training methods are + equivalent. + - You can observe the current average loss value by calling get_average_loss(). + - The network training will happen in another thread. Therefore, after + calling this function you should call get_net() before you touch the net + object from the calling thread to ensure no other threads are still + accessing the network. + - #get_train_one_step_calls() == get_train_one_step_calls() + 1. + !*/ + + double get_average_loss ( + ) const; + /*! + ensures + - returns the average loss value observed during previous calls to + train_one_step() or train(). That is, the average output of + net_type::update() during the previous mini-batch updates. + - Note that, if be_verbose() has been called, then this object will + automatically call clear_average_loss() periodically when it logs the + loss to the console. + - This function blocks until all threads inside the dnn_trainer have + stopped touching the net. + !*/ + + void clear_average_loss ( + ); + /*! + ensures + - #get_average_loss() == 0 + - get_average_loss() uses a dlib::running_stats object to keep a running + average of the loss values seen during the previous mini-batch updates + applied during training. Calling clear_average_loss() resets the + running_stats object so it forgets about all previous loss values + observed. + - This function blocks until all threads inside the dnn_trainer have + stopped touching the net. + !*/ + + // ---------------------- + + double get_average_test_loss ( + ) const; + /*! + ensures + - returns the average loss value observed during previous calls to + test_one_step(). + - This function blocks until all threads inside the dnn_trainer have + stopped touching the net. + !*/ + + void test_one_step ( + const std::vector& data, + const std::vector& labels + ); + /*! + requires + - data.size() == labels.size() + - data.size() > 0 + - net_type uses a supervised loss. + i.e. net_type::training_label_type != no_label_type. + ensures + - Runs the given data through the network and computes and records the loss. + - This call does not modify network parameters. The point of + test_one_step() is two fold, to allow you to observe the accuracy of the + network on hold out data during training, and to allow the trainer to + automatically adjust the learning rate when the test loss stops + improving. It should be noted that you are not required to use + test_one_step() at all, but if you want to do this kind of thing it is + available. + - You can observe the current average loss value by calling get_average_test_loss(). + - The computation will happen in another thread. Therefore, after calling + this function you should call get_net() before you touch the net object + from the calling thread to ensure no other threads are still accessing + the network. + - #get_test_one_step_calls() == get_test_one_step_calls() + 1. + !*/ + + template < + typename data_iterator, + typename label_iterator + > + void test_one_step ( + data_iterator dbegin, + data_iterator dend, + label_iterator lbegin + ); + /*! + requires + - std::advance(lbegin, std::distance(dbegin, dend) - 1) is dereferencable + - std::distance(dbegin, dend) > 0 + - net_type uses a supervised loss. + i.e. net_type::training_label_type != no_label_type. + ensures + - Runs the given data through the network and computes and records the loss. + - This call does not modify network parameters. The point of + test_one_step() is two fold, to allow you to observe the accuracy of the + network on hold out data during training, and to allow the trainer to + automatically adjust the learning rate when the test loss stops + improving. It should be noted that you are not required to use + test_one_step() at all, but if you want to do this kind of thing it is + available. + - You can observe the current average loss value by calling get_average_test_loss(). + - The computation will happen in another thread. Therefore, after calling + this function you should call get_net() before you touch the net object + from the calling thread to ensure no other threads are still accessing + the network. + - #get_test_one_step_calls() == get_test_one_step_calls() + 1. + !*/ + + void test_one_step ( + const std::vector& data + ); + /*! + requires + - data.size() > 0 + - net_type uses an unsupervised loss. + i.e. net_type::training_label_type == no_label_type. + ensures + - Runs the given data through the network and computes and records the loss. + - This call does not modify network parameters. The point of + test_one_step() is two fold, to allow you to observe the accuracy of the + network on hold out data during training, and to allow the trainer to + automatically adjust the learning rate when the test loss stops + improving. It should be noted that you are not required to use + test_one_step() at all, but if you want to do this kind of thing it is + available. + - You can observe the current average loss value by calling get_average_test_loss(). + - The computation will happen in another thread. Therefore, after calling + this function you should call get_net() before you touch the net object + from the calling thread to ensure no other threads are still accessing + the network. + - #get_test_one_step_calls() == get_test_one_step_calls() + 1. + !*/ + + template < + typename data_iterator + > + void test_one_step ( + data_iterator dbegin, + data_iterator dend + ); + /*! + requires + - std::distance(dbegin, dend) > 0 + - net_type uses an unsupervised loss. + i.e. net_type::training_label_type == no_label_type. + ensures + - Runs the given data through the network and computes and records the loss. + - This call does not modify network parameters. The point of + test_one_step() is two fold, to allow you to observe the accuracy of the + network on hold out data during training, and to allow the trainer to + automatically adjust the learning rate when the test loss stops + improving. It should be noted that you are not required to use + test_one_step() at all, but if you want to do this kind of thing it is + available. + - You can observe the current average loss value by calling get_average_test_loss(). + - The computation will happen in another thread. Therefore, after calling + this function you should call get_net() before you touch the net object + from the calling thread to ensure no other threads are still accessing + the network. + - #get_test_one_step_calls() == get_test_one_step_calls() + 1. + !*/ + + void set_test_iterations_without_progress_threshold ( + unsigned long thresh + ); + /*! + ensures + - #get_test_iterations_without_progress_threshold() == thresh + - #get_learning_rate_schedule().size() == 0 + - This function blocks until all threads inside the dnn_trainer have + stopped touching the net. + !*/ + + unsigned long get_test_iterations_without_progress_threshold ( + ) const; + /*! + ensures + - This object monitors the progress of training and estimates if the + testing error is being reduced. It does this by looking at the previous + get_test_iterations_without_progress_threshold() mini-batch results from + test_one_step() and applying the statistical test defined by the + running_gradient object to see if the testing error is getting smaller. + If it isn't being reduced then get_learning_rate() is made smaller by a + factor of get_learning_rate_shrink_factor(). + + Therefore, get_test_iterations_without_progress_threshold() should always be + set to something sensibly large so that this test can be done with + reasonably high confidence. Think of this test as saying "if the testing loss + hasn't decreased for the previous get_test_iterations_without_progress_threshold() + calls to test_one_step() then shrink the learning rate". + !*/ + + unsigned long get_test_steps_without_progress ( + ) const; + /*! + ensures + - if (get_learning_rate_shrink_factor() != 1) then + - returns an estimate of how many mini-batches have executed without us + observing a statistically significant decrease in the testing error + (i.e. the error on the data given to the trainer via test_one_step() + calls). + - else + - returns 0 + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename net_type, + typename solver_type + > + std::ostream& operator<< ( + std::ostream& out, + dnn_trainer& trainer + ); + /*! + ensures + - Prints a log of the current parameters of trainer to out. + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DNn_TRAINER_ABSTRACT_H_ + + diff --git a/lib/3rdParty/dlib/include/dlib/dnn/utilities.h b/lib/3rdParty/dlib/include/dlib/dnn/utilities.h new file mode 100644 index 00000000..976128c8 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/dnn/utilities.h @@ -0,0 +1,281 @@ +// Copyright (C) 2016 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DNn_UTILITIES_H_ +#define DLIB_DNn_UTILITIES_H_ + +#include "core.h" +#include "utilities_abstract.h" +#include "../geometry.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + inline double log1pexp(double x) + { + using std::exp; + using namespace std; // Do this instead of using std::log1p because some compilers + // error out otherwise (E.g. gcc 4.9 in cygwin) + if (x <= -37) + return exp(x); + else if (-37 < x && x <= 18) + return log1p(exp(x)); + else if (18 < x && x <= 33.3) + return x + exp(-x); + else + return x; + } + +// ---------------------------------------------------------------------------------------- + + inline void randomize_parameters ( + tensor& params, + unsigned long num_inputs_and_outputs, + dlib::rand& rnd + ) + { + for (auto& val : params) + { + // Draw a random number to initialize the layer according to formula (16) + // from Understanding the difficulty of training deep feedforward neural + // networks by Xavier Glorot and Yoshua Bengio. + val = 2*rnd.get_random_float()-1; + val *= std::sqrt(6.0/(num_inputs_and_outputs)); + } + } + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + class visitor_net_to_xml + { + public: + + visitor_net_to_xml(std::ostream& out_) : out(out_) {} + + template + void operator()(size_t idx, const input_layer_type& l) + { + out << "\n"; + to_xml(l,out); + out << "\n"; + } + + template + void operator()(size_t idx, const add_loss_layer& l) + { + out << "\n"; + to_xml(l.loss_details(),out); + out << "\n"; + } + + template + void operator()(size_t idx, const add_layer& l) + { + out << "\n"; + to_xml(l.layer_details(),out); + out << "\n"; + } + + template + void operator()(size_t idx, const add_tag_layer& l) + { + out << "\n"; + } + + template class T, typename U> + void operator()(size_t idx, const add_skip_layer& l) + { + out << "\n"; + } + + private: + + std::ostream& out; + }; + } + + template + void net_to_xml ( + const net_type& net, + std::ostream& out + ) + { + auto old_precision = out.precision(9); + out << "\n"; + visit_layers(net, impl::visitor_net_to_xml(out)); + out << "\n"; + // restore the original stream precision. + out.precision(old_precision); + } + + template + void net_to_xml ( + const net_type& net, + const std::string& filename + ) + { + std::ofstream fout(filename); + net_to_xml(net, fout); + } + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + + class visitor_net_map_input_to_output + { + public: + + visitor_net_map_input_to_output(dpoint& p_) : p(p_) {} + + dpoint& p; + + template + void operator()(const input_layer_type& net) + { + } + + template + void operator()(const add_loss_layer& net) + { + (*this)(net.subnet()); + } + + template + void operator()(const add_layer& net) + { + (*this)(net.subnet()); + p = net.layer_details().map_input_to_output(p); + } + template + void operator()(const dimpl::subnet_wrapper,B>& net) + { + (*this)(net.subnet()); + p = net.layer_details().map_input_to_output(p); + } + + + template + void operator()(const add_tag_layer& net) + { + // tag layers are an identity transform, so do nothing + (*this)(net.subnet()); + } + template + void operator()(const dimpl::subnet_wrapper,is_first>& net) + { + // tag layers are an identity transform, so do nothing + (*this)(net.subnet()); + } + + + template class TAG_TYPE, typename U> + void operator()(const add_skip_layer& net) + { + (*this)(layer(net)); + } + template class TAG_TYPE, typename SUBNET> + void operator()(const dimpl::subnet_wrapper,is_first>& net) + { + // skip layers are an identity transform, so do nothing + (*this)(layer(net)); + } + + }; + + class visitor_net_map_output_to_input + { + public: + visitor_net_map_output_to_input(dpoint& p_) : p(p_) {} + + dpoint& p; + + template + void operator()(const input_layer_type& net) + { + } + + template + void operator()(const add_loss_layer& net) + { + (*this)(net.subnet()); + } + + template + void operator()(const add_layer& net) + { + p = net.layer_details().map_output_to_input(p); + (*this)(net.subnet()); + } + template + void operator()(const dimpl::subnet_wrapper,B>& net) + { + p = net.layer_details().map_output_to_input(p); + (*this)(net.subnet()); + } + + + template + void operator()(const add_tag_layer& net) + { + // tag layers are an identity transform, so do nothing + (*this)(net.subnet()); + } + template + void operator()(const dimpl::subnet_wrapper,is_first>& net) + { + // tag layers are an identity transform, so do nothing + (*this)(net.subnet()); + } + + + template class TAG_TYPE, typename U> + void operator()(const add_skip_layer& net) + { + (*this)(layer(net)); + } + template class TAG_TYPE, typename SUBNET> + void operator()(const dimpl::subnet_wrapper,is_first>& net) + { + // skip layers are an identity transform, so do nothing + (*this)(layer(net)); + } + + }; + } + + template + inline dpoint input_tensor_to_output_tensor( + const net_type& net, + dpoint p + ) + { + impl::visitor_net_map_input_to_output temp(p); + temp(net); + return p; + } + + template + inline dpoint output_tensor_to_input_tensor( + const net_type& net, + dpoint p + ) + { + impl::visitor_net_map_output_to_input temp(p); + temp(net); + return p; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DNn_UTILITIES_H_ + + + diff --git a/lib/3rdParty/dlib/include/dlib/dnn/utilities_abstract.h b/lib/3rdParty/dlib/include/dlib/dnn/utilities_abstract.h new file mode 100644 index 00000000..2a9a3d3f --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/dnn/utilities_abstract.h @@ -0,0 +1,127 @@ +// Copyright (C) 2016 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_DNn_UTILITIES_ABSTRACT_H_ +#ifdef DLIB_DNn_UTILITIES_ABSTRACT_H_ + +#include "core_abstract.h" +#include "../geometry/vector_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + double log1pexp( + double x + ); + /*! + ensures + - returns log(1+exp(x)) + (except computes it using a numerically accurate method) + !*/ + +// ---------------------------------------------------------------------------------------- + + void randomize_parameters ( + tensor& params, + unsigned long num_inputs_and_outputs, + dlib::rand& rnd + ); + /*! + ensures + - This function assigns random values into params based on the given random + number generator. In particular, it uses the parameter initialization method + of formula 16 from the paper "Understanding the difficulty of training deep + feedforward neural networks" by Xavier Glorot and Yoshua Bengio. + - It is assumed that the total number of inputs and outputs from the layer is + num_inputs_and_outputs. That is, you should set num_inputs_and_outputs to + the sum of the dimensionalities of the vectors going into and out of the + layer that uses params as its parameters. + !*/ + +// ---------------------------------------------------------------------------------------- + + template + void net_to_xml ( + const net_type& net, + std::ostream& out + ); + /*! + requires + - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or + add_tag_layer. + - All layers in the net must provide to_xml() functions. + ensures + - Prints the given neural network object as an XML document to the given output + stream. + !*/ + + template + void net_to_xml ( + const net_type& net, + const std::string& filename + ); + /*! + requires + - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or + add_tag_layer. + - All layers in the net must provide to_xml() functions. + ensures + - This function is just like the above net_to_xml(), except it writes to a file + rather than an ostream. + !*/ + +// ---------------------------------------------------------------------------------------- + + template + dpoint input_tensor_to_output_tensor( + const net_type& net, + dpoint p + ); + /*! + requires + - net_type is an object of type add_layer, add_skip_layer, or add_tag_layer. + - All layers in the net must provide map_input_to_output() functions. + ensures + - Given a dpoint (i.e. a row,column coordinate) in the input tensor given to + net, this function returns the corresponding dpoint in the output tensor + net.get_output(). This kind of mapping is useful when working with fully + convolutional networks as you will often want to know what parts of the + output feature maps correspond to what parts of the input. + - If the network contains skip layers then any layers skipped over by the skip + layer are ignored for the purpose of computing this coordinate mapping. That + is, if you walk the network from the output layer to the input layer, where + each time you encounter a skip layer you jump to the layer indicated by the + skip layer, you will visit exactly the layers in the network involved in the + input_tensor_to_output_tensor() calculation. This behavior is useful since it + allows you to compute some auxiliary DNN as a separate branch of computation + that is separate from the main network's job of running some kind of fully + convolutional network over an image. For instance, you might want to have a + branch in your network that computes some global image level + summarization/feature. + !*/ + +// ---------------------------------------------------------------------------------------- + + template + dpoint output_tensor_to_input_tensor( + const net_type& net, + dpoint p + ); + /*! + requires + - net_type is an object of type add_layer, add_skip_layer, or add_tag_layer. + - All layers in the net must provide map_output_to_input() functions. + ensures + - This function provides the reverse mapping of input_tensor_to_output_tensor(). + That is, given a dpoint in net.get_output(), what is the corresponding dpoint + in the input tensor? + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DNn_UTILITIES_ABSTRACT_H_ + + diff --git a/lib/3rdParty/dlib/include/dlib/dnn/validation.h b/lib/3rdParty/dlib/include/dlib/dnn/validation.h new file mode 100644 index 00000000..c65cb452 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/dnn/validation.h @@ -0,0 +1,122 @@ +// Copyright (C) 2016 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DNn_VALIDATION_H_ +#define DLIB_DNn_VALIDATION_H_ + +#include "../svm/cross_validate_object_detection_trainer_abstract.h" +#include "../svm/cross_validate_object_detection_trainer.h" +#include "layers.h" +#include + +namespace dlib +{ + namespace impl + { + inline std::set get_labels ( + const std::vector& rects1, + const std::vector& rects2 + ) + { + std::set labels; + for (auto& rr : rects1) + labels.insert(rr.label); + for (auto& rr : rects2) + labels.insert(rr.label); + return labels; + } + } + + template < + typename SUBNET, + typename image_array_type + > + const matrix test_object_detection_function ( + loss_mmod& detector, + const image_array_type& images, + const std::vector>& truth_dets, + const test_box_overlap& overlap_tester = test_box_overlap(), + const double adjust_threshold = 0, + const test_box_overlap& overlaps_ignore_tester = test_box_overlap() + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( is_learning_problem(images,truth_dets) == true , + "\t matrix test_object_detection_function()" + << "\n\t invalid inputs were given to this function" + << "\n\t is_learning_problem(images,truth_dets): " << is_learning_problem(images,truth_dets) + << "\n\t images.size(): " << images.size() + ); + + + + double correct_hits = 0; + double total_true_targets = 0; + + std::vector > all_dets; + unsigned long missing_detections = 0; + + resizable_tensor temp; + + for (unsigned long i = 0; i < images.size(); ++i) + { + std::vector hits; + detector.to_tensor(&images[i], &images[i]+1, temp); + detector.subnet().forward(temp); + detector.loss_details().to_label(temp, detector.subnet(), &hits, adjust_threshold); + + + for (auto& label : impl::get_labels(truth_dets[i], hits)) + { + std::vector truth_boxes; + std::vector ignore; + std::vector> boxes; + // copy hits and truth_dets into the above three objects + for (auto&& b : truth_dets[i]) + { + if (b.ignore) + { + ignore.push_back(b); + } + else if (b.label == label) + { + truth_boxes.push_back(full_object_detection(b.rect)); + ++total_true_targets; + } + } + for (auto&& b : hits) + { + if (b.label == label) + boxes.push_back(std::make_pair(b.detection_confidence, b.rect)); + } + + correct_hits += impl::number_of_truth_hits(truth_boxes, ignore, boxes, overlap_tester, all_dets, missing_detections, overlaps_ignore_tester); + } + } + + std::sort(all_dets.rbegin(), all_dets.rend()); + + double precision, recall; + + double total_hits = all_dets.size(); + + if (total_hits == 0) + precision = 1; + else + precision = correct_hits / total_hits; + + if (total_true_targets == 0) + recall = 1; + else + recall = correct_hits / total_true_targets; + + matrix res; + res = precision, recall, average_precision(all_dets, missing_detections); + return res; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DNn_VALIDATION_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/enable_if.h b/lib/3rdParty/dlib/include/dlib/enable_if.h index d72ae57b..f081dea6 100644 --- a/lib/3rdParty/dlib/include/dlib/enable_if.h +++ b/lib/3rdParty/dlib/include/dlib/enable_if.h @@ -1,28 +1,14 @@ -// Boost enable_if library - // Copyright 2003 (C) The Trustees of Indiana University. - // Use, modification, and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) - // Authors: Jaakko Jarvi (jajarvi at osl.iu.edu) // Jeremiah Willcock (jewillco at osl.iu.edu) // Andrew Lumsdaine (lums at osl.iu.edu) - #ifndef DLIB_BOOST_UTILITY_ENABLE_IF_HPP #define DLIB_BOOST_UTILITY_ENABLE_IF_HPP - -#ifndef BOOST_UTILITY_ENABLE_IF_HPP -#define BOOST_UTILITY_ENABLE_IF_HPP - -// Even the definition of enable_if causes problems on some compilers, -// so it's macroed out for all compilers that do not support SFINAE - -#ifndef BOOST_NO_SFINAE - -namespace boost +namespace dlib { template @@ -70,71 +56,7 @@ namespace boost template struct lazy_disable_if : public lazy_disable_if_c {}; -} // namespace boost - -#else - -namespace boost -{ - - namespace detail { typedef void enable_if_default_T; } - - template - struct enable_if_does_not_work_on_this_compiler; - - template - struct enable_if_c : enable_if_does_not_work_on_this_compiler - { }; - - template - struct disable_if_c : enable_if_does_not_work_on_this_compiler - { }; - - template - struct lazy_enable_if_c : enable_if_does_not_work_on_this_compiler - { }; - - template - struct lazy_disable_if_c : enable_if_does_not_work_on_this_compiler - { }; - - template - struct enable_if : enable_if_does_not_work_on_this_compiler - { }; - - template - struct disable_if : enable_if_does_not_work_on_this_compiler - { }; - - template - struct lazy_enable_if : enable_if_does_not_work_on_this_compiler - { }; - - template - struct lazy_disable_if : enable_if_does_not_work_on_this_compiler - { }; - -} // namespace boost - -#endif // BOOST_NO_SFINAE - -#endif // BOOST_UTILITY_ENABLE_IF_HPP - -namespace dlib -{ - using boost::enable_if_c; - using boost::enable_if_c; - using boost::enable_if; - using boost::lazy_enable_if_c; - using boost::lazy_enable_if_c; - using boost::lazy_enable_if; - using boost::disable_if_c; - using boost::disable_if_c; - using boost::disable_if; - using boost::lazy_disable_if_c; - using boost::lazy_disable_if_c; - using boost::lazy_disable_if; -} +} // namespace dlib #endif // DLIB_BOOST_UTILITY_ENABLE_IF_HPP diff --git a/lib/3rdParty/dlib/include/dlib/entropy_decoder/entropy_decoder_kernel_1.cpp b/lib/3rdParty/dlib/include/dlib/entropy_decoder/entropy_decoder_kernel_1.cpp deleted file mode 100644 index 82c58363..00000000 --- a/lib/3rdParty/dlib/include/dlib/entropy_decoder/entropy_decoder_kernel_1.cpp +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_ENTROPY_DECODER_KERNEL_1_CPp_ -#define DLIB_ENTROPY_DECODER_KERNEL_1_CPp_ -#include "entropy_decoder_kernel_1.h" -#include -#include -#include - -#include "../assert.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - entropy_decoder_kernel_1:: - entropy_decoder_kernel_1( - ) : - initial_low(0x00000001), - initial_high(0xffffffff), - in(0), - low(initial_low), - high(initial_high), - buf(0), - buf_used(0), - target(0x00000000), - r(0) - { - } - -// ---------------------------------------------------------------------------------------- - - entropy_decoder_kernel_1:: - ~entropy_decoder_kernel_1 ( - ) - { - } - -// ---------------------------------------------------------------------------------------- - - void entropy_decoder_kernel_1:: - clear( - ) - { - in = 0; - buf_used = 0; - buf = 0; - r = 0; - low = initial_low; - high = initial_high; - target = 0x00000000; - } - -// ---------------------------------------------------------------------------------------- - - void entropy_decoder_kernel_1:: - set_stream ( - std::istream& in_ - ) - { - buf_used = 0; - buf = 0; - r = 0; - low = initial_low; - high = initial_high; - target = 0x00000000; - - in = &in_; - streambuf = in_.rdbuf(); - - - - unsigned char ch; - - - streambuf->sgetn((char*)&ch,1); - target = ch; - - target <<= 8; - if (streambuf->sgetn((char*)&ch,1)) - target += ch; - - - target <<= 8; - if (streambuf->sgetn((char*)&ch,1)) - target += ch; - - - target <<= 8; - if (streambuf->sgetn((char*)&ch,1)) - target += ch; - - } - -// ---------------------------------------------------------------------------------------- - - bool entropy_decoder_kernel_1:: - stream_is_set ( - ) const - { - if (in != 0) - return true; - else - return false; - } - -// ---------------------------------------------------------------------------------------- - - std::istream& entropy_decoder_kernel_1:: - get_stream ( - ) const - { - return *in; - } - -// ---------------------------------------------------------------------------------------- - - void entropy_decoder_kernel_1:: - decode ( - uint32 low_count, - uint32 high_count - ) - { - // note that we must subtract 1 to preserve the convention that - // high == the real upper range - 1 - high = low + r*high_count - 1; - low = low + r*low_count; - r = 0; - - - - while (true) - { - - // if the highest order bit in high and low is the same - if ( low >= 0x80000000 || high < 0x80000000) - { - // make sure buf isn't empty - if (buf_used == 0) - { - buf_used = 8; - if (streambuf->sgetn(reinterpret_cast(&buf),1)==0) - { - // if there isn't anything else in the streambuffer then just - // make buf zero. - buf = 0; - } - } - - // we will be taking one bit from buf to replace the one we threw away - --buf_used; - - // roll off the bit in target - target <<= 1; - - // roll off the bit - high <<= 1; - low <<= 1; - high |= 1; // note that it is ok to add one to high here because - // of the convention that high == real upper range - 1. - // so that means that if we want to shift the upper range - // left by one then we must shift a one into high also - // since real upper range == high + 0.999999999... - - // make sure low is never zero - if (low == 0) - low = 1; - - // take a bit from buf to fill in the one we threw away - target += (buf>>buf_used)&0x01; - } - // if the distance between high and low is small and there aren't - // any bits we can roll off then round low up or high down. - else if (high-low < 0x10000) - { - if (high == 0x80000000) - high = 0x7fffffff; - else - low = 0x80000000; - } - else - { - break; - } - } // while (true) - - } - -// ---------------------------------------------------------------------------------------- - - bool entropy_decoder_kernel_1:: - get_target_called ( - ) const - { - return (r != 0); - } - -// ---------------------------------------------------------------------------------------- - - uint32 entropy_decoder_kernel_1:: - get_target ( - uint32 total - ) - { - // note that we must add one because of the convention that - // high == the real upper range minus 1 - r = (high-low+1)/total; - uint32 temp = (target-low)/r; - if (temp < total) - return temp; - else - return total-1; - } - -// ---------------------------------------------------------------------------------------- - -} -#endif // DLIB_ENTROPY_DECODER_KERNEL_1_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/entropy_decoder/entropy_decoder_kernel_2.cpp b/lib/3rdParty/dlib/include/dlib/entropy_decoder/entropy_decoder_kernel_2.cpp deleted file mode 100644 index 5b986273..00000000 --- a/lib/3rdParty/dlib/include/dlib/entropy_decoder/entropy_decoder_kernel_2.cpp +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (C) 2004 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_ENTROPY_DECODER_KERNEL_2_CPp_ -#define DLIB_ENTROPY_DECODER_KERNEL_2_CPp_ -#include "entropy_decoder_kernel_2.h" -#include -#include -#include - -#include "../assert.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - entropy_decoder_kernel_2:: - entropy_decoder_kernel_2( - ) : - initial_low(0x00000001), - initial_high(0xffffffff), - in(0), - low(initial_low), - high(initial_high), - target(0x00000000), - r(0) - { - } - -// ---------------------------------------------------------------------------------------- - - entropy_decoder_kernel_2:: - ~entropy_decoder_kernel_2 ( - ) - { - } - -// ---------------------------------------------------------------------------------------- - - void entropy_decoder_kernel_2:: - clear( - ) - { - in = 0; - r = 0; - low = initial_low; - high = initial_high; - target = 0x00000000; - } - -// ---------------------------------------------------------------------------------------- - - void entropy_decoder_kernel_2:: - set_stream ( - std::istream& in_ - ) - { - r = 0; - low = initial_low; - high = initial_high; - target = 0x00000000; - - in = &in_; - streambuf = in_.rdbuf(); - - - - unsigned char ch; - - - streambuf->sgetn((char*)&ch,1); - target = ch; - - target <<= 8; - if (streambuf->sgetn((char*)&ch,1)) - target += ch; - - - target <<= 8; - if (streambuf->sgetn((char*)&ch,1)) - target += ch; - - - target <<= 8; - if (streambuf->sgetn((char*)&ch,1)) - target += ch; - } - -// ---------------------------------------------------------------------------------------- - - bool entropy_decoder_kernel_2:: - stream_is_set ( - ) const - { - if (in != 0) - return true; - else - return false; - } - -// ---------------------------------------------------------------------------------------- - - std::istream& entropy_decoder_kernel_2:: - get_stream ( - ) const - { - return *in; - } - -// ---------------------------------------------------------------------------------------- - - void entropy_decoder_kernel_2:: - decode ( - uint32 low_count, - uint32 high_count - ) - { - // note that we must subtract 1 to preserve the convention that - // high == the real upper range - 1 - high = low + r*high_count - 1; - low = low + r*low_count; - r = 0; - - - while (true ) - { - - // if high and low don't have the same 8 high order bits - if ((high&0xFF000000) != (low&0xFF000000)) - { - // if the distance between high and low is small and there aren't - // any bits we can roll off then force high and low to have common high - // order bits. - if ((high-low < 0x10000)) - { - if (high-low > 0x1000) - { - high>>=1; - low>>=1; - high = low = high+low; - high += 0xFF; - low -= 0xFF; - } - else /**/ - { - high>>=1; - low>>=1; - high = low = high+low; - } - } - else - { - // there are no bits to roll off and high and low are not - // too close so just quit the loop - break; - } - - } - // else if there are 8 bits we can roll off - else - { - unsigned char buf; - if (streambuf->sgetn(reinterpret_cast(&buf),1)==0) - { - // if there isn't anything else in the streambuffer then just - // make buf zero. - buf = 0; - } - - // also roll off the bits in target - target <<= 8; - - // roll off the bits - high <<= 8; - low <<= 8; - high |= 0xFF; // note that it is ok to add 0xFF to high here because - // of the convention that high == real upper range - 1. - // so that means that if we want to shift the upper range - // left by one then we must shift a one into high also - // since real upper range == high + 0.999999999... - - // make sure low is never zero - if (low == 0) - low = 1; - - - // put the new bits into target - target |= static_cast(buf); - } - - } // while (true) - } - -// ---------------------------------------------------------------------------------------- - - bool entropy_decoder_kernel_2:: - get_target_called ( - ) const - { - return (r != 0); - } - -// ---------------------------------------------------------------------------------------- - - uint32 entropy_decoder_kernel_2:: - get_target ( - uint32 total - ) - { - // note that we must add one because of the convention that - // high == the real upper range minus 1 - r = (high-low+1)/total; - uint32 temp = (target-low)/r; - if (temp < total) - return temp; - else - return total-1; - } - -// ---------------------------------------------------------------------------------------- - -} -#endif // DLIB_ENTROPY_DECODER_KERNEL_2_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/entropy_encoder/entropy_encoder_kernel_1.cpp b/lib/3rdParty/dlib/include/dlib/entropy_encoder/entropy_encoder_kernel_1.cpp deleted file mode 100644 index 028609d0..00000000 --- a/lib/3rdParty/dlib/include/dlib/entropy_encoder/entropy_encoder_kernel_1.cpp +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_ -#define DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_ -#include "entropy_encoder_kernel_1.h" -#include -#include - -namespace dlib -{ - - -// ---------------------------------------------------------------------------------------- - - entropy_encoder_kernel_1:: - entropy_encoder_kernel_1( - ) : - initial_low(0x00000001), - initial_high(0xffffffff), - out(0), - low(initial_low), - high(initial_high), - buf(0), - buf_used(0) - { - } - -// ---------------------------------------------------------------------------------------- - - entropy_encoder_kernel_1:: - ~entropy_encoder_kernel_1 ( - ) - { - try { - if (out != 0) - { - flush(); - } - } catch (...) {} - } - -// ---------------------------------------------------------------------------------------- - - void entropy_encoder_kernel_1:: - clear( - ) - { - if (out != 0) - { - flush(); - } - out = 0; - } - -// ---------------------------------------------------------------------------------------- - - void entropy_encoder_kernel_1:: - set_stream ( - std::ostream& out_ - ) - { - if (out != 0) - { - // if a stream is currently set then flush the buffers to it before - // we switch to the new stream - flush(); - } - - out = &out_; - streambuf = out_.rdbuf(); - - // reset the encoder state - buf_used = 0; - buf = 0; - low = initial_low; - high = initial_high; - } - -// ---------------------------------------------------------------------------------------- - - bool entropy_encoder_kernel_1:: - stream_is_set ( - ) const - { - if (out != 0) - return true; - else - return false; - } - -// ---------------------------------------------------------------------------------------- - - std::ostream& entropy_encoder_kernel_1:: - get_stream ( - ) const - { - return *out; - } - -// ---------------------------------------------------------------------------------------- - - void entropy_encoder_kernel_1:: - encode ( - uint32 low_count, - uint32 high_count, - uint32 total - ) - { - // note that we must add one because of the convention that - // high == the real upper range minus 1 - uint32 r = (high-low+1)/total; - - // note that we must subtract 1 to preserve the convention that - // high == the real upper range - 1 - high = low + r*high_count-1; - low = low + r*low_count; - - - while (true) - { - - // if the highest order bit in high and low is the same - if ( low >= 0x80000000 || high < 0x80000000) - { - // if buf is full then write it out - if (buf_used == 8) - { - if (streambuf->sputn(reinterpret_cast(&buf),1)==0) - { - throw std::ios_base::failure("error occured in the entropy_encoder object"); - } - buf = 0; - buf_used = 0; - } - - - // write the high order bit from low into buf - buf <<= 1; - ++buf_used; - if (low&0x80000000) - buf |= 0x1; - - // roll off the bit we just wrote to buf - low <<= 1; - high <<= 1; - high |= 1; // note that it is ok to add one to high here because - // of the convention that high == real upper range - 1. - // so that means that if we want to shift the upper range - // left by one then we must shift a one into high also - // since real upper range == high + 0.999999999... - - // make sure low is never zero - if (low == 0) - low = 1; - } - // if the distance between high and low is small and there aren't - // any bits we can roll off then round low up or high down. - else if (high-low < 0x10000) - { - if (high == 0x80000000) - high = 0x7fffffff; - else - low = 0x80000000; - } - else - { - break; - } - } // while (true) - - } - -// ---------------------------------------------------------------------------------------- - - void entropy_encoder_kernel_1:: - flush ( - ) - { - // flush the next 4 or 5 bytes that are buffered - // thats whatever is contained in buf and then all of low plus any extra - // bits needed to pad that to be an even 4 or 5 bytes - - - if (buf_used != 8) - { - buf <<= (8-buf_used); - buf |= static_cast(low>>(24+buf_used)); - low <<= (8-buf_used); - } - - if (streambuf->sputn(reinterpret_cast(&buf),1) == 0) - throw std::ios_base::failure("error occured in the entropy_encoder object"); - - - - buf = static_cast((low >> 24)&0xFF); - if (streambuf->sputn(reinterpret_cast(&buf),1) == 0) - throw std::ios_base::failure("error occured in the entropy_encoder object"); - - - - - buf = static_cast((low >> 16)&0xFF); - if (streambuf->sputn(reinterpret_cast(&buf),1)==0) - throw std::ios_base::failure("error occured in the entropy_encoder object"); - - - - buf = static_cast((low >> 8)&0xFF); - if (streambuf->sputn(reinterpret_cast(&buf),1)==0) - throw std::ios_base::failure("error occured in the entropy_encoder object"); - - - - if (buf_used != 0) - { - buf = static_cast((low)&0xFF); - if (streambuf->sputn(reinterpret_cast(&buf),1)==0) - throw std::ios_base::failure("error occured in the entropy_encoder object"); - } - - - - // make sure the stream buffer flushes to its I/O channel - streambuf->pubsync(); - - - // reset the encoder state - buf_used = 0; - buf = 0; - low = initial_low; - high = initial_high; - } - -// ---------------------------------------------------------------------------------------- - -} -#endif // DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/entropy_encoder/entropy_encoder_kernel_2.cpp b/lib/3rdParty/dlib/include/dlib/entropy_encoder/entropy_encoder_kernel_2.cpp deleted file mode 100644 index d88030f2..00000000 --- a/lib/3rdParty/dlib/include/dlib/entropy_encoder/entropy_encoder_kernel_2.cpp +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright (C) 2004 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_ENTROPY_ENCODER_KERNEL_2_CPp_ -#define DLIB_ENTROPY_ENCODER_KERNEL_2_CPp_ -#include "entropy_encoder_kernel_2.h" -#include -#include - -namespace dlib -{ - - -// ---------------------------------------------------------------------------------------- - - entropy_encoder_kernel_2:: - entropy_encoder_kernel_2( - ) : - initial_low(0x00000001), - initial_high(0xffffffff), - out(0), - low(initial_low), - high(initial_high) - { - } - -// ---------------------------------------------------------------------------------------- - - entropy_encoder_kernel_2:: - ~entropy_encoder_kernel_2 ( - ) - { - try { - if (out != 0) - { - flush(); - } - } catch (...) {} - } - -// ---------------------------------------------------------------------------------------- - - void entropy_encoder_kernel_2:: - clear( - ) - { - if (out != 0) - { - flush(); - } - out = 0; - } - -// ---------------------------------------------------------------------------------------- - - void entropy_encoder_kernel_2:: - set_stream ( - std::ostream& out_ - ) - { - if (out != 0) - { - // if a stream is currently set then flush the buffers to it before - // we switch to the new stream - flush(); - } - - out = &out_; - streambuf = out_.rdbuf(); - - // reset the encoder state - low = initial_low; - high = initial_high; - } - -// ---------------------------------------------------------------------------------------- - - bool entropy_encoder_kernel_2:: - stream_is_set ( - ) const - { - if (out != 0) - return true; - else - return false; - } - -// ---------------------------------------------------------------------------------------- - - std::ostream& entropy_encoder_kernel_2:: - get_stream ( - ) const - { - return *out; - } - -// ---------------------------------------------------------------------------------------- - - void entropy_encoder_kernel_2:: - encode ( - uint32 low_count, - uint32 high_count, - uint32 total - ) - { - // note that we must add one because of the convention that - // high == the real upper range minus 1 - uint32 r = (high-low+1)/total; - - // note that we must subtract 1 to preserve the convention that - // high == the real upper range - 1 - high = low + r*high_count-1; - low = low + r*low_count; - - - - while (true ) - { - - // if high and low don't have the same 8 high order bits - if ((high&0xFF000000) != (low&0xFF000000)) - { - // if the distance between high and low is small and there aren't - // any bits we can roll off then force high and low to have common high - // order bits. - if ((high-low < 0x10000)) - { - if (high-low > 0x1000) - { - high>>=1; - low>>=1; - high = low = high+low; - high += 0xFF; - low -= 0xFF; - } - else /**/ - { - high>>=1; - low>>=1; - high = low = high+low; - } - } - else - { - // there are no bits to roll off and high and low are not - // too close so just quit the loop - break; - } - - } - // else if there are 8 bits we can roll off - else - { - // write the 8 high order bits from low into buf - unsigned char buf = static_cast(low>>24); - - - // roll off the bits we just wrote to buf - high <<= 8; - low <<= 8; - high |= 0xFF; // note that it is ok to add 0xFF to high here because - // of the convention that high == real upper range - 1. - // so that means that if we want to shift the upper range - // left by one then we must shift a one into high also - // since real upper range == high + 0.999999999... - - // make sure low is never zero - if (low == 0) - low = 1; - - // write buf to the output stream - if (streambuf->sputn(reinterpret_cast(&buf),1)==0) - { - throw std::ios_base::failure("error occured in the entropy_encoder object"); - } - - } - - } // while (true) - - } - -// ---------------------------------------------------------------------------------------- - - void entropy_encoder_kernel_2:: - flush ( - ) - { - - // flush low to the output stream - - - unsigned char buf; - - - buf = static_cast((low >> 24)&0xFF); - if (streambuf->sputn(reinterpret_cast(&buf),1) == 0) - throw std::ios_base::failure("error occured in the entropy_encoder object"); - - - - - buf = static_cast((low >> 16)&0xFF); - if (streambuf->sputn(reinterpret_cast(&buf),1)==0) - throw std::ios_base::failure("error occured in the entropy_encoder object"); - - - - buf = static_cast((low >> 8)&0xFF); - if (streambuf->sputn(reinterpret_cast(&buf),1)==0) - throw std::ios_base::failure("error occured in the entropy_encoder object"); - - - buf = static_cast((low)&0xFF); - if (streambuf->sputn(reinterpret_cast(&buf),1)==0) - throw std::ios_base::failure("error occured in the entropy_encoder object"); - - - - - // make sure the stream buffer flushes to its I/O channel - streambuf->pubsync(); - - - // reset the encoder state - low = initial_low; - high = initial_high; - } - -// ---------------------------------------------------------------------------------------- - -} -#endif // DLIB_ENTROPY_ENCODER_KERNEL_2_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/error.h b/lib/3rdParty/dlib/include/dlib/error.h index 3431ca8c..ce9b95b1 100644 --- a/lib/3rdParty/dlib/include/dlib/error.h +++ b/lib/3rdParty/dlib/include/dlib/error.h @@ -254,6 +254,13 @@ namespace dlib void check_for_previous_fatal_errors() { + // If dlib is being use to create plugins for some other application, like + // MATLAB, then don't do these checks since it terminates the over arching + // system. Just let the errors go to the plugin handler and it will deal with + // them. +#if defined(MATLAB_MEX_FILE) || defined(DLIB_NO_ABORT_ON_2ND_FATAL_ERROR) + return; +#else static bool is_first_fatal_error = true; if (is_first_fatal_error == false) { @@ -283,6 +290,7 @@ namespace dlib std::set_terminate(&dlib_fatal_error_terminate); } is_first_fatal_error = false; +#endif } }; @@ -412,6 +420,27 @@ namespace dlib !*/ }; +// ---------------------------------------------------------------------------------------- + + class impossible_labeling_error : public dlib::error + { + /*! + WHAT THIS OBJECT REPRESENTS + This is the exception thrown by code that trains object detectors (e.g. + structural_svm_object_detection_problem) when they detect that the set of + truth boxes given to the training algorithm contains some impossible to + obtain outputs. + + This kind of problem can happen when the set of image positions scanned by + the underlying object detection method doesn't include the truth rectangle + as a possible output. Another possibility is when two truth boxes are very + close together and hard coded non-max suppression logic would prevent two + boxes in such close proximity from being output. + !*/ + public: + impossible_labeling_error(const std::string& msg) : dlib::error(msg) {}; + }; + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/external/cblas/cblas.h b/lib/3rdParty/dlib/include/dlib/external/cblas/cblas.h new file mode 100644 index 00000000..7a899e34 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/cblas/cblas.h @@ -0,0 +1,580 @@ +#ifndef CBLAS_H +#define CBLAS_H +#include +#include + +/* + * Enumerated and derived types + */ +#define CBLAS_INDEX size_t /* this may vary between platforms */ + +enum CBLAS_ORDER {CblasRowMajor=101, CblasColMajor=102}; +enum CBLAS_TRANSPOSE {CblasNoTrans=111, CblasTrans=112, CblasConjTrans=113}; +enum CBLAS_UPLO {CblasUpper=121, CblasLower=122}; +enum CBLAS_DIAG {CblasNonUnit=131, CblasUnit=132}; +enum CBLAS_SIDE {CblasLeft=141, CblasRight=142}; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef CBLAS_INT_TYPE +#define CBLAS_INT_TYPE int +#endif + +/* + * =========================================================================== + * Prototypes for level 1 BLAS functions (complex are recast as routines) + * =========================================================================== + */ +float cblas_sdsdot(const CBLAS_INT_TYPE N, const float alpha, const float *X, + const CBLAS_INT_TYPE incX, const float *Y, const CBLAS_INT_TYPE incY); +double cblas_dsdot(const CBLAS_INT_TYPE N, const float *X, const CBLAS_INT_TYPE incX, const float *Y, + const CBLAS_INT_TYPE incY); +float cblas_sdot(const CBLAS_INT_TYPE N, const float *X, const CBLAS_INT_TYPE incX, + const float *Y, const CBLAS_INT_TYPE incY); +double cblas_ddot(const CBLAS_INT_TYPE N, const double *X, const CBLAS_INT_TYPE incX, + const double *Y, const CBLAS_INT_TYPE incY); + +/* + * Functions having prefixes Z and C only + */ +void cblas_cdotu_sub(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *dotu); +void cblas_cdotc_sub(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *dotc); + +void cblas_zdotu_sub(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *dotu); +void cblas_zdotc_sub(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *dotc); + + +/* + * Functions having prefixes S D SC DZ + */ +float cblas_snrm2(const CBLAS_INT_TYPE N, const float *X, const CBLAS_INT_TYPE incX); +float cblas_sasum(const CBLAS_INT_TYPE N, const float *X, const CBLAS_INT_TYPE incX); + +double cblas_dnrm2(const CBLAS_INT_TYPE N, const double *X, const CBLAS_INT_TYPE incX); +double cblas_dasum(const CBLAS_INT_TYPE N, const double *X, const CBLAS_INT_TYPE incX); + +float cblas_scnrm2(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX); +float cblas_scasum(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX); + +double cblas_dznrm2(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX); +double cblas_dzasum(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX); + + +/* + * Functions having standard 4 prefixes (S D C Z) + */ +CBLAS_INDEX cblas_isamax(const CBLAS_INT_TYPE N, const float *X, const CBLAS_INT_TYPE incX); +CBLAS_INDEX cblas_idamax(const CBLAS_INT_TYPE N, const double *X, const CBLAS_INT_TYPE incX); +CBLAS_INDEX cblas_icamax(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX); +CBLAS_INDEX cblas_izamax(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX); + +/* + * =========================================================================== + * Prototypes for level 1 BLAS routines + * =========================================================================== + */ + +/* + * Routines with standard 4 prefixes (s, d, c, z) + */ +void cblas_sswap(const CBLAS_INT_TYPE N, float *X, const CBLAS_INT_TYPE incX, + float *Y, const CBLAS_INT_TYPE incY); +void cblas_scopy(const CBLAS_INT_TYPE N, const float *X, const CBLAS_INT_TYPE incX, + float *Y, const CBLAS_INT_TYPE incY); +void cblas_saxpy(const CBLAS_INT_TYPE N, const float alpha, const float *X, + const CBLAS_INT_TYPE incX, float *Y, const CBLAS_INT_TYPE incY); + +void cblas_dswap(const CBLAS_INT_TYPE N, double *X, const CBLAS_INT_TYPE incX, + double *Y, const CBLAS_INT_TYPE incY); +void cblas_dcopy(const CBLAS_INT_TYPE N, const double *X, const CBLAS_INT_TYPE incX, + double *Y, const CBLAS_INT_TYPE incY); +void cblas_daxpy(const CBLAS_INT_TYPE N, const double alpha, const double *X, + const CBLAS_INT_TYPE incX, double *Y, const CBLAS_INT_TYPE incY); + +void cblas_cswap(const CBLAS_INT_TYPE N, void *X, const CBLAS_INT_TYPE incX, + void *Y, const CBLAS_INT_TYPE incY); +void cblas_ccopy(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX, + void *Y, const CBLAS_INT_TYPE incY); +void cblas_caxpy(const CBLAS_INT_TYPE N, const void *alpha, const void *X, + const CBLAS_INT_TYPE incX, void *Y, const CBLAS_INT_TYPE incY); + +void cblas_zswap(const CBLAS_INT_TYPE N, void *X, const CBLAS_INT_TYPE incX, + void *Y, const CBLAS_INT_TYPE incY); +void cblas_zcopy(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX, + void *Y, const CBLAS_INT_TYPE incY); +void cblas_zaxpy(const CBLAS_INT_TYPE N, const void *alpha, const void *X, + const CBLAS_INT_TYPE incX, void *Y, const CBLAS_INT_TYPE incY); + + +/* + * Routines with S and D prefix only + */ +void cblas_srotg(float *a, float *b, float *c, float *s); +void cblas_srotmg(float *d1, float *d2, float *b1, const float b2, float *P); +void cblas_srot(const CBLAS_INT_TYPE N, float *X, const CBLAS_INT_TYPE incX, + float *Y, const CBLAS_INT_TYPE incY, const float c, const float s); +void cblas_srotm(const CBLAS_INT_TYPE N, float *X, const CBLAS_INT_TYPE incX, + float *Y, const CBLAS_INT_TYPE incY, const float *P); + +void cblas_drotg(double *a, double *b, double *c, double *s); +void cblas_drotmg(double *d1, double *d2, double *b1, const double b2, double *P); +void cblas_drot(const CBLAS_INT_TYPE N, double *X, const CBLAS_INT_TYPE incX, + double *Y, const CBLAS_INT_TYPE incY, const double c, const double s); +void cblas_drotm(const CBLAS_INT_TYPE N, double *X, const CBLAS_INT_TYPE incX, + double *Y, const CBLAS_INT_TYPE incY, const double *P); + + +/* + * Routines with S D C Z CS and ZD prefixes + */ +void cblas_sscal(const CBLAS_INT_TYPE N, const float alpha, float *X, const CBLAS_INT_TYPE incX); +void cblas_dscal(const CBLAS_INT_TYPE N, const double alpha, double *X, const CBLAS_INT_TYPE incX); +void cblas_cscal(const CBLAS_INT_TYPE N, const void *alpha, void *X, const CBLAS_INT_TYPE incX); +void cblas_zscal(const CBLAS_INT_TYPE N, const void *alpha, void *X, const CBLAS_INT_TYPE incX); +void cblas_csscal(const CBLAS_INT_TYPE N, const float alpha, void *X, const CBLAS_INT_TYPE incX); +void cblas_zdscal(const CBLAS_INT_TYPE N, const double alpha, void *X, const CBLAS_INT_TYPE incX); + +/* + * =========================================================================== + * Prototypes for level 2 BLAS + * =========================================================================== + */ + +/* + * Routines with standard 4 prefixes (S, D, C, Z) + */ +void cblas_sgemv(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const float alpha, const float *A, const CBLAS_INT_TYPE lda, + const float *X, const CBLAS_INT_TYPE incX, const float beta, + float *Y, const CBLAS_INT_TYPE incY); +void cblas_sgbmv(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const CBLAS_INT_TYPE KL, const CBLAS_INT_TYPE KU, const float alpha, + const float *A, const CBLAS_INT_TYPE lda, const float *X, + const CBLAS_INT_TYPE incX, const float beta, float *Y, const CBLAS_INT_TYPE incY); +void cblas_strmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const float *A, const CBLAS_INT_TYPE lda, + float *X, const CBLAS_INT_TYPE incX); +void cblas_stbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const float *A, const CBLAS_INT_TYPE lda, + float *X, const CBLAS_INT_TYPE incX); +void cblas_stpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const float *Ap, float *X, const CBLAS_INT_TYPE incX); +void cblas_strsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const float *A, const CBLAS_INT_TYPE lda, float *X, + const CBLAS_INT_TYPE incX); +void cblas_stbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const float *A, const CBLAS_INT_TYPE lda, + float *X, const CBLAS_INT_TYPE incX); +void cblas_stpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const float *Ap, float *X, const CBLAS_INT_TYPE incX); + +void cblas_dgemv(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const double alpha, const double *A, const CBLAS_INT_TYPE lda, + const double *X, const CBLAS_INT_TYPE incX, const double beta, + double *Y, const CBLAS_INT_TYPE incY); +void cblas_dgbmv(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const CBLAS_INT_TYPE KL, const CBLAS_INT_TYPE KU, const double alpha, + const double *A, const CBLAS_INT_TYPE lda, const double *X, + const CBLAS_INT_TYPE incX, const double beta, double *Y, const CBLAS_INT_TYPE incY); +void cblas_dtrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const double *A, const CBLAS_INT_TYPE lda, + double *X, const CBLAS_INT_TYPE incX); +void cblas_dtbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const double *A, const CBLAS_INT_TYPE lda, + double *X, const CBLAS_INT_TYPE incX); +void cblas_dtpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const double *Ap, double *X, const CBLAS_INT_TYPE incX); +void cblas_dtrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const double *A, const CBLAS_INT_TYPE lda, double *X, + const CBLAS_INT_TYPE incX); +void cblas_dtbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const double *A, const CBLAS_INT_TYPE lda, + double *X, const CBLAS_INT_TYPE incX); +void cblas_dtpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const double *Ap, double *X, const CBLAS_INT_TYPE incX); + +void cblas_cgemv(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *A, const CBLAS_INT_TYPE lda, + const void *X, const CBLAS_INT_TYPE incX, const void *beta, + void *Y, const CBLAS_INT_TYPE incY); +void cblas_cgbmv(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const CBLAS_INT_TYPE KL, const CBLAS_INT_TYPE KU, const void *alpha, + const void *A, const CBLAS_INT_TYPE lda, const void *X, + const CBLAS_INT_TYPE incX, const void *beta, void *Y, const CBLAS_INT_TYPE incY); +void cblas_ctrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const void *A, const CBLAS_INT_TYPE lda, + void *X, const CBLAS_INT_TYPE incX); +void cblas_ctbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const void *A, const CBLAS_INT_TYPE lda, + void *X, const CBLAS_INT_TYPE incX); +void cblas_ctpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const void *Ap, void *X, const CBLAS_INT_TYPE incX); +void cblas_ctrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const void *A, const CBLAS_INT_TYPE lda, void *X, + const CBLAS_INT_TYPE incX); +void cblas_ctbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const void *A, const CBLAS_INT_TYPE lda, + void *X, const CBLAS_INT_TYPE incX); +void cblas_ctpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const void *Ap, void *X, const CBLAS_INT_TYPE incX); + +void cblas_zgemv(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *A, const CBLAS_INT_TYPE lda, + const void *X, const CBLAS_INT_TYPE incX, const void *beta, + void *Y, const CBLAS_INT_TYPE incY); +void cblas_zgbmv(const enum CBLAS_ORDER order, + const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const CBLAS_INT_TYPE KL, const CBLAS_INT_TYPE KU, const void *alpha, + const void *A, const CBLAS_INT_TYPE lda, const void *X, + const CBLAS_INT_TYPE incX, const void *beta, void *Y, const CBLAS_INT_TYPE incY); +void cblas_ztrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const void *A, const CBLAS_INT_TYPE lda, + void *X, const CBLAS_INT_TYPE incX); +void cblas_ztbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const void *A, const CBLAS_INT_TYPE lda, + void *X, const CBLAS_INT_TYPE incX); +void cblas_ztpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const void *Ap, void *X, const CBLAS_INT_TYPE incX); +void cblas_ztrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const void *A, const CBLAS_INT_TYPE lda, void *X, + const CBLAS_INT_TYPE incX); +void cblas_ztbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const void *A, const CBLAS_INT_TYPE lda, + void *X, const CBLAS_INT_TYPE incX); +void cblas_ztpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag, + const CBLAS_INT_TYPE N, const void *Ap, void *X, const CBLAS_INT_TYPE incX); + + +/* + * Routines with S and D prefixes only + */ +void cblas_ssymv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const float alpha, const float *A, + const CBLAS_INT_TYPE lda, const float *X, const CBLAS_INT_TYPE incX, + const float beta, float *Y, const CBLAS_INT_TYPE incY); +void cblas_ssbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const float alpha, const float *A, + const CBLAS_INT_TYPE lda, const float *X, const CBLAS_INT_TYPE incX, + const float beta, float *Y, const CBLAS_INT_TYPE incY); +void cblas_sspmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const float alpha, const float *Ap, + const float *X, const CBLAS_INT_TYPE incX, + const float beta, float *Y, const CBLAS_INT_TYPE incY); +void cblas_sger(const enum CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const float alpha, const float *X, const CBLAS_INT_TYPE incX, + const float *Y, const CBLAS_INT_TYPE incY, float *A, const CBLAS_INT_TYPE lda); +void cblas_ssyr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const float alpha, const float *X, + const CBLAS_INT_TYPE incX, float *A, const CBLAS_INT_TYPE lda); +void cblas_sspr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const float alpha, const float *X, + const CBLAS_INT_TYPE incX, float *Ap); +void cblas_ssyr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const float alpha, const float *X, + const CBLAS_INT_TYPE incX, const float *Y, const CBLAS_INT_TYPE incY, float *A, + const CBLAS_INT_TYPE lda); +void cblas_sspr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const float alpha, const float *X, + const CBLAS_INT_TYPE incX, const float *Y, const CBLAS_INT_TYPE incY, float *A); + +void cblas_dsymv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const double alpha, const double *A, + const CBLAS_INT_TYPE lda, const double *X, const CBLAS_INT_TYPE incX, + const double beta, double *Y, const CBLAS_INT_TYPE incY); +void cblas_dsbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const double alpha, const double *A, + const CBLAS_INT_TYPE lda, const double *X, const CBLAS_INT_TYPE incX, + const double beta, double *Y, const CBLAS_INT_TYPE incY); +void cblas_dspmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const double alpha, const double *Ap, + const double *X, const CBLAS_INT_TYPE incX, + const double beta, double *Y, const CBLAS_INT_TYPE incY); +void cblas_dger(const enum CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const double alpha, const double *X, const CBLAS_INT_TYPE incX, + const double *Y, const CBLAS_INT_TYPE incY, double *A, const CBLAS_INT_TYPE lda); +void cblas_dsyr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const double alpha, const double *X, + const CBLAS_INT_TYPE incX, double *A, const CBLAS_INT_TYPE lda); +void cblas_dspr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const double alpha, const double *X, + const CBLAS_INT_TYPE incX, double *Ap); +void cblas_dsyr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const double alpha, const double *X, + const CBLAS_INT_TYPE incX, const double *Y, const CBLAS_INT_TYPE incY, double *A, + const CBLAS_INT_TYPE lda); +void cblas_dspr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const double alpha, const double *X, + const CBLAS_INT_TYPE incX, const double *Y, const CBLAS_INT_TYPE incY, double *A); + + +/* + * Routines with C and Z prefixes only + */ +void cblas_chemv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const void *alpha, const void *A, + const CBLAS_INT_TYPE lda, const void *X, const CBLAS_INT_TYPE incX, + const void *beta, void *Y, const CBLAS_INT_TYPE incY); +void cblas_chbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const void *alpha, const void *A, + const CBLAS_INT_TYPE lda, const void *X, const CBLAS_INT_TYPE incX, + const void *beta, void *Y, const CBLAS_INT_TYPE incY); +void cblas_chpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const void *alpha, const void *Ap, + const void *X, const CBLAS_INT_TYPE incX, + const void *beta, void *Y, const CBLAS_INT_TYPE incY); +void cblas_cgeru(const enum CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda); +void cblas_cgerc(const enum CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda); +void cblas_cher(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const float alpha, const void *X, const CBLAS_INT_TYPE incX, + void *A, const CBLAS_INT_TYPE lda); +void cblas_chpr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const float alpha, const void *X, + const CBLAS_INT_TYPE incX, void *A); +void cblas_cher2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE N, + const void *alpha, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda); +void cblas_chpr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE N, + const void *alpha, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *Ap); + +void cblas_zhemv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const void *alpha, const void *A, + const CBLAS_INT_TYPE lda, const void *X, const CBLAS_INT_TYPE incX, + const void *beta, void *Y, const CBLAS_INT_TYPE incY); +void cblas_zhbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const void *alpha, const void *A, + const CBLAS_INT_TYPE lda, const void *X, const CBLAS_INT_TYPE incX, + const void *beta, void *Y, const CBLAS_INT_TYPE incY); +void cblas_zhpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const void *alpha, const void *Ap, + const void *X, const CBLAS_INT_TYPE incX, + const void *beta, void *Y, const CBLAS_INT_TYPE incY); +void cblas_zgeru(const enum CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda); +void cblas_zgerc(const enum CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda); +void cblas_zher(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const double alpha, const void *X, const CBLAS_INT_TYPE incX, + void *A, const CBLAS_INT_TYPE lda); +void cblas_zhpr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, + const CBLAS_INT_TYPE N, const double alpha, const void *X, + const CBLAS_INT_TYPE incX, void *A); +void cblas_zher2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE N, + const void *alpha, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda); +void cblas_zhpr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE N, + const void *alpha, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *Ap); + +/* + * =========================================================================== + * Prototypes for level 3 BLAS + * =========================================================================== + */ + +/* + * Routines with standard 4 prefixes (S, D, C, Z) + */ +void cblas_sgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const CBLAS_INT_TYPE K, const float alpha, const float *A, + const CBLAS_INT_TYPE lda, const float *B, const CBLAS_INT_TYPE ldb, + const float beta, float *C, const CBLAS_INT_TYPE ldc); +void cblas_ssymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const float alpha, const float *A, const CBLAS_INT_TYPE lda, + const float *B, const CBLAS_INT_TYPE ldb, const float beta, + float *C, const CBLAS_INT_TYPE ldc); +void cblas_ssyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, + const float alpha, const float *A, const CBLAS_INT_TYPE lda, + const float beta, float *C, const CBLAS_INT_TYPE ldc); +void cblas_ssyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, + const float alpha, const float *A, const CBLAS_INT_TYPE lda, + const float *B, const CBLAS_INT_TYPE ldb, const float beta, + float *C, const CBLAS_INT_TYPE ldc); +void cblas_strmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const float alpha, const float *A, const CBLAS_INT_TYPE lda, + float *B, const CBLAS_INT_TYPE ldb); +void cblas_strsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const float alpha, const float *A, const CBLAS_INT_TYPE lda, + float *B, const CBLAS_INT_TYPE ldb); + +void cblas_dgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const CBLAS_INT_TYPE K, const double alpha, const double *A, + const CBLAS_INT_TYPE lda, const double *B, const CBLAS_INT_TYPE ldb, + const double beta, double *C, const CBLAS_INT_TYPE ldc); +void cblas_dsymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const double alpha, const double *A, const CBLAS_INT_TYPE lda, + const double *B, const CBLAS_INT_TYPE ldb, const double beta, + double *C, const CBLAS_INT_TYPE ldc); +void cblas_dsyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, + const double alpha, const double *A, const CBLAS_INT_TYPE lda, + const double beta, double *C, const CBLAS_INT_TYPE ldc); +void cblas_dsyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, + const double alpha, const double *A, const CBLAS_INT_TYPE lda, + const double *B, const CBLAS_INT_TYPE ldb, const double beta, + double *C, const CBLAS_INT_TYPE ldc); +void cblas_dtrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const double alpha, const double *A, const CBLAS_INT_TYPE lda, + double *B, const CBLAS_INT_TYPE ldb); +void cblas_dtrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const double alpha, const double *A, const CBLAS_INT_TYPE lda, + double *B, const CBLAS_INT_TYPE ldb); + +void cblas_cgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const CBLAS_INT_TYPE K, const void *alpha, const void *A, + const CBLAS_INT_TYPE lda, const void *B, const CBLAS_INT_TYPE ldb, + const void *beta, void *C, const CBLAS_INT_TYPE ldc); +void cblas_csymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *A, const CBLAS_INT_TYPE lda, + const void *B, const CBLAS_INT_TYPE ldb, const void *beta, + void *C, const CBLAS_INT_TYPE ldc); +void cblas_csyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, + const void *alpha, const void *A, const CBLAS_INT_TYPE lda, + const void *beta, void *C, const CBLAS_INT_TYPE ldc); +void cblas_csyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, + const void *alpha, const void *A, const CBLAS_INT_TYPE lda, + const void *B, const CBLAS_INT_TYPE ldb, const void *beta, + void *C, const CBLAS_INT_TYPE ldc); +void cblas_ctrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *A, const CBLAS_INT_TYPE lda, + void *B, const CBLAS_INT_TYPE ldb); +void cblas_ctrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *A, const CBLAS_INT_TYPE lda, + void *B, const CBLAS_INT_TYPE ldb); + +void cblas_zgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const CBLAS_INT_TYPE K, const void *alpha, const void *A, + const CBLAS_INT_TYPE lda, const void *B, const CBLAS_INT_TYPE ldb, + const void *beta, void *C, const CBLAS_INT_TYPE ldc); +void cblas_zsymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *A, const CBLAS_INT_TYPE lda, + const void *B, const CBLAS_INT_TYPE ldb, const void *beta, + void *C, const CBLAS_INT_TYPE ldc); +void cblas_zsyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, + const void *alpha, const void *A, const CBLAS_INT_TYPE lda, + const void *beta, void *C, const CBLAS_INT_TYPE ldc); +void cblas_zsyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, + const void *alpha, const void *A, const CBLAS_INT_TYPE lda, + const void *B, const CBLAS_INT_TYPE ldb, const void *beta, + void *C, const CBLAS_INT_TYPE ldc); +void cblas_ztrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *A, const CBLAS_INT_TYPE lda, + void *B, const CBLAS_INT_TYPE ldb); +void cblas_ztrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, + const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *A, const CBLAS_INT_TYPE lda, + void *B, const CBLAS_INT_TYPE ldb); + + +/* + * Routines with prefixes C and Z only + */ +void cblas_chemm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *A, const CBLAS_INT_TYPE lda, + const void *B, const CBLAS_INT_TYPE ldb, const void *beta, + void *C, const CBLAS_INT_TYPE ldc); +void cblas_cherk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, + const float alpha, const void *A, const CBLAS_INT_TYPE lda, + const float beta, void *C, const CBLAS_INT_TYPE ldc); +void cblas_cher2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, + const void *alpha, const void *A, const CBLAS_INT_TYPE lda, + const void *B, const CBLAS_INT_TYPE ldb, const float beta, + void *C, const CBLAS_INT_TYPE ldc); + +void cblas_zhemm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, + const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *A, const CBLAS_INT_TYPE lda, + const void *B, const CBLAS_INT_TYPE ldb, const void *beta, + void *C, const CBLAS_INT_TYPE ldc); +void cblas_zherk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, + const double alpha, const void *A, const CBLAS_INT_TYPE lda, + const double beta, void *C, const CBLAS_INT_TYPE ldc); +void cblas_zher2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo, + const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, + const void *alpha, const void *A, const CBLAS_INT_TYPE lda, + const void *B, const CBLAS_INT_TYPE ldb, const double beta, + void *C, const CBLAS_INT_TYPE ldc); + +void cblas_xerbla(int p, const char *rout, const char *form, ...); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib/3rdParty/dlib/include/dlib/external/cblas/cblas_f77.h b/lib/3rdParty/dlib/include/dlib/external/cblas/cblas_f77.h new file mode 100644 index 00000000..18435cd3 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/cblas/cblas_f77.h @@ -0,0 +1,701 @@ +/* + * cblas_f77.h + * Written by Keita Teranishi + * + * Updated by Jeff Horner + * Merged cblas_f77.h and cblas_fortran_header.h + */ + +#ifndef CBLAS_F77_H +#define CBLAS_f77_H + +#ifdef CRAY + #include + #define F77_CHAR _fcd + #define C2F_CHAR(a) ( _cptofcd( (a), 1 ) ) + #define C2F_STR(a, i) ( _cptofcd( (a), (i) ) ) + #define F77_STRLEN(a) (_fcdlen) +#endif + +#ifdef WeirdNEC + #define F77_INT long +#endif + +#ifdef F77_CHAR + #define FCHAR F77_CHAR +#else + #define FCHAR char * +#endif + +#ifdef F77_INT + #define FINT const F77_INT * + #define FINT2 F77_INT * +#else + #define FINT const int * + #define FINT2 int * +#endif + +#if defined(ADD_) +/* + * Level 1 BLAS + */ +#define F77_xerbla xerbla_ + #define F77_srotg srotg_ + #define F77_srotmg srotmg_ + #define F77_srot srot_ + #define F77_srotm srotm_ + #define F77_drotg drotg_ + #define F77_drotmg drotmg_ + #define F77_drot drot_ + #define F77_drotm drotm_ + #define F77_sswap sswap_ + #define F77_scopy scopy_ + #define F77_saxpy saxpy_ + #define F77_isamax_sub isamaxsub_ + #define F77_dswap dswap_ + #define F77_dcopy dcopy_ + #define F77_daxpy daxpy_ + #define F77_idamax_sub idamaxsub_ + #define F77_cswap cswap_ + #define F77_ccopy ccopy_ + #define F77_caxpy caxpy_ + #define F77_icamax_sub icamaxsub_ + #define F77_zswap zswap_ + #define F77_zcopy zcopy_ + #define F77_zaxpy zaxpy_ + #define F77_izamax_sub izamaxsub_ + #define F77_sdot_sub sdotsub_ + #define F77_ddot_sub ddotsub_ + #define F77_dsdot_sub dsdotsub_ + #define F77_sscal sscal_ + #define F77_dscal dscal_ + #define F77_cscal cscal_ + #define F77_zscal zscal_ + #define F77_csscal csscal_ + #define F77_zdscal zdscal_ + #define F77_cdotu_sub cdotusub_ + #define F77_cdotc_sub cdotcsub_ + #define F77_zdotu_sub zdotusub_ + #define F77_zdotc_sub zdotcsub_ + #define F77_snrm2_sub snrm2sub_ + #define F77_sasum_sub sasumsub_ + #define F77_dnrm2_sub dnrm2sub_ + #define F77_dasum_sub dasumsub_ + #define F77_scnrm2_sub scnrm2sub_ + #define F77_scasum_sub scasumsub_ + #define F77_dznrm2_sub dznrm2sub_ + #define F77_dzasum_sub dzasumsub_ + #define F77_sdsdot_sub sdsdotsub_ +/* + * Level 2 BLAS + */ + #define F77_ssymv ssymv_ + #define F77_ssbmv ssbmv_ + #define F77_sspmv sspmv_ + #define F77_sger sger_ + #define F77_ssyr ssyr_ + #define F77_sspr sspr_ + #define F77_ssyr2 ssyr2_ + #define F77_sspr2 sspr2_ + #define F77_dsymv dsymv_ + #define F77_dsbmv dsbmv_ + #define F77_dspmv dspmv_ + #define F77_dger dger_ + #define F77_dsyr dsyr_ + #define F77_dspr dspr_ + #define F77_dsyr2 dsyr2_ + #define F77_dspr2 dspr2_ + #define F77_chemv chemv_ + #define F77_chbmv chbmv_ + #define F77_chpmv chpmv_ + #define F77_cgeru cgeru_ + #define F77_cgerc cgerc_ + #define F77_cher cher_ + #define F77_chpr chpr_ + #define F77_cher2 cher2_ + #define F77_chpr2 chpr2_ + #define F77_zhemv zhemv_ + #define F77_zhbmv zhbmv_ + #define F77_zhpmv zhpmv_ + #define F77_zgeru zgeru_ + #define F77_zgerc zgerc_ + #define F77_zher zher_ + #define F77_zhpr zhpr_ + #define F77_zher2 zher2_ + #define F77_zhpr2 zhpr2_ + #define F77_sgemv sgemv_ + #define F77_sgbmv sgbmv_ + #define F77_strmv strmv_ + #define F77_stbmv stbmv_ + #define F77_stpmv stpmv_ + #define F77_strsv strsv_ + #define F77_stbsv stbsv_ + #define F77_stpsv stpsv_ + #define F77_dgemv dgemv_ + #define F77_dgbmv dgbmv_ + #define F77_dtrmv dtrmv_ + #define F77_dtbmv dtbmv_ + #define F77_dtpmv dtpmv_ + #define F77_dtrsv dtrsv_ + #define F77_dtbsv dtbsv_ + #define F77_dtpsv dtpsv_ + #define F77_cgemv cgemv_ + #define F77_cgbmv cgbmv_ + #define F77_ctrmv ctrmv_ + #define F77_ctbmv ctbmv_ + #define F77_ctpmv ctpmv_ + #define F77_ctrsv ctrsv_ + #define F77_ctbsv ctbsv_ + #define F77_ctpsv ctpsv_ + #define F77_zgemv zgemv_ + #define F77_zgbmv zgbmv_ + #define F77_ztrmv ztrmv_ + #define F77_ztbmv ztbmv_ + #define F77_ztpmv ztpmv_ + #define F77_ztrsv ztrsv_ + #define F77_ztbsv ztbsv_ + #define F77_ztpsv ztpsv_ +/* + * Level 3 BLAS + */ + #define F77_chemm chemm_ + #define F77_cherk cherk_ + #define F77_cher2k cher2k_ + #define F77_zhemm zhemm_ + #define F77_zherk zherk_ + #define F77_zher2k zher2k_ + #define F77_sgemm sgemm_ + #define F77_ssymm ssymm_ + #define F77_ssyrk ssyrk_ + #define F77_ssyr2k ssyr2k_ + #define F77_strmm strmm_ + #define F77_strsm strsm_ + #define F77_dgemm dgemm_ + #define F77_dsymm dsymm_ + #define F77_dsyrk dsyrk_ + #define F77_dsyr2k dsyr2k_ + #define F77_dtrmm dtrmm_ + #define F77_dtrsm dtrsm_ + #define F77_cgemm cgemm_ + #define F77_csymm csymm_ + #define F77_csyrk csyrk_ + #define F77_csyr2k csyr2k_ + #define F77_ctrmm ctrmm_ + #define F77_ctrsm ctrsm_ + #define F77_zgemm zgemm_ + #define F77_zsymm zsymm_ + #define F77_zsyrk zsyrk_ + #define F77_zsyr2k zsyr2k_ + #define F77_ztrmm ztrmm_ + #define F77_ztrsm ztrsm_ +#elif defined(UPCASE) +/* + * Level 1 BLAS + */ +#define F77_xerbla XERBLA + #define F77_srotg SROTG + #define F77_srotmg SROTMG + #define F77_srot SROT + #define F77_srotm SROTM + #define F77_drotg DROTG + #define F77_drotmg DROTMG + #define F77_drot DROT + #define F77_drotm DROTM + #define F77_sswap SSWAP + #define F77_scopy SCOPY + #define F77_saxpy SAXPY + #define F77_isamax_sub ISAMAXSUB + #define F77_dswap DSWAP + #define F77_dcopy DCOPY + #define F77_daxpy DAXPY + #define F77_idamax_sub IDAMAXSUB + #define F77_cswap CSWAP + #define F77_ccopy CCOPY + #define F77_caxpy CAXPY + #define F77_icamax_sub ICAMAXSUB + #define F77_zswap ZSWAP + #define F77_zcopy ZCOPY + #define F77_zaxpy ZAXPY + #define F77_izamax_sub IZAMAXSUB + #define F77_sdot_sub SDOTSUB + #define F77_ddot_sub DDOTSUB + #define F77_dsdot_sub DSDOTSUB + #define F77_sscal SSCAL + #define F77_dscal DSCAL + #define F77_cscal CSCAL + #define F77_zscal ZSCAL + #define F77_csscal CSSCAL + #define F77_zdscal ZDSCAL + #define F77_cdotu_sub CDOTUSUB + #define F77_cdotc_sub CDOTCSUB + #define F77_zdotu_sub ZDOTUSUB + #define F77_zdotc_sub ZDOTCSUB + #define F77_snrm2_sub SNRM2SUB + #define F77_sasum_sub SASUMSUB + #define F77_dnrm2_sub DNRM2SUB + #define F77_dasum_sub DASUMSUB + #define F77_scnrm2_sub SCNRM2SUB + #define F77_scasum_sub SCASUMSUB + #define F77_dznrm2_sub DZNRM2SUB + #define F77_dzasum_sub DZASUMSUB + #define F77_sdsdot_sub SDSDOTSUB +/* + * Level 2 BLAS + */ + #define F77_ssymv SSYMV + #define F77_ssbmv SSBMV + #define F77_sspmv SSPMV + #define F77_sger SGER + #define F77_ssyr SSYR + #define F77_sspr SSPR + #define F77_ssyr2 SSYR2 + #define F77_sspr2 SSPR2 + #define F77_dsymv DSYMV + #define F77_dsbmv DSBMV + #define F77_dspmv DSPMV + #define F77_dger DGER + #define F77_dsyr DSYR + #define F77_dspr DSPR + #define F77_dsyr2 DSYR2 + #define F77_dspr2 DSPR2 + #define F77_chemv CHEMV + #define F77_chbmv CHBMV + #define F77_chpmv CHPMV + #define F77_cgeru CGERU + #define F77_cgerc CGERC + #define F77_cher CHER + #define F77_chpr CHPR + #define F77_cher2 CHER2 + #define F77_chpr2 CHPR2 + #define F77_zhemv ZHEMV + #define F77_zhbmv ZHBMV + #define F77_zhpmv ZHPMV + #define F77_zgeru ZGERU + #define F77_zgerc ZGERC + #define F77_zher ZHER + #define F77_zhpr ZHPR + #define F77_zher2 ZHER2 + #define F77_zhpr2 ZHPR2 + #define F77_sgemv SGEMV + #define F77_sgbmv SGBMV + #define F77_strmv STRMV + #define F77_stbmv STBMV + #define F77_stpmv STPMV + #define F77_strsv STRSV + #define F77_stbsv STBSV + #define F77_stpsv STPSV + #define F77_dgemv DGEMV + #define F77_dgbmv DGBMV + #define F77_dtrmv DTRMV + #define F77_dtbmv DTBMV + #define F77_dtpmv DTPMV + #define F77_dtrsv DTRSV + #define F77_dtbsv DTBSV + #define F77_dtpsv DTPSV + #define F77_cgemv CGEMV + #define F77_cgbmv CGBMV + #define F77_ctrmv CTRMV + #define F77_ctbmv CTBMV + #define F77_ctpmv CTPMV + #define F77_ctrsv CTRSV + #define F77_ctbsv CTBSV + #define F77_ctpsv CTPSV + #define F77_zgemv ZGEMV + #define F77_zgbmv ZGBMV + #define F77_ztrmv ZTRMV + #define F77_ztbmv ZTBMV + #define F77_ztpmv ZTPMV + #define F77_ztrsv ZTRSV + #define F77_ztbsv ZTBSV + #define F77_ztpsv ZTPSV +/* + * Level 3 BLAS + */ + #define F77_chemm CHEMM + #define F77_cherk CHERK + #define F77_cher2k CHER2K + #define F77_zhemm ZHEMM + #define F77_zherk ZHERK + #define F77_zher2k ZHER2K + #define F77_sgemm SGEMM + #define F77_ssymm SSYMM + #define F77_ssyrk SSYRK + #define F77_ssyr2k SSYR2K + #define F77_strmm STRMM + #define F77_strsm STRSM + #define F77_dgemm DGEMM + #define F77_dsymm DSYMM + #define F77_dsyrk DSYRK + #define F77_dsyr2k DSYR2K + #define F77_dtrmm DTRMM + #define F77_dtrsm DTRSM + #define F77_cgemm CGEMM + #define F77_csymm CSYMM + #define F77_csyrk CSYRK + #define F77_csyr2k CSYR2K + #define F77_ctrmm CTRMM + #define F77_ctrsm CTRSM + #define F77_zgemm ZGEMM + #define F77_zsymm ZSYMM + #define F77_zsyrk ZSYRK + #define F77_zsyr2k ZSYR2K + #define F77_ztrmm ZTRMM + #define F77_ztrsm ZTRSM +#elif defined(NOCHANGE) +/* + * Level 1 BLAS + */ +#define F77_xerbla xerbla + #define F77_srotg srotg + #define F77_srotmg srotmg + #define F77_srot srot + #define F77_srotm srotm + #define F77_drotg drotg + #define F77_drotmg drotmg + #define F77_drot drot + #define F77_drotm drotm + #define F77_sswap sswap + #define F77_scopy scopy + #define F77_saxpy saxpy + #define F77_isamax_sub isamaxsub + #define F77_dswap dswap + #define F77_dcopy dcopy + #define F77_daxpy daxpy + #define F77_idamax_sub idamaxsub + #define F77_cswap cswap + #define F77_ccopy ccopy + #define F77_caxpy caxpy + #define F77_icamax_sub icamaxsub + #define F77_zswap zswap + #define F77_zcopy zcopy + #define F77_zaxpy zaxpy + #define F77_izamax_sub izamaxsub + #define F77_sdot_sub sdotsub + #define F77_ddot_sub ddotsub + #define F77_dsdot_sub dsdotsub + #define F77_sscal sscal + #define F77_dscal dscal + #define F77_cscal cscal + #define F77_zscal zscal + #define F77_csscal csscal + #define F77_zdscal zdscal + #define F77_cdotu_sub cdotusub + #define F77_cdotc_sub cdotcsub + #define F77_zdotu_sub zdotusub + #define F77_zdotc_sub zdotcsub + #define F77_snrm2_sub snrm2sub + #define F77_sasum_sub sasumsub + #define F77_dnrm2_sub dnrm2sub + #define F77_dasum_sub dasumsub + #define F77_scnrm2_sub scnrm2sub + #define F77_scasum_sub scasumsub + #define F77_dznrm2_sub dznrm2sub + #define F77_dzasum_sub dzasumsub + #define F77_sdsdot_sub sdsdotsub +/* + * Level 2 BLAS + */ + #define F77_ssymv ssymv + #define F77_ssbmv ssbmv + #define F77_sspmv sspmv + #define F77_sger sger + #define F77_ssyr ssyr + #define F77_sspr sspr + #define F77_ssyr2 ssyr2 + #define F77_sspr2 sspr2 + #define F77_dsymv dsymv + #define F77_dsbmv dsbmv + #define F77_dspmv dspmv + #define F77_dger dger + #define F77_dsyr dsyr + #define F77_dspr dspr + #define F77_dsyr2 dsyr2 + #define F77_dspr2 dspr2 + #define F77_chemv chemv + #define F77_chbmv chbmv + #define F77_chpmv chpmv + #define F77_cgeru cgeru + #define F77_cgerc cgerc + #define F77_cher cher + #define F77_chpr chpr + #define F77_cher2 cher2 + #define F77_chpr2 chpr2 + #define F77_zhemv zhemv + #define F77_zhbmv zhbmv + #define F77_zhpmv zhpmv + #define F77_zgeru zgeru + #define F77_zgerc zgerc + #define F77_zher zher + #define F77_zhpr zhpr + #define F77_zher2 zher2 + #define F77_zhpr2 zhpr2 + #define F77_sgemv sgemv + #define F77_sgbmv sgbmv + #define F77_strmv strmv + #define F77_stbmv stbmv + #define F77_stpmv stpmv + #define F77_strsv strsv + #define F77_stbsv stbsv + #define F77_stpsv stpsv + #define F77_dgemv dgemv + #define F77_dgbmv dgbmv + #define F77_dtrmv dtrmv + #define F77_dtbmv dtbmv + #define F77_dtpmv dtpmv + #define F77_dtrsv dtrsv + #define F77_dtbsv dtbsv + #define F77_dtpsv dtpsv + #define F77_cgemv cgemv + #define F77_cgbmv cgbmv + #define F77_ctrmv ctrmv + #define F77_ctbmv ctbmv + #define F77_ctpmv ctpmv + #define F77_ctrsv ctrsv + #define F77_ctbsv ctbsv + #define F77_ctpsv ctpsv + #define F77_zgemv zgemv + #define F77_zgbmv zgbmv + #define F77_ztrmv ztrmv + #define F77_ztbmv ztbmv + #define F77_ztpmv ztpmv + #define F77_ztrsv ztrsv + #define F77_ztbsv ztbsv + #define F77_ztpsv ztpsv +/* + * Level 3 BLAS + */ + #define F77_chemm chemm + #define F77_cherk cherk + #define F77_cher2k cher2k + #define F77_zhemm zhemm + #define F77_zherk zherk + #define F77_zher2k zher2k + #define F77_sgemm sgemm + #define F77_ssymm ssymm + #define F77_ssyrk ssyrk + #define F77_ssyr2k ssyr2k + #define F77_strmm strmm + #define F77_strsm strsm + #define F77_dgemm dgemm + #define F77_dsymm dsymm + #define F77_dsyrk dsyrk + #define F77_dsyr2k dsyr2k + #define F77_dtrmm dtrmm + #define F77_dtrsm dtrsm + #define F77_cgemm cgemm + #define F77_csymm csymm + #define F77_csyrk csyrk + #define F77_csyr2k csyr2k + #define F77_ctrmm ctrmm + #define F77_ctrsm ctrsm + #define F77_zgemm zgemm + #define F77_zsymm zsymm + #define F77_zsyrk zsyrk + #define F77_zsyr2k zsyr2k + #define F77_ztrmm ztrmm + #define F77_ztrsm ztrsm +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + void F77_xerbla(FCHAR, void *); +/* + * Level 1 Fortran Prototypes + */ + +/* Single Precision */ + + void F77_srot(FINT, float *, FINT, float *, FINT, const float *, const float *); + void F77_srotg(float *,float *,float *,float *); + void F77_srotm( FINT, float *, FINT, float *, FINT, const float *); + void F77_srotmg(float *,float *,float *,const float *, float *); + void F77_sswap( FINT, float *, FINT, float *, FINT); + void F77_scopy( FINT, const float *, FINT, float *, FINT); + void F77_saxpy( FINT, const float *, const float *, FINT, float *, FINT); + void F77_sdot_sub(FINT, const float *, FINT, const float *, FINT, float *); + void F77_sdsdot_sub( FINT, const float *, const float *, FINT, const float *, FINT, float *); + void F77_sscal( FINT, const float *, float *, FINT); + void F77_snrm2_sub( FINT, const float *, FINT, float *); + void F77_sasum_sub( FINT, const float *, FINT, float *); + void F77_isamax_sub( FINT, const float * , FINT, FINT2); + +/* Double Precision */ + + void F77_drot(FINT, double *, FINT, double *, FINT, const double *, const double *); + void F77_drotg(double *,double *,double *,double *); + void F77_drotm( FINT, double *, FINT, double *, FINT, const double *); + void F77_drotmg(double *,double *,double *,const double *, double *); + void F77_dswap( FINT, double *, FINT, double *, FINT); + void F77_dcopy( FINT, const double *, FINT, double *, FINT); + void F77_daxpy( FINT, const double *, const double *, FINT, double *, FINT); + void F77_dswap( FINT, double *, FINT, double *, FINT); + void F77_dsdot_sub(FINT, const float *, FINT, const float *, FINT, double *); + void F77_ddot_sub( FINT, const double *, FINT, const double *, FINT, double *); + void F77_dscal( FINT, const double *, double *, FINT); + void F77_dnrm2_sub( FINT, const double *, FINT, double *); + void F77_dasum_sub( FINT, const double *, FINT, double *); + void F77_idamax_sub( FINT, const double * , FINT, FINT2); + +/* Single Complex Precision */ + + void F77_cswap( FINT, void *, FINT, void *, FINT); + void F77_ccopy( FINT, const void *, FINT, void *, FINT); + void F77_caxpy( FINT, const void *, const void *, FINT, void *, FINT); + void F77_cswap( FINT, void *, FINT, void *, FINT); + void F77_cdotc_sub( FINT, const void *, FINT, const void *, FINT, void *); + void F77_cdotu_sub( FINT, const void *, FINT, const void *, FINT, void *); + void F77_cscal( FINT, const void *, void *, FINT); + void F77_icamax_sub( FINT, const void *, FINT, FINT2); + void F77_csscal( FINT, const float *, void *, FINT); + void F77_scnrm2_sub( FINT, const void *, FINT, float *); + void F77_scasum_sub( FINT, const void *, FINT, float *); + +/* Double Complex Precision */ + + void F77_zswap( FINT, void *, FINT, void *, FINT); + void F77_zcopy( FINT, const void *, FINT, void *, FINT); + void F77_zaxpy( FINT, const void *, const void *, FINT, void *, FINT); + void F77_zswap( FINT, void *, FINT, void *, FINT); + void F77_zdotc_sub( FINT, const void *, FINT, const void *, FINT, void *); + void F77_zdotu_sub( FINT, const void *, FINT, const void *, FINT, void *); + void F77_zdscal( FINT, const double *, void *, FINT); + void F77_zscal( FINT, const void *, void *, FINT); + void F77_dznrm2_sub( FINT, const void *, FINT, double *); + void F77_dzasum_sub( FINT, const void *, FINT, double *); + void F77_izamax_sub( FINT, const void *, FINT, FINT2); + +/* + * Level 2 Fortran Prototypes + */ + +/* Single Precision */ + + void F77_sgemv(FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT); + void F77_sgbmv(FCHAR, FINT, FINT, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT); + void F77_ssymv(FCHAR, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT); + void F77_ssbmv(FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT); + void F77_sspmv(FCHAR, FINT, const float *, const float *, const float *, FINT, const float *, float *, FINT); + void F77_strmv( FCHAR, FCHAR, FCHAR, FINT, const float *, FINT, float *, FINT); + void F77_stbmv( FCHAR, FCHAR, FCHAR, FINT, FINT, const float *, FINT, float *, FINT); + void F77_strsv( FCHAR, FCHAR, FCHAR, FINT, const float *, FINT, float *, FINT); + void F77_stbsv( FCHAR, FCHAR, FCHAR, FINT, FINT, const float *, FINT, float *, FINT); + void F77_stpmv( FCHAR, FCHAR, FCHAR, FINT, const float *, float *, FINT); + void F77_stpsv( FCHAR, FCHAR, FCHAR, FINT, const float *, float *, FINT); + void F77_sger( FINT, FINT, const float *, const float *, FINT, const float *, FINT, float *, FINT); + void F77_ssyr(FCHAR, FINT, const float *, const float *, FINT, float *, FINT); + void F77_sspr(FCHAR, FINT, const float *, const float *, FINT, float *); + void F77_sspr2(FCHAR, FINT, const float *, const float *, FINT, const float *, FINT, float *); + void F77_ssyr2(FCHAR, FINT, const float *, const float *, FINT, const float *, FINT, float *, FINT); + +/* Double Precision */ + + void F77_dgemv(FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT); + void F77_dgbmv(FCHAR, FINT, FINT, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT); + void F77_dsymv(FCHAR, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT); + void F77_dsbmv(FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT); + void F77_dspmv(FCHAR, FINT, const double *, const double *, const double *, FINT, const double *, double *, FINT); + void F77_dtrmv( FCHAR, FCHAR, FCHAR, FINT, const double *, FINT, double *, FINT); + void F77_dtbmv( FCHAR, FCHAR, FCHAR, FINT, FINT, const double *, FINT, double *, FINT); + void F77_dtrsv( FCHAR, FCHAR, FCHAR, FINT, const double *, FINT, double *, FINT); + void F77_dtbsv( FCHAR, FCHAR, FCHAR, FINT, FINT, const double *, FINT, double *, FINT); + void F77_dtpmv( FCHAR, FCHAR, FCHAR, FINT, const double *, double *, FINT); + void F77_dtpsv( FCHAR, FCHAR, FCHAR, FINT, const double *, double *, FINT); + void F77_dger( FINT, FINT, const double *, const double *, FINT, const double *, FINT, double *, FINT); + void F77_dsyr(FCHAR, FINT, const double *, const double *, FINT, double *, FINT); + void F77_dspr(FCHAR, FINT, const double *, const double *, FINT, double *); + void F77_dspr2(FCHAR, FINT, const double *, const double *, FINT, const double *, FINT, double *); + void F77_dsyr2(FCHAR, FINT, const double *, const double *, FINT, const double *, FINT, double *, FINT); + +/* Single Complex Precision */ + + void F77_cgemv(FCHAR, FINT, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT); + void F77_cgbmv(FCHAR, FINT, FINT, FINT, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT); + void F77_chemv(FCHAR, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT); + void F77_chbmv(FCHAR, FINT, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT); + void F77_chpmv(FCHAR, FINT, const void *, const void *, const void *, FINT, const void *, void *, FINT); + void F77_ctrmv( FCHAR, FCHAR, FCHAR, FINT, const void *, FINT, void *, FINT); + void F77_ctbmv( FCHAR, FCHAR, FCHAR, FINT, FINT, const void *, FINT, void *, FINT); + void F77_ctpmv( FCHAR, FCHAR, FCHAR, FINT, const void *, void *, FINT); + void F77_ctrsv( FCHAR, FCHAR, FCHAR, FINT, const void *, FINT, void *, FINT); + void F77_ctbsv( FCHAR, FCHAR, FCHAR, FINT, FINT, const void *, FINT, void *, FINT); + void F77_ctpsv( FCHAR, FCHAR, FCHAR, FINT, const void *, void *,FINT); + void F77_cgerc( FINT, FINT, const void *, const void *, FINT, const void *, FINT, void *, FINT); + void F77_cgeru( FINT, FINT, const void *, const void *, FINT, const void *, FINT, void *, FINT); + void F77_cher(FCHAR, FINT, const float *, const void *, FINT, void *, FINT); + void F77_cher2(FCHAR, FINT, const void *, const void *, FINT, const void *, FINT, void *, FINT); + void F77_chpr(FCHAR, FINT, const float *, const void *, FINT, void *); + void F77_chpr2(FCHAR, FINT, const float *, const void *, FINT, const void *, FINT, void *); + +/* Double Complex Precision */ + + void F77_zgemv(FCHAR, FINT, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT); + void F77_zgbmv(FCHAR, FINT, FINT, FINT, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT); + void F77_zhemv(FCHAR, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT); + void F77_zhbmv(FCHAR, FINT, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT); + void F77_zhpmv(FCHAR, FINT, const void *, const void *, const void *, FINT, const void *, void *, FINT); + void F77_ztrmv( FCHAR, FCHAR, FCHAR, FINT, const void *, FINT, void *, FINT); + void F77_ztbmv( FCHAR, FCHAR, FCHAR, FINT, FINT, const void *, FINT, void *, FINT); + void F77_ztpmv( FCHAR, FCHAR, FCHAR, FINT, const void *, void *, FINT); + void F77_ztrsv( FCHAR, FCHAR, FCHAR, FINT, const void *, FINT, void *, FINT); + void F77_ztbsv( FCHAR, FCHAR, FCHAR, FINT, FINT, const void *, FINT, void *, FINT); + void F77_ztpsv( FCHAR, FCHAR, FCHAR, FINT, const void *, void *,FINT); + void F77_zgerc( FINT, FINT, const void *, const void *, FINT, const void *, FINT, void *, FINT); + void F77_zgeru( FINT, FINT, const void *, const void *, FINT, const void *, FINT, void *, FINT); + void F77_zher(FCHAR, FINT, const double *, const void *, FINT, void *, FINT); + void F77_zher2(FCHAR, FINT, const void *, const void *, FINT, const void *, FINT, void *, FINT); + void F77_zhpr(FCHAR, FINT, const double *, const void *, FINT, void *); + void F77_zhpr2(FCHAR, FINT, const double *, const void *, FINT, const void *, FINT, void *); + +/* + * Level 3 Fortran Prototypes + */ + +/* Single Precision */ + + void F77_sgemm(FCHAR, FCHAR, FINT, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT); + void F77_ssymm(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT); + void F77_ssyrk(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, float *, FINT); + void F77_ssyr2k(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT); + void F77_strmm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, float *, FINT); + void F77_strsm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, float *, FINT); + +/* Double Precision */ + + void F77_dgemm(FCHAR, FCHAR, FINT, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT); + void F77_dsymm(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT); + void F77_dsyrk(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, double *, FINT); + void F77_dsyr2k(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT); + void F77_dtrmm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, double *, FINT); + void F77_dtrsm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, double *, FINT); + +/* Single Complex Precision */ + + void F77_cgemm(FCHAR, FCHAR, FINT, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT); + void F77_csymm(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT); + void F77_chemm(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT); + void F77_csyrk(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, float *, FINT); + void F77_cherk(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, float *, FINT); + void F77_csyr2k(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT); + void F77_cher2k(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT); + void F77_ctrmm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, float *, FINT); + void F77_ctrsm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, float *, FINT); + +/* Double Complex Precision */ + + void F77_zgemm(FCHAR, FCHAR, FINT, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT); + void F77_zsymm(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT); + void F77_zhemm(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT); + void F77_zsyrk(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, double *, FINT); + void F77_zherk(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, double *, FINT); + void F77_zsyr2k(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT); + void F77_zher2k(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT); + void F77_ztrmm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, double *, FINT); + void F77_ztrsm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, double *, FINT); + +#ifdef __cplusplus +} +#endif + +#endif /* CBLAS_F77_H */ diff --git a/lib/3rdParty/dlib/include/dlib/external/libjpeg/jchuff.h b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jchuff.h new file mode 100644 index 00000000..2d184ec5 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jchuff.h @@ -0,0 +1,47 @@ +/* + * jchuff.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy encoding routines + * that are shared between the sequential encoder (jchuff.c) and the + * progressive encoder (jcphuff.c). No other modules need to see these. + */ + +/* The legal range of a DCT coefficient is + * -1024 .. +1023 for 8-bit data; + * -16384 .. +16383 for 12-bit data. + * Hence the magnitude should always fit in 10 or 14 bits respectively. + */ + +#if BITS_IN_JSAMPLE == 8 +#define MAX_COEF_BITS 10 +#else +#define MAX_COEF_BITS 14 +#endif + +/* Derived data constructed for each Huffman table */ + +typedef struct { + unsigned int ehufco[256]; /* code for each symbol */ + char ehufsi[256]; /* length of code for each symbol */ + /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */ +} c_derived_tbl; + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_c_derived_tbl jMkCDerived +#define jpeg_gen_optimal_table jGenOptTbl +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Expand a Huffman table definition into the derived format */ +EXTERN(void) jpeg_make_c_derived_tbl + JPP((j_compress_ptr cinfo, int isDC, int tblno, + c_derived_tbl ** pdtbl)); + +/* Generate an optimal table definition given the specified counts */ +EXTERN(void) jpeg_gen_optimal_table + JPP((j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])); diff --git a/lib/3rdParty/dlib/include/dlib/external/libjpeg/jconfig.h b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jconfig.h new file mode 100644 index 00000000..9594ec56 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jconfig.h @@ -0,0 +1,45 @@ +/* jconfig.h. Generated automatically by configure. */ +/* jconfig.cfg --- source file edited by configure script */ +/* see jconfig.doc for explanations */ + +#define HAVE_PROTOTYPES +#define HAVE_UNSIGNED_CHAR +#define HAVE_UNSIGNED_SHORT +#undef void +#undef const +#undef CHAR_IS_UNSIGNED +#define HAVE_STDDEF_H +#define HAVE_STDLIB_H +#undef NEED_BSD_STRINGS +#undef NEED_SYS_TYPES_H +#undef NEED_FAR_POINTERS +#undef NEED_SHORT_EXTERNAL_NAMES +/* Define this if you get warnings about undefined structures. */ +#undef INCOMPLETE_TYPES_BROKEN + +#ifdef JPEG_INTERNALS + +#undef RIGHT_SHIFT_IS_UNSIGNED +#define INLINE __inline__ +/* These are for configuring the JPEG memory manager. */ +#undef DEFAULT_MAX_MEM +#undef NO_MKTEMP + +#endif /* JPEG_INTERNALS */ + +#ifdef JPEG_CJPEG_DJPEG + +#define BMP_SUPPORTED /* BMP image file format */ +#define GIF_SUPPORTED /* GIF image file format */ +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ +#undef RLE_SUPPORTED /* Utah RLE image file format */ +#define TARGA_SUPPORTED /* Targa image file format */ + +#undef TWO_FILE_COMMANDLINE +#undef NEED_SIGNAL_CATCHER +#undef DONT_USE_B_MODE + +/* Define this if you want percent-done progress reports from cjpeg/djpeg. */ +#undef PROGRESS_REPORT + +#endif /* JPEG_CJPEG_DJPEG */ diff --git a/lib/3rdParty/dlib/include/dlib/external/libjpeg/jdct.h b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jdct.h new file mode 100644 index 00000000..a89c9550 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jdct.h @@ -0,0 +1,176 @@ +/* + * jdct.h + * + * Copyright (C) 1994-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file contains common declarations for the forward and + * inverse DCT modules. These declarations are private to the DCT managers + * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms. + * The individual DCT algorithms are kept in separate files to ease + * machine-dependent tuning (e.g., assembly coding). + */ + + +/* + * A forward DCT routine is given a pointer to a work area of type DCTELEM[]; + * the DCT is to be performed in-place in that buffer. Type DCTELEM is int + * for 8-bit samples, long for 12-bit samples. (NOTE: Floating-point DCT + * implementations use an array of type FAST_FLOAT, instead.) + * The DCT inputs are expected to be signed (range +-CENTERJSAMPLE). + * The DCT outputs are returned scaled up by a factor of 8; they therefore + * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This + * convention improves accuracy in integer implementations and saves some + * work in floating-point ones. + * Quantization of the output coefficients is done by jcdctmgr.c. + */ + +#if BITS_IN_JSAMPLE == 8 +typedef int DCTELEM; /* 16 or 32 bits is fine */ +#else +typedef long DCTELEM; /* must have 32 bits */ +#endif + +typedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data)); +typedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data)); + + +/* + * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer + * to an output sample array. The routine must dequantize the input data as + * well as perform the IDCT; for dequantization, it uses the multiplier table + * pointed to by compptr->dct_table. The output data is to be placed into the + * sample array starting at a specified column. (Any row offset needed will + * be applied to the array pointer before it is passed to the IDCT code.) + * Note that the number of samples emitted by the IDCT routine is + * DCT_scaled_size * DCT_scaled_size. + */ + +/* typedef inverse_DCT_method_ptr is declared in jpegint.h */ + +/* + * Each IDCT routine has its own ideas about the best dct_table element type. + */ + +typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */ +#if BITS_IN_JSAMPLE == 8 +typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */ +#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */ +#else +typedef long IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */ +#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */ +#endif +typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */ + + +/* + * Each IDCT routine is responsible for range-limiting its results and + * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could + * be quite far out of range if the input data is corrupt, so a bulletproof + * range-limiting step is required. We use a mask-and-table-lookup method + * to do the combined operations quickly. See the comments with + * prepare_range_limit_table (in jdmaster.c) for more info. + */ + +#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE) + +#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_fdct_islow jFDislow +#define jpeg_fdct_ifast jFDifast +#define jpeg_fdct_float jFDfloat +#define jpeg_idct_islow jRDislow +#define jpeg_idct_ifast jRDifast +#define jpeg_idct_float jRDfloat +#define jpeg_idct_4x4 jRD4x4 +#define jpeg_idct_2x2 jRD2x2 +#define jpeg_idct_1x1 jRD1x1 +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + +/* Extern declarations for the forward and inverse DCT routines. */ + +EXTERN(void) jpeg_fdct_islow JPP((DCTELEM * data)); +EXTERN(void) jpeg_fdct_ifast JPP((DCTELEM * data)); +EXTERN(void) jpeg_fdct_float JPP((FAST_FLOAT * data)); + +EXTERN(void) jpeg_idct_islow + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_ifast + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_float + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_4x4 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_2x2 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); +EXTERN(void) jpeg_idct_1x1 + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); + + +/* + * Macros for handling fixed-point arithmetic; these are used by many + * but not all of the DCT/IDCT modules. + * + * All values are expected to be of type long. + * Fractional constants are scaled left by CONST_BITS bits. + * CONST_BITS is defined within each module using these macros, + * and may differ from one module to the next. + */ + +#define ONE ((long) 1) +#define CONST_SCALE (ONE << CONST_BITS) + +/* Convert a positive real constant to an integer scaled by CONST_SCALE. + * Caution: some C compilers fail to reduce "FIX(constant)" at compile time, + * thus causing a lot of useless floating-point operations at run time. + */ + +#define FIX(x) ((long) ((x) * CONST_SCALE + 0.5)) + +/* Descale and correctly round an long value that's scaled by N bits. + * We assume RIGHT_SHIFT rounds towards minus infinity, so adding + * the fudge factor is correct for either sign of X. + */ + +#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n) + +/* Multiply an long variable by an long constant to yield an long result. + * This macro is used only when the two inputs will actually be no more than + * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a + * full 32x32 multiply. This provides a useful speedup on many machines. + * Unfortunately there is no way to specify a 16x16->32 multiply portably + * in C, but some C compilers will do the right thing if you provide the + * correct combination of casts. + */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16C16(var,const) (((short) (var)) * ((short) (const))) +#endif +#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */ +#define MULTIPLY16C16(var,const) (((short) (var)) * ((long) (const))) +#endif + +#ifndef MULTIPLY16C16 /* default definition */ +#define MULTIPLY16C16(var,const) ((var) * (const)) +#endif + +/* Same except both inputs are variables. */ + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ +#define MULTIPLY16V16(var1,var2) (((short) (var1)) * ((short) (var2))) +#endif + +#ifndef MULTIPLY16V16 /* default definition */ +#define MULTIPLY16V16(var1,var2) ((var1) * (var2)) +#endif diff --git a/lib/3rdParty/dlib/include/dlib/external/libjpeg/jdhuff.h b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jdhuff.h new file mode 100644 index 00000000..6a0e939a --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jdhuff.h @@ -0,0 +1,201 @@ +/* + * jdhuff.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy decoding routines + * that are shared between the sequential decoder (jdhuff.c) and the + * progressive decoder (jdphuff.c). No other modules need to see these. + */ + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_d_derived_tbl jMkDDerived +#define jpeg_fill_bit_buffer jFilBitBuf +#define jpeg_huff_decode jHufDecode +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Derived data constructed for each Huffman table */ + +#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */ + +typedef struct { + /* Basic tables: (element [0] of each array is unused) */ + long maxcode[18]; /* largest code of length k (-1 if none) */ + /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */ + long valoffset[17]; /* huffval[] offset for codes of length k */ + /* valoffset[k] = huffval[] index of 1st symbol of code length k, less + * the smallest code of length k; so given a code of length k, the + * corresponding symbol is huffval[code + valoffset[k]] + */ + + /* Link to public Huffman table (needed only in jpeg_huff_decode) */ + JHUFF_TBL *pub; + + /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of + * the input data stream. If the next Huffman code is no more + * than HUFF_LOOKAHEAD bits long, we can obtain its length and + * the corresponding symbol directly from these tables. + */ + int look_nbits[1< 32 bits on your machine, and shifting/masking longs is + * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE + * appropriately should be a win. Unfortunately we can't define the size + * with something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8) + * because not all machines measure sizeof in 8-bit bytes. + */ + +typedef struct { /* Bitreading state saved across MCUs */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ +} bitread_perm_state; + +typedef struct { /* Bitreading working state within an MCU */ + /* Current data source location */ + /* We need a copy, rather than munging the original, in case of suspension */ + const JOCTET * next_input_byte; /* => next byte to read from source */ + size_t bytes_in_buffer; /* # of bytes remaining in source buffer */ + /* Bit input buffer --- note these values are kept in variables, + * not in this struct, inside the inner loops. + */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ + /* Pointer needed by jpeg_fill_bit_buffer. */ + j_decompress_ptr cinfo; /* back link to decompress master record */ +} bitread_working_state; + +/* Macros to declare and load/save bitread local variables. */ +#define BITREAD_STATE_VARS \ + bit_buf_type get_buffer; \ + int bits_left; \ + bitread_working_state br_state + +#define BITREAD_LOAD_STATE(cinfop,permstate) \ + br_state.cinfo = cinfop; \ + br_state.next_input_byte = cinfop->src->next_input_byte; \ + br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \ + get_buffer = permstate.get_buffer; \ + bits_left = permstate.bits_left; + +#define BITREAD_SAVE_STATE(cinfop,permstate) \ + cinfop->src->next_input_byte = br_state.next_input_byte; \ + cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \ + permstate.get_buffer = get_buffer; \ + permstate.bits_left = bits_left + +/* + * These macros provide the in-line portion of bit fetching. + * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer + * before using GET_BITS, PEEK_BITS, or DROP_BITS. + * The variables get_buffer and bits_left are assumed to be locals, + * but the state struct might not be (jpeg_huff_decode needs this). + * CHECK_BIT_BUFFER(state,n,action); + * Ensure there are N bits in get_buffer; if suspend, take action. + * val = GET_BITS(n); + * Fetch next N bits. + * val = PEEK_BITS(n); + * Fetch next N bits without removing them from the buffer. + * DROP_BITS(n); + * Discard next N bits. + * The value N should be a simple variable, not an expression, because it + * is evaluated multiple times. + */ + +#define CHECK_BIT_BUFFER(state,nbits,action) \ + { if (bits_left < (nbits)) { \ + if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \ + { action; } \ + get_buffer = (state).get_buffer; bits_left = (state).bits_left; } } + +#define GET_BITS(nbits) \ + (((int) (get_buffer >> (bits_left -= (nbits)))) & ((1<<(nbits))-1)) + +#define PEEK_BITS(nbits) \ + (((int) (get_buffer >> (bits_left - (nbits)))) & ((1<<(nbits))-1)) + +#define DROP_BITS(nbits) \ + (bits_left -= (nbits)) + +/* Load up the bit buffer to a depth of at least nbits */ +EXTERN(int) jpeg_fill_bit_buffer + JPP((bitread_working_state * state, bit_buf_type get_buffer, + int bits_left, int nbits)); + + +/* + * Code for extracting next Huffman-coded symbol from input bit stream. + * Again, this is time-critical and we make the main paths be macros. + * + * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits + * without looping. Usually, more than 95% of the Huffman codes will be 8 + * or fewer bits long. The few overlength codes are handled with a loop, + * which need not be inline code. + * + * Notes about the HUFF_DECODE macro: + * 1. Near the end of the data segment, we may fail to get enough bits + * for a lookahead. In that case, we do it the hard way. + * 2. If the lookahead table contains no entry, the next code must be + * more than HUFF_LOOKAHEAD bits long. + * 3. jpeg_huff_decode returns -1 if forced to suspend. + */ + +#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \ +{ int nb, look; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + nb = 1; goto slowlabel; \ + } \ + } \ + look = PEEK_BITS(HUFF_LOOKAHEAD); \ + if ((nb = htbl->look_nbits[look]) != 0) { \ + DROP_BITS(nb); \ + result = htbl->look_sym[look]; \ + } else { \ + nb = HUFF_LOOKAHEAD+1; \ +slowlabel: \ + if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \ + { failaction; } \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + } \ +} + +/* Out-of-line case for Huffman code fetching */ +EXTERN(int) jpeg_huff_decode + JPP((bitread_working_state * state, bit_buf_type get_buffer, + int bits_left, d_derived_tbl * htbl, int min_bits)); diff --git a/lib/3rdParty/dlib/include/dlib/external/libjpeg/jerror.h b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jerror.h new file mode 100644 index 00000000..fc2fffea --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jerror.h @@ -0,0 +1,291 @@ +/* + * jerror.h + * + * Copyright (C) 1994-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the JPEG library. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + * A set of error-reporting macros are defined too. Some applications using + * the JPEG library may wish to include this file to get the error codes + * and/or the macros. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef JERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* JERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */ + +/* For maintenance convenience, list is alphabetical by message code name */ +JMESSAGE(JERR_ARITH_NOTIMPL, + "Sorry, there are legal restrictions on arithmetic coding") +JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix") +JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") +JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") +JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") +JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range") +JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported") +JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition") +JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace") +JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace") +JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length") +JMESSAGE(JERR_BAD_LIB_VERSION, + "Wrong JPEG library version: library is %d, caller expects %d") +JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan") +JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d") +JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d") +JMESSAGE(JERR_BAD_PROGRESSION, + "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d") +JMESSAGE(JERR_BAD_PROG_SCRIPT, + "Invalid progressive parameters at scan script entry %d") +JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors") +JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d") +JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d") +JMESSAGE(JERR_BAD_STRUCT_SIZE, + "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u") +JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access") +JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small") +JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here") +JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet") +JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d") +JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request") +JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d") +JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x") +JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d") +JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d") +JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)") +JMESSAGE(JERR_EMS_READ, "Read from EMS failed") +JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed") +JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan") +JMESSAGE(JERR_FILE_READ, "Input file read error") +JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?") +JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet") +JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow") +JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry") +JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels") +JMESSAGE(JERR_INPUT_EMPTY, "Empty input file") +JMESSAGE(JERR_INPUT_EOF, "Premature end of input file") +JMESSAGE(JERR_MISMATCHED_QUANT_TABLE, + "Cannot transcode due to multiple use of quantization table %d") +JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") +JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") +JMESSAGE(JERR_NOTIMPL, "Not implemented yet") +JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") +JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") +JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") +JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") +JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined") +JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x") +JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)") +JMESSAGE(JERR_QUANT_COMPONENTS, + "Cannot quantize more than %d color components") +JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors") +JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors") +JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers") +JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker") +JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x") +JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers") +JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF") +JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s") +JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file") +JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file") +JMESSAGE(JERR_TFILE_WRITE, + "Write failed on temporary file --- out of disk space?") +JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines") +JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x") +JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up") +JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation") +JMESSAGE(JERR_XMS_READ, "Read from XMS failed") +JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed") +JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT) +JMESSAGE(JMSG_VERSION, JVERSION) +JMESSAGE(JTRC_16BIT_TABLES, + "Caution: quantization tables are too coarse for baseline JPEG") +JMESSAGE(JTRC_ADOBE, + "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d") +JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u") +JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u") +JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x") +JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x") +JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d") +JMESSAGE(JTRC_DRI, "Define Restart Interval %u") +JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u") +JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u") +JMESSAGE(JTRC_EOI, "End Of Image") +JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d") +JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d") +JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE, + "Warning: thumbnail image size does not match data length %u") +JMESSAGE(JTRC_JFIF_EXTENSION, + "JFIF extension marker: type 0x%02x, length %u") +JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image") +JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u") +JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x") +JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u") +JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors") +JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors") +JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization") +JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d") +JMESSAGE(JTRC_RST, "RST%d") +JMESSAGE(JTRC_SMOOTH_NOTIMPL, + "Smoothing not supported with nonstandard sampling ratios") +JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d") +JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d") +JMESSAGE(JTRC_SOI, "Start of Image") +JMESSAGE(JTRC_SOS, "Start Of Scan: %d components") +JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d") +JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d") +JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s") +JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s") +JMESSAGE(JTRC_THUMB_JPEG, + "JFIF extension marker: JPEG-compressed thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_PALETTE, + "JFIF extension marker: palette thumbnail image, length %u") +JMESSAGE(JTRC_THUMB_RGB, + "JFIF extension marker: RGB thumbnail image, length %u") +JMESSAGE(JTRC_UNKNOWN_IDS, + "Unrecognized component IDs %d %d %d, assuming YCbCr") +JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") +JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") +JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") +JMESSAGE(JWRN_BOGUS_PROGRESSION, + "Inconsistent progression sequence for component %d coefficient %d") +JMESSAGE(JWRN_EXTRANEOUS_DATA, + "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x") +JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment") +JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code") +JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d") +JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file") +JMESSAGE(JWRN_MUST_RESYNC, + "Corrupt JPEG data: found marker 0x%02x instead of RST%d") +JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG") +JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTMSGCODE +} J_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE + + +#ifndef JERROR_H +#define JERROR_H + +/* Macros to simplify using the error and trace message stuff */ +/* The first parameter is either type of cinfo pointer */ + +/* Fatal errors (print message and exit) */ +#define ERREXIT(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT3(cinfo,code,p1,p2,p3) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (cinfo)->err->msg_parm.i[3] = (p4), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXITS(cinfo,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) + +#define MAKESTMT(stuff) do { stuff } while (0) + +/* Nonfatal errors (we can keep going, but the data is probably corrupt) */ +#define WARNMS(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) + +/* Informational/debugging messages */ +#define TRACEMS(cinfo,lvl,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS1(cinfo,lvl,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS2(cinfo,lvl,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMSS(cinfo,lvl,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) + +#endif /* JERROR_H */ diff --git a/lib/3rdParty/dlib/include/dlib/external/libjpeg/jinclude.h b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jinclude.h new file mode 100644 index 00000000..0a4f1514 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jinclude.h @@ -0,0 +1,91 @@ +/* + * jinclude.h + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file exists to provide a single place to fix any problems with + * including the wrong system include files. (Common problems are taken + * care of by the standard jconfig symbols, but on really weird systems + * you may have to edit this file.) + * + * NOTE: this file is NOT intended to be included by applications using the + * JPEG library. Most applications need only include jpeglib.h. + */ + + +/* Include auto-config file to find out which system include files we need. */ + +#include "jconfig.h" /* auto configuration options */ +#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ + +/* + * We need the NULL macro and size_t typedef. + * On an ANSI-conforming system it is sufficient to include . + * Otherwise, we get them from or ; we may have to + * pull in as well. + * Note that the core JPEG library does not require ; + * only the default error handler and data source/destination modules do. + * But we must pull it in because of the references to FILE in jpeglib.h. + * You can remove those references if you want to compile without . + */ + +#ifdef HAVE_STDDEF_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef NEED_SYS_TYPES_H +#include +#endif + +#include + +/* + * We need memory copying and zeroing functions, plus strncpy(). + * ANSI and System V implementations declare these in . + * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). + * Some systems may declare memset and memcpy in . + * + * NOTE: we assume the size parameters to these functions are of type size_t. + * Change the casts in these macros if not! + */ + +#ifdef NEED_BSD_STRINGS + +#include +#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) +#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) + +#else /* not BSD, assume ANSI/SysV string lib */ + +#include +#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) +#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) + +#endif + +/* + * In ANSI C, and indeed any rational implementation, size_t is also the + * type returned by sizeof(). However, it seems there are some irrational + * implementations out there, in which sizeof() returns an int even though + * size_t is defined as long or unsigned long. To ensure consistent results + * we always use this SIZEOF() macro in place of using sizeof() directly. + */ + +#define SIZEOF(object) ((size_t) sizeof(object)) + +/* + * The modules that use fread() and fwrite() always invoke them through + * these macros. On some systems you may need to twiddle the argument casts. + * CAUTION: argument order is different from underlying functions! + */ + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) diff --git a/lib/3rdParty/dlib/include/dlib/external/libjpeg/jmemsys.h b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jmemsys.h new file mode 100644 index 00000000..6c3c6d34 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jmemsys.h @@ -0,0 +1,198 @@ +/* + * jmemsys.h + * + * Copyright (C) 1992-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This include file defines the interface between the system-independent + * and system-dependent portions of the JPEG memory manager. No other + * modules need include it. (The system-independent portion is jmemmgr.c; + * there are several different versions of the system-dependent portion.) + * + * This file works as-is for the system-dependent memory managers supplied + * in the IJG distribution. You may need to modify it if you write a + * custom memory manager. If system-dependent changes are needed in + * this file, the best method is to #ifdef them based on a configuration + * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR + * and USE_MAC_MEMMGR. + */ + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_get_small jGetSmall +#define jpeg_free_small jFreeSmall +#define jpeg_get_large jGetLarge +#define jpeg_free_large jFreeLarge +#define jpeg_mem_available jMemAvail +#define jpeg_open_backing_store jOpenBackStore +#define jpeg_mem_init jMemInit +#define jpeg_mem_term jMemTerm +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* + * These two functions are used to allocate and release small chunks of + * memory. (Typically the total amount requested through jpeg_get_small is + * no more than 20K or so; this will be requested in chunks of a few K each.) + * Behavior should be the same as for the standard library functions malloc + * and free; in particular, jpeg_get_small must return NULL on failure. + * On most systems, these ARE malloc and free. jpeg_free_small is passed the + * size of the object being freed, just in case it's needed. + * On an 80x86 machine using small-data memory model, these manage near heap. + */ + +EXTERN(void *) jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject)); +EXTERN(void) jpeg_free_small JPP((j_common_ptr cinfo, void * object, + size_t sizeofobject)); + +/* + * These two functions are used to allocate and release large chunks of + * memory (up to the total free space designated by jpeg_mem_available). + * The interface is the same as above, except that on an 80x86 machine, + * far pointers are used. On most other machines these are identical to + * the jpeg_get/free_small routines; but we keep them separate anyway, + * in case a different allocation strategy is desirable for large chunks. + */ + +EXTERN(void FAR *) jpeg_get_large JPP((j_common_ptr cinfo, + size_t sizeofobject)); +EXTERN(void) jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object, + size_t sizeofobject)); + +/* + * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may + * be requested in a single call to jpeg_get_large (and jpeg_get_small for that + * matter, but that case should never come into play). This macro is needed + * to model the 64Kb-segment-size limit of far addressing on 80x86 machines. + * On those machines, we expect that jconfig.h will provide a proper value. + * On machines with 32-bit flat address spaces, any large constant may be used. + * + * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type + * size_t and will be a multiple of sizeof(align_type). + */ + +#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */ +#define MAX_ALLOC_CHUNK 1000000000L +#endif + +/* + * This routine computes the total space still available for allocation by + * jpeg_get_large. If more space than this is needed, backing store will be + * used. NOTE: any memory already allocated must not be counted. + * + * There is a minimum space requirement, corresponding to the minimum + * feasible buffer sizes; jmemmgr.c will request that much space even if + * jpeg_mem_available returns zero. The maximum space needed, enough to hold + * all working storage in memory, is also passed in case it is useful. + * Finally, the total space already allocated is passed. If no better + * method is available, cinfo->mem->max_memory_to_use - already_allocated + * is often a suitable calculation. + * + * It is OK for jpeg_mem_available to underestimate the space available + * (that'll just lead to more backing-store access than is really necessary). + * However, an overestimate will lead to failure. Hence it's wise to subtract + * a slop factor from the true available space. 5% should be enough. + * + * On machines with lots of virtual memory, any large constant may be returned. + * Conversely, zero may be returned to always use the minimum amount of memory. + */ + +EXTERN(long) jpeg_mem_available JPP((j_common_ptr cinfo, + long min_bytes_needed, + long max_bytes_needed, + long already_allocated)); + + +/* + * This structure holds whatever state is needed to access a single + * backing-store object. The read/write/close method pointers are called + * by jmemmgr.c to manipulate the backing-store object; all other fields + * are private to the system-dependent backing store routines. + */ + +#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */ + + +#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */ + +typedef unsigned short XMSH; /* type of extended-memory handles */ +typedef unsigned short EMSH; /* type of expanded-memory handles */ + +typedef union { + short file_handle; /* DOS file handle if it's a temp file */ + XMSH xms_handle; /* handle if it's a chunk of XMS */ + EMSH ems_handle; /* handle if it's a chunk of EMS */ +} handle_union; + +#endif /* USE_MSDOS_MEMMGR */ + +#ifdef USE_MAC_MEMMGR /* Mac-specific junk */ +#include +#endif /* USE_MAC_MEMMGR */ + + +typedef struct backing_store_struct * backing_store_ptr; + +typedef struct backing_store_struct { + /* Methods for reading/writing/closing this backing-store object */ + JMETHOD(void, read_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, write_backing_store, (j_common_ptr cinfo, + backing_store_ptr info, + void FAR * buffer_address, + long file_offset, long byte_count)); + JMETHOD(void, close_backing_store, (j_common_ptr cinfo, + backing_store_ptr info)); + + /* Private fields for system-dependent backing-store management */ +#ifdef USE_MSDOS_MEMMGR + /* For the MS-DOS manager (jmemdos.c), we need: */ + handle_union handle; /* reference to backing-store storage object */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else +#ifdef USE_MAC_MEMMGR + /* For the Mac manager (jmemmac.c), we need: */ + short temp_file; /* file reference number to temp file */ + FSSpec tempSpec; /* the FSSpec for the temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ +#else + /* For a typical implementation with temp files, we need: */ + FILE * temp_file; /* stdio reference to temp file */ + char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */ +#endif +#endif +} backing_store_info; + + +/* + * Initial opening of a backing-store object. This must fill in the + * read/write/close pointers in the object. The read/write routines + * may take an error exit if the specified maximum file size is exceeded. + * (If jpeg_mem_available always returns a large value, this routine can + * just take an error exit.) + */ + +EXTERN(void) jpeg_open_backing_store JPP((j_common_ptr cinfo, + backing_store_ptr info, + long total_bytes_needed)); + + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. jpeg_mem_init will be called before anything is + * allocated (and, therefore, nothing in cinfo is of use except the error + * manager pointer). It should return a suitable default value for + * max_memory_to_use; this may subsequently be overridden by the surrounding + * application. (Note that max_memory_to_use is only important if + * jpeg_mem_available chooses to consult it ... no one else will.) + * jpeg_mem_term may assume that all requested memory has been freed and that + * all opened backing-store objects have been closed. + */ + +EXTERN(long) jpeg_mem_init JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_mem_term JPP((j_common_ptr cinfo)); diff --git a/lib/3rdParty/dlib/include/dlib/external/libjpeg/jmorecfg.h b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jmorecfg.h new file mode 100644 index 00000000..6082f069 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jmorecfg.h @@ -0,0 +1,356 @@ +/* + * jmorecfg.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains additional configuration options that customize the + * JPEG software for special applications or support machine-dependent + * optimizations. Most users will not need to touch this file. + */ + + +/* + * Define BITS_IN_JSAMPLE as either + * 8 for 8-bit sample values (the usual setting) + * 12 for 12-bit sample values + * Only 8 and 12 are legal data precisions for lossy JPEG according to the + * JPEG standard, and the IJG code does not support anything else! + * We do not support run-time selection of data precision, sorry. + */ + +#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ + + +/* + * Maximum number of components (color channels) allowed in JPEG image. + * To meet the letter of the JPEG spec, set this to 255. However, darn + * few applications need more than 4 channels (maybe 5 for CMYK + alpha + * mask). We recommend 10 as a reasonable compromise; use 4 if you are + * really short on memory. (Each allowed component costs a hundred or so + * bytes of storage, whether actually used in an image or not.) + */ + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + +/* + * Basic data types. + * You may need to change these if you have a machine with unusual data + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + * but it had better be at least 16. + */ + +/* Representation of a single sample (pixel element value). + * We frequently allocate large arrays of these, so it's important to keep + * them small. But if you have memory to burn and access to char or short + * arrays is very slow on your hardware, you might want to change these. + */ + + +#ifdef _MSC_VER +// Disable the following warnings for Visual Studio +// This is a warning you get from visual studio 2005 about things in the standard C++ +// library being "deprecated." I checked the C++ standard and it doesn't say jack +// about any of them (I checked the searchable PDF). So this warning is total Bunk. +#pragma warning(disable : 4996) +#endif + + +#if BITS_IN_JSAMPLE == 8 +/* JSAMPLE should be the smallest type that will hold the values 0..255. + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JSAMPLE; +#ifdef CHAR_IS_UNSIGNED +#define GETJSAMPLE(value) ((int) (value)) +#else +#define GETJSAMPLE(value) ((int) (value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 + +#endif /* BITS_IN_JSAMPLE == 8 */ + + +#if BITS_IN_JSAMPLE == 12 +/* JSAMPLE should be the smallest type that will hold the values 0..4095. + * On nearly all machines "short" will do nicely. + */ + +typedef short JSAMPLE; +#define GETJSAMPLE(value) ((int) (value)) + +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 + +#endif /* BITS_IN_JSAMPLE == 12 */ + + +/* Representation of a DCT frequency coefficient. + * This should be a signed value of at least 16 bits; "short" is usually OK. + * Again, we allocate large arrays of these, but you can change to int + * if you have memory to burn and "short" is really slow. + */ + +typedef short JCOEF; + + +/* Compressed datastreams are represented as arrays of JOCTET. + * These must be EXACTLY 8 bits wide, at least once they are written to + * external storage. Note that when using the stdio data source/destination + * managers, this is also the data type passed to fread/fwrite. + */ + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char JOCTET; +#define GETJOCTET(value) (value) + +#else /* not HAVE_UNSIGNED_CHAR */ + +typedef char JOCTET; +#ifdef CHAR_IS_UNSIGNED +#define GETJOCTET(value) (value) +#else +#define GETJOCTET(value) ((value) & 0xFF) +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + + +/* These typedefs are used for various table entries and so forth. + * They must be at least as wide as specified; but making them too big + * won't cost a huge amount of memory, so we don't provide special + * extraction code like we did for JSAMPLE. (In other words, these + * typedefs live at a different point on the speed/space tradeoff curve.) + */ + +/* unsigned char must hold at least the values 0..255. */ + + +/* unsigned short must hold at least the values 0..65535. */ + + + +/* Datatype used for image dimensions. The JPEG standard only supports + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + * "unsigned int" is sufficient on all machines. However, if you need to + * handle larger images and you don't mind deviating from the spec, you + * can change this datatype. + */ + +typedef unsigned int JDIMENSION; + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + +/* These macros are used in all function definitions and extern declarations. + * You could modify them if you need to change function linkage conventions; + * in particular, you'll need to do that to make the library a Windows DLL. + * Another application is to make all functions global for use with debuggers + * or code profilers that require it. + */ + +/* a function called through method pointers: */ +#define METHODDEF(type) static type +/* a function used only in its module: */ +#define LOCAL(type) static type +/* a function referenced thru EXTERNs: */ +#define GLOBAL(type) type +/* + Use C linking unless we are supposed to be compiling our own copy of + libjpeg. Then let it use C++ linking so that we are less likely to get + linker name conflicts with other libraries that happen to statically include + libjpeg as well. +*/ +#if defined(__cplusplus) && !defined(DLIB_JPEG_STATIC) +#define EXTERN(type) extern "C" type +#else +#define EXTERN(type) extern type +#endif + + +/* This macro is used to declare a "method", that is, a function pointer. + * We want to supply prototype parameters if the compiler can cope. + * Note that the arglist parameter must be parenthesized! + * Again, you can customize this if you need special linkage keywords. + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + * by just saying "FAR *" where such a pointer is needed. In a few places + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + */ + +#ifdef NEED_FAR_POINTERS +#define FAR far +#else +#ifndef FAR + #define FAR +#endif +#endif + + +/* + * On a few systems, type boolean and/or its values FALSE, TRUE may appear + * in standard header files. Or you may have conflicts with application- + * specific header files that you want to include together with these files. + * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. + */ + +#ifndef FALSE /* in case these macros already exist */ +#define FALSE 0 /* values of boolean */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif + + +/* + * The remaining options affect code selection within the JPEG library, + * but they don't need to be visible to most applications using the library. + * To minimize application namespace pollution, the symbols won't be + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + */ + +#ifdef JPEG_INTERNALS +#define JPEG_INTERNAL_OPTIONS +#endif + +#ifdef JPEG_INTERNAL_OPTIONS + + +/* + * These defines indicate whether to include various optional functions. + * Undefining some of these symbols will produce a smaller but less capable + * library. Note that you can leave certain source files out of the + * compilation/linking process if you've #undef'd the corresponding symbols. + * (You may HAVE to do that if your compiler doesn't like null source files.) + */ + +/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */ + +/* Capability options common to encoder and decoder: */ + +#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ +#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ +#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ + +/* Encoder capability options: */ + +#undef C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ +/* Note: if you selected 12-bit data precision, it is dangerous to turn off + * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit + * precision, so jchuff.c normally uses entropy optimization to compute + * usable tables for higher precision. If you don't want to do optimization, + * you'll have to supply different default Huffman tables. + * The exact same statements apply for progressive JPEG: the default tables + * don't work for progressive mode. (This may get fixed, however.) + */ +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + +/* Decoder capability options: */ + +#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ +#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ +#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ +#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ +#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ +#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + +/* more capability options later, no doubt */ + + +/* + * Ordering of RGB data in scanlines passed to or from the application. + * If your application wants to deal with data in the order B,G,R, just + * change these macros. You can also deal with formats such as R,G,B,X + * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing + * the offsets will also change the order in which colormap data is organized. + * RESTRICTIONS: + * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. + * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not + * useful if you are using JPEG color spaces other than YCbCr or grayscale. + * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + * is not 3 (they don't understand about dummy color components!). So you + * can't use color quantization if you change that value. + */ + +#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ +#define RGB_GREEN 1 /* Offset of Green */ +#define RGB_BLUE 2 /* Offset of Blue */ +#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */ + + +/* Definitions for speed-related optimizations. */ + + +/* If your compiler supports inline functions, define INLINE + * as the inline keyword; otherwise define it as empty. + */ + +#ifndef INLINE +#ifdef __GNUC__ /* for instance, GNU C knows about inline */ +#define INLINE __inline__ +#endif +#ifndef INLINE +#define INLINE /* default is to define it as empty */ +#endif +#endif + + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + */ + +#ifndef MULTIPLIER +#define MULTIPLIER int /* type for fastest integer multiply */ +#endif + + +/* FAST_FLOAT should be either float or double, whichever is done faster + * by your compiler. (Note that this type is only used in the floating point + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + * Typically, float is faster in ANSI C compilers, while double is faster in + * pre-ANSI compilers (because they insist on converting to double anyway). + * The code below therefore chooses float if we have ANSI-style prototypes. + */ + +#ifndef FAST_FLOAT +#ifdef HAVE_PROTOTYPES +#define FAST_FLOAT float +#else +#define FAST_FLOAT double +#endif +#endif + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/lib/3rdParty/dlib/include/dlib/external/libjpeg/jpegint.h b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jpegint.h new file mode 100644 index 00000000..65406796 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jpegint.h @@ -0,0 +1,392 @@ +/* + * jpegint.h + * + * Copyright (C) 1991-1997, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file provides common declarations for the various JPEG modules. + * These declarations are considered internal to the JPEG library; most + * applications using the library shouldn't need to include this file. + */ + + +/* Declarations for both compression & decompression */ + +typedef enum { /* Operating modes for buffer controllers */ + JBUF_PASS_THRU, /* Plain stripwise operation */ + /* Remaining modes require a full-image buffer to have been created */ + JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ + JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ + JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ +} J_BUF_MODE; + +/* Values of global_state field (jdapi.c has some dependencies on ordering!) */ +#define CSTATE_START 100 /* after create_compress */ +#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ +#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ +#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ +#define DSTATE_START 200 /* after create_decompress */ +#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ +#define DSTATE_READY 202 /* found SOS, ready for start_decompress */ +#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ +#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ +#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ +#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ +#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ +#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ +#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ +#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ + + +/* Declarations for compression modules */ + +/* Master control module */ +struct jpeg_comp_master { + JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); + JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); + + /* State variables made visible to other modules */ + int call_pass_startup; /* True if pass_startup must be called */ + int is_last_pass; /* True during last pass */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_c_main_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail)); +}; + +/* Compression preprocessing (downsampling input buffer control) */ +struct jpeg_c_prep_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, + JDIMENSION *in_row_ctr, + JDIMENSION in_rows_avail, + JSAMPIMAGE output_buf, + JDIMENSION *out_row_group_ctr, + JDIMENSION out_row_groups_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_c_coef_controller { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(int, compress_data, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf)); +}; + +/* Colorspace conversion */ +struct jpeg_color_converter { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, color_convert, (j_compress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + JDIMENSION output_row, int num_rows)); +}; + +/* Downsampling */ +struct jpeg_downsampler { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + JMETHOD(void, downsample, (j_compress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + JSAMPIMAGE output_buf, + JDIMENSION out_row_group_index)); + + int need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Forward DCT (also controls coefficient quantization) */ +struct jpeg_forward_dct { + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + /* perhaps this should be an array??? */ + JMETHOD(void, forward_DCT, (j_compress_ptr cinfo, + jpeg_component_info * compptr, + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + JDIMENSION start_row, JDIMENSION start_col, + JDIMENSION num_blocks)); +}; + +/* Entropy encoding */ +struct jpeg_entropy_encoder { + JMETHOD(void, start_pass, (j_compress_ptr cinfo, int gather_statistics)); + JMETHOD(int, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data)); + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); +}; + +/* Marker writing */ +struct jpeg_marker_writer { + JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); + JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); + JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); + /* These routines are exported to allow insertion of extra markers */ + /* Probably only COM and APPn markers should be written this way */ + JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker, + unsigned int datalen)); + JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val)); +}; + + +/* Declarations for decompression modules */ + +/* Master control module */ +struct jpeg_decomp_master { + JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + int is_dummy_pass; /* True during 1st pass for 2-pass quant */ +}; + +/* Input control module */ +struct jpeg_input_controller { + JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); + JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); + + /* State variables made visible to other modules */ + int has_multiple_scans; /* True if file has multiple scans */ + int eoi_reached; /* True when EOI has been consumed */ +}; + +/* Main buffer control (downsampled-data buffer) */ +struct jpeg_d_main_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, process_data, (j_decompress_ptr cinfo, + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Coefficient buffer control */ +struct jpeg_d_coef_controller { + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); + JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, + JSAMPIMAGE output_buf)); + /* Pointer to array of coefficient virtual arrays, or NULL if none */ + jvirt_barray_ptr *coef_arrays; +}; + +/* Decompression postprocessing (color quantization buffer control) */ +struct jpeg_d_post_controller { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); +}; + +/* Marker reading & parsing */ +struct jpeg_marker_reader { + JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); + /* Read markers until SOS or EOI. + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); + /* Read a restart marker --- exported for use by entropy decoder only */ + jpeg_marker_parser_method read_restart_marker; + + /* State of marker reader --- nominally internal, but applications + * supplying COM or APPn handlers might like to know the state. + */ + int saw_SOI; /* found SOI? */ + int saw_SOF; /* found SOF? */ + int next_restart_num; /* next restart number expected (0-7) */ + unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ +}; + +/* Entropy decoding */ +struct jpeg_entropy_decoder { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(int, decode_mcu, (j_decompress_ptr cinfo, + JBLOCKROW *MCU_data)); + + /* This is here to share code between baseline and progressive decoders; */ + /* other modules probably should not use it */ + int insufficient_data; /* set TRUE after emitting warning */ +}; + +/* Inverse DCT (also performs dequantization) */ +typedef JMETHOD(void, inverse_DCT_method_ptr, + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + JCOEFPTR coef_block, + JSAMPARRAY output_buf, JDIMENSION output_col)); + +struct jpeg_inverse_dct { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + /* It is useful to allow each component to have a separate IDCT method. */ + inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; +}; + +/* Upsampling (note that upsampler must also call color converter) */ +struct jpeg_upsampler { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, upsample, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, + JDIMENSION *in_row_group_ctr, + JDIMENSION in_row_groups_avail, + JSAMPARRAY output_buf, + JDIMENSION *out_row_ctr, + JDIMENSION out_rows_avail)); + + int need_context_rows; /* TRUE if need rows above & below */ +}; + +/* Colorspace conversion */ +struct jpeg_color_deconverter { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, color_convert, (j_decompress_ptr cinfo, + JSAMPIMAGE input_buf, JDIMENSION input_row, + JSAMPARRAY output_buf, int num_rows)); +}; + +/* Color quantization or color precision reduction */ +struct jpeg_color_quantizer { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, int is_pre_scan)); + JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, + int num_rows)); + JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); +}; + + +/* Miscellaneous useful macros */ + +#undef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#undef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + + +/* We assume that right shift corresponds to signed division by 2 with + * rounding towards minus infinity. This is correct for typical "arithmetic + * shift" instructions that shift in copies of the sign bit. But some + * C compilers implement >> with an unsigned shift. For these machines you + * must define RIGHT_SHIFT_IS_UNSIGNED. + * RIGHT_SHIFT provides a proper signed right shift of an long quantity. + * It is only applied with constant shift counts. SHIFT_TEMPS must be + * included in the variables of any routine using RIGHT_SHIFT. + */ + +#ifdef RIGHT_SHIFT_IS_UNSIGNED +#define SHIFT_TEMPS long shift_temp; +#define RIGHT_SHIFT(x,shft) \ + ((shift_temp = (x)) < 0 ? \ + (shift_temp >> (shft)) | ((~((long) 0)) << (32-(shft))) : \ + (shift_temp >> (shft))) +#else +#define SHIFT_TEMPS +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jinit_compress_master jICompress +#define jinit_c_master_control jICMaster +#define jinit_c_main_controller jICMainC +#define jinit_c_prep_controller jICPrepC +#define jinit_c_coef_controller jICCoefC +#define jinit_color_converter jICColor +#define jinit_downsampler jIDownsampler +#define jinit_forward_dct jIFDCT +#define jinit_huff_encoder jIHEncoder +#define jinit_phuff_encoder jIPHEncoder +#define jinit_marker_writer jIMWriter +#define jinit_master_decompress jIDMaster +#define jinit_d_main_controller jIDMainC +#define jinit_d_coef_controller jIDCoefC +#define jinit_d_post_controller jIDPostC +#define jinit_input_controller jIInCtlr +#define jinit_marker_reader jIMReader +#define jinit_huff_decoder jIHDecoder +#define jinit_phuff_decoder jIPHDecoder +#define jinit_inverse_dct jIIDCT +#define jinit_upsampler jIUpsampler +#define jinit_color_deconverter jIDColor +#define jinit_1pass_quantizer jI1Quant +#define jinit_2pass_quantizer jI2Quant +#define jinit_merged_upsampler jIMUpsampler +#define jinit_memory_mgr jIMemMgr +#define jdiv_round_up jDivRound +#define jround_up jRound +#define jcopy_sample_rows jCopySamples +#define jcopy_block_row jCopyBlocks +#define jzero_far jZeroFar +#define jpeg_zigzag_order jZIGTable +#define jpeg_natural_order jZAGTable +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Compression module initialization routines */ +EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo, + int transcode_only)); +EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, + int need_full_buffer)); +EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, + int need_full_buffer)); +EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo, + int need_full_buffer)); +EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_phuff_encoder JPP((j_compress_ptr cinfo)); +EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo)); +/* Decompression module initialization routines */ +EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, + int need_full_buffer)); +EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo, + int need_full_buffer)); +EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, + int need_full_buffer)); +EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); +EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); +/* Memory manager initialization */ +EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); + +/* Utility routines in jutils.c */ +EXTERN(long) jdiv_round_up JPP((long a, long b)); +EXTERN(long) jround_up JPP((long a, long b)); +EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, + JSAMPARRAY output_array, int dest_row, + int num_rows, JDIMENSION num_cols)); +EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, + JDIMENSION num_blocks)); +EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero)); +/* Constant tables in jutils.c */ +#if 0 /* This table is not actually needed in v6a */ +extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ +#endif +extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ + +/* Suppress undefined-structure complaints if necessary. */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +#endif +#endif /* INCOMPLETE_TYPES_BROKEN */ diff --git a/lib/3rdParty/dlib/include/dlib/external/libjpeg/jpeglib.h b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jpeglib.h new file mode 100644 index 00000000..e611602d --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jpeglib.h @@ -0,0 +1,1096 @@ +/* + * jpeglib.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + +/* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ +#include "jconfig.h" /* widely used configuration options */ +#endif +#include "jmorecfg.h" /* seldom changed options */ + + +/* Version ID for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". + */ + +#define JPEG_LIB_VERSION 62 /* Version 6b */ + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, so don't change them + * if you want to be compatible. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. + * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ +#ifndef D_MAX_BLOCKS_IN_MCU +#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + * On 80x86 machines, the image arrays are too big for near pointers, + * but the pointer arrays can fit in near memory. + */ + +typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This array gives the coefficient quantizers in natural array order + * (not the zigzag order in which they are stored in a JPEG DQT marker). + * CAUTION: IJG versions prior to v6a kept this array in zigzag order. + */ + unsigned short quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + int sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + unsigned char bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + unsigned char huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + int sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in DCT blocks. + * Any dummy blocks added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_blocks; + JDIMENSION height_in_blocks; + /* Size of a DCT block in samples. Always DCTSIZE for compression. + * For decompression this is the size of the output from one DCT block, + * reflecting any scaling we choose to apply during the IDCT step. + * Values of 1,2,4,8 are likely to be supported. Note that different + * components may receive different IDCT scalings. + */ + int DCT_scaled_size; + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface), thus + * downsampled_width = ceil(image_width * Hi/Hmax) + * and similarly for height. For decompression, IDCT scaling is included, so + * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE) + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + int component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of blocks per MCU, horizontally */ + int MCU_height; /* number of blocks per MCU, vertically */ + int MCU_blocks; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */ + int last_col_width; /* # of non-dummy blocks across in last MCU */ + int last_row_height; /* # of non-dummy blocks down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is currently used only for decompression. + */ + JQUANT_TBL * quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void * dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ + int Ss, Se; /* progressive JPEG spectral selection parms */ + int Ah, Al; /* progressive JPEG successive approx. parms */ +} jpeg_scan_info; + +/* The decompressor can save APPn and COM markers in a list of these: */ + +typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr; + +struct jpeg_marker_struct { + jpeg_saved_marker_ptr next; /* next in list, or NULL */ + unsigned char marker; /* marker code: JPEG_COM, or JPEG_APP0+n */ + unsigned int original_length; /* # bytes of data in the file */ + unsigned int data_length; /* # bytes of data saved at data[] */ + JOCTET FAR * data; /* the data contained in the marker */ + /* the marker length word is not counted in data_length or original_length */ +}; + +/* Known color spaces. */ + +typedef enum { + JCS_UNKNOWN, /* error/unspecified */ + JCS_GRAYSCALE, /* monochrome */ + JCS_RGB, /* red/green/blue */ + JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + JCS_CMYK, /* C/M/Y/K */ + JCS_YCCK /* Y/Cb/Cr/K */ +} J_COLOR_SPACE; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* slow but accurate integer algorithm */ + JDCT_IFAST, /* faster, less accurate integer method */ + JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr * err; /* Error handler module */\ + struct jpeg_memory_mgr * mem; /* Memory manager module */\ + struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ + void * client_data; /* Available for use by application */\ + int is_decompressor; /* So common code can tell which is which */\ + int global_state /* For checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct * j_common_ptr; +typedef struct jpeg_compress_struct * j_compress_ptr; +typedef struct jpeg_decompress_struct * j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr * dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; /* input image width */ + JDIMENSION image_height; /* input image height */ + int input_components; /* # of color components in input image */ + J_COLOR_SPACE in_color_space; /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + + int data_precision; /* bits of precision in image data */ + + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + unsigned char arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + unsigned char arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + unsigned char arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + int num_scans; /* # of entries in scan_info array */ + const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + int raw_data_in; /* TRUE=caller supplies downsampled data */ + int arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + int optimize_coding; /* TRUE=optimize entropy encoding parms */ + int CCIR601_sampling; /* TRUE=first samples are cosited */ + int smoothing_factor; /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + int write_JFIF_header; /* should a JFIF marker be written? */ + unsigned char JFIF_major_version; /* What to write for the JFIF version number */ + unsigned char JFIF_minor_version; + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + unsigned char density_unit; /* JFIF code for pixel size units */ + unsigned short X_density; /* Horizontal pixel density */ + unsigned short Y_density; /* Vertical pixel density */ + int write_Adobe_marker; /* should an Adobe marker be written? */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + int progressive_mode; /* TRUE if scan script uses progressive mode */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ + /* The coefficient controller receives data in units of MCU rows as defined + * for fully interleaved scans (whether the JPEG file is interleaved or not). + * There are v_samp_factor * DCTSIZE sample rows of each component in an + * "iMCU" (interleaved MCU) row. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[C_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master * master; + struct jpeg_c_main_controller * main; + struct jpeg_c_prep_controller * prep; + struct jpeg_c_coef_controller * coef; + struct jpeg_marker_writer * marker; + struct jpeg_color_converter * cconvert; + struct jpeg_downsampler * downsample; + struct jpeg_forward_dct * fdct; + struct jpeg_entropy_encoder * entropy; + jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */ + int script_space_size; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr * src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION image_height; /* nominal image height */ + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; /* colorspace for output */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + double output_gamma; /* image gamma wanted in output */ + + int buffered_image; /* TRUE=multiple output passes */ + int raw_data_out; /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; /* IDCT algorithm selector */ + int do_fancy_upsampling; /* TRUE=apply fancy upsampling */ + int do_block_smoothing; /* TRUE=apply interblock smoothing */ + + int quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; /* type of color dithering to use */ + int two_pass_quantize; /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + int enable_1pass_quant; /* enable future use of 1-pass quantizer */ + int enable_external_quant;/* enable future use of external colormap */ + int enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; /* scaled image width */ + JDIMENSION output_height; /* scaled image height */ + int out_color_components; /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; /* bits of precision in image data */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + int progressive_mode; /* TRUE if SOFn specifies progressive mode */ + int arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + + unsigned char arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + unsigned char arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + unsigned char arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + int saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */ + unsigned char JFIF_major_version; /* JFIF version number */ + unsigned char JFIF_minor_version; + unsigned char density_unit; /* JFIF code for pixel size units */ + unsigned short X_density; /* Horizontal pixel density */ + unsigned short Y_density; /* Vertical pixel density */ + int saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ + unsigned char Adobe_transform; /* Color transform code from Adobe marker */ + + int CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Aside from the specific data retained from APPn markers known to the + * library, the uninterpreted contents of any or all APPn and COM markers + * can be saved in a list for examination by the application. + */ + jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The coefficient controller's input and output progress is measured in + * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows + * in fully interleaved JPEG scans, but are used whether the scan is + * interleaved or not. We define an iMCU row as v_samp_factor DCT block + * rows of each component. Therefore, the IDCT output contains + * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row. + */ + + JSAMPLE * sample_range_limit; /* table for fast range-limiting */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[D_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master * master; + struct jpeg_d_main_controller * main; + struct jpeg_d_coef_controller * coef; + struct jpeg_d_post_controller * post; + struct jpeg_input_controller * inputctl; + struct jpeg_marker_reader * marker; + struct jpeg_entropy_decoder * entropy; + struct jpeg_inverse_dct * idct; + struct jpeg_upsampler * upsample; + struct jpeg_color_deconverter * cconvert; + struct jpeg_color_quantizer * cquantize; +}; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + JMETHOD(void, error_exit, (j_common_ptr cinfo)); + /* Conditionally emit a trace or warning message */ + JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); + /* Routine that actually outputs a trace or error message */ + JMETHOD(void, output_message, (j_common_ptr cinfo)); + /* Format a message string for the most recent JPEG error or message */ + JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char * const * jpeg_message_table; /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char * const * addon_message_table; /* Non-library errors */ + int first_addon_message; /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); + + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + JMETHOD(void, init_destination, (j_compress_ptr cinfo)); + JMETHOD(int, empty_output_buffer, (j_compress_ptr cinfo)); + JMETHOD(void, term_destination, (j_compress_ptr cinfo)); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + + JMETHOD(void, init_source, (j_decompress_ptr cinfo)); + JMETHOD(int, fill_input_buffer, (j_decompress_ptr cinfo)); + JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); + JMETHOD(int, resync_to_restart, (j_decompress_ptr cinfo, int desired)); + JMETHOD(void, term_source, (j_decompress_ptr cinfo)); +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control * jvirt_sarray_ptr; +typedef struct jvirt_barray_control * jvirt_barray_ptr; + + +struct jpeg_memory_mgr { + /* Method pointers */ + JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, + JDIMENSION numrows)); + JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, + JDIMENSION numrows)); + JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, + int pool_id, + int pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, + int pool_id, + int pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); + JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, + jvirt_sarray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + int writable)); + JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, + jvirt_barray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + int writable)); + JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); + JMETHOD(void, self_destruct, (j_common_ptr cinfo)); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; + + /* Maximum allocation request accepted by alloc_large. */ + long max_alloc_chunk; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef JMETHOD(int, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); + + +/* Declarations for routines called by application. + * The JPP macro hides prototype parameters from compilers that can't cope. + * Note JPP requires double parentheses. + */ + +#ifdef HAVE_PROTOTYPES +#define JPP(arglist) arglist +#else +#define JPP(arglist) () +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. + * We shorten external names to be unique in the first six letters, which + * is good enough for all known systems. + * (If your compiler itself needs names to be unique in less than 15 + * characters, you are out of luck. Get a better compiler.) + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_error jStdError +#define jpeg_CreateCompress jCreaCompress +#define jpeg_CreateDecompress jCreaDecompress +#define jpeg_destroy_compress jDestCompress +#define jpeg_destroy_decompress jDestDecompress +#define jpeg_stdio_dest jStdDest +#define jpeg_stdio_src jStdSrc +#define jpeg_set_defaults jSetDefaults +#define jpeg_set_colorspace jSetColorspace +#define jpeg_default_colorspace jDefColorspace +#define jpeg_set_quality jSetQuality +#define jpeg_set_linear_quality jSetLQuality +#define jpeg_add_quant_table jAddQuantTable +#define jpeg_quality_scaling jQualityScaling +#define jpeg_simple_progression jSimProgress +#define jpeg_suppress_tables jSuppressTables +#define jpeg_alloc_quant_table jAlcQTable +#define jpeg_alloc_huff_table jAlcHTable +#define jpeg_start_compress jStrtCompress +#define jpeg_write_scanlines jWrtScanlines +#define jpeg_finish_compress jFinCompress +#define jpeg_write_raw_data jWrtRawData +#define jpeg_write_marker jWrtMarker +#define jpeg_write_m_header jWrtMHeader +#define jpeg_write_m_byte jWrtMByte +#define jpeg_write_tables jWrtTables +#define jpeg_read_header jReadHeader +#define jpeg_start_decompress jStrtDecompress +#define jpeg_read_scanlines jReadScanlines +#define jpeg_finish_decompress jFinDecompress +#define jpeg_read_raw_data jReadRawData +#define jpeg_has_multiple_scans jHasMultScn +#define jpeg_start_output jStrtOutput +#define jpeg_finish_output jFinOutput +#define jpeg_input_complete jInComplete +#define jpeg_new_colormap jNewCMap +#define jpeg_consume_input jConsumeInput +#define jpeg_calc_output_dimensions jCalcDimensions +#define jpeg_save_markers jSaveMarkers +#define jpeg_set_marker_processor jSetMarker +#define jpeg_read_coefficients jReadCoefs +#define jpeg_write_coefficients jWrtCoefs +#define jpeg_copy_critical_parameters jCopyCrit +#define jpeg_abort_compress jAbrtCompress +#define jpeg_abort_decompress jAbrtDecompress +#define jpeg_abort jAbort +#define jpeg_destroy jDestroy +#define jpeg_resync_to_restart jResyncRestart +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Default error-management setup */ +EXTERN(struct jpeg_error_mgr *) jpeg_std_error + JPP((struct jpeg_error_mgr * err)); + +/* Initialization of JPEG compression objects. + * jpeg_create_compress() and jpeg_create_decompress() are the exported + * names that applications should call. These expand to calls on + * jpeg_CreateCompress and jpeg_CreateDecompress with additional information + * passed for version mismatch checking. + * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. + */ +#define jpeg_create_compress(cinfo) \ + jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_compress_struct)) +#define jpeg_create_decompress(cinfo) \ + jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \ + (size_t) sizeof(struct jpeg_decompress_struct)) +EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo, + int version, size_t structsize)); +EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo, + int version, size_t structsize)); +/* Destruction of JPEG compression objects */ +EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); +EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile)); + +/* Default parameter setup for compression */ +EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo)); +/* Compression parameter setup aids */ +EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo, + J_COLOR_SPACE colorspace)); +EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, + int force_baseline)); +EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo, + int scale_factor, + int force_baseline)); +EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, + int force_baseline)); +EXTERN(int) jpeg_quality_scaling JPP((int quality)); +EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo, + int suppress)); +EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); +EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); + +/* Main entry points for compression */ +EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo, + int write_all_tables)); +EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION num_lines)); +EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo)); + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION num_lines)); + +/* Write a special marker. See libjpeg.doc concerning safe usage. */ +EXTERN(void) jpeg_write_marker + JPP((j_compress_ptr cinfo, int marker, + const JOCTET * dataptr, unsigned int datalen)); +/* Same, but piecemeal. */ +EXTERN(void) jpeg_write_m_header + JPP((j_compress_ptr cinfo, int marker, unsigned int datalen)); +EXTERN(void) jpeg_write_m_byte + JPP((j_compress_ptr cinfo, int val)); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo)); + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo, + int require_image)); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN(int) jpeg_start_decompress JPP((j_decompress_ptr cinfo)); +EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION max_lines)); +EXTERN(int) jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION max_lines)); + +/* Additional entry points for buffered-image mode. */ +EXTERN(int) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); +EXTERN(int) jpeg_start_output JPP((j_decompress_ptr cinfo, + int scan_number)); +EXTERN(int) jpeg_finish_output JPP((j_decompress_ptr cinfo)); +EXTERN(int) jpeg_input_complete JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo)); +EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo)); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); + +/* Control saving of COM and APPn markers into marker_list. */ +EXTERN(void) jpeg_save_markers + JPP((j_decompress_ptr cinfo, int marker_code, + unsigned int length_limit)); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN(void) jpeg_set_marker_processor + JPP((j_decompress_ptr cinfo, int marker_code, + jpeg_marker_parser_method routine)); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays)); +EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, + j_compress_ptr dstinfo)); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo)); +EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo)); +EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo)); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN(int) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, + int desired)); + + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#endif /* JPEGLIB_H */ diff --git a/lib/3rdParty/dlib/include/dlib/external/libjpeg/jversion.h b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jversion.h new file mode 100644 index 00000000..6472c58d --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/libjpeg/jversion.h @@ -0,0 +1,14 @@ +/* + * jversion.h + * + * Copyright (C) 1991-1998, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains software version identification. + */ + + +#define JVERSION "6b 27-Mar-1998" + +#define JCOPYRIGHT "Copyright (C) 1998, Thomas G. Lane" diff --git a/lib/3rdParty/dlib/include/dlib/external/libpng/png.h b/lib/3rdParty/dlib/include/dlib/external/libpng/png.h new file mode 100644 index 00000000..52739273 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/libpng/png.h @@ -0,0 +1,3319 @@ + +/* png.h - header file for PNG reference library + * + * libpng version 1.6.7 - November 14, 2013 + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license (See LICENSE, below) + * + * Authors and maintainers: + * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat + * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger + * libpng versions 0.97, January 1998, through 1.6.7 - November 14, 2013: Glenn + * See also "Contributing Authors", below. + * + * Note about libpng version numbers: + * + * Due to various miscommunications, unforeseen code incompatibilities + * and occasional factors outside the authors' control, version numbering + * on the library has not always been consistent and straightforward. + * The following table summarizes matters since version 0.89c, which was + * the first widely used release: + * + * source png.h png.h shared-lib + * version string int version + * ------- ------ ----- ---------- + * 0.89c "1.0 beta 3" 0.89 89 1.0.89 + * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90] + * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95] + * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96] + * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97] + * 0.97c 0.97 97 2.0.97 + * 0.98 0.98 98 2.0.98 + * 0.99 0.99 98 2.0.99 + * 0.99a-m 0.99 99 2.0.99 + * 1.00 1.00 100 2.1.0 [100 should be 10000] + * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000] + * 1.0.1 png.h string is 10001 2.1.0 + * 1.0.1a-e identical to the 10002 from here on, the shared library + * 1.0.2 source version) 10002 is 2.V where V is the source code + * 1.0.2a-b 10003 version, except as noted. + * 1.0.3 10003 + * 1.0.3a-d 10004 + * 1.0.4 10004 + * 1.0.4a-f 10005 + * 1.0.5 (+ 2 patches) 10005 + * 1.0.5a-d 10006 + * 1.0.5e-r 10100 (not source compatible) + * 1.0.5s-v 10006 (not binary compatible) + * 1.0.6 (+ 3 patches) 10006 (still binary incompatible) + * 1.0.6d-f 10007 (still binary incompatible) + * 1.0.6g 10007 + * 1.0.6h 10007 10.6h (testing xy.z so-numbering) + * 1.0.6i 10007 10.6i + * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0) + * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible) + * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible) + * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible) + * 1.0.7 1 10007 (still compatible) + * 1.0.8beta1-4 1 10008 2.1.0.8beta1-4 + * 1.0.8rc1 1 10008 2.1.0.8rc1 + * 1.0.8 1 10008 2.1.0.8 + * 1.0.9beta1-6 1 10009 2.1.0.9beta1-6 + * 1.0.9rc1 1 10009 2.1.0.9rc1 + * 1.0.9beta7-10 1 10009 2.1.0.9beta7-10 + * 1.0.9rc2 1 10009 2.1.0.9rc2 + * 1.0.9 1 10009 2.1.0.9 + * 1.0.10beta1 1 10010 2.1.0.10beta1 + * 1.0.10rc1 1 10010 2.1.0.10rc1 + * 1.0.10 1 10010 2.1.0.10 + * 1.0.11beta1-3 1 10011 2.1.0.11beta1-3 + * 1.0.11rc1 1 10011 2.1.0.11rc1 + * 1.0.11 1 10011 2.1.0.11 + * 1.0.12beta1-2 2 10012 2.1.0.12beta1-2 + * 1.0.12rc1 2 10012 2.1.0.12rc1 + * 1.0.12 2 10012 2.1.0.12 + * 1.1.0a-f - 10100 2.1.1.0a-f (branch abandoned) + * 1.2.0beta1-2 2 10200 2.1.2.0beta1-2 + * 1.2.0beta3-5 3 10200 3.1.2.0beta3-5 + * 1.2.0rc1 3 10200 3.1.2.0rc1 + * 1.2.0 3 10200 3.1.2.0 + * 1.2.1beta1-4 3 10201 3.1.2.1beta1-4 + * 1.2.1rc1-2 3 10201 3.1.2.1rc1-2 + * 1.2.1 3 10201 3.1.2.1 + * 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6 + * 1.0.13beta1 10 10013 10.so.0.1.0.13beta1 + * 1.0.13rc1 10 10013 10.so.0.1.0.13rc1 + * 1.2.2rc1 12 10202 12.so.0.1.2.2rc1 + * 1.0.13 10 10013 10.so.0.1.0.13 + * 1.2.2 12 10202 12.so.0.1.2.2 + * 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6 + * 1.2.3 12 10203 12.so.0.1.2.3 + * 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3 + * 1.0.14rc1 13 10014 10.so.0.1.0.14rc1 + * 1.2.4rc1 13 10204 12.so.0.1.2.4rc1 + * 1.0.14 10 10014 10.so.0.1.0.14 + * 1.2.4 13 10204 12.so.0.1.2.4 + * 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2 + * 1.0.15rc1-3 10 10015 10.so.0.1.0.15rc1-3 + * 1.2.5rc1-3 13 10205 12.so.0.1.2.5rc1-3 + * 1.0.15 10 10015 10.so.0.1.0.15 + * 1.2.5 13 10205 12.so.0.1.2.5 + * 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4 + * 1.0.16 10 10016 10.so.0.1.0.16 + * 1.2.6 13 10206 12.so.0.1.2.6 + * 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2 + * 1.0.17rc1 10 10017 12.so.0.1.0.17rc1 + * 1.2.7rc1 13 10207 12.so.0.1.2.7rc1 + * 1.0.17 10 10017 12.so.0.1.0.17 + * 1.2.7 13 10207 12.so.0.1.2.7 + * 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5 + * 1.0.18rc1-5 10 10018 12.so.0.1.0.18rc1-5 + * 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5 + * 1.0.18 10 10018 12.so.0.1.0.18 + * 1.2.8 13 10208 12.so.0.1.2.8 + * 1.2.9beta1-3 13 10209 12.so.0.1.2.9beta1-3 + * 1.2.9beta4-11 13 10209 12.so.0.9[.0] + * 1.2.9rc1 13 10209 12.so.0.9[.0] + * 1.2.9 13 10209 12.so.0.9[.0] + * 1.2.10beta1-7 13 10210 12.so.0.10[.0] + * 1.2.10rc1-2 13 10210 12.so.0.10[.0] + * 1.2.10 13 10210 12.so.0.10[.0] + * 1.4.0beta1-5 14 10400 14.so.0.0[.0] + * 1.2.11beta1-4 13 10211 12.so.0.11[.0] + * 1.4.0beta7-8 14 10400 14.so.0.0[.0] + * 1.2.11 13 10211 12.so.0.11[.0] + * 1.2.12 13 10212 12.so.0.12[.0] + * 1.4.0beta9-14 14 10400 14.so.0.0[.0] + * 1.2.13 13 10213 12.so.0.13[.0] + * 1.4.0beta15-36 14 10400 14.so.0.0[.0] + * 1.4.0beta37-87 14 10400 14.so.14.0[.0] + * 1.4.0rc01 14 10400 14.so.14.0[.0] + * 1.4.0beta88-109 14 10400 14.so.14.0[.0] + * 1.4.0rc02-08 14 10400 14.so.14.0[.0] + * 1.4.0 14 10400 14.so.14.0[.0] + * 1.4.1beta01-03 14 10401 14.so.14.1[.0] + * 1.4.1rc01 14 10401 14.so.14.1[.0] + * 1.4.1beta04-12 14 10401 14.so.14.1[.0] + * 1.4.1 14 10401 14.so.14.1[.0] + * 1.4.2 14 10402 14.so.14.2[.0] + * 1.4.3 14 10403 14.so.14.3[.0] + * 1.4.4 14 10404 14.so.14.4[.0] + * 1.5.0beta01-58 15 10500 15.so.15.0[.0] + * 1.5.0rc01-07 15 10500 15.so.15.0[.0] + * 1.5.0 15 10500 15.so.15.0[.0] + * 1.5.1beta01-11 15 10501 15.so.15.1[.0] + * 1.5.1rc01-02 15 10501 15.so.15.1[.0] + * 1.5.1 15 10501 15.so.15.1[.0] + * 1.5.2beta01-03 15 10502 15.so.15.2[.0] + * 1.5.2rc01-03 15 10502 15.so.15.2[.0] + * 1.5.2 15 10502 15.so.15.2[.0] + * 1.5.3beta01-10 15 10503 15.so.15.3[.0] + * 1.5.3rc01-02 15 10503 15.so.15.3[.0] + * 1.5.3beta11 15 10503 15.so.15.3[.0] + * 1.5.3 [omitted] + * 1.5.4beta01-08 15 10504 15.so.15.4[.0] + * 1.5.4rc01 15 10504 15.so.15.4[.0] + * 1.5.4 15 10504 15.so.15.4[.0] + * 1.5.5beta01-08 15 10505 15.so.15.5[.0] + * 1.5.5rc01 15 10505 15.so.15.5[.0] + * 1.5.5 15 10505 15.so.15.5[.0] + * 1.5.6beta01-07 15 10506 15.so.15.6[.0] + * 1.5.6rc01-03 15 10506 15.so.15.6[.0] + * 1.5.6 15 10506 15.so.15.6[.0] + * 1.5.7beta01-05 15 10507 15.so.15.7[.0] + * 1.5.7rc01-03 15 10507 15.so.15.7[.0] + * 1.5.7 15 10507 15.so.15.7[.0] + * 1.6.0beta01-40 16 10600 16.so.16.0[.0] + * 1.6.0rc01-08 16 10600 16.so.16.0[.0] + * 1.6.0 16 10600 16.so.16.0[.0] + * 1.6.1beta01-09 16 10601 16.so.16.1[.0] + * 1.6.1rc01 16 10601 16.so.16.1[.0] + * 1.6.1 16 10601 16.so.16.1[.0] + * 1.6.2beta01 16 10602 16.so.16.2[.0] + * 1.6.2rc01-06 16 10602 16.so.16.2[.0] + * 1.6.2 16 10602 16.so.16.2[.0] + * 1.6.3beta01-11 16 10603 16.so.16.3[.0] + * 1.6.3rc01 16 10603 16.so.16.3[.0] + * 1.6.3 16 10603 16.so.16.3[.0] + * 1.6.4beta01-02 16 10604 16.so.16.4[.0] + * 1.6.4rc01 16 10604 16.so.16.4[.0] + * 1.6.4 16 10604 16.so.16.4[.0] + * 1.6.5 16 10605 16.so.16.5[.0] + * 1.6.6 16 10606 16.so.16.6[.0] + * 1.6.7beta01-04 16 10607 16.so.16.7[.0] + * 1.6.7rc01-02 16 10607 16.so.16.7[.0] + * 1.6.7 16 10607 16.so.16.7[.0] + * + * Henceforth the source version will match the shared-library major + * and minor numbers; the shared-library major version number will be + * used for changes in backward compatibility, as it is intended. The + * PNG_LIBPNG_VER macro, which is not used within libpng but is available + * for applications, is an unsigned integer of the form xyyzz corresponding + * to the source version x.y.z (leading zeros in y and z). Beta versions + * were given the previous public release number plus a letter, until + * version 1.0.6j; from then on they were given the upcoming public + * release number plus "betaNN" or "rcNN". + * + * Binary incompatibility exists only when applications make direct access + * to the info_ptr or png_ptr members through png.h, and the compiled + * application is loaded with a different version of the library. + * + * DLLNUM will change each time there are forward or backward changes + * in binary compatibility (e.g., when a new feature is added). + * + * See libpng-manual.txt or libpng.3 for more information. The PNG + * specification is available as a W3C Recommendation and as an ISO + * Specification, defines should NOT be changed. + */ +#define PNG_INFO_gAMA 0x0001 +#define PNG_INFO_sBIT 0x0002 +#define PNG_INFO_cHRM 0x0004 +#define PNG_INFO_PLTE 0x0008 +#define PNG_INFO_tRNS 0x0010 +#define PNG_INFO_bKGD 0x0020 +#define PNG_INFO_hIST 0x0040 +#define PNG_INFO_pHYs 0x0080 +#define PNG_INFO_oFFs 0x0100 +#define PNG_INFO_tIME 0x0200 +#define PNG_INFO_pCAL 0x0400 +#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */ +#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */ +#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */ +#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */ +#define PNG_INFO_IDAT 0x8000 /* ESR, 1.0.6 */ + +/* This is used for the transformation routines, as some of them + * change these values for the row. It also should enable using + * the routines for other purposes. + */ +typedef struct png_row_info_struct +{ + png_uint_32 width; /* width of row */ + png_size_t rowbytes; /* number of bytes in row */ + png_byte color_type; /* color type of row */ + png_byte bit_depth; /* bit depth of row */ + png_byte channels; /* number of channels (1, 2, 3, or 4) */ + png_byte pixel_depth; /* bits per pixel (depth * channels) */ +} png_row_info; + +typedef png_row_info * png_row_infop; +typedef png_row_info * * png_row_infopp; + +/* These are the function types for the I/O functions and for the functions + * that allow the user to override the default I/O functions with his or her + * own. The png_error_ptr type should match that of user-supplied warning + * and error functions, while the png_rw_ptr type should match that of the + * user read/write data functions. Note that the 'write' function must not + * modify the buffer it is passed. The 'read' function, on the other hand, is + * expected to return the read data in the buffer. + */ +typedef PNG_CALLBACK(void, *png_error_ptr, (png_structp, png_const_charp)); +typedef PNG_CALLBACK(void, *png_rw_ptr, (png_structp, png_bytep, png_size_t)); +typedef PNG_CALLBACK(void, *png_flush_ptr, (png_structp)); +typedef PNG_CALLBACK(void, *png_read_status_ptr, (png_structp, png_uint_32, + int)); +typedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32, + int)); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop)); +typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop)); + +/* The following callback receives png_uint_32 row_number, int pass for the + * png_bytep data of the row. When transforming an interlaced image the + * row number is the row number within the sub-image of the interlace pass, so + * the value will increase to the height of the sub-image (not the full image) + * then reset to 0 for the next pass. + * + * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to + * find the output pixel (x,y) given an interlaced sub-image pixel + * (row,col,pass). (See below for these macros.) + */ +typedef PNG_CALLBACK(void, *png_progressive_row_ptr, (png_structp, png_bytep, + png_uint_32, int)); +#endif + +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) +typedef PNG_CALLBACK(void, *png_user_transform_ptr, (png_structp, png_row_infop, + png_bytep)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +typedef PNG_CALLBACK(int, *png_user_chunk_ptr, (png_structp, + png_unknown_chunkp)); +#endif +#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED +/* not used anywhere */ +/* typedef PNG_CALLBACK(void, *png_unknown_chunk_ptr, (png_structp)); */ +#endif + +#ifdef PNG_SETJMP_SUPPORTED +/* This must match the function definition in , and the application + * must include this before png.h to obtain the definition of jmp_buf. The + * function is required to be PNG_NORETURN, but this is not checked. If the + * function does return the application will crash via an abort() or similar + * system level call. + * + * If you get a warning here while building the library you may need to make + * changes to ensure that pnglibconf.h records the calling convention used by + * your compiler. This may be very difficult - try using a different compiler + * to build the library! + */ +PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), typedef); +#endif + +/* Transform masks for the high-level interface */ +#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */ +#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */ +#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */ +#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */ +#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */ +#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */ +#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */ +#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */ +#define PNG_TRANSFORM_BGR 0x0080 /* read and write */ +#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */ +#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */ +#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */ +#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* write only */ +/* Added to libpng-1.2.34 */ +#define PNG_TRANSFORM_STRIP_FILLER_BEFORE PNG_TRANSFORM_STRIP_FILLER +#define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */ +/* Added to libpng-1.4.0 */ +#define PNG_TRANSFORM_GRAY_TO_RGB 0x2000 /* read only */ +/* Added to libpng-1.5.4 */ +#define PNG_TRANSFORM_EXPAND_16 0x4000 /* read only */ +#define PNG_TRANSFORM_SCALE_16 0x8000 /* read only */ + +/* Flags for MNG supported features */ +#define PNG_FLAG_MNG_EMPTY_PLTE 0x01 +#define PNG_FLAG_MNG_FILTER_64 0x04 +#define PNG_ALL_MNG_FEATURES 0x05 + +/* NOTE: prior to 1.5 these functions had no 'API' style declaration, + * this allowed the zlib default functions to be used on Windows + * platforms. In 1.5 the zlib default malloc (which just calls malloc and + * ignores the first argument) should be completely compatible with the + * following. + */ +typedef PNG_CALLBACK(png_voidp, *png_malloc_ptr, (png_structp, + png_alloc_size_t)); +typedef PNG_CALLBACK(void, *png_free_ptr, (png_structp, png_voidp)); + +/* Section 3: exported functions + * Here are the function definitions most commonly used. This is not + * the place to find out how to use libpng. See libpng-manual.txt for the + * full explanation, see example.c for the summary. This just provides + * a simple one line description of the use of each function. + * + * The PNG_EXPORT() and PNG_EXPORTA() macros used below are defined in + * pngconf.h and in the *.dfn files in the scripts directory. + * + * PNG_EXPORT(ordinal, type, name, (args)); + * + * ordinal: ordinal that is used while building + * *.def files. The ordinal value is only + * relevant when preprocessing png.h with + * the *.dfn files for building symbol table + * entries, and are removed by pngconf.h. + * type: return type of the function + * name: function name + * args: function arguments, with types + * + * When we wish to append attributes to a function prototype we use + * the PNG_EXPORTA() macro instead. + * + * PNG_EXPORTA(ordinal, type, name, (args), attributes); + * + * ordinal, type, name, and args: same as in PNG_EXPORT(). + * attributes: function attributes + */ + +/* Returns the version number of the library */ +PNG_EXPORT(1, png_uint_32, png_access_version_number, (void)); + +/* Tell lib we have already handled the first magic bytes. + * Handling more than 8 bytes from the beginning of the file is an error. + */ +PNG_EXPORT(2, void, png_set_sig_bytes, (png_structrp png_ptr, int num_bytes)); + +/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a + * PNG file. Returns zero if the supplied bytes match the 8-byte PNG + * signature, and non-zero otherwise. Having num_to_check == 0 or + * start > 7 will always fail (ie return non-zero). + */ +PNG_EXPORT(3, int, png_sig_cmp, (png_const_bytep sig, png_size_t start, + png_size_t num_to_check)); + +/* Simple signature checking function. This is the same as calling + * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n). + */ +#define png_check_sig(sig, n) !png_sig_cmp((sig), 0, (n)) + +/* Allocate and initialize png_ptr struct for reading, and any other memory. */ +PNG_EXPORTA(4, png_structp, png_create_read_struct, + (png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn), + PNG_ALLOCATED); + +/* Allocate and initialize png_ptr struct for writing, and any other memory */ +PNG_EXPORTA(5, png_structp, png_create_write_struct, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn), + PNG_ALLOCATED); + +PNG_EXPORT(6, png_size_t, png_get_compression_buffer_size, + (png_const_structrp png_ptr)); + +PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structrp png_ptr, + png_size_t size)); + +/* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp + * match up. + */ +#ifdef PNG_SETJMP_SUPPORTED +/* This function returns the jmp_buf built in to *png_ptr. It must be + * supplied with an appropriate 'longjmp' function to use on that jmp_buf + * unless the default error function is overridden in which case NULL is + * acceptable. The size of the jmp_buf is checked against the actual size + * allocated by the library - the call will return NULL on a mismatch + * indicating an ABI mismatch. + */ +PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, (png_structrp png_ptr, + png_longjmp_ptr longjmp_fn, size_t jmp_buf_size)); +# define png_jmpbuf(png_ptr) \ + (*png_set_longjmp_fn((png_ptr), longjmp, (sizeof (jmp_buf)))) +#else +# define png_jmpbuf(png_ptr) \ + (LIBPNG_WAS_COMPILED_WITH__PNG_NO_SETJMP) +#endif +/* This function should be used by libpng applications in place of + * longjmp(png_ptr->jmpbuf, val). If longjmp_fn() has been set, it + * will use it; otherwise it will call PNG_ABORT(). This function was + * added in libpng-1.5.0. + */ +PNG_EXPORTA(9, void, png_longjmp, (png_const_structrp png_ptr, int val), + PNG_NORETURN); + +#ifdef PNG_READ_SUPPORTED +/* Reset the compression stream */ +PNG_EXPORTA(10, int, png_reset_zstream, (png_structrp png_ptr), PNG_DEPRECATED); +#endif + +/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ +#ifdef PNG_USER_MEM_SUPPORTED +PNG_EXPORTA(11, png_structp, png_create_read_struct_2, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn, + png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn), + PNG_ALLOCATED); +PNG_EXPORTA(12, png_structp, png_create_write_struct_2, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn, + png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn), + PNG_ALLOCATED); +#endif + +/* Write the PNG file signature. */ +PNG_EXPORT(13, void, png_write_sig, (png_structrp png_ptr)); + +/* Write a PNG chunk - size, type, (optional) data, CRC. */ +PNG_EXPORT(14, void, png_write_chunk, (png_structrp png_ptr, png_const_bytep + chunk_name, png_const_bytep data, png_size_t length)); + +/* Write the start of a PNG chunk - length and chunk name. */ +PNG_EXPORT(15, void, png_write_chunk_start, (png_structrp png_ptr, + png_const_bytep chunk_name, png_uint_32 length)); + +/* Write the data of a PNG chunk started with png_write_chunk_start(). */ +PNG_EXPORT(16, void, png_write_chunk_data, (png_structrp png_ptr, + png_const_bytep data, png_size_t length)); + +/* Finish a chunk started with png_write_chunk_start() (includes CRC). */ +PNG_EXPORT(17, void, png_write_chunk_end, (png_structrp png_ptr)); + +/* Allocate and initialize the info structure */ +PNG_EXPORTA(18, png_infop, png_create_info_struct, (png_const_structrp png_ptr), + PNG_ALLOCATED); + +/* DEPRECATED: this function allowed init structures to be created using the + * default allocation method (typically malloc). Use is deprecated in 1.6.0 and + * the API will be removed in the future. + */ +PNG_EXPORTA(19, void, png_info_init_3, (png_infopp info_ptr, + png_size_t png_info_struct_size), PNG_DEPRECATED); + +/* Writes all the PNG information before the image. */ +PNG_EXPORT(20, void, png_write_info_before_PLTE, + (png_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(21, void, png_write_info, + (png_structrp png_ptr, png_const_inforp info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the information before the actual image data. */ +PNG_EXPORT(22, void, png_read_info, + (png_structrp png_ptr, png_inforp info_ptr)); +#endif + +#ifdef PNG_TIME_RFC1123_SUPPORTED + /* Convert to a US string format: there is no localization support in this + * routine. The original implementation used a 29 character buffer in + * png_struct, this will be removed in future versions. + */ +#if PNG_LIBPNG_VER < 10700 +/* To do: remove this from libpng17 (and from libpng17/png.c and pngstruct.h) */ +PNG_EXPORTA(23, png_const_charp, png_convert_to_rfc1123, (png_structrp png_ptr, + png_const_timep ptime),PNG_DEPRECATED); +#endif +PNG_EXPORT(241, int, png_convert_to_rfc1123_buffer, (char out[29], + png_const_timep ptime)); +#endif + +#ifdef PNG_CONVERT_tIME_SUPPORTED +/* Convert from a struct tm to png_time */ +PNG_EXPORT(24, void, png_convert_from_struct_tm, (png_timep ptime, + const struct tm * ttime)); + +/* Convert from time_t to png_time. Uses gmtime() */ +PNG_EXPORT(25, void, png_convert_from_time_t, (png_timep ptime, time_t ttime)); +#endif /* PNG_CONVERT_tIME_SUPPORTED */ + +#ifdef PNG_READ_EXPAND_SUPPORTED +/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ +PNG_EXPORT(26, void, png_set_expand, (png_structrp png_ptr)); +PNG_EXPORT(27, void, png_set_expand_gray_1_2_4_to_8, (png_structrp png_ptr)); +PNG_EXPORT(28, void, png_set_palette_to_rgb, (png_structrp png_ptr)); +PNG_EXPORT(29, void, png_set_tRNS_to_alpha, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_EXPAND_16_SUPPORTED +/* Expand to 16-bit channels, forces conversion of palette to RGB and expansion + * of a tRNS chunk if present. + */ +PNG_EXPORT(221, void, png_set_expand_16, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +/* Use blue, green, red order for pixels. */ +PNG_EXPORT(30, void, png_set_bgr, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +/* Expand the grayscale to 24-bit RGB if necessary. */ +PNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +/* Reduce RGB to grayscale. */ +#define PNG_ERROR_ACTION_NONE 1 +#define PNG_ERROR_ACTION_WARN 2 +#define PNG_ERROR_ACTION_ERROR 3 +#define PNG_RGB_TO_GRAY_DEFAULT (-1)/*for red/green coefficients*/ + +PNG_FP_EXPORT(32, void, png_set_rgb_to_gray, (png_structrp png_ptr, + int error_action, double red, double green)) +PNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed, (png_structrp png_ptr, + int error_action, png_fixed_point red, png_fixed_point green)) + +PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structrp + png_ptr)); +#endif + +#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth, + png_colorp palette)); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +/* How the alpha channel is interpreted - this affects how the color channels of + * a PNG file are returned when an alpha channel, or tRNS chunk in a palette + * file, is present. + * + * This has no effect on the way pixels are written into a PNG output + * datastream. The color samples in a PNG datastream are never premultiplied + * with the alpha samples. + * + * The default is to return data according to the PNG specification: the alpha + * channel is a linear measure of the contribution of the pixel to the + * corresponding composited pixel. The gamma encoded color channels must be + * scaled according to the contribution and to do this it is necessary to undo + * the encoding, scale the color values, perform the composition and reencode + * the values. This is the 'PNG' mode. + * + * The alternative is to 'associate' the alpha with the color information by + * storing color channel values that have been scaled by the alpha. The + * advantage is that the color channels can be resampled (the image can be + * scaled) in this form. The disadvantage is that normal practice is to store + * linear, not (gamma) encoded, values and this requires 16-bit channels for + * still images rather than the 8-bit channels that are just about sufficient if + * gamma encoding is used. In addition all non-transparent pixel values, + * including completely opaque ones, must be gamma encoded to produce the final + * image. This is the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' mode (the + * latter being the two common names for associated alpha color channels.) + * + * Since it is not necessary to perform arithmetic on opaque color values so + * long as they are not to be resampled and are in the final color space it is + * possible to optimize the handling of alpha by storing the opaque pixels in + * the PNG format (adjusted for the output color space) while storing partially + * opaque pixels in the standard, linear, format. The accuracy required for + * standard alpha composition is relatively low, because the pixels are + * isolated, therefore typically the accuracy loss in storing 8-bit linear + * values is acceptable. (This is not true if the alpha channel is used to + * simulate transparency over large areas - use 16 bits or the PNG mode in + * this case!) This is the 'OPTIMIZED' mode. For this mode a pixel is + * treated as opaque only if the alpha value is equal to the maximum value. + * + * The final choice is to gamma encode the alpha channel as well. This is + * broken because, in practice, no implementation that uses this choice + * correctly undoes the encoding before handling alpha composition. Use this + * choice only if other serious errors in the software or hardware you use + * mandate it; the typical serious error is for dark halos to appear around + * opaque areas of the composited PNG image because of arithmetic overflow. + * + * The API function png_set_alpha_mode specifies which of these choices to use + * with an enumerated 'mode' value and the gamma of the required output: + */ +#define PNG_ALPHA_PNG 0 /* according to the PNG standard */ +#define PNG_ALPHA_STANDARD 1 /* according to Porter/Duff */ +#define PNG_ALPHA_ASSOCIATED 1 /* as above; this is the normal practice */ +#define PNG_ALPHA_PREMULTIPLIED 1 /* as above */ +#define PNG_ALPHA_OPTIMIZED 2 /* 'PNG' for opaque pixels, else 'STANDARD' */ +#define PNG_ALPHA_BROKEN 3 /* the alpha channel is gamma encoded */ + +PNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structrp png_ptr, int mode, + double output_gamma)) +PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structrp png_ptr, + int mode, png_fixed_point output_gamma)) +#endif + +#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED) +/* The output_gamma value is a screen gamma in libpng terminology: it expresses + * how to decode the output values, not how they are encoded. The values used + * correspond to the normal numbers used to describe the overall gamma of a + * computer display system; for example 2.2 for an sRGB conformant system. The + * values are scaled by 100000 in the _fixed version of the API (so 220000 for + * sRGB.) + * + * The inverse of the value is always used to provide a default for the PNG file + * encoding if it has no gAMA chunk and if png_set_gamma() has not been called + * to override the PNG gamma information. + * + * When the ALPHA_OPTIMIZED mode is selected the output gamma is used to encode + * opaque pixels however pixels with lower alpha values are not encoded, + * regardless of the output gamma setting. + * + * When the standard Porter Duff handling is requested with mode 1 the output + * encoding is set to be linear and the output_gamma value is only relevant + * as a default for input data that has no gamma information. The linear output + * encoding will be overridden if png_set_gamma() is called - the results may be + * highly unexpected! + * + * The following numbers are derived from the sRGB standard and the research + * behind it. sRGB is defined to be approximated by a PNG gAMA chunk value of + * 0.45455 (1/2.2) for PNG. The value implicitly includes any viewing + * correction required to take account of any differences in the color + * environment of the original scene and the intended display environment; the + * value expresses how to *decode* the image for display, not how the original + * data was *encoded*. + * + * sRGB provides a peg for the PNG standard by defining a viewing environment. + * sRGB itself, and earlier TV standards, actually use a more complex transform + * (a linear portion then a gamma 2.4 power law) than PNG can express. (PNG is + * limited to simple power laws.) By saying that an image for direct display on + * an sRGB conformant system should be stored with a gAMA chunk value of 45455 + * (11.3.3.2 and 11.3.3.5 of the ISO PNG specification) the PNG specification + * makes it possible to derive values for other display systems and + * environments. + * + * The Mac value is deduced from the sRGB based on an assumption that the actual + * extra viewing correction used in early Mac display systems was implemented as + * a power 1.45 lookup table. + * + * Any system where a programmable lookup table is used or where the behavior of + * the final display device characteristics can be changed requires system + * specific code to obtain the current characteristic. However this can be + * difficult and most PNG gamma correction only requires an approximate value. + * + * By default, if png_set_alpha_mode() is not called, libpng assumes that all + * values are unencoded, linear, values and that the output device also has a + * linear characteristic. This is only very rarely correct - it is invariably + * better to call png_set_alpha_mode() with PNG_DEFAULT_sRGB than rely on the + * default if you don't know what the right answer is! + * + * The special value PNG_GAMMA_MAC_18 indicates an older Mac system (pre Mac OS + * 10.6) which used a correction table to implement a somewhat lower gamma on an + * otherwise sRGB system. + * + * Both these values are reserved (not simple gamma values) in order to allow + * more precise correction internally in the future. + * + * NOTE: the following values can be passed to either the fixed or floating + * point APIs, but the floating point API will also accept floating point + * values. + */ +#define PNG_DEFAULT_sRGB -1 /* sRGB gamma and color space */ +#define PNG_GAMMA_MAC_18 -2 /* Old Mac '1.8' gamma and color space */ +#define PNG_GAMMA_sRGB 220000 /* Television standards--matches sRGB gamma */ +#define PNG_GAMMA_LINEAR PNG_FP_1 /* Linear */ +#endif + +/* The following are examples of calls to png_set_alpha_mode to achieve the + * required overall gamma correction and, where necessary, alpha + * premultiplication. + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + * This is the default libpng handling of the alpha channel - it is not + * pre-multiplied into the color components. In addition the call states + * that the output is for a sRGB system and causes all PNG files without gAMA + * chunks to be assumed to be encoded using sRGB. + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + * In this case the output is assumed to be something like an sRGB conformant + * display preceeded by a power-law lookup table of power 1.45. This is how + * early Mac systems behaved. + * + * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR); + * This is the classic Jim Blinn approach and will work in academic + * environments where everything is done by the book. It has the shortcoming + * of assuming that input PNG data with no gamma information is linear - this + * is unlikely to be correct unless the PNG files where generated locally. + * Most of the time the output precision will be so low as to show + * significant banding in dark areas of the image. + * + * png_set_expand_16(pp); + * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB); + * This is a somewhat more realistic Jim Blinn inspired approach. PNG files + * are assumed to have the sRGB encoding if not marked with a gamma value and + * the output is always 16 bits per component. This permits accurate scaling + * and processing of the data. If you know that your input PNG files were + * generated locally you might need to replace PNG_DEFAULT_sRGB with the + * correct value for your system. + * + * png_set_alpha_mode(pp, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB); + * If you just need to composite the PNG image onto an existing background + * and if you control the code that does this you can use the optimization + * setting. In this case you just copy completely opaque pixels to the + * output. For pixels that are not completely transparent (you just skip + * those) you do the composition math using png_composite or png_composite_16 + * below then encode the resultant 8-bit or 16-bit values to match the output + * encoding. + * + * Other cases + * If neither the PNG nor the standard linear encoding work for you because + * of the software or hardware you use then you have a big problem. The PNG + * case will probably result in halos around the image. The linear encoding + * will probably result in a washed out, too bright, image (it's actually too + * contrasty.) Try the ALPHA_OPTIMIZED mode above - this will probably + * substantially reduce the halos. Alternatively try: + * + * png_set_alpha_mode(pp, PNG_ALPHA_BROKEN, PNG_DEFAULT_sRGB); + * This option will also reduce the halos, but there will be slight dark + * halos round the opaque parts of the image where the background is light. + * In the OPTIMIZED mode the halos will be light halos where the background + * is dark. Take your pick - the halos are unavoidable unless you can get + * your hardware/software fixed! (The OPTIMIZED approach is slightly + * faster.) + * + * When the default gamma of PNG files doesn't match the output gamma. + * If you have PNG files with no gamma information png_set_alpha_mode allows + * you to provide a default gamma, but it also sets the ouput gamma to the + * matching value. If you know your PNG files have a gamma that doesn't + * match the output you can take advantage of the fact that + * png_set_alpha_mode always sets the output gamma but only sets the PNG + * default if it is not already set: + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + * The first call sets both the default and the output gamma values, the + * second call overrides the output gamma without changing the default. This + * is easier than achieving the same effect with png_set_gamma. You must use + * PNG_ALPHA_PNG for the first call - internal checking in png_set_alpha will + * fire if more than one call to png_set_alpha_mode and png_set_background is + * made in the same read operation, however multiple calls with PNG_ALPHA_PNG + * are ignored. + */ + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED +PNG_EXPORT(36, void, png_set_strip_alpha, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) +PNG_EXPORT(37, void, png_set_swap_alpha, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ + defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) +PNG_EXPORT(38, void, png_set_invert_alpha, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) +/* Add a filler byte to 8-bit Gray or 24-bit RGB images. */ +PNG_EXPORT(39, void, png_set_filler, (png_structrp png_ptr, png_uint_32 filler, + int flags)); +/* The values of the PNG_FILLER_ defines should NOT be changed */ +# define PNG_FILLER_BEFORE 0 +# define PNG_FILLER_AFTER 1 +/* Add an alpha byte to 8-bit Gray or 24-bit RGB images. */ +PNG_EXPORT(40, void, png_set_add_alpha, (png_structrp png_ptr, + png_uint_32 filler, int flags)); +#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */ + +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +/* Swap bytes in 16-bit depth files. */ +PNG_EXPORT(41, void, png_set_swap, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) +/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ +PNG_EXPORT(42, void, png_set_packing, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ + defined(PNG_WRITE_PACKSWAP_SUPPORTED) +/* Swap packing order of pixels in bytes. */ +PNG_EXPORT(43, void, png_set_packswap, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) +/* Converts files to legal bit depths. */ +PNG_EXPORT(44, void, png_set_shift, (png_structrp png_ptr, png_const_color_8p + true_bits)); +#endif + +#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ + defined(PNG_WRITE_INTERLACING_SUPPORTED) +/* Have the code handle the interlacing. Returns the number of passes. + * MUST be called before png_read_update_info or png_start_read_image, + * otherwise it will not have the desired effect. Note that it is still + * necessary to call png_read_row or png_read_rows png_get_image_height + * times for each pass. +*/ +PNG_EXPORT(45, int, png_set_interlace_handling, (png_structrp png_ptr)); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +/* Invert monochrome files */ +PNG_EXPORT(46, void, png_set_invert_mono, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_BACKGROUND_SUPPORTED +/* Handle alpha and tRNS by replacing with a background color. Prior to + * libpng-1.5.4 this API must not be called before the PNG file header has been + * read. Doing so will result in unexpected behavior and possible warnings or + * errors if the PNG file contains a bKGD chunk. + */ +PNG_FP_EXPORT(47, void, png_set_background, (png_structrp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, double background_gamma)) +PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structrp png_ptr, + png_const_color_16p background_color, int background_gamma_code, + int need_expand, png_fixed_point background_gamma)) +#endif +#ifdef PNG_READ_BACKGROUND_SUPPORTED +# define PNG_BACKGROUND_GAMMA_UNKNOWN 0 +# define PNG_BACKGROUND_GAMMA_SCREEN 1 +# define PNG_BACKGROUND_GAMMA_FILE 2 +# define PNG_BACKGROUND_GAMMA_UNIQUE 3 +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +/* Scale a 16-bit depth file down to 8-bit, accurately. */ +PNG_EXPORT(229, void, png_set_scale_16, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +#define PNG_READ_16_TO_8 SUPPORTED /* Name prior to 1.5.4 */ +/* Strip the second byte of information from a 16-bit depth file. */ +PNG_EXPORT(48, void, png_set_strip_16, (png_structrp png_ptr)); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +/* Turn on quantizing, and reduce the palette to the number of colors + * available. + */ +PNG_EXPORT(49, void, png_set_quantize, (png_structrp png_ptr, + png_colorp palette, int num_palette, int maximum_colors, + png_const_uint_16p histogram, int full_quantize)); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* The threshold on gamma processing is configurable but hard-wired into the + * library. The following is the floating point variant. + */ +#define PNG_GAMMA_THRESHOLD (PNG_GAMMA_THRESHOLD_FIXED*.00001) + +/* Handle gamma correction. Screen_gamma=(display_exponent). + * NOTE: this API simply sets the screen and file gamma values. It will + * therefore override the value for gamma in a PNG file if it is called after + * the file header has been read - use with care - call before reading the PNG + * file for best results! + * + * These routines accept the same gamma values as png_set_alpha_mode (described + * above). The PNG_GAMMA_ defines and PNG_DEFAULT_sRGB can be passed to either + * API (floating point or fixed.) Notice, however, that the 'file_gamma' value + * is the inverse of a 'screen gamma' value. + */ +PNG_FP_EXPORT(50, void, png_set_gamma, (png_structrp png_ptr, + double screen_gamma, double override_file_gamma)) +PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structrp png_ptr, + png_fixed_point screen_gamma, png_fixed_point override_file_gamma)) +#endif + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +/* Set how many lines between output flushes - 0 for no flushing */ +PNG_EXPORT(51, void, png_set_flush, (png_structrp png_ptr, int nrows)); +/* Flush the current PNG output buffer */ +PNG_EXPORT(52, void, png_write_flush, (png_structrp png_ptr)); +#endif + +/* Optional update palette with requested transformations */ +PNG_EXPORT(53, void, png_start_read_image, (png_structrp png_ptr)); + +/* Optional call to update the users info structure */ +PNG_EXPORT(54, void, png_read_update_info, (png_structrp png_ptr, + png_inforp info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read one or more rows of image data. */ +PNG_EXPORT(55, void, png_read_rows, (png_structrp png_ptr, png_bytepp row, + png_bytepp display_row, png_uint_32 num_rows)); +#endif + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read a row of data. */ +PNG_EXPORT(56, void, png_read_row, (png_structrp png_ptr, png_bytep row, + png_bytep display_row)); +#endif + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the whole image into memory at once. */ +PNG_EXPORT(57, void, png_read_image, (png_structrp png_ptr, png_bytepp image)); +#endif + +/* Write a row of image data */ +PNG_EXPORT(58, void, png_write_row, (png_structrp png_ptr, + png_const_bytep row)); + +/* Write a few rows of image data: (*row) is not written; however, the type + * is declared as writeable to maintain compatibility with previous versions + * of libpng and to allow the 'display_row' array from read_rows to be passed + * unchanged to write_rows. + */ +PNG_EXPORT(59, void, png_write_rows, (png_structrp png_ptr, png_bytepp row, + png_uint_32 num_rows)); + +/* Write the image data */ +PNG_EXPORT(60, void, png_write_image, (png_structrp png_ptr, png_bytepp image)); + +/* Write the end of the PNG file. */ +PNG_EXPORT(61, void, png_write_end, (png_structrp png_ptr, + png_inforp info_ptr)); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +/* Read the end of the PNG file. */ +PNG_EXPORT(62, void, png_read_end, (png_structrp png_ptr, png_inforp info_ptr)); +#endif + +/* Free any memory associated with the png_info_struct */ +PNG_EXPORT(63, void, png_destroy_info_struct, (png_const_structrp png_ptr, + png_infopp info_ptr_ptr)); + +/* Free any memory associated with the png_struct and the png_info_structs */ +PNG_EXPORT(64, void, png_destroy_read_struct, (png_structpp png_ptr_ptr, + png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); + +/* Free any memory associated with the png_struct and the png_info_structs */ +PNG_EXPORT(65, void, png_destroy_write_struct, (png_structpp png_ptr_ptr, + png_infopp info_ptr_ptr)); + +/* Set the libpng method of handling chunk CRC errors */ +PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action, + int ancil_action)); + +/* Values for png_set_crc_action() say how to handle CRC errors in + * ancillary and critical chunks, and whether to use the data contained + * therein. Note that it is impossible to "discard" data in a critical + * chunk. For versions prior to 0.90, the action was always error/quit, + * whereas in version 0.90 and later, the action for CRC errors in ancillary + * chunks is warn/discard. These values should NOT be changed. + * + * value action:critical action:ancillary + */ +#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */ +#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */ +#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */ +#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */ +#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ +#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ + +/* These functions give the user control over the scan-line filtering in + * libpng and the compression methods used by zlib. These functions are + * mainly useful for testing, as the defaults should work with most users. + * Those users who are tight on memory or want faster performance at the + * expense of compression can modify them. See the compression library + * header file (zlib.h) for an explination of the compression functions. + */ + +/* Set the filtering method(s) used by libpng. Currently, the only valid + * value for "method" is 0. + */ +PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method, + int filters)); + +/* Flags for png_set_filter() to say which filters to use. The flags + * are chosen so that they don't conflict with real filter types + * below, in case they are supplied instead of the #defined constants. + * These values should NOT be changed. + */ +#define PNG_NO_FILTERS 0x00 +#define PNG_FILTER_NONE 0x08 +#define PNG_FILTER_SUB 0x10 +#define PNG_FILTER_UP 0x20 +#define PNG_FILTER_AVG 0x40 +#define PNG_FILTER_PAETH 0x80 +#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \ + PNG_FILTER_AVG | PNG_FILTER_PAETH) + +/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now. + * These defines should NOT be changed. + */ +#define PNG_FILTER_VALUE_NONE 0 +#define PNG_FILTER_VALUE_SUB 1 +#define PNG_FILTER_VALUE_UP 2 +#define PNG_FILTER_VALUE_AVG 3 +#define PNG_FILTER_VALUE_PAETH 4 +#define PNG_FILTER_VALUE_LAST 5 + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* EXPERIMENTAL */ +/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_ + * defines, either the default (minimum-sum-of-absolute-differences), or + * the experimental method (weighted-minimum-sum-of-absolute-differences). + * + * Weights are factors >= 1.0, indicating how important it is to keep the + * filter type consistent between rows. Larger numbers mean the current + * filter is that many times as likely to be the same as the "num_weights" + * previous filters. This is cumulative for each previous row with a weight. + * There needs to be "num_weights" values in "filter_weights", or it can be + * NULL if the weights aren't being specified. Weights have no influence on + * the selection of the first row filter. Well chosen weights can (in theory) + * improve the compression for a given image. + * + * Costs are factors >= 1.0 indicating the relative decoding costs of a + * filter type. Higher costs indicate more decoding expense, and are + * therefore less likely to be selected over a filter with lower computational + * costs. There needs to be a value in "filter_costs" for each valid filter + * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't + * setting the costs. Costs try to improve the speed of decompression without + * unduly increasing the compressed image size. + * + * A negative weight or cost indicates the default value is to be used, and + * values in the range [0.0, 1.0) indicate the value is to remain unchanged. + * The default values for both weights and costs are currently 1.0, but may + * change if good general weighting/cost heuristics can be found. If both + * the weights and costs are set to 1.0, this degenerates the WEIGHTED method + * to the UNWEIGHTED method, but with added encoding time/computation. + */ +PNG_FP_EXPORT(68, void, png_set_filter_heuristics, (png_structrp png_ptr, + int heuristic_method, int num_weights, png_const_doublep filter_weights, + png_const_doublep filter_costs)) +PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed, + (png_structrp png_ptr, int heuristic_method, int num_weights, + png_const_fixed_point_p filter_weights, + png_const_fixed_point_p filter_costs)) +#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ + +/* Heuristic used for row filter selection. These defines should NOT be + * changed. + */ +#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */ +#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */ +#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ +#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ + +#ifdef PNG_WRITE_SUPPORTED +/* Set the library compression level. Currently, valid values range from + * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 + * (0 - no compression, 9 - "maximal" compression). Note that tests have + * shown that zlib compression levels 3-6 usually perform as well as level 9 + * for PNG images, and do considerably fewer caclulations. In the future, + * these values may not correspond directly to the zlib compression levels. + */ +PNG_EXPORT(69, void, png_set_compression_level, (png_structrp png_ptr, + int level)); + +PNG_EXPORT(70, void, png_set_compression_mem_level, (png_structrp png_ptr, + int mem_level)); + +PNG_EXPORT(71, void, png_set_compression_strategy, (png_structrp png_ptr, + int strategy)); + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structrp png_ptr, + int window_bits)); + +PNG_EXPORT(73, void, png_set_compression_method, (png_structrp png_ptr, + int method)); +#endif + +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +/* Also set zlib parameters for compressing non-IDAT chunks */ +PNG_EXPORT(222, void, png_set_text_compression_level, (png_structrp png_ptr, + int level)); + +PNG_EXPORT(223, void, png_set_text_compression_mem_level, (png_structrp png_ptr, + int mem_level)); + +PNG_EXPORT(224, void, png_set_text_compression_strategy, (png_structrp png_ptr, + int strategy)); + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +PNG_EXPORT(225, void, png_set_text_compression_window_bits, + (png_structrp png_ptr, int window_bits)); + +PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr, + int method)); +#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ + +/* These next functions are called for input/output, memory, and error + * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, + * and call standard C I/O routines such as fread(), fwrite(), and + * fprintf(). These functions can be made to use other I/O routines + * at run time for those applications that need to handle I/O in a + * different manner by calling png_set_???_fn(). See libpng-manual.txt for + * more information. + */ + +#ifdef PNG_STDIO_SUPPORTED +/* Initialize the input/output for the PNG file to the default functions. */ +PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp)); +#endif + +/* Replace the (error and abort), and warning functions with user + * supplied functions. If no messages are to be printed you must still + * write and use replacement functions. The replacement error_fn should + * still do a longjmp to the last setjmp location if you are using this + * method of error handling. If error_fn or warning_fn is NULL, the + * default function will be used. + */ + +PNG_EXPORT(75, void, png_set_error_fn, (png_structrp png_ptr, + png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn)); + +/* Return the user pointer associated with the error functions */ +PNG_EXPORT(76, png_voidp, png_get_error_ptr, (png_const_structrp png_ptr)); + +/* Replace the default data output functions with a user supplied one(s). + * If buffered output is not used, then output_flush_fn can be set to NULL. + * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time + * output_flush_fn will be ignored (and thus can be NULL). + * It is probably a mistake to use NULL for output_flush_fn if + * write_data_fn is not also NULL unless you have built libpng with + * PNG_WRITE_FLUSH_SUPPORTED undefined, because in this case libpng's + * default flush function, which uses the standard *FILE structure, will + * be used. + */ +PNG_EXPORT(77, void, png_set_write_fn, (png_structrp png_ptr, png_voidp io_ptr, + png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)); + +/* Replace the default data input function with a user supplied one. */ +PNG_EXPORT(78, void, png_set_read_fn, (png_structrp png_ptr, png_voidp io_ptr, + png_rw_ptr read_data_fn)); + +/* Return the user pointer associated with the I/O functions */ +PNG_EXPORT(79, png_voidp, png_get_io_ptr, (png_const_structrp png_ptr)); + +PNG_EXPORT(80, void, png_set_read_status_fn, (png_structrp png_ptr, + png_read_status_ptr read_row_fn)); + +PNG_EXPORT(81, void, png_set_write_status_fn, (png_structrp png_ptr, + png_write_status_ptr write_row_fn)); + +#ifdef PNG_USER_MEM_SUPPORTED +/* Replace the default memory allocation functions with user supplied one(s). */ +PNG_EXPORT(82, void, png_set_mem_fn, (png_structrp png_ptr, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +/* Return the user pointer associated with the memory functions */ +PNG_EXPORT(83, png_voidp, png_get_mem_ptr, (png_const_structrp png_ptr)); +#endif + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED +PNG_EXPORT(84, void, png_set_read_user_transform_fn, (png_structrp png_ptr, + png_user_transform_ptr read_user_transform_fn)); +#endif + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED +PNG_EXPORT(85, void, png_set_write_user_transform_fn, (png_structrp png_ptr, + png_user_transform_ptr write_user_transform_fn)); +#endif + +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED +PNG_EXPORT(86, void, png_set_user_transform_info, (png_structrp png_ptr, + png_voidp user_transform_ptr, int user_transform_depth, + int user_transform_channels)); +/* Return the user pointer associated with the user transform functions */ +PNG_EXPORT(87, png_voidp, png_get_user_transform_ptr, + (png_const_structrp png_ptr)); +#endif + +#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED +/* Return information about the row currently being processed. Note that these + * APIs do not fail but will return unexpected results if called outside a user + * transform callback. Also note that when transforming an interlaced image the + * row number is the row number within the sub-image of the interlace pass, so + * the value will increase to the height of the sub-image (not the full image) + * then reset to 0 for the next pass. + * + * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to + * find the output pixel (x,y) given an interlaced sub-image pixel + * (row,col,pass). (See below for these macros.) + */ +PNG_EXPORT(217, png_uint_32, png_get_current_row_number, (png_const_structrp)); +PNG_EXPORT(218, png_byte, png_get_current_pass_number, (png_const_structrp)); +#endif + +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED +/* This callback is called only for *unknown* chunks. If + * PNG_HANDLE_AS_UNKNOWN_SUPPORTED is set then it is possible to set known + * chunks to be treated as unknown, however in this case the callback must do + * any processing required by the chunk (e.g. by calling the appropriate + * png_set_ APIs.) + * + * There is no write support - on write, by default, all the chunks in the + * 'unknown' list are written in the specified position. + * + * The integer return from the callback function is interpreted thus: + * + * negative: An error occured, png_chunk_error will be called. + * zero: The chunk was not handled, the chunk will be saved. A critical + * chunk will cause an error at this point unless it is to be saved. + * positive: The chunk was handled, libpng will ignore/discard it. + * + * See "INTERACTION WTIH USER CHUNK CALLBACKS" below for important notes about + * how this behavior will change in libpng 1.7 + */ +PNG_EXPORT(88, void, png_set_read_user_chunk_fn, (png_structrp png_ptr, + png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); +#endif + +#ifdef PNG_USER_CHUNKS_SUPPORTED +PNG_EXPORT(89, png_voidp, png_get_user_chunk_ptr, (png_const_structrp png_ptr)); +#endif + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +/* Sets the function callbacks for the push reader, and a pointer to a + * user-defined structure available to the callback functions. + */ +PNG_EXPORT(90, void, png_set_progressive_read_fn, (png_structrp png_ptr, + png_voidp progressive_ptr, png_progressive_info_ptr info_fn, + png_progressive_row_ptr row_fn, png_progressive_end_ptr end_fn)); + +/* Returns the user pointer associated with the push read functions */ +PNG_EXPORT(91, png_voidp, png_get_progressive_ptr, + (png_const_structrp png_ptr)); + +/* Function to be called when data becomes available */ +PNG_EXPORT(92, void, png_process_data, (png_structrp png_ptr, + png_inforp info_ptr, png_bytep buffer, png_size_t buffer_size)); + +/* A function which may be called *only* within png_process_data to stop the + * processing of any more data. The function returns the number of bytes + * remaining, excluding any that libpng has cached internally. A subsequent + * call to png_process_data must supply these bytes again. If the argument + * 'save' is set to true the routine will first save all the pending data and + * will always return 0. + */ +PNG_EXPORT(219, png_size_t, png_process_data_pause, (png_structrp, int save)); + +/* A function which may be called *only* outside (after) a call to + * png_process_data. It returns the number of bytes of data to skip in the + * input. Normally it will return 0, but if it returns a non-zero value the + * application must skip than number of bytes of input data and pass the + * following data to the next call to png_process_data. + */ +PNG_EXPORT(220, png_uint_32, png_process_data_skip, (png_structrp)); + +#ifdef PNG_READ_INTERLACING_SUPPORTED +/* Function that combines rows. 'new_row' is a flag that should come from + * the callback and be non-NULL if anything needs to be done; the library + * stores its own version of the new data internally and ignores the passed + * in value. + */ +PNG_EXPORT(93, void, png_progressive_combine_row, (png_const_structrp png_ptr, + png_bytep old_row, png_const_bytep new_row)); +#endif /* PNG_READ_INTERLACING_SUPPORTED */ +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +PNG_EXPORTA(94, png_voidp, png_malloc, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); +/* Added at libpng version 1.4.0 */ +PNG_EXPORTA(95, png_voidp, png_calloc, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); + +/* Added at libpng version 1.2.4 */ +PNG_EXPORTA(96, png_voidp, png_malloc_warn, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); + +/* Frees a pointer allocated by png_malloc() */ +PNG_EXPORT(97, void, png_free, (png_const_structrp png_ptr, png_voidp ptr)); + +/* Free data that was allocated internally */ +PNG_EXPORT(98, void, png_free_data, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 free_me, int num)); + +/* Reassign responsibility for freeing existing data, whether allocated + * by libpng or by the application; this works on the png_info structure passed + * in, it does not change the state for other png_info structures. + * + * It is unlikely that this function works correctly as of 1.6.0 and using it + * may result either in memory leaks or double free of allocated data. + */ +PNG_EXPORTA(99, void, png_data_freer, (png_const_structrp png_ptr, + png_inforp info_ptr, int freer, png_uint_32 mask), PNG_DEPRECATED); + +/* Assignments for png_data_freer */ +#define PNG_DESTROY_WILL_FREE_DATA 1 +#define PNG_SET_WILL_FREE_DATA 1 +#define PNG_USER_WILL_FREE_DATA 2 +/* Flags for png_ptr->free_me and info_ptr->free_me */ +#define PNG_FREE_HIST 0x0008 +#define PNG_FREE_ICCP 0x0010 +#define PNG_FREE_SPLT 0x0020 +#define PNG_FREE_ROWS 0x0040 +#define PNG_FREE_PCAL 0x0080 +#define PNG_FREE_SCAL 0x0100 +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_FREE_UNKN 0x0200 +#endif +/* PNG_FREE_LIST 0x0400 removed in 1.6.0 because it is ignored */ +#define PNG_FREE_PLTE 0x1000 +#define PNG_FREE_TRNS 0x2000 +#define PNG_FREE_TEXT 0x4000 +#define PNG_FREE_ALL 0x7fff +#define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ + +#ifdef PNG_USER_MEM_SUPPORTED +PNG_EXPORTA(100, png_voidp, png_malloc_default, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED PNG_DEPRECATED); +PNG_EXPORTA(101, void, png_free_default, (png_const_structrp png_ptr, + png_voidp ptr), PNG_DEPRECATED); +#endif + +#ifdef PNG_ERROR_TEXT_SUPPORTED +/* Fatal error in PNG image of libpng - can't continue */ +PNG_EXPORTA(102, void, png_error, (png_const_structrp png_ptr, + png_const_charp error_message), PNG_NORETURN); + +/* The same, but the chunk name is prepended to the error string. */ +PNG_EXPORTA(103, void, png_chunk_error, (png_const_structrp png_ptr, + png_const_charp error_message), PNG_NORETURN); + +#else +/* Fatal error in PNG image of libpng - can't continue */ +PNG_EXPORTA(104, void, png_err, (png_const_structrp png_ptr), PNG_NORETURN); +#endif + +#ifdef PNG_WARNINGS_SUPPORTED +/* Non-fatal error in libpng. Can continue, but may have a problem. */ +PNG_EXPORT(105, void, png_warning, (png_const_structrp png_ptr, + png_const_charp warning_message)); + +/* Non-fatal error in libpng, chunk name is prepended to message. */ +PNG_EXPORT(106, void, png_chunk_warning, (png_const_structrp png_ptr, + png_const_charp warning_message)); +#endif + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +/* Benign error in libpng. Can continue, but may have a problem. + * User can choose whether to handle as a fatal error or as a warning. */ +PNG_EXPORT(107, void, png_benign_error, (png_const_structrp png_ptr, + png_const_charp warning_message)); + +#ifdef PNG_READ_SUPPORTED +/* Same, chunk name is prepended to message (only during read) */ +PNG_EXPORT(108, void, png_chunk_benign_error, (png_const_structrp png_ptr, + png_const_charp warning_message)); +#endif + +PNG_EXPORT(109, void, png_set_benign_errors, + (png_structrp png_ptr, int allowed)); +#else +# ifdef PNG_ALLOW_BENIGN_ERRORS +# define png_benign_error png_warning +# define png_chunk_benign_error png_chunk_warning +# else +# define png_benign_error png_error +# define png_chunk_benign_error png_chunk_error +# endif +#endif + +/* The png_set_ functions are for storing values in the png_info_struct. + * Similarly, the png_get_ calls are used to read values from the + * png_info_struct, either storing the parameters in the passed variables, or + * setting pointers into the png_info_struct where the data is stored. The + * png_get_ functions return a non-zero value if the data was available + * in info_ptr, or return zero and do not change any of the parameters if the + * data was not available. + * + * These functions should be used instead of directly accessing png_info + * to avoid problems with future changes in the size and internal layout of + * png_info_struct. + */ +/* Returns "flag" if chunk data is valid in info_ptr. */ +PNG_EXPORT(110, png_uint_32, png_get_valid, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 flag)); + +/* Returns number of bytes needed to hold a transformed row. */ +PNG_EXPORT(111, png_size_t, png_get_rowbytes, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +#ifdef PNG_INFO_IMAGE_SUPPORTED +/* Returns row_pointers, which is an array of pointers to scanlines that was + * returned from png_read_png(). + */ +PNG_EXPORT(112, png_bytepp, png_get_rows, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Set row_pointers, which is an array of pointers to scanlines for use + * by png_write_png(). + */ +PNG_EXPORT(113, void, png_set_rows, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytepp row_pointers)); +#endif + +/* Returns number of color channels in image. */ +PNG_EXPORT(114, png_byte, png_get_channels, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +#ifdef PNG_EASY_ACCESS_SUPPORTED +/* Returns image width in pixels. */ +PNG_EXPORT(115, png_uint_32, png_get_image_width, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image height in pixels. */ +PNG_EXPORT(116, png_uint_32, png_get_image_height, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image bit_depth. */ +PNG_EXPORT(117, png_byte, png_get_bit_depth, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image color_type. */ +PNG_EXPORT(118, png_byte, png_get_color_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image filter_type. */ +PNG_EXPORT(119, png_byte, png_get_filter_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image interlace_type. */ +PNG_EXPORT(120, png_byte, png_get_interlace_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image compression_type. */ +PNG_EXPORT(121, png_byte, png_get_compression_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); + +/* Returns image resolution in pixels per meter, from pHYs chunk data. */ +PNG_EXPORT(122, png_uint_32, png_get_pixels_per_meter, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(123, png_uint_32, png_get_x_pixels_per_meter, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(124, png_uint_32, png_get_y_pixels_per_meter, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +/* Returns pixel aspect ratio, computed from pHYs chunk data. */ +PNG_FP_EXPORT(125, float, png_get_pixel_aspect_ratio, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +PNG_FIXED_EXPORT(210, png_fixed_point, png_get_pixel_aspect_ratio_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) + +/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ +PNG_EXPORT(126, png_int_32, png_get_x_offset_pixels, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(127, png_int_32, png_get_y_offset_pixels, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(128, png_int_32, png_get_x_offset_microns, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(129, png_int_32, png_get_y_offset_microns, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +#endif /* PNG_EASY_ACCESS_SUPPORTED */ + +#ifdef PNG_READ_SUPPORTED +/* Returns pointer to signature string read from PNG header */ +PNG_EXPORT(130, png_const_bytep, png_get_signature, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); +#endif + +#ifdef PNG_bKGD_SUPPORTED +PNG_EXPORT(131, png_uint_32, png_get_bKGD, (png_const_structrp png_ptr, + png_inforp info_ptr, png_color_16p *background)); +#endif + +#ifdef PNG_bKGD_SUPPORTED +PNG_EXPORT(132, void, png_set_bKGD, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_color_16p background)); +#endif + +#ifdef PNG_cHRM_SUPPORTED +PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *white_x, double *white_y, double *red_x, + double *red_y, double *green_x, double *green_y, double *blue_x, + double *blue_y)) +PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *red_X, double *red_Y, double *red_Z, + double *green_X, double *green_Y, double *green_Z, double *blue_X, + double *blue_Y, double *blue_Z)) +PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_white_x, png_fixed_point *int_white_y, + png_fixed_point *int_red_x, png_fixed_point *int_red_y, + png_fixed_point *int_green_x, png_fixed_point *int_green_y, + png_fixed_point *int_blue_x, png_fixed_point *int_blue_y)) +PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_red_X, png_fixed_point *int_red_Y, + png_fixed_point *int_red_Z, png_fixed_point *int_green_X, + png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, + png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, + png_fixed_point *int_blue_Z)) +#endif + +#ifdef PNG_cHRM_SUPPORTED +PNG_FP_EXPORT(135, void, png_set_cHRM, (png_const_structrp png_ptr, + png_inforp info_ptr, + double white_x, double white_y, double red_x, double red_y, double green_x, + double green_y, double blue_x, double blue_y)) +PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_const_structrp png_ptr, + png_inforp info_ptr, double red_X, double red_Y, double red_Z, + double green_X, double green_Y, double green_Z, double blue_X, + double blue_Y, double blue_Z)) +PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_white_x, + png_fixed_point int_white_y, png_fixed_point int_red_x, + png_fixed_point int_red_y, png_fixed_point int_green_x, + png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)) +PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y, + png_fixed_point int_red_Z, png_fixed_point int_green_X, + png_fixed_point int_green_Y, png_fixed_point int_green_Z, + png_fixed_point int_blue_X, png_fixed_point int_blue_Y, + png_fixed_point int_blue_Z)) +#endif + +#ifdef PNG_gAMA_SUPPORTED +PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *file_gamma)) +PNG_FIXED_EXPORT(138, png_uint_32, png_get_gAMA_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, + png_fixed_point *int_file_gamma)) +#endif + +#ifdef PNG_gAMA_SUPPORTED +PNG_FP_EXPORT(139, void, png_set_gAMA, (png_const_structrp png_ptr, + png_inforp info_ptr, double file_gamma)) +PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_file_gamma)) +#endif + +#ifdef PNG_hIST_SUPPORTED +PNG_EXPORT(141, png_uint_32, png_get_hIST, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_16p *hist)); +#endif + +#ifdef PNG_hIST_SUPPORTED +PNG_EXPORT(142, void, png_set_hIST, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_uint_16p hist)); +#endif + +PNG_EXPORT(143, png_uint_32, png_get_IHDR, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *width, png_uint_32 *height, + int *bit_depth, int *color_type, int *interlace_method, + int *compression_method, int *filter_method)); + +PNG_EXPORT(144, void, png_set_IHDR, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_method, int compression_method, + int filter_method)); + +#ifdef PNG_oFFs_SUPPORTED +PNG_EXPORT(145, png_uint_32, png_get_oFFs, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, + int *unit_type)); +#endif + +#ifdef PNG_oFFs_SUPPORTED +PNG_EXPORT(146, void, png_set_oFFs, (png_const_structrp png_ptr, + png_inforp info_ptr, png_int_32 offset_x, png_int_32 offset_y, + int unit_type)); +#endif + +#ifdef PNG_pCAL_SUPPORTED +PNG_EXPORT(147, png_uint_32, png_get_pCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, png_charp *purpose, png_int_32 *X0, + png_int_32 *X1, int *type, int *nparams, png_charp *units, + png_charpp *params)); +#endif + +#ifdef PNG_pCAL_SUPPORTED +PNG_EXPORT(148, void, png_set_pCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_charp purpose, png_int_32 X0, png_int_32 X1, + int type, int nparams, png_const_charp units, png_charpp params)); +#endif + +#ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(149, png_uint_32, png_get_pHYs, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, + int *unit_type)); +#endif + +#ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(150, void, png_set_pHYs, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type)); +#endif + +PNG_EXPORT(151, png_uint_32, png_get_PLTE, (png_const_structrp png_ptr, + png_inforp info_ptr, png_colorp *palette, int *num_palette)); + +PNG_EXPORT(152, void, png_set_PLTE, (png_structrp png_ptr, + png_inforp info_ptr, png_const_colorp palette, int num_palette)); + +#ifdef PNG_sBIT_SUPPORTED +PNG_EXPORT(153, png_uint_32, png_get_sBIT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_color_8p *sig_bit)); +#endif + +#ifdef PNG_sBIT_SUPPORTED +PNG_EXPORT(154, void, png_set_sBIT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_color_8p sig_bit)); +#endif + +#ifdef PNG_sRGB_SUPPORTED +PNG_EXPORT(155, png_uint_32, png_get_sRGB, (png_const_structrp png_ptr, + png_const_inforp info_ptr, int *file_srgb_intent)); +#endif + +#ifdef PNG_sRGB_SUPPORTED +PNG_EXPORT(156, void, png_set_sRGB, (png_const_structrp png_ptr, + png_inforp info_ptr, int srgb_intent)); +PNG_EXPORT(157, void, png_set_sRGB_gAMA_and_cHRM, (png_const_structrp png_ptr, + png_inforp info_ptr, int srgb_intent)); +#endif + +#ifdef PNG_iCCP_SUPPORTED +PNG_EXPORT(158, png_uint_32, png_get_iCCP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_charpp name, int *compression_type, + png_bytepp profile, png_uint_32 *proflen)); +#endif + +#ifdef PNG_iCCP_SUPPORTED +PNG_EXPORT(159, void, png_set_iCCP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_charp name, int compression_type, + png_const_bytep profile, png_uint_32 proflen)); +#endif + +#ifdef PNG_sPLT_SUPPORTED +PNG_EXPORT(160, int, png_get_sPLT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_sPLT_tpp entries)); +#endif + +#ifdef PNG_sPLT_SUPPORTED +PNG_EXPORT(161, void, png_set_sPLT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_sPLT_tp entries, int nentries)); +#endif + +#ifdef PNG_TEXT_SUPPORTED +/* png_get_text also returns the number of text chunks in *num_text */ +PNG_EXPORT(162, int, png_get_text, (png_const_structrp png_ptr, + png_inforp info_ptr, png_textp *text_ptr, int *num_text)); +#endif + +/* Note while png_set_text() will accept a structure whose text, + * language, and translated keywords are NULL pointers, the structure + * returned by png_get_text will always contain regular + * zero-terminated C strings. They might be empty strings but + * they will never be NULL pointers. + */ + +#ifdef PNG_TEXT_SUPPORTED +PNG_EXPORT(163, void, png_set_text, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_textp text_ptr, int num_text)); +#endif + +#ifdef PNG_tIME_SUPPORTED +PNG_EXPORT(164, png_uint_32, png_get_tIME, (png_const_structrp png_ptr, + png_inforp info_ptr, png_timep *mod_time)); +#endif + +#ifdef PNG_tIME_SUPPORTED +PNG_EXPORT(165, void, png_set_tIME, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_timep mod_time)); +#endif + +#ifdef PNG_tRNS_SUPPORTED +PNG_EXPORT(166, png_uint_32, png_get_tRNS, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytep *trans_alpha, int *num_trans, + png_color_16p *trans_color)); +#endif + +#ifdef PNG_tRNS_SUPPORTED +PNG_EXPORT(167, void, png_set_tRNS, (png_structrp png_ptr, + png_inforp info_ptr, png_const_bytep trans_alpha, int num_trans, + png_const_color_16p trans_color)); +#endif + +#ifdef PNG_sCAL_SUPPORTED +PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL, (png_const_structrp png_ptr, + png_const_inforp info_ptr, int *unit, double *width, double *height)) +#if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \ + defined(PNG_FLOATING_POINT_SUPPORTED) +/* NOTE: this API is currently implemented using floating point arithmetic, + * consequently it can only be used on systems with floating point support. + * In any case the range of values supported by png_fixed_point is small and it + * is highly recommended that png_get_sCAL_s be used instead. + */ +PNG_FIXED_EXPORT(214, png_uint_32, png_get_sCAL_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, + png_fixed_point *width, png_fixed_point *height)) +#endif +PNG_EXPORT(169, png_uint_32, png_get_sCAL_s, + (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, + png_charpp swidth, png_charpp sheight)); + +PNG_FP_EXPORT(170, void, png_set_sCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, double width, double height)) +PNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, png_fixed_point width, + png_fixed_point height)) +PNG_EXPORT(171, void, png_set_sCAL_s, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, + png_const_charp swidth, png_const_charp sheight)); +#endif /* PNG_sCAL_SUPPORTED */ + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +/* Provide the default handling for all unknown chunks or, optionally, for + * specific unknown chunks. + * + * NOTE: prior to 1.6.0 the handling specified for particular chunks on read was + * ignored and the default was used, the per-chunk setting only had an effect on + * write. If you wish to have chunk-specific handling on read in code that must + * work on earlier versions you must use a user chunk callback to specify the + * desired handling (keep or discard.) + * + * The 'keep' parameter is a PNG_HANDLE_CHUNK_ value as listed below. The + * parameter is interpreted as follows: + * + * READ: + * PNG_HANDLE_CHUNK_AS_DEFAULT: + * Known chunks: do normal libpng processing, do not keep the chunk (but + * see the comments below about PNG_HANDLE_AS_UNKNOWN_SUPPORTED) + * Unknown chunks: for a specific chunk use the global default, when used + * as the default discard the chunk data. + * PNG_HANDLE_CHUNK_NEVER: + * Discard the chunk data. + * PNG_HANDLE_CHUNK_IF_SAFE: + * Keep the chunk data if the chunk is not critical else raise a chunk + * error. + * PNG_HANDLE_CHUNK_ALWAYS: + * Keep the chunk data. + * + * If the chunk data is saved it can be retrieved using png_get_unknown_chunks, + * below. Notice that specifying "AS_DEFAULT" as a global default is equivalent + * to specifying "NEVER", however when "AS_DEFAULT" is used for specific chunks + * it simply resets the behavior to the libpng default. + * + * INTERACTION WTIH USER CHUNK CALLBACKS: + * The per-chunk handling is always used when there is a png_user_chunk_ptr + * callback and the callback returns 0; the chunk is then always stored *unless* + * it is critical and the per-chunk setting is other than ALWAYS. Notice that + * the global default is *not* used in this case. (In effect the per-chunk + * value is incremented to at least IF_SAFE.) + * + * IMPORTANT NOTE: this behavior will change in libpng 1.7 - the global and + * per-chunk defaults will be honored. If you want to preserve the current + * behavior when your callback returns 0 you must set PNG_HANDLE_CHUNK_IF_SAFE + * as the default - if you don't do this libpng 1.6 will issue a warning. + * + * If you want unhandled unknown chunks to be discarded in libpng 1.6 and + * earlier simply return '1' (handled). + * + * PNG_HANDLE_AS_UNKNOWN_SUPPORTED: + * If this is *not* set known chunks will always be handled by libpng and + * will never be stored in the unknown chunk list. Known chunks listed to + * png_set_keep_unknown_chunks will have no effect. If it is set then known + * chunks listed with a keep other than AS_DEFAULT will *never* be processed + * by libpng, in addition critical chunks must either be processed by the + * callback or saved. + * + * The IHDR and IEND chunks must not be listed. Because this turns off the + * default handling for chunks that would otherwise be recognized the + * behavior of libpng transformations may well become incorrect! + * + * WRITE: + * When writing chunks the options only apply to the chunks specified by + * png_set_unknown_chunks (below), libpng will *always* write known chunks + * required by png_set_ calls and will always write the core critical chunks + * (as required for PLTE). + * + * Each chunk in the png_set_unknown_chunks list is looked up in the + * png_set_keep_unknown_chunks list to find the keep setting, this is then + * interpreted as follows: + * + * PNG_HANDLE_CHUNK_AS_DEFAULT: + * Write safe-to-copy chunks and write other chunks if the global + * default is set to _ALWAYS, otherwise don't write this chunk. + * PNG_HANDLE_CHUNK_NEVER: + * Do not write the chunk. + * PNG_HANDLE_CHUNK_IF_SAFE: + * Write the chunk if it is safe-to-copy, otherwise do not write it. + * PNG_HANDLE_CHUNK_ALWAYS: + * Write the chunk. + * + * Note that the default behavior is effectively the opposite of the read case - + * in read unknown chunks are not stored by default, in write they are written + * by default. Also the behavior of PNG_HANDLE_CHUNK_IF_SAFE is very different + * - on write the safe-to-copy bit is checked, on read the critical bit is + * checked and on read if the chunk is critical an error will be raised. + * + * num_chunks: + * =========== + * If num_chunks is positive, then the "keep" parameter specifies the manner + * for handling only those chunks appearing in the chunk_list array, + * otherwise the chunk list array is ignored. + * + * If num_chunks is 0 the "keep" parameter specifies the default behavior for + * unknown chunks, as described above. + * + * If num_chunks is negative, then the "keep" parameter specifies the manner + * for handling all unknown chunks plus all chunks recognized by libpng + * except for the IHDR, PLTE, tRNS, IDAT, and IEND chunks (which continue to + * be processed by libpng. + */ +PNG_EXPORT(172, void, png_set_keep_unknown_chunks, (png_structrp png_ptr, + int keep, png_const_bytep chunk_list, int num_chunks)); + +/* The "keep" PNG_HANDLE_CHUNK_ parameter for the specified chunk is returned; + * the result is therefore true (non-zero) if special handling is required, + * false for the default handling. + */ +PNG_EXPORT(173, int, png_handle_as_unknown, (png_const_structrp png_ptr, + png_const_bytep chunk_name)); +#endif + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +PNG_EXPORT(174, void, png_set_unknown_chunks, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_unknown_chunkp unknowns, + int num_unknowns)); + /* NOTE: prior to 1.6.0 this routine set the 'location' field of the added + * unknowns to the location currently stored in the png_struct. This is + * invariably the wrong value on write. To fix this call the following API + * for each chunk in the list with the correct location. If you know your + * code won't be compiled on earlier versions you can rely on + * png_set_unknown_chunks(write-ptr, png_get_unknown_chunks(read-ptr)) doing + * the correct thing. + */ + +PNG_EXPORT(175, void, png_set_unknown_chunk_location, + (png_const_structrp png_ptr, png_inforp info_ptr, int chunk, int location)); + +PNG_EXPORT(176, int, png_get_unknown_chunks, (png_const_structrp png_ptr, + png_inforp info_ptr, png_unknown_chunkpp entries)); +#endif + +/* Png_free_data() will turn off the "valid" flag for anything it frees. + * If you need to turn it off for a chunk that your application has freed, + * you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); + */ +PNG_EXPORT(177, void, png_set_invalid, (png_const_structrp png_ptr, + png_inforp info_ptr, int mask)); + +#ifdef PNG_INFO_IMAGE_SUPPORTED +/* The "params" pointer is currently not used and is for future expansion. */ +PNG_EXPORT(178, void, png_read_png, (png_structrp png_ptr, png_inforp info_ptr, + int transforms, png_voidp params)); +PNG_EXPORT(179, void, png_write_png, (png_structrp png_ptr, png_inforp info_ptr, + int transforms, png_voidp params)); +#endif + +PNG_EXPORT(180, png_const_charp, png_get_copyright, + (png_const_structrp png_ptr)); +PNG_EXPORT(181, png_const_charp, png_get_header_ver, + (png_const_structrp png_ptr)); +PNG_EXPORT(182, png_const_charp, png_get_header_version, + (png_const_structrp png_ptr)); +PNG_EXPORT(183, png_const_charp, png_get_libpng_ver, + (png_const_structrp png_ptr)); + +#ifdef PNG_MNG_FEATURES_SUPPORTED +PNG_EXPORT(184, png_uint_32, png_permit_mng_features, (png_structrp png_ptr, + png_uint_32 mng_features_permitted)); +#endif + +/* For use in png_set_keep_unknown, added to version 1.2.6 */ +#define PNG_HANDLE_CHUNK_AS_DEFAULT 0 +#define PNG_HANDLE_CHUNK_NEVER 1 +#define PNG_HANDLE_CHUNK_IF_SAFE 2 +#define PNG_HANDLE_CHUNK_ALWAYS 3 +#define PNG_HANDLE_CHUNK_LAST 4 + +/* Strip the prepended error numbers ("#nnn ") from error and warning + * messages before passing them to the error or warning handler. + */ +#ifdef PNG_ERROR_NUMBERS_SUPPORTED +PNG_EXPORT(185, void, png_set_strip_error_numbers, (png_structrp png_ptr, + png_uint_32 strip_mode)); +#endif + +/* Added in libpng-1.2.6 */ +#ifdef PNG_SET_USER_LIMITS_SUPPORTED +PNG_EXPORT(186, void, png_set_user_limits, (png_structrp png_ptr, + png_uint_32 user_width_max, png_uint_32 user_height_max)); +PNG_EXPORT(187, png_uint_32, png_get_user_width_max, + (png_const_structrp png_ptr)); +PNG_EXPORT(188, png_uint_32, png_get_user_height_max, + (png_const_structrp png_ptr)); +/* Added in libpng-1.4.0 */ +PNG_EXPORT(189, void, png_set_chunk_cache_max, (png_structrp png_ptr, + png_uint_32 user_chunk_cache_max)); +PNG_EXPORT(190, png_uint_32, png_get_chunk_cache_max, + (png_const_structrp png_ptr)); +/* Added in libpng-1.4.1 */ +PNG_EXPORT(191, void, png_set_chunk_malloc_max, (png_structrp png_ptr, + png_alloc_size_t user_chunk_cache_max)); +PNG_EXPORT(192, png_alloc_size_t, png_get_chunk_malloc_max, + (png_const_structrp png_ptr)); +#endif + +#if defined(PNG_INCH_CONVERSIONS_SUPPORTED) +PNG_EXPORT(193, png_uint_32, png_get_pixels_per_inch, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +PNG_EXPORT(194, png_uint_32, png_get_x_pixels_per_inch, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +PNG_EXPORT(195, png_uint_32, png_get_y_pixels_per_inch, + (png_const_structrp png_ptr, png_const_inforp info_ptr)); + +PNG_FP_EXPORT(196, float, png_get_x_offset_inches, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ +PNG_FIXED_EXPORT(211, png_fixed_point, png_get_x_offset_inches_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +#endif + +PNG_FP_EXPORT(197, float, png_get_y_offset_inches, (png_const_structrp png_ptr, + png_const_inforp info_ptr)) +#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ +PNG_FIXED_EXPORT(212, png_fixed_point, png_get_y_offset_inches_fixed, + (png_const_structrp png_ptr, png_const_inforp info_ptr)) +#endif + +# ifdef PNG_pHYs_SUPPORTED +PNG_EXPORT(198, png_uint_32, png_get_pHYs_dpi, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, + int *unit_type)); +# endif /* PNG_pHYs_SUPPORTED */ +#endif /* PNG_INCH_CONVERSIONS_SUPPORTED */ + +/* Added in libpng-1.4.0 */ +#ifdef PNG_IO_STATE_SUPPORTED +PNG_EXPORT(199, png_uint_32, png_get_io_state, (png_const_structrp png_ptr)); + +/* Removed from libpng 1.6; use png_get_io_chunk_type. */ +PNG_REMOVED(200, png_const_bytep, png_get_io_chunk_name, (png_structrp png_ptr), + PNG_DEPRECATED) + +PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type, + (png_const_structrp png_ptr)); + +/* The flags returned by png_get_io_state() are the following: */ +# define PNG_IO_NONE 0x0000 /* no I/O at this moment */ +# define PNG_IO_READING 0x0001 /* currently reading */ +# define PNG_IO_WRITING 0x0002 /* currently writing */ +# define PNG_IO_SIGNATURE 0x0010 /* currently at the file signature */ +# define PNG_IO_CHUNK_HDR 0x0020 /* currently at the chunk header */ +# define PNG_IO_CHUNK_DATA 0x0040 /* currently at the chunk data */ +# define PNG_IO_CHUNK_CRC 0x0080 /* currently at the chunk crc */ +# define PNG_IO_MASK_OP 0x000f /* current operation: reading/writing */ +# define PNG_IO_MASK_LOC 0x00f0 /* current location: sig/hdr/data/crc */ +#endif /* ?PNG_IO_STATE_SUPPORTED */ + +/* Interlace support. The following macros are always defined so that if + * libpng interlace handling is turned off the macros may be used to handle + * interlaced images within the application. + */ +#define PNG_INTERLACE_ADAM7_PASSES 7 + +/* Two macros to return the first row and first column of the original, + * full, image which appears in a given pass. 'pass' is in the range 0 + * to 6 and the result is in the range 0 to 7. + */ +#define PNG_PASS_START_ROW(pass) (((1&~(pass))<<(3-((pass)>>1)))&7) +#define PNG_PASS_START_COL(pass) (((1& (pass))<<(3-(((pass)+1)>>1)))&7) + +/* A macro to return the offset between pixels in the output row for a pair of + * pixels in the input - effectively the inverse of the 'COL_SHIFT' macro that + * follows. Note that ROW_OFFSET is the offset from one row to the next whereas + * COL_OFFSET is from one column to the next, within a row. + */ +#define PNG_PASS_ROW_OFFSET(pass) ((pass)>2?(8>>(((pass)-1)>>1)):8) +#define PNG_PASS_COL_OFFSET(pass) (1<<((7-(pass))>>1)) + +/* Two macros to help evaluate the number of rows or columns in each + * pass. This is expressed as a shift - effectively log2 of the number or + * rows or columns in each 8x8 tile of the original image. + */ +#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3) +#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3) + +/* Hence two macros to determine the number of rows or columns in a given + * pass of an image given its height or width. In fact these macros may + * return non-zero even though the sub-image is empty, because the other + * dimension may be empty for a small image. + */ +#define PNG_PASS_ROWS(height, pass) (((height)+(((1<>PNG_PASS_ROW_SHIFT(pass)) +#define PNG_PASS_COLS(width, pass) (((width)+(((1<>PNG_PASS_COL_SHIFT(pass)) + +/* For the reader row callbacks (both progressive and sequential) it is + * necessary to find the row in the output image given a row in an interlaced + * image, so two more macros: + */ +#define PNG_ROW_FROM_PASS_ROW(y_in, pass) \ + (((y_in)<>(((7-(off))-(pass))<<2)) & 0xF) | \ + ((0x01145AF0>>(((7-(off))-(pass))<<2)) & 0xF0)) + +#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \ + ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1) +#define PNG_COL_IN_INTERLACE_PASS(x, pass) \ + ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1) + +#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED +/* With these routines we avoid an integer divide, which will be slower on + * most machines. However, it does take more operations than the corresponding + * divide method, so it may be slower on a few RISC systems. There are two + * shifts (by 8 or 16 bits) and an addition, versus a single integer divide. + * + * Note that the rounding factors are NOT supposed to be the same! 128 and + * 32768 are correct for the NODIV code; 127 and 32767 are correct for the + * standard method. + * + * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ] + */ + + /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */ + +# define png_composite(composite, fg, alpha, bg) \ + { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) \ + * (png_uint_16)(alpha) \ + + (png_uint_16)(bg)*(png_uint_16)(255 \ + - (png_uint_16)(alpha)) + 128); \ + (composite) = (png_byte)((temp + (temp >> 8)) >> 8); } + +# define png_composite_16(composite, fg, alpha, bg) \ + { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) \ + * (png_uint_32)(alpha) \ + + (png_uint_32)(bg)*(65535 \ + - (png_uint_32)(alpha)) + 32768); \ + (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); } + +#else /* Standard method using integer division */ + +# define png_composite(composite, fg, alpha, bg) \ + (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \ + (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ + 127) / 255) + +# define png_composite_16(composite, fg, alpha, bg) \ + (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \ + (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) + \ + 32767) / 65535) +#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */ + +#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED +PNG_EXPORT(201, png_uint_32, png_get_uint_32, (png_const_bytep buf)); +PNG_EXPORT(202, png_uint_16, png_get_uint_16, (png_const_bytep buf)); +PNG_EXPORT(203, png_int_32, png_get_int_32, (png_const_bytep buf)); +#endif + +PNG_EXPORT(204, png_uint_32, png_get_uint_31, (png_const_structrp png_ptr, + png_const_bytep buf)); +/* No png_get_int_16 -- may be added if there's a real need for it. */ + +/* Place a 32-bit number into a buffer in PNG byte order (big-endian). */ +#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED +PNG_EXPORT(205, void, png_save_uint_32, (png_bytep buf, png_uint_32 i)); +#endif +#ifdef PNG_SAVE_INT_32_SUPPORTED +PNG_EXPORT(206, void, png_save_int_32, (png_bytep buf, png_int_32 i)); +#endif + +/* Place a 16-bit number into a buffer in PNG byte order. + * The parameter is declared unsigned int, not png_uint_16, + * just to avoid potential problems on pre-ANSI C compilers. + */ +#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED +PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i)); +/* No png_save_int_16 -- may be added if there's a real need for it. */ +#endif + +#ifdef PNG_USE_READ_MACROS +/* Inline macros to do direct reads of bytes from the input buffer. + * The png_get_int_32() routine assumes we are using two's complement + * format for negative values, which is almost certainly true. + */ +# define PNG_get_uint_32(buf) \ + (((png_uint_32)(*(buf)) << 24) + \ + ((png_uint_32)(*((buf) + 1)) << 16) + \ + ((png_uint_32)(*((buf) + 2)) << 8) + \ + ((png_uint_32)(*((buf) + 3)))) + + /* From libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the + * function) incorrectly returned a value of type png_uint_32. + */ +# define PNG_get_uint_16(buf) \ + ((png_uint_16) \ + (((unsigned int)(*(buf)) << 8) + \ + ((unsigned int)(*((buf) + 1))))) + +# define PNG_get_int_32(buf) \ + ((png_int_32)((*(buf) & 0x80) \ + ? -((png_int_32)((png_get_uint_32(buf) ^ 0xffffffffL) + 1)) \ + : (png_int_32)png_get_uint_32(buf))) + + /* If PNG_PREFIX is defined the same thing as below happens in pnglibconf.h, + * but defining a macro name prefixed with PNG_PREFIX. + */ +# ifndef PNG_PREFIX +# define png_get_uint_32(buf) PNG_get_uint_32(buf) +# define png_get_uint_16(buf) PNG_get_uint_16(buf) +# define png_get_int_32(buf) PNG_get_int_32(buf) +# endif +#else +# ifdef PNG_PREFIX + /* No macros; revert to the (redefined) function */ +# define PNG_get_uint_32 (png_get_uint_32) +# define PNG_get_uint_16 (png_get_uint_16) +# define PNG_get_int_32 (png_get_int_32) +# endif +#endif + +/******************************************************************************* + * SIMPLIFIED API + ******************************************************************************* + * + * Please read the documentation in libpng-manual.txt (TODO: write said + * documentation) if you don't understand what follows. + * + * The simplified API hides the details of both libpng and the PNG file format + * itself. It allows PNG files to be read into a very limited number of + * in-memory bitmap formats or to be written from the same formats. If these + * formats do not accomodate your needs then you can, and should, use the more + * sophisticated APIs above - these support a wide variety of in-memory formats + * and a wide variety of sophisticated transformations to those formats as well + * as a wide variety of APIs to manipulate ancillary information. + * + * To read a PNG file using the simplified API: + * + * 1) Declare a 'png_image' structure (see below) on the stack and set the + * version field to PNG_IMAGE_VERSION. + * 2) Call the appropriate png_image_begin_read... function. + * 3) Set the png_image 'format' member to the required sample format. + * 4) Allocate a buffer for the image and, if required, the color-map. + * 5) Call png_image_finish_read to read the image and, if required, the + * color-map into your buffers. + * + * There are no restrictions on the format of the PNG input itself; all valid + * color types, bit depths, and interlace methods are acceptable, and the + * input image is transformed as necessary to the requested in-memory format + * during the png_image_finish_read() step. The only caveat is that if you + * request a color-mapped image from a PNG that is full-color or makes + * complex use of an alpha channel the transformation is extremely lossy and the + * result may look terrible. + * + * To write a PNG file using the simplified API: + * + * 1) Declare a 'png_image' structure on the stack and memset() it to all zero. + * 2) Initialize the members of the structure that describe the image, setting + * the 'format' member to the format of the image samples. + * 3) Call the appropriate png_image_write... function with a pointer to the + * image and, if necessary, the color-map to write the PNG data. + * + * png_image is a structure that describes the in-memory format of an image + * when it is being read or defines the in-memory format of an image that you + * need to write: + */ +#define PNG_IMAGE_VERSION 1 + +typedef struct png_control *png_controlp; +typedef struct +{ + png_controlp opaque; /* Initialize to NULL, free with png_image_free */ + png_uint_32 version; /* Set to PNG_IMAGE_VERSION */ + png_uint_32 width; /* Image width in pixels (columns) */ + png_uint_32 height; /* Image height in pixels (rows) */ + png_uint_32 format; /* Image format as defined below */ + png_uint_32 flags; /* A bit mask containing informational flags */ + png_uint_32 colormap_entries; + /* Number of entries in the color-map */ + + /* In the event of an error or warning the following field will be set to a + * non-zero value and the 'message' field will contain a '\0' terminated + * string with the libpng error or warning message. If both warnings and + * an error were encountered, only the error is recorded. If there + * are multiple warnings, only the first one is recorded. + * + * The upper 30 bits of this value are reserved, the low two bits contain + * a value as follows: + */ +# define PNG_IMAGE_WARNING 1 +# define PNG_IMAGE_ERROR 2 + /* + * The result is a two bit code such that a value more than 1 indicates + * a failure in the API just called: + * + * 0 - no warning or error + * 1 - warning + * 2 - error + * 3 - error preceded by warning + */ +# define PNG_IMAGE_FAILED(png_cntrl) ((((png_cntrl).warning_or_error)&0x03)>1) + + png_uint_32 warning_or_error; + + char message[64]; +} png_image, *png_imagep; + +/* The samples of the image have one to four channels whose components have + * original values in the range 0 to 1.0: + * + * 1: A single gray or luminance channel (G). + * 2: A gray/luminance channel and an alpha channel (GA). + * 3: Three red, green, blue color channels (RGB). + * 4: Three color channels and an alpha channel (RGBA). + * + * The components are encoded in one of two ways: + * + * a) As a small integer, value 0..255, contained in a single byte. For the + * alpha channel the original value is simply value/255. For the color or + * luminance channels the value is encoded according to the sRGB specification + * and matches the 8-bit format expected by typical display devices. + * + * The color/gray channels are not scaled (pre-multiplied) by the alpha + * channel and are suitable for passing to color management software. + * + * b) As a value in the range 0..65535, contained in a 2-byte integer. All + * channels can be converted to the original value by dividing by 65535; all + * channels are linear. Color channels use the RGB encoding (RGB end-points) of + * the sRGB specification. This encoding is identified by the + * PNG_FORMAT_FLAG_LINEAR flag below. + * + * When the simplified API needs to convert between sRGB and linear colorspaces, + * the actual sRGB transfer curve defined in the sRGB specification (see the + * article at http://en.wikipedia.org/wiki/SRGB) is used, not the gamma=1/2.2 + * approximation used elsewhere in libpng. + * + * When an alpha channel is present it is expected to denote pixel coverage + * of the color or luminance channels and is returned as an associated alpha + * channel: the color/gray channels are scaled (pre-multiplied) by the alpha + * value. + * + * The samples are either contained directly in the image data, between 1 and 8 + * bytes per pixel according to the encoding, or are held in a color-map indexed + * by bytes in the image data. In the case of a color-map the color-map entries + * are individual samples, encoded as above, and the image data has one byte per + * pixel to select the relevant sample from the color-map. + */ + +/* PNG_FORMAT_* + * + * #defines to be used in png_image::format. Each #define identifies a + * particular layout of sample data and, if present, alpha values. There are + * separate defines for each of the two component encodings. + * + * A format is built up using single bit flag values. All combinations are + * valid. Formats can be built up from the flag values or you can use one of + * the predefined values below. When testing formats always use the FORMAT_FLAG + * macros to test for individual features - future versions of the library may + * add new flags. + * + * When reading or writing color-mapped images the format should be set to the + * format of the entries in the color-map then png_image_{read,write}_colormap + * called to read or write the color-map and set the format correctly for the + * image data. Do not set the PNG_FORMAT_FLAG_COLORMAP bit directly! + * + * NOTE: libpng can be built with particular features disabled, if you see + * compiler errors because the definition of one of the following flags has been + * compiled out it is because libpng does not have the required support. It is + * possible, however, for the libpng configuration to enable the format on just + * read or just write; in that case you may see an error at run time. You can + * guard against this by checking for the definition of the appropriate + * "_SUPPORTED" macro, one of: + * + * PNG_SIMPLIFIED_{READ,WRITE}_{BGR,AFIRST}_SUPPORTED + */ +#define PNG_FORMAT_FLAG_ALPHA 0x01U /* format with an alpha channel */ +#define PNG_FORMAT_FLAG_COLOR 0x02U /* color format: otherwise grayscale */ +#define PNG_FORMAT_FLAG_LINEAR 0x04U /* 2 byte channels else 1 byte */ +#define PNG_FORMAT_FLAG_COLORMAP 0x08U /* image data is color-mapped */ + +#ifdef PNG_FORMAT_BGR_SUPPORTED +# define PNG_FORMAT_FLAG_BGR 0x10U /* BGR colors, else order is RGB */ +#endif + +#ifdef PNG_FORMAT_AFIRST_SUPPORTED +# define PNG_FORMAT_FLAG_AFIRST 0x20U /* alpha channel comes first */ +#endif + +/* Commonly used formats have predefined macros. + * + * First the single byte (sRGB) formats: + */ +#define PNG_FORMAT_GRAY 0 +#define PNG_FORMAT_GA PNG_FORMAT_FLAG_ALPHA +#define PNG_FORMAT_AG (PNG_FORMAT_GA|PNG_FORMAT_FLAG_AFIRST) +#define PNG_FORMAT_RGB PNG_FORMAT_FLAG_COLOR +#define PNG_FORMAT_BGR (PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_BGR) +#define PNG_FORMAT_RGBA (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_ARGB (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_AFIRST) +#define PNG_FORMAT_BGRA (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_ABGR (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_AFIRST) + +/* Then the linear 2-byte formats. When naming these "Y" is used to + * indicate a luminance (gray) channel. + */ +#define PNG_FORMAT_LINEAR_Y PNG_FORMAT_FLAG_LINEAR +#define PNG_FORMAT_LINEAR_Y_ALPHA (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_ALPHA) +#define PNG_FORMAT_LINEAR_RGB (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR) +#define PNG_FORMAT_LINEAR_RGB_ALPHA \ + (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA) + +/* With color-mapped formats the image data is one byte for each pixel, the byte + * is an index into the color-map which is formatted as above. To obtain a + * color-mapped format it is sufficient just to add the PNG_FOMAT_FLAG_COLORMAP + * to one of the above definitions, or you can use one of the definitions below. + */ +#define PNG_FORMAT_RGB_COLORMAP (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_BGR_COLORMAP (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_RGBA_COLORMAP (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_ARGB_COLORMAP (PNG_FORMAT_ARGB|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_BGRA_COLORMAP (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_COLORMAP) +#define PNG_FORMAT_ABGR_COLORMAP (PNG_FORMAT_ABGR|PNG_FORMAT_FLAG_COLORMAP) + +/* PNG_IMAGE macros + * + * These are convenience macros to derive information from a png_image + * structure. The PNG_IMAGE_SAMPLE_ macros return values appropriate to the + * actual image sample values - either the entries in the color-map or the + * pixels in the image. The PNG_IMAGE_PIXEL_ macros return corresponding values + * for the pixels and will always return 1 for color-mapped formats. The + * remaining macros return information about the rows in the image and the + * complete image. + * + * NOTE: All the macros that take a png_image::format parameter are compile time + * constants if the format parameter is, itself, a constant. Therefore these + * macros can be used in array declarations and case labels where required. + * Similarly the macros are also pre-processor constants (sizeof is not used) so + * they can be used in #if tests. + * + * First the information about the samples. + */ +#define PNG_IMAGE_SAMPLE_CHANNELS(fmt)\ + (((fmt)&(PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA))+1) + /* Return the total number of channels in a given format: 1..4 */ + +#define PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)\ + ((((fmt) & PNG_FORMAT_FLAG_LINEAR) >> 2)+1) + /* Return the size in bytes of a single component of a pixel or color-map + * entry (as appropriate) in the image: 1 or 2. + */ + +#define PNG_IMAGE_SAMPLE_SIZE(fmt)\ + (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)) + /* This is the size of the sample data for one sample. If the image is + * color-mapped it is the size of one color-map entry (and image pixels are + * one byte in size), otherwise it is the size of one image pixel. + */ + +#define PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(fmt)\ + (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * 256) + /* The maximum size of the color-map required by the format expressed in a + * count of components. This can be used to compile-time allocate a + * color-map: + * + * png_uint_16 colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(linear_fmt)]; + * + * png_byte colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(sRGB_fmt)]; + * + * Alternatively use the PNG_IMAGE_COLORMAP_SIZE macro below to use the + * information from one of the png_image_begin_read_ APIs and dynamically + * allocate the required memory. + */ + +/* Corresponding information about the pixels */ +#define PNG_IMAGE_PIXEL_(test,fmt)\ + (((fmt)&PNG_FORMAT_FLAG_COLORMAP)?1:test(fmt)) + +#define PNG_IMAGE_PIXEL_CHANNELS(fmt)\ + PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_CHANNELS,fmt) + /* The number of separate channels (components) in a pixel; 1 for a + * color-mapped image. + */ + +#define PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)\ + PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_COMPONENT_SIZE,fmt) + /* The size, in bytes, of each component in a pixel; 1 for a color-mapped + * image. + */ + +#define PNG_IMAGE_PIXEL_SIZE(fmt) PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_SIZE,fmt) + /* The size, in bytes, of a complete pixel; 1 for a color-mapped image. */ + +/* Information about the whole row, or whole image */ +#define PNG_IMAGE_ROW_STRIDE(image)\ + (PNG_IMAGE_PIXEL_CHANNELS((image).format) * (image).width) + /* Return the total number of components in a single row of the image; this + * is the minimum 'row stride', the minimum count of components between each + * row. For a color-mapped image this is the minimum number of bytes in a + * row. + */ + +#define PNG_IMAGE_BUFFER_SIZE(image, row_stride)\ + (PNG_IMAGE_PIXEL_COMPONENT_SIZE((image).format)*(image).height*(row_stride)) + /* Return the size, in bytes, of an image buffer given a png_image and a row + * stride - the number of components to leave space for in each row. + */ + +#define PNG_IMAGE_SIZE(image)\ + PNG_IMAGE_BUFFER_SIZE(image, PNG_IMAGE_ROW_STRIDE(image)) + /* Return the size, in bytes, of the image in memory given just a png_image; + * the row stride is the minimum stride required for the image. + */ + +#define PNG_IMAGE_COLORMAP_SIZE(image)\ + (PNG_IMAGE_SAMPLE_SIZE((image).format) * (image).colormap_entries) + /* Return the size, in bytes, of the color-map of this image. If the image + * format is not a color-map format this will return a size sufficient for + * 256 entries in the given format; check PNG_FORMAT_FLAG_COLORMAP if + * you don't want to allocate a color-map in this case. + */ + +/* PNG_IMAGE_FLAG_* + * + * Flags containing additional information about the image are held in the + * 'flags' field of png_image. + */ +#define PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB 0x01 + /* This indicates the the RGB values of the in-memory bitmap do not + * correspond to the red, green and blue end-points defined by sRGB. + */ + +#define PNG_IMAGE_FLAG_FAST 0x02 + /* On write emphasise speed over compression; the resultant PNG file will be + * larger but will be produced significantly faster, particular for large + * images. Do not use this option for images which will be distributed, only + * used it when producing intermediate files that will be read back in + * repeatedly. For a typical 24-bit image the option will double the read + * speed at the cost of increasing the image size by 25%, however for many + * more compressible images the PNG file can be 10 times larger with only a + * slight speed gain. + */ + +#define PNG_IMAGE_FLAG_16BIT_sRGB 0x04 + /* On read if the image is a 16-bit per component image and there is no gAMA + * or sRGB chunk assume that the components are sRGB encoded. Notice that + * images output by the simplified API always have gamma information; setting + * this flag only affects the interpretation of 16-bit images from an + * external source. It is recommended that the application expose this flag + * to the user; the user can normally easily recognize the difference between + * linear and sRGB encoding. This flag has no effect on write - the data + * passed to the write APIs must have the correct encoding (as defined + * above.) + * + * If the flag is not set (the default) input 16-bit per component data is + * assumed to be linear. + * + * NOTE: the flag can only be set after the png_image_begin_read_ call, + * because that call initializes the 'flags' field. + */ + +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +/* READ APIs + * --------- + * + * The png_image passed to the read APIs must have been initialized by setting + * the png_controlp field 'opaque' to NULL (or, safer, memset the whole thing.) + */ +#ifdef PNG_STDIO_SUPPORTED +PNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image, + const char *file_name)); + /* The named file is opened for read and the image header is filled in + * from the PNG header in the file. + */ + +PNG_EXPORT(235, int, png_image_begin_read_from_stdio, (png_imagep image, + FILE* file)); + /* The PNG header is read from the stdio FILE object. */ +#endif /* PNG_STDIO_SUPPORTED */ + +PNG_EXPORT(236, int, png_image_begin_read_from_memory, (png_imagep image, + png_const_voidp memory, png_size_t size)); + /* The PNG header is read from the given memory buffer. */ + +PNG_EXPORT(237, int, png_image_finish_read, (png_imagep image, + png_const_colorp background, void *buffer, png_int_32 row_stride, + void *colormap)); + /* Finish reading the image into the supplied buffer and clean up the + * png_image structure. + * + * row_stride is the step, in byte or 2-byte units as appropriate, + * between adjacent rows. A positive stride indicates that the top-most row + * is first in the buffer - the normal top-down arrangement. A negative + * stride indicates that the bottom-most row is first in the buffer. + * + * background need only be supplied if an alpha channel must be removed from + * a png_byte format and the removal is to be done by compositing on a solid + * color; otherwise it may be NULL and any composition will be done directly + * onto the buffer. The value is an sRGB color to use for the background, + * for grayscale output the green channel is used. + * + * background must be supplied when an alpha channel must be removed from a + * single byte color-mapped output format, in other words if: + * + * 1) The original format from png_image_begin_read_from_* had + * PNG_FORMAT_FLAG_ALPHA set. + * 2) The format set by the application does not. + * 3) The format set by the application has PNG_FORMAT_FLAG_COLORMAP set and + * PNG_FORMAT_FLAG_LINEAR *not* set. + * + * For linear output removing the alpha channel is always done by compositing + * on black and background is ignored. + * + * colormap must be supplied when PNG_FORMAT_FLAG_COLORMAP is set. It must + * be at least the size (in bytes) returned by PNG_IMAGE_COLORMAP_SIZE. + * image->colormap_entries will be updated to the actual number of entries + * written to the colormap; this may be less than the original value. + */ + +PNG_EXPORT(238, void, png_image_free, (png_imagep image)); + /* Free any data allocated by libpng in image->opaque, setting the pointer to + * NULL. May be called at any time after the structure is initialized. + */ +#endif /* PNG_SIMPLIFIED_READ_SUPPORTED */ + +#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED +#ifdef PNG_STDIO_SUPPORTED +/* WRITE APIS + * ---------- + * For write you must initialize a png_image structure to describe the image to + * be written. To do this use memset to set the whole structure to 0 then + * initialize fields describing your image. + * + * version: must be set to PNG_IMAGE_VERSION + * opaque: must be initialized to NULL + * width: image width in pixels + * height: image height in rows + * format: the format of the data (image and color-map) you wish to write + * flags: set to 0 unless one of the defined flags applies; set + * PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB for color format images where the RGB + * values do not correspond to the colors in sRGB. + * colormap_entries: set to the number of entries in the color-map (0 to 256) + */ +PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image, + const char *file, int convert_to_8bit, const void *buffer, + png_int_32 row_stride, const void *colormap)); + /* Write the image to the named file. */ + +PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file, + int convert_to_8_bit, const void *buffer, png_int_32 row_stride, + const void *colormap)); + /* Write the image to the given (FILE*). */ + +/* With both write APIs if image is in one of the linear formats with 16-bit + * data then setting convert_to_8_bit will cause the output to be an 8-bit PNG + * gamma encoded according to the sRGB specification, otherwise a 16-bit linear + * encoded PNG file is written. + * + * With color-mapped data formats the colormap parameter point to a color-map + * with at least image->colormap_entries encoded in the specified format. If + * the format is linear the written PNG color-map will be converted to sRGB + * regardless of the convert_to_8_bit flag. + * + * With all APIs row_stride is handled as in the read APIs - it is the spacing + * from one row to the next in component sized units (1 or 2 bytes) and if + * negative indicates a bottom-up row layout in the buffer. + * + * Note that the write API does not support interlacing or sub-8-bit pixels. + */ +#endif /* PNG_STDIO_SUPPORTED */ +#endif /* PNG_SIMPLIFIED_WRITE_SUPPORTED */ +/******************************************************************************* + * END OF SIMPLIFIED API + ******************************************************************************/ + +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED +PNG_EXPORT(242, void, png_set_check_for_invalid_index, + (png_structrp png_ptr, int allowed)); +# ifdef PNG_GET_PALETTE_MAX_SUPPORTED +PNG_EXPORT(243, int, png_get_palette_max, (png_const_structp png_ptr, + png_const_infop info_ptr)); +# endif +#endif /* CHECK_FOR_INVALID_INDEX */ + +/******************************************************************************* + * IMPLEMENTATION OPTIONS + ******************************************************************************* + * + * Support for arbitrary implementation-specific optimizations. The API allows + * particular options to be turned on or off. 'Option' is the number of the + * option and 'onoff' is 0 (off) or non-0 (on). The value returned is given + * by the PNG_OPTION_ defines below. + * + * HARDWARE: normally hardware capabilites, such as the Intel SSE instructions, + * are detected at run time, however sometimes it may be impossible + * to do this in user mode, in which case it is necessary to discover + * the capabilities in an OS specific way. Such capabilities are + * listed here when libpng has support for them and must be turned + * ON by the application if present. + * + * SOFTWARE: sometimes software optimizations actually result in performance + * decrease on some architectures or systems, or with some sets of + * PNG images. 'Software' options allow such optimizations to be + * selected at run time. + */ +#ifdef PNG_SET_OPTION_SUPPORTED +#ifdef PNG_ARM_NEON_API_SUPPORTED +# define PNG_ARM_NEON 0 /* HARDWARE: ARM Neon SIMD instructions supported */ +#endif +#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */ +#define PNG_OPTION_NEXT 4 /* Next option - numbers must be even */ + +/* Return values: NOTE: there are four values and 'off' is *not* zero */ +#define PNG_OPTION_UNSET 0 /* Unset - defaults to off */ +#define PNG_OPTION_INVALID 1 /* Option number out of range */ +#define PNG_OPTION_OFF 2 +#define PNG_OPTION_ON 3 + +PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option, + int onoff)); +#endif + +/******************************************************************************* + * END OF HARDWARE OPTIONS + ******************************************************************************/ + +/* Maintainer: Put new public prototypes here ^, in libpng.3, and project + * defs, scripts/pnglibconf.h, and scripts/pnglibconf.h.prebuilt + */ + +/* The last ordinal number (this is the *last* one already used; the next + * one to use is one more than this.) Maintainer, remember to add an entry to + * scripts/symbols.def as well. + */ +#ifdef PNG_EXPORT_LAST_ORDINAL + PNG_EXPORT_LAST_ORDINAL(244); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PNG_VERSION_INFO_ONLY */ +/* Do not put anything past this line */ +#endif /* PNG_H */ diff --git a/lib/3rdParty/dlib/include/dlib/external/libpng/pngconf.h b/lib/3rdParty/dlib/include/dlib/external/libpng/pngconf.h new file mode 100644 index 00000000..8c534722 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/libpng/pngconf.h @@ -0,0 +1,626 @@ + +/* pngconf.h - machine configurable file for libpng + * + * libpng version 1.6.7 - November 14, 2013 + * + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * + */ + +/* Any machine specific code is near the front of this file, so if you + * are configuring libpng for a machine, you may want to read the section + * starting here down to where it starts to typedef png_color, png_text, + * and png_info. + */ + +#ifdef _MSC_VER +// Disable the following warnings for Visual Studio +// This is a warning you get from visual studio 2005 about things in the standard C++ +// library being "deprecated." I checked the C++ standard and it doesn't say jack +// about any of them (I checked the searchable PDF). So this warning is total Bunk. +#pragma warning(disable : 4996) +#endif + + +#ifndef PNGCONF_H +#define PNGCONF_H + +/* To do: Do all of this in scripts/pnglibconf.dfa */ +#ifdef PNG_SAFE_LIMITS_SUPPORTED +# ifdef PNG_USER_WIDTH_MAX +# undef PNG_USER_WIDTH_MAX +# define PNG_USER_WIDTH_MAX 1000000L +# endif +# ifdef PNG_USER_HEIGHT_MAX +# undef PNG_USER_HEIGHT_MAX +# define PNG_USER_HEIGHT_MAX 1000000L +# endif +# ifdef PNG_USER_CHUNK_MALLOC_MAX +# undef PNG_USER_CHUNK_MALLOC_MAX +# define PNG_USER_CHUNK_MALLOC_MAX 4000000L +# endif +# ifdef PNG_USER_CHUNK_CACHE_MAX +# undef PNG_USER_CHUNK_CACHE_MAX +# define PNG_USER_CHUNK_CACHE_MAX 128 +# endif +#endif + +#ifndef PNG_BUILDING_SYMBOL_TABLE /* else includes may cause problems */ + +/* From libpng 1.6.0 libpng requires an ANSI X3.159-1989 ("ISOC90") compliant C + * compiler for correct compilation. The following header files are required by + * the standard. If your compiler doesn't provide these header files, or they + * do not match the standard, you will need to provide/improve them. + */ +#include +#include + +/* Library header files. These header files are all defined by ISOC90; libpng + * expects conformant implementations, however, an ISOC90 conformant system need + * not provide these header files if the functionality cannot be implemented. + * In this case it will be necessary to disable the relevant parts of libpng in + * the build of pnglibconf.h. + * + * Prior to 1.6.0 string.h was included here; the API changes in 1.6.0 to not + * include this unnecessary header file. + */ + +#ifdef PNG_STDIO_SUPPORTED + /* Required for the definition of FILE: */ +# include +#endif + +#ifdef PNG_SETJMP_SUPPORTED + /* Required for the definition of jmp_buf and the declaration of longjmp: */ +# include +#endif + +#ifdef PNG_CONVERT_tIME_SUPPORTED + /* Required for struct tm: */ +# include +#endif + +#endif /* PNG_BUILDING_SYMBOL_TABLE */ + +/* Prior to 1.6.0 it was possible to turn off 'const' in declarations using + * PNG_NO_CONST; this is no longer supported except for data declarations which + * apparently still cause problems in 2011 on some compilers. + */ +#define PNG_CONST const /* backward compatibility only */ + +/* This controls optimization of the reading of 16 and 32 bit values + * from PNG files. It can be set on a per-app-file basis - it + * just changes whether a macro is used when the function is called. + * The library builder sets the default; if read functions are not + * built into the library the macro implementation is forced on. + */ +#ifndef PNG_READ_INT_FUNCTIONS_SUPPORTED +# define PNG_USE_READ_MACROS +#endif +#if !defined(PNG_NO_USE_READ_MACROS) && !defined(PNG_USE_READ_MACROS) +# if PNG_DEFAULT_READ_MACROS +# define PNG_USE_READ_MACROS +# endif +#endif + +/* COMPILER SPECIFIC OPTIONS. + * + * These options are provided so that a variety of difficult compilers + * can be used. Some are fixed at build time (e.g. PNG_API_RULE + * below) but still have compiler specific implementations, others + * may be changed on a per-file basis when compiling against libpng. + */ + +/* The PNGARG macro was used in versions of libpng prior to 1.6.0 to protect + * against legacy (pre ISOC90) compilers that did not understand function + * prototypes. It is not required for modern C compilers. + */ +#ifndef PNGARG +# define PNGARG(arglist) arglist +#endif + +/* Function calling conventions. + * ============================= + * Normally it is not necessary to specify to the compiler how to call + * a function - it just does it - however on x86 systems derived from + * Microsoft and Borland C compilers ('IBM PC', 'DOS', 'Windows' systems + * and some others) there are multiple ways to call a function and the + * default can be changed on the compiler command line. For this reason + * libpng specifies the calling convention of every exported function and + * every function called via a user supplied function pointer. This is + * done in this file by defining the following macros: + * + * PNGAPI Calling convention for exported functions. + * PNGCBAPI Calling convention for user provided (callback) functions. + * PNGCAPI Calling convention used by the ANSI-C library (required + * for longjmp callbacks and sometimes used internally to + * specify the calling convention for zlib). + * + * These macros should never be overridden. If it is necessary to + * change calling convention in a private build this can be done + * by setting PNG_API_RULE (which defaults to 0) to one of the values + * below to select the correct 'API' variants. + * + * PNG_API_RULE=0 Use PNGCAPI - the 'C' calling convention - throughout. + * This is correct in every known environment. + * PNG_API_RULE=1 Use the operating system convention for PNGAPI and + * the 'C' calling convention (from PNGCAPI) for + * callbacks (PNGCBAPI). This is no longer required + * in any known environment - if it has to be used + * please post an explanation of the problem to the + * libpng mailing list. + * + * These cases only differ if the operating system does not use the C + * calling convention, at present this just means the above cases + * (x86 DOS/Windows sytems) and, even then, this does not apply to + * Cygwin running on those systems. + * + * Note that the value must be defined in pnglibconf.h so that what + * the application uses to call the library matches the conventions + * set when building the library. + */ + +/* Symbol export + * ============= + * When building a shared library it is almost always necessary to tell + * the compiler which symbols to export. The png.h macro 'PNG_EXPORT' + * is used to mark the symbols. On some systems these symbols can be + * extracted at link time and need no special processing by the compiler, + * on other systems the symbols are flagged by the compiler and just + * the declaration requires a special tag applied (unfortunately) in a + * compiler dependent way. Some systems can do either. + * + * A small number of older systems also require a symbol from a DLL to + * be flagged to the program that calls it. This is a problem because + * we do not know in the header file included by application code that + * the symbol will come from a shared library, as opposed to a statically + * linked one. For this reason the application must tell us by setting + * the magic flag PNG_USE_DLL to turn on the special processing before + * it includes png.h. + * + * Four additional macros are used to make this happen: + * + * PNG_IMPEXP The magic (if any) to cause a symbol to be exported from + * the build or imported if PNG_USE_DLL is set - compiler + * and system specific. + * + * PNG_EXPORT_TYPE(type) A macro that pre or appends PNG_IMPEXP to + * 'type', compiler specific. + * + * PNG_DLL_EXPORT Set to the magic to use during a libpng build to + * make a symbol exported from the DLL. Not used in the + * public header files; see pngpriv.h for how it is used + * in the libpng build. + * + * PNG_DLL_IMPORT Set to the magic to force the libpng symbols to come + * from a DLL - used to define PNG_IMPEXP when + * PNG_USE_DLL is set. + */ + +/* System specific discovery. + * ========================== + * This code is used at build time to find PNG_IMPEXP, the API settings + * and PNG_EXPORT_TYPE(), it may also set a macro to indicate the DLL + * import processing is possible. On Windows systems it also sets + * compiler-specific macros to the values required to change the calling + * conventions of the various functions. + */ +#if defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\ + defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) + /* Windows system (DOS doesn't support DLLs). Includes builds under Cygwin or + * MinGW on any architecture currently supported by Windows. Also includes + * Watcom builds but these need special treatment because they are not + * compatible with GCC or Visual C because of different calling conventions. + */ +# if PNG_API_RULE == 2 + /* If this line results in an error, either because __watcall is not + * understood or because of a redefine just below you cannot use *this* + * build of the library with the compiler you are using. *This* build was + * build using Watcom and applications must also be built using Watcom! + */ +# define PNGCAPI __watcall +# endif + +# if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER >= 800)) +# define PNGCAPI __cdecl +# if PNG_API_RULE == 1 + /* If this line results in an error __stdcall is not understood and + * PNG_API_RULE should not have been set to '1'. + */ +# define PNGAPI __stdcall +# endif +# else + /* An older compiler, or one not detected (erroneously) above, + * if necessary override on the command line to get the correct + * variants for the compiler. + */ +# ifndef PNGCAPI +# define PNGCAPI _cdecl +# endif +# if PNG_API_RULE == 1 && !defined(PNGAPI) +# define PNGAPI _stdcall +# endif +# endif /* compiler/api */ + + /* NOTE: PNGCBAPI always defaults to PNGCAPI. */ + +# if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD) +# error "PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed" +# endif + +# if (defined(_MSC_VER) && _MSC_VER < 800) ||\ + (defined(__BORLANDC__) && __BORLANDC__ < 0x500) + /* older Borland and MSC + * compilers used '__export' and required this to be after + * the type. + */ +# ifndef PNG_EXPORT_TYPE +# define PNG_EXPORT_TYPE(type) type PNG_IMPEXP +# endif +# define PNG_DLL_EXPORT __export +# else /* newer compiler */ +# define PNG_DLL_EXPORT __declspec(dllexport) +# ifndef PNG_DLL_IMPORT +# define PNG_DLL_IMPORT __declspec(dllimport) +# endif +# endif /* compiler */ + +#else /* !Windows */ +# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) +# define PNGAPI _System +# else /* !Windows/x86 && !OS/2 */ + /* Use the defaults, or define PNG*API on the command line (but + * this will have to be done for every compile!) + */ +# endif /* other system, !OS/2 */ +#endif /* !Windows/x86 */ + +/* Now do all the defaulting . */ +#ifndef PNGCAPI +# define PNGCAPI +#endif +#ifndef PNGCBAPI +# define PNGCBAPI PNGCAPI +#endif +#ifndef PNGAPI +# define PNGAPI PNGCAPI +#endif + +/* PNG_IMPEXP may be set on the compilation system command line or (if not set) + * then in an internal header file when building the library, otherwise (when + * using the library) it is set here. + */ +#ifndef PNG_IMPEXP +# if defined(PNG_USE_DLL) && defined(PNG_DLL_IMPORT) + /* This forces use of a DLL, disallowing static linking */ +# define PNG_IMPEXP PNG_DLL_IMPORT +# endif + +# ifndef PNG_IMPEXP +# define PNG_IMPEXP +# endif +#endif + +/* In 1.5.2 the definition of PNG_FUNCTION has been changed to always treat + * 'attributes' as a storage class - the attributes go at the start of the + * function definition, and attributes are always appended regardless of the + * compiler. This considerably simplifies these macros but may cause problems + * if any compilers both need function attributes and fail to handle them as + * a storage class (this is unlikely.) + */ +#ifndef PNG_FUNCTION +# define PNG_FUNCTION(type, name, args, attributes) attributes type name args +#endif + +#ifndef PNG_EXPORT_TYPE +# define PNG_EXPORT_TYPE(type) PNG_IMPEXP type +#endif + + /* The ordinal value is only relevant when preprocessing png.h for symbol + * table entries, so we discard it here. See the .dfn files in the + * scripts directory. + */ +#ifndef PNG_EXPORTA + +# define PNG_EXPORTA(ordinal, type, name, args, attributes)\ + PNG_FUNCTION(PNG_EXPORT_TYPE(type),(PNGAPI name),PNGARG(args), \ + extern attributes) +#endif + +/* ANSI-C (C90) does not permit a macro to be invoked with an empty argument, + * so make something non-empty to satisfy the requirement: + */ +#define PNG_EMPTY /*empty list*/ + +#define PNG_EXPORT(ordinal, type, name, args)\ + PNG_EXPORTA(ordinal, type, name, args, PNG_EMPTY) + +/* Use PNG_REMOVED to comment out a removed interface. */ +#ifndef PNG_REMOVED +# define PNG_REMOVED(ordinal, type, name, args, attributes) +#endif + +#ifndef PNG_CALLBACK +# define PNG_CALLBACK(type, name, args) type (PNGCBAPI name) PNGARG(args) +#endif + +/* Support for compiler specific function attributes. These are used + * so that where compiler support is available incorrect use of API + * functions in png.h will generate compiler warnings. + * + * Added at libpng-1.2.41. + */ + +#ifndef PNG_NO_PEDANTIC_WARNINGS +# ifndef PNG_PEDANTIC_WARNINGS_SUPPORTED +# define PNG_PEDANTIC_WARNINGS_SUPPORTED +# endif +#endif + +#ifdef PNG_PEDANTIC_WARNINGS_SUPPORTED + /* Support for compiler specific function attributes. These are used + * so that where compiler support is available, incorrect use of API + * functions in png.h will generate compiler warnings. Added at libpng + * version 1.2.41. Disabling these removes the warnings but may also produce + * less efficient code. + */ +# if defined(__GNUC__) +# ifndef PNG_USE_RESULT +# define PNG_USE_RESULT __attribute__((__warn_unused_result__)) +# endif +# ifndef PNG_NORETURN +# define PNG_NORETURN __attribute__((__noreturn__)) +# endif +# if __GNUC__ >= 3 +# ifndef PNG_ALLOCATED +# define PNG_ALLOCATED __attribute__((__malloc__)) +# endif +# ifndef PNG_DEPRECATED +# define PNG_DEPRECATED __attribute__((__deprecated__)) +# endif +# ifndef PNG_PRIVATE +# if 0 /* Doesn't work so we use deprecated instead*/ +# define PNG_PRIVATE \ + __attribute__((warning("This function is not exported by libpng."))) +# else +# define PNG_PRIVATE \ + __attribute__((__deprecated__)) +# endif +# endif +# if ((__GNUC__ != 3) || !defined(__GNUC_MINOR__) || (__GNUC_MINOR__ >= 1)) +# ifndef PNG_RESTRICT +# define PNG_RESTRICT __restrict +# endif +# endif /* __GNUC__ == 3.0 */ +# endif /* __GNUC__ >= 3 */ + +# elif defined(_MSC_VER) && (_MSC_VER >= 1300) +# ifndef PNG_USE_RESULT +# define PNG_USE_RESULT /* not supported */ +# endif +# ifndef PNG_NORETURN +# define PNG_NORETURN __declspec(noreturn) +# endif +# ifndef PNG_ALLOCATED +# if (_MSC_VER >= 1400) +# define PNG_ALLOCATED __declspec(restrict) +# endif +# endif +# ifndef PNG_DEPRECATED +# define PNG_DEPRECATED __declspec(deprecated) +# endif +# ifndef PNG_PRIVATE +# define PNG_PRIVATE __declspec(deprecated) +# endif +# ifndef PNG_RESTRICT +# if (_MSC_VER >= 1400) +# define PNG_RESTRICT __restrict +# endif +# endif + +# elif defined(__WATCOMC__) +# ifndef PNG_RESTRICT +# define PNG_RESTRICT __restrict +# endif +# endif /* _MSC_VER */ +#endif /* PNG_PEDANTIC_WARNINGS */ + +#ifndef PNG_DEPRECATED +# define PNG_DEPRECATED /* Use of this function is deprecated */ +#endif +#ifndef PNG_USE_RESULT +# define PNG_USE_RESULT /* The result of this function must be checked */ +#endif +#ifndef PNG_NORETURN +# define PNG_NORETURN /* This function does not return */ +#endif +#ifndef PNG_ALLOCATED +# define PNG_ALLOCATED /* The result of the function is new memory */ +#endif +#ifndef PNG_PRIVATE +# define PNG_PRIVATE /* This is a private libpng function */ +#endif +#ifndef PNG_RESTRICT +# define PNG_RESTRICT /* The C99 "restrict" feature */ +#endif +#ifndef PNG_FP_EXPORT /* A floating point API. */ +# ifdef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FP_EXPORT(ordinal, type, name, args)\ + PNG_EXPORT(ordinal, type, name, args); +# else /* No floating point APIs */ +# define PNG_FP_EXPORT(ordinal, type, name, args) +# endif +#endif +#ifndef PNG_FIXED_EXPORT /* A fixed point API. */ +# ifdef PNG_FIXED_POINT_SUPPORTED +# define PNG_FIXED_EXPORT(ordinal, type, name, args)\ + PNG_EXPORT(ordinal, type, name, args); +# else /* No fixed point APIs */ +# define PNG_FIXED_EXPORT(ordinal, type, name, args) +# endif +#endif + +#ifndef PNG_BUILDING_SYMBOL_TABLE +/* Some typedefs to get us started. These should be safe on most of the common + * platforms. + * + * png_uint_32 and png_int_32 may, currently, be larger than required to hold a + * 32-bit value however this is not normally advisable. + * + * png_uint_16 and png_int_16 should always be two bytes in size - this is + * verified at library build time. + * + * png_byte must always be one byte in size. + * + * The checks below use constants from limits.h, as defined by the ISOC90 + * standard. + */ +#if CHAR_BIT == 8 && UCHAR_MAX == 255 + typedef unsigned char png_byte; +#else +# error "libpng requires 8 bit bytes" +#endif + +#if INT_MIN == -32768 && INT_MAX == 32767 + typedef int png_int_16; +#elif SHRT_MIN == -32768 && SHRT_MAX == 32767 + typedef short png_int_16; +#else +# error "libpng requires a signed 16 bit type" +#endif + +#if UINT_MAX == 65535 + typedef unsigned int png_uint_16; +#elif USHRT_MAX == 65535 + typedef unsigned short png_uint_16; +#else +# error "libpng requires an unsigned 16 bit type" +#endif + +#if INT_MIN < -2147483646 && INT_MAX > 2147483646 + typedef int png_int_32; +#elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646 + typedef long int png_int_32; +#else +# error "libpng requires a signed 32 bit (or more) type" +#endif + +#if UINT_MAX > 4294967294 + typedef unsigned int png_uint_32; +#elif ULONG_MAX > 4294967294 + typedef unsigned long int png_uint_32; +#else +# error "libpng requires an unsigned 32 bit (or more) type" +#endif + +/* Prior to 1.6.0 it was possible to disable the use of size_t, 1.6.0, however, + * requires an ISOC90 compiler and relies on consistent behavior of sizeof. + */ +typedef size_t png_size_t; +typedef ptrdiff_t png_ptrdiff_t; + +/* libpng needs to know the maximum value of 'size_t' and this controls the + * definition of png_alloc_size_t, below. This maximum value of size_t limits + * but does not control the maximum allocations the library makes - there is + * direct application control of this through png_set_user_limits(). + */ +#ifndef PNG_SMALL_SIZE_T + /* Compiler specific tests for systems where size_t is known to be less than + * 32 bits (some of these systems may no longer work because of the lack of + * 'far' support; see above.) + */ +# if (defined(__TURBOC__) && !defined(__FLAT__)) ||\ + (defined(_MSC_VER) && defined(MAXSEG_64K)) +# define PNG_SMALL_SIZE_T +# endif +#endif + +/* png_alloc_size_t is guaranteed to be no smaller than png_size_t, and no + * smaller than png_uint_32. Casts from png_size_t or png_uint_32 to + * png_alloc_size_t are not necessary; in fact, it is recommended not to use + * them at all so that the compiler can complain when something turns out to be + * problematic. + * + * Casts in the other direction (from png_alloc_size_t to png_size_t or + * png_uint_32) should be explicitly applied; however, we do not expect to + * encounter practical situations that require such conversions. + * + * PNG_SMALL_SIZE_T must be defined if the maximum value of size_t is less than + * 4294967295 - i.e. less than the maximum value of png_uint_32. + */ +#ifdef PNG_SMALL_SIZE_T + typedef png_uint_32 png_alloc_size_t; +#else + typedef png_size_t png_alloc_size_t; +#endif + +/* Prior to 1.6.0 libpng offered limited support for Microsoft C compiler + * implementations of Intel CPU specific support of user-mode segmented address + * spaces, where 16-bit pointers address more than 65536 bytes of memory using + * separate 'segment' registers. The implementation requires two different + * types of pointer (only one of which includes the segment value.) + * + * If required this support is available in version 1.2 of libpng and may be + * available in versions through 1.5, although the correctness of the code has + * not been verified recently. + */ + +/* Typedef for floating-point numbers that are converted to fixed-point with a + * multiple of 100,000, e.g., gamma + */ +typedef png_int_32 png_fixed_point; + +/* Add typedefs for pointers */ +typedef void * png_voidp; +typedef const void * png_const_voidp; +typedef png_byte * png_bytep; +typedef const png_byte * png_const_bytep; +typedef png_uint_32 * png_uint_32p; +typedef const png_uint_32 * png_const_uint_32p; +typedef png_int_32 * png_int_32p; +typedef const png_int_32 * png_const_int_32p; +typedef png_uint_16 * png_uint_16p; +typedef const png_uint_16 * png_const_uint_16p; +typedef png_int_16 * png_int_16p; +typedef const png_int_16 * png_const_int_16p; +typedef char * png_charp; +typedef const char * png_const_charp; +typedef png_fixed_point * png_fixed_point_p; +typedef const png_fixed_point * png_const_fixed_point_p; +typedef png_size_t * png_size_tp; +typedef const png_size_t * png_const_size_tp; + +#ifdef PNG_STDIO_SUPPORTED +typedef FILE * png_FILE_p; +#endif + +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double * png_doublep; +typedef const double * png_const_doublep; +#endif + +/* Pointers to pointers; i.e. arrays */ +typedef png_byte * * png_bytepp; +typedef png_uint_32 * * png_uint_32pp; +typedef png_int_32 * * png_int_32pp; +typedef png_uint_16 * * png_uint_16pp; +typedef png_int_16 * * png_int_16pp; +typedef const char * * png_const_charpp; +typedef char * * png_charpp; +typedef png_fixed_point * * png_fixed_point_pp; +#ifdef PNG_FLOATING_POINT_SUPPORTED +typedef double * * png_doublepp; +#endif + +/* Pointers to pointers to pointers; i.e., pointer to array */ +typedef char * * * png_charppp; + +#endif /* PNG_BUILDING_SYMBOL_TABLE */ + +#endif /* PNGCONF_H */ diff --git a/lib/3rdParty/dlib/include/dlib/external/libpng/pngdebug.h b/lib/3rdParty/dlib/include/dlib/external/libpng/pngdebug.h new file mode 100644 index 00000000..16f81fdd --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/libpng/pngdebug.h @@ -0,0 +1,157 @@ + +/* pngdebug.h - Debugging macros for libpng, also used in pngtest.c + * + * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * Last changed in libpng 1.5.0 [January 6, 2011] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +/* Define PNG_DEBUG at compile time for debugging information. Higher + * numbers for PNG_DEBUG mean more debugging information. This has + * only been added since version 0.95 so it is not implemented throughout + * libpng yet, but more support will be added as needed. + * + * png_debug[1-2]?(level, message ,arg{0-2}) + * Expands to a statement (either a simple expression or a compound + * do..while(0) statement) that outputs a message with parameter + * substitution if PNG_DEBUG is defined to 2 or more. If PNG_DEBUG + * is undefined, 0 or 1 every png_debug expands to a simple expression + * (actually ((void)0)). + * + * level: level of detail of message, starting at 0. A level 'n' + * message is preceded by 'n' tab characters (not implemented + * on Microsoft compilers unless PNG_DEBUG_FILE is also + * defined, to allow debug DLL compilation with no standard IO). + * message: a printf(3) style text string. A trailing '\n' is added + * to the message. + * arg: 0 to 2 arguments for printf(3) style substitution in message. + */ +#ifndef PNGDEBUG_H +#define PNGDEBUG_H +/* These settings control the formatting of messages in png.c and pngerror.c */ +/* Moved to pngdebug.h at 1.5.0 */ +# ifndef PNG_LITERAL_SHARP +# define PNG_LITERAL_SHARP 0x23 +# endif +# ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET +# define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b +# endif +# ifndef PNG_LITERAL_RIGHT_SQUARE_BRACKET +# define PNG_LITERAL_RIGHT_SQUARE_BRACKET 0x5d +# endif +# ifndef PNG_STRING_NEWLINE +# define PNG_STRING_NEWLINE "\n" +# endif + +#ifdef PNG_DEBUG +# if (PNG_DEBUG > 0) +# if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER) +# include +# if (PNG_DEBUG > 1) +# ifndef _DEBUG +# define _DEBUG +# endif +# ifndef png_debug +# define png_debug(l,m) _RPT0(_CRT_WARN,m PNG_STRING_NEWLINE) +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m PNG_STRING_NEWLINE,p1) +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + _RPT2(_CRT_WARN,m PNG_STRING_NEWLINE,p1,p2) +# endif +# endif +# else /* PNG_DEBUG_FILE || !_MSC_VER */ +# ifndef PNG_STDIO_SUPPORTED +# include /* not included yet */ +# endif +# ifndef PNG_DEBUG_FILE +# define PNG_DEBUG_FILE stderr +# endif /* PNG_DEBUG_FILE */ + +# if (PNG_DEBUG > 1) +/* Note: ["%s"m PNG_STRING_NEWLINE] probably does not work on + * non-ISO compilers + */ +# ifdef __STDC__ +# ifndef png_debug +# define png_debug(l,m) \ + do { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \ + } while (0) +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) \ + do { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \ + } while (0) +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + do { \ + int num_tabs=l; \ + fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \ + } while (0) +# endif +# else /* __STDC __ */ +# ifndef png_debug +# define png_debug(l,m) \ + do { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format); \ + } while (0) +# endif +# ifndef png_debug1 +# define png_debug1(l,m,p1) \ + do { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format,p1); \ + } while (0) +# endif +# ifndef png_debug2 +# define png_debug2(l,m,p1,p2) \ + do { \ + int num_tabs=l; \ + char format[256]; \ + snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ + m,PNG_STRING_NEWLINE); \ + fprintf(PNG_DEBUG_FILE,format,p1,p2); \ + } while (0) +# endif +# endif /* __STDC __ */ +# endif /* (PNG_DEBUG > 1) */ + +# endif /* _MSC_VER */ +# endif /* (PNG_DEBUG > 0) */ +#endif /* PNG_DEBUG */ +#ifndef png_debug +# define png_debug(l, m) ((void)0) +#endif +#ifndef png_debug1 +# define png_debug1(l, m, p1) ((void)0) +#endif +#ifndef png_debug2 +# define png_debug2(l, m, p1, p2) ((void)0) +#endif +#endif /* PNGDEBUG_H */ diff --git a/lib/3rdParty/dlib/include/dlib/external/libpng/pnginfo.h b/lib/3rdParty/dlib/include/dlib/external/libpng/pnginfo.h new file mode 100644 index 00000000..26bf2650 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/libpng/pnginfo.h @@ -0,0 +1,260 @@ + +/* pnginfo.h - header file for PNG reference library + * + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * Last changed in libpng 1.6.1 [March 28, 2013] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + + /* png_info is a structure that holds the information in a PNG file so + * that the application can find out the characteristics of the image. + * If you are reading the file, this structure will tell you what is + * in the PNG file. If you are writing the file, fill in the information + * you want to put into the PNG file, using png_set_*() functions, then + * call png_write_info(). + * + * The names chosen should be very close to the PNG specification, so + * consult that document for information about the meaning of each field. + * + * With libpng < 0.95, it was only possible to directly set and read the + * the values in the png_info_struct, which meant that the contents and + * order of the values had to remain fixed. With libpng 0.95 and later, + * however, there are now functions that abstract the contents of + * png_info_struct from the application, so this makes it easier to use + * libpng with dynamic libraries, and even makes it possible to use + * libraries that don't have all of the libpng ancillary chunk-handing + * functionality. In libpng-1.5.0 this was moved into a separate private + * file that is not visible to applications. + * + * The following members may have allocated storage attached that should be + * cleaned up before the structure is discarded: palette, trans, text, + * pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile, + * splt_palettes, scal_unit, row_pointers, and unknowns. By default, these + * are automatically freed when the info structure is deallocated, if they were + * allocated internally by libpng. This behavior can be changed by means + * of the png_data_freer() function. + * + * More allocation details: all the chunk-reading functions that + * change these members go through the corresponding png_set_* + * functions. A function to clear these members is available: see + * png_free_data(). The png_set_* functions do not depend on being + * able to point info structure members to any of the storage they are + * passed (they make their own copies), EXCEPT that the png_set_text + * functions use the same storage passed to them in the text_ptr or + * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns + * functions do not make their own copies. + */ +#ifndef PNGINFO_H +#define PNGINFO_H + +struct png_info_def +{ + /* The following are necessary for every PNG file */ + png_uint_32 width; /* width of image in pixels (from IHDR) */ + png_uint_32 height; /* height of image in pixels (from IHDR) */ + png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */ + png_size_t rowbytes; /* bytes needed to hold an untransformed row */ + png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */ + png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */ + png_uint_16 num_trans; /* number of transparent palette color (tRNS) */ + png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */ + png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */ + /* The following three should have been named *_method not *_type */ + png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */ + png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */ + png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + + /* The following are set by png_set_IHDR, called from the application on + * write, but the are never actually used by the write code. + */ + png_byte channels; /* number of data channels per pixel (1, 2, 3, 4) */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte spare_byte; /* to align the data, and for future use */ + +#ifdef PNG_READ_SUPPORTED + /* This is never set during write */ + png_byte signature[8]; /* magic bytes read by libpng from start of file */ +#endif + + /* The rest of the data is optional. If you are reading, check the + * valid field to see if the information in these are valid. If you + * are writing, set the valid field to those chunks you want written, + * and initialize the appropriate fields below. + */ + +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) + /* png_colorspace only contains 'flags' if neither GAMMA or COLORSPACE are + * defined. When COLORSPACE is switched on all the colorspace-defining + * chunks should be enabled, when GAMMA is switched on all the gamma-defining + * chunks should be enabled. If this is not done it becomes possible to read + * inconsistent PNG files and assign a probably incorrect interpretation to + * the information. (In other words, by carefully choosing which chunks to + * recognize the system configuration can select an interpretation for PNG + * files containing ambiguous data and this will result in inconsistent + * behavior between different libpng builds!) + */ + png_colorspace colorspace; +#endif + +#ifdef PNG_iCCP_SUPPORTED + /* iCCP chunk data. */ + png_charp iccp_name; /* profile name */ + png_bytep iccp_profile; /* International Color Consortium profile data */ + png_uint_32 iccp_proflen; /* ICC profile data length */ +#endif + +#ifdef PNG_TEXT_SUPPORTED + /* The tEXt, and zTXt chunks contain human-readable textual data in + * uncompressed, compressed, and optionally compressed forms, respectively. + * The data in "text" is an array of pointers to uncompressed, + * null-terminated C strings. Each chunk has a keyword that describes the + * textual data contained in that chunk. Keywords are not required to be + * unique, and the text string may be empty. Any number of text chunks may + * be in an image. + */ + int num_text; /* number of comments read or comments to write */ + int max_text; /* current size of text array */ + png_textp text; /* array of comments read or comments to write */ +#endif /* PNG_TEXT_SUPPORTED */ + +#ifdef PNG_tIME_SUPPORTED + /* The tIME chunk holds the last time the displayed image data was + * modified. See the png_time struct for the contents of this struct. + */ + png_time mod_time; +#endif + +#ifdef PNG_sBIT_SUPPORTED + /* The sBIT chunk specifies the number of significant high-order bits + * in the pixel data. Values are in the range [1, bit_depth], and are + * only specified for the channels in the pixel data. The contents of + * the low-order bits is not specified. Data is valid if + * (valid & PNG_INFO_sBIT) is non-zero. + */ + png_color_8 sig_bit; /* significant bits in color channels */ +#endif + +#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_EXPAND_SUPPORTED) || \ +defined(PNG_READ_BACKGROUND_SUPPORTED) + /* The tRNS chunk supplies transparency data for paletted images and + * other image types that don't need a full alpha channel. There are + * "num_trans" transparency values for a paletted image, stored in the + * same order as the palette colors, starting from index 0. Values + * for the data are in the range [0, 255], ranging from fully transparent + * to fully opaque, respectively. For non-paletted images, there is a + * single color specified that should be treated as fully transparent. + * Data is valid if (valid & PNG_INFO_tRNS) is non-zero. + */ + png_bytep trans_alpha; /* alpha values for paletted image */ + png_color_16 trans_color; /* transparent color for non-palette image */ +#endif + +#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + /* The bKGD chunk gives the suggested image background color if the + * display program does not have its own background color and the image + * is needs to composited onto a background before display. The colors + * in "background" are normally in the same color space/depth as the + * pixel data. Data is valid if (valid & PNG_INFO_bKGD) is non-zero. + */ + png_color_16 background; +#endif + +#ifdef PNG_oFFs_SUPPORTED + /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards + * and downwards from the top-left corner of the display, page, or other + * application-specific co-ordinate space. See the PNG_OFFSET_ defines + * below for the unit types. Valid if (valid & PNG_INFO_oFFs) non-zero. + */ + png_int_32 x_offset; /* x offset on page */ + png_int_32 y_offset; /* y offset on page */ + png_byte offset_unit_type; /* offset units type */ +#endif + +#ifdef PNG_pHYs_SUPPORTED + /* The pHYs chunk gives the physical pixel density of the image for + * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_ + * defines below). Data is valid if (valid & PNG_INFO_pHYs) is non-zero. + */ + png_uint_32 x_pixels_per_unit; /* horizontal pixel density */ + png_uint_32 y_pixels_per_unit; /* vertical pixel density */ + png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */ +#endif + +#ifdef PNG_hIST_SUPPORTED + /* The hIST chunk contains the relative frequency or importance of the + * various palette entries, so that a viewer can intelligently select a + * reduced-color palette, if required. Data is an array of "num_palette" + * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST) + * is non-zero. + */ + png_uint_16p hist; +#endif + +#ifdef PNG_pCAL_SUPPORTED + /* The pCAL chunk describes a transformation between the stored pixel + * values and original physical data values used to create the image. + * The integer range [0, 2^bit_depth - 1] maps to the floating-point + * range given by [pcal_X0, pcal_X1], and are further transformed by a + * (possibly non-linear) transformation function given by "pcal_type" + * and "pcal_params" into "pcal_units". Please see the PNG_EQUATION_ + * defines below, and the PNG-Group's PNG extensions document for a + * complete description of the transformations and how they should be + * implemented, and for a description of the ASCII parameter strings. + * Data values are valid if (valid & PNG_INFO_pCAL) non-zero. + */ + png_charp pcal_purpose; /* pCAL chunk description string */ + png_int_32 pcal_X0; /* minimum value */ + png_int_32 pcal_X1; /* maximum value */ + png_charp pcal_units; /* Latin-1 string giving physical units */ + png_charpp pcal_params; /* ASCII strings containing parameter values */ + png_byte pcal_type; /* equation type (see PNG_EQUATION_ below) */ + png_byte pcal_nparams; /* number of parameters given in pcal_params */ +#endif + +/* New members added in libpng-1.0.6 */ + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED + /* Storage for unknown chunks that the library doesn't recognize. */ + png_unknown_chunkp unknown_chunks; + + /* The type of this field is limited by the type of + * png_struct::user_chunk_cache_max, else overflow can occur. + */ + int unknown_chunks_num; +#endif + +#ifdef PNG_sPLT_SUPPORTED + /* Data on sPLT chunks (there may be more than one). */ + png_sPLT_tp splt_palettes; + int splt_palettes_num; /* Match type returned by png_get API */ +#endif + +#ifdef PNG_sCAL_SUPPORTED + /* The sCAL chunk describes the actual physical dimensions of the + * subject matter of the graphic. The chunk contains a unit specification + * a byte value, and two ASCII strings representing floating-point + * values. The values are width and height corresponsing to one pixel + * in the image. Data values are valid if (valid & PNG_INFO_sCAL) is + * non-zero. + */ + png_byte scal_unit; /* unit of physical scale */ + png_charp scal_s_width; /* string containing height */ + png_charp scal_s_height; /* string containing width */ +#endif + +#ifdef PNG_INFO_IMAGE_SUPPORTED + /* Memory has been allocated if (valid & PNG_ALLOCATED_INFO_ROWS) + non-zero */ + /* Data valid if (valid & PNG_INFO_IDAT) non-zero */ + png_bytepp row_pointers; /* the image bits */ +#endif + +}; +#endif /* PNGINFO_H */ diff --git a/lib/3rdParty/dlib/include/dlib/external/libpng/pnglibconf.h b/lib/3rdParty/dlib/include/dlib/external/libpng/pnglibconf.h new file mode 100644 index 00000000..6e9a4115 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/libpng/pnglibconf.h @@ -0,0 +1,211 @@ +/* libpng 1.6.7 STANDARD API DEFINITION */ + +/* pnglibconf.h - library build configuration */ + +/* Libpng version 1.6.7 - November 14, 2013 */ + +/* Copyright (c) 1998-2013 Glenn Randers-Pehrson */ + +/* This code is released under the libpng license. */ +/* For conditions of distribution and use, see the disclaimer */ +/* and license in png.h */ + +/* pnglibconf.h */ +/* Machine generated file: DO NOT EDIT */ +/* Derived from: scripts/pnglibconf.dfa */ +#ifndef PNGLCONF_H +#define PNGLCONF_H +/* options */ +#define PNG_16BIT_SUPPORTED +#define PNG_ALIGNED_MEMORY_SUPPORTED +/*#undef PNG_ARM_NEON_API_SUPPORTED*/ +/*#undef PNG_ARM_NEON_CHECK_SUPPORTED*/ +#define PNG_BENIGN_ERRORS_SUPPORTED +#define PNG_BENIGN_READ_ERRORS_SUPPORTED +/*#undef PNG_BENIGN_WRITE_ERRORS_SUPPORTED*/ +#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +#define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED +#define PNG_COLORSPACE_SUPPORTED +#define PNG_CONSOLE_IO_SUPPORTED +#define PNG_CONVERT_tIME_SUPPORTED +#define PNG_EASY_ACCESS_SUPPORTED +/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/ +#define PNG_ERROR_TEXT_SUPPORTED +#define PNG_FIXED_POINT_SUPPORTED +#define PNG_FLOATING_ARITHMETIC_SUPPORTED +#define PNG_FLOATING_POINT_SUPPORTED +#define PNG_FORMAT_AFIRST_SUPPORTED +#define PNG_FORMAT_BGR_SUPPORTED +#define PNG_GAMMA_SUPPORTED +#define PNG_GET_PALETTE_MAX_SUPPORTED +#define PNG_HANDLE_AS_UNKNOWN_SUPPORTED +#define PNG_INCH_CONVERSIONS_SUPPORTED +#define PNG_INFO_IMAGE_SUPPORTED +#define PNG_IO_STATE_SUPPORTED +#define PNG_MNG_FEATURES_SUPPORTED +#define PNG_POINTER_INDEXING_SUPPORTED +#define PNG_PROGRESSIVE_READ_SUPPORTED +#define PNG_READ_16BIT_SUPPORTED +#define PNG_READ_ALPHA_MODE_SUPPORTED +#define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED +#define PNG_READ_BACKGROUND_SUPPORTED +#define PNG_READ_BGR_SUPPORTED +#define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED +#define PNG_READ_COMPOSITE_NODIV_SUPPORTED +#define PNG_READ_COMPRESSED_TEXT_SUPPORTED +#define PNG_READ_EXPAND_16_SUPPORTED +#define PNG_READ_EXPAND_SUPPORTED +#define PNG_READ_FILLER_SUPPORTED +#define PNG_READ_GAMMA_SUPPORTED +#define PNG_READ_GET_PALETTE_MAX_SUPPORTED +#define PNG_READ_GRAY_TO_RGB_SUPPORTED +#define PNG_READ_INTERLACING_SUPPORTED +#define PNG_READ_INT_FUNCTIONS_SUPPORTED +#define PNG_READ_INVERT_ALPHA_SUPPORTED +#define PNG_READ_INVERT_SUPPORTED +#define PNG_READ_OPT_PLTE_SUPPORTED +#define PNG_READ_PACKSWAP_SUPPORTED +#define PNG_READ_PACK_SUPPORTED +#define PNG_READ_QUANTIZE_SUPPORTED +#define PNG_READ_RGB_TO_GRAY_SUPPORTED +#define PNG_READ_SCALE_16_TO_8_SUPPORTED +#define PNG_READ_SHIFT_SUPPORTED +#define PNG_READ_STRIP_16_TO_8_SUPPORTED +#define PNG_READ_STRIP_ALPHA_SUPPORTED +#define PNG_READ_SUPPORTED +#define PNG_READ_SWAP_ALPHA_SUPPORTED +#define PNG_READ_SWAP_SUPPORTED +#define PNG_READ_TEXT_SUPPORTED +#define PNG_READ_TRANSFORMS_SUPPORTED +#define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_READ_USER_CHUNKS_SUPPORTED +#define PNG_READ_USER_TRANSFORM_SUPPORTED +#define PNG_READ_bKGD_SUPPORTED +#define PNG_READ_cHRM_SUPPORTED +#define PNG_READ_gAMA_SUPPORTED +#define PNG_READ_hIST_SUPPORTED +#define PNG_READ_iCCP_SUPPORTED +#define PNG_READ_iTXt_SUPPORTED +#define PNG_READ_oFFs_SUPPORTED +#define PNG_READ_pCAL_SUPPORTED +#define PNG_READ_pHYs_SUPPORTED +#define PNG_READ_sBIT_SUPPORTED +#define PNG_READ_sCAL_SUPPORTED +#define PNG_READ_sPLT_SUPPORTED +#define PNG_READ_sRGB_SUPPORTED +#define PNG_READ_tEXt_SUPPORTED +#define PNG_READ_tIME_SUPPORTED +#define PNG_READ_tRNS_SUPPORTED +#define PNG_READ_zTXt_SUPPORTED +/*#undef PNG_SAFE_LIMITS_SUPPORTED*/ +#define PNG_SAVE_INT_32_SUPPORTED +#define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_SEQUENTIAL_READ_SUPPORTED +#define PNG_SETJMP_SUPPORTED +#define PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED +#define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED +#define PNG_SET_OPTION_SUPPORTED +#define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_SET_USER_LIMITS_SUPPORTED +#define PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED +#define PNG_SIMPLIFIED_READ_BGR_SUPPORTED +#define PNG_SIMPLIFIED_READ_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_SUPPORTED +#define PNG_STDIO_SUPPORTED +#define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_TEXT_SUPPORTED +#define PNG_TIME_RFC1123_SUPPORTED +#define PNG_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_USER_CHUNKS_SUPPORTED +#define PNG_USER_LIMITS_SUPPORTED +#define PNG_USER_MEM_SUPPORTED +#define PNG_USER_TRANSFORM_INFO_SUPPORTED +#define PNG_USER_TRANSFORM_PTR_SUPPORTED +#define PNG_WARNINGS_SUPPORTED +#define PNG_WRITE_16BIT_SUPPORTED +#define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED +#define PNG_WRITE_BGR_SUPPORTED +#define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED +#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED +#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +#define PNG_WRITE_FILLER_SUPPORTED +#define PNG_WRITE_FILTER_SUPPORTED +#define PNG_WRITE_FLUSH_SUPPORTED +#define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED +#define PNG_WRITE_INTERLACING_SUPPORTED +#define PNG_WRITE_INT_FUNCTIONS_SUPPORTED +#define PNG_WRITE_INVERT_ALPHA_SUPPORTED +#define PNG_WRITE_INVERT_SUPPORTED +#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED +#define PNG_WRITE_PACKSWAP_SUPPORTED +#define PNG_WRITE_PACK_SUPPORTED +#define PNG_WRITE_SHIFT_SUPPORTED +#define PNG_WRITE_SUPPORTED +#define PNG_WRITE_SWAP_ALPHA_SUPPORTED +#define PNG_WRITE_SWAP_SUPPORTED +#define PNG_WRITE_TEXT_SUPPORTED +#define PNG_WRITE_TRANSFORMS_SUPPORTED +#define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +#define PNG_WRITE_USER_TRANSFORM_SUPPORTED +#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +#define PNG_WRITE_bKGD_SUPPORTED +#define PNG_WRITE_cHRM_SUPPORTED +#define PNG_WRITE_gAMA_SUPPORTED +#define PNG_WRITE_hIST_SUPPORTED +#define PNG_WRITE_iCCP_SUPPORTED +#define PNG_WRITE_iTXt_SUPPORTED +#define PNG_WRITE_oFFs_SUPPORTED +#define PNG_WRITE_pCAL_SUPPORTED +#define PNG_WRITE_pHYs_SUPPORTED +#define PNG_WRITE_sBIT_SUPPORTED +#define PNG_WRITE_sCAL_SUPPORTED +#define PNG_WRITE_sPLT_SUPPORTED +#define PNG_WRITE_sRGB_SUPPORTED +#define PNG_WRITE_tEXt_SUPPORTED +#define PNG_WRITE_tIME_SUPPORTED +#define PNG_WRITE_tRNS_SUPPORTED +#define PNG_WRITE_zTXt_SUPPORTED +#define PNG_bKGD_SUPPORTED +#define PNG_cHRM_SUPPORTED +#define PNG_gAMA_SUPPORTED +#define PNG_hIST_SUPPORTED +#define PNG_iCCP_SUPPORTED +#define PNG_iTXt_SUPPORTED +#define PNG_oFFs_SUPPORTED +#define PNG_pCAL_SUPPORTED +#define PNG_pHYs_SUPPORTED +#define PNG_sBIT_SUPPORTED +#define PNG_sCAL_SUPPORTED +#define PNG_sPLT_SUPPORTED +#define PNG_sRGB_SUPPORTED +#define PNG_tEXt_SUPPORTED +#define PNG_tIME_SUPPORTED +#define PNG_tRNS_SUPPORTED +#define PNG_zTXt_SUPPORTED +/* end of options */ +/* settings */ +#define PNG_API_RULE 0 +#define PNG_CALLOC_SUPPORTED +#define PNG_COST_SHIFT 3 +#define PNG_DEFAULT_READ_MACROS 1 +#define PNG_GAMMA_THRESHOLD_FIXED 5000 +#define PNG_IDAT_READ_SIZE PNG_ZBUF_SIZE +#define PNG_INFLATE_BUF_SIZE 1024 +#define PNG_MAX_GAMMA_8 11 +#define PNG_QUANTIZE_BLUE_BITS 5 +#define PNG_QUANTIZE_GREEN_BITS 5 +#define PNG_QUANTIZE_RED_BITS 5 +#define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1) +#define PNG_TEXT_Z_DEFAULT_STRATEGY 0 +#define PNG_WEIGHT_SHIFT 8 +#define PNG_ZBUF_SIZE 8192 +#define PNG_ZLIB_VERNUM 0 /* unknown */ +#define PNG_Z_DEFAULT_COMPRESSION (-1) +#define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0 +#define PNG_Z_DEFAULT_STRATEGY 1 +#define PNG_sCAL_PRECISION 5 +#define PNG_sRGB_PROFILE_CHECKS 2 +/* end of settings */ +#endif /* PNGLCONF_H */ diff --git a/lib/3rdParty/dlib/include/dlib/external/libpng/pngpriv.h b/lib/3rdParty/dlib/include/dlib/external/libpng/pngpriv.h new file mode 100644 index 00000000..43b2ef4c --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/libpng/pngpriv.h @@ -0,0 +1,2047 @@ + +/* pngpriv.h - private declarations for use inside libpng + * + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * Last changed in libpng 1.6.7 [November 14, 2013] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +/* The symbols declared in this file (including the functions declared + * as extern) are PRIVATE. They are not part of the libpng public + * interface, and are not recommended for use by regular applications. + * Some of them may become public in the future; others may stay private, + * change in an incompatible way, or even disappear. + * Although the libpng users are not forbidden to include this header, + * they should be well aware of the issues that may arise from doing so. + */ + +#ifndef PNGPRIV_H +#define PNGPRIV_H + +/* Feature Test Macros. The following are defined here to ensure that correctly + * implemented libraries reveal the APIs libpng needs to build and hide those + * that are not needed and potentially damaging to the compilation. + * + * Feature Test Macros must be defined before any system header is included (see + * POSIX 1003.1 2.8.2 "POSIX Symbols." + * + * These macros only have an effect if the operating system supports either + * POSIX 1003.1 or C99, or both. On other operating systems (particularly + * Windows/Visual Studio) there is no effect; the OS specific tests below are + * still required (as of 2011-05-02.) + */ +#define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */ + +#ifndef PNG_VERSION_INFO_ONLY +/* Standard library headers not required by png.h: */ +# include +# include +#endif + +#define PNGLIB_BUILD /*libpng is being built, not used*/ + +/* If HAVE_CONFIG_H is defined during the build then the build system must + * provide an appropriate "config.h" file on the include path. The header file + * must provide definitions as required below (search for "HAVE_CONFIG_H"); + * see configure.ac for more details of the requirements. The macro + * "PNG_NO_CONFIG_H" is provided for maintainers to test for dependencies on + * 'configure'; define this macro to prevent the configure build including the + * configure generated config.h. Libpng is expected to compile without *any* + * special build system support on a reasonably ANSI-C compliant system. + */ +#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) +# include + + /* Pick up the definition of 'restrict' from config.h if it was read: */ +# define PNG_RESTRICT restrict +#endif + +/* To support symbol prefixing it is necessary to know *before* including png.h + * whether the fixed point (and maybe other) APIs are exported, because if they + * are not internal definitions may be required. This is handled below just + * before png.h is included, but load the configuration now if it is available. + */ +#ifndef PNGLCONF_H +# include "pnglibconf.h" +#endif + +/* Local renames may change non-exported API functions from png.h */ +#if defined(PNG_PREFIX) && !defined(PNGPREFIX_H) +# include "pngprefix.h" +#endif + +#ifdef PNG_USER_CONFIG +# include "pngusr.h" + /* These should have been defined in pngusr.h */ +# ifndef PNG_USER_PRIVATEBUILD +# define PNG_USER_PRIVATEBUILD "Custom libpng build" +# endif +# ifndef PNG_USER_DLLFNAME_POSTFIX +# define PNG_USER_DLLFNAME_POSTFIX "Cb" +# endif +#endif + +/* Compile time options. + * ===================== + * In a multi-arch build the compiler may compile the code several times for the + * same object module, producing different binaries for different architectures. + * When this happens configure-time setting of the target host options cannot be + * done and this interferes with the handling of the ARM NEON optimizations, and + * possibly other similar optimizations. Put additional tests here; in general + * this is needed when the same option can be changed at both compile time and + * run time depending on the target OS (i.e. iOS vs Android.) + * + * NOTE: symbol prefixing does not pass $(CFLAGS) to the preprocessor, because + * this is not possible with certain compilers (Oracle SUN OS CC), as a result + * it is necessary to ensure that all extern functions that *might* be used + * regardless of $(CFLAGS) get declared in this file. The test on __ARM_NEON__ + * below is one example of this behavior because it is controlled by the + * presence or not of -mfpu=neon on the GCC command line, it is possible to do + * this in $(CC), e.g. "CC=gcc -mfpu=neon", but people who build libpng rarely + * do this. + */ +#ifndef PNG_ARM_NEON_OPT + /* ARM NEON optimizations are being controlled by the compiler settings, + * typically the target FPU. If the FPU has been set to NEON (-mfpu=neon + * with GCC) then the compiler will define __ARM_NEON__ and we can rely + * unconditionally on NEON instructions not crashing, otherwise we must + * disable use of NEON instructions: + */ +# ifdef __ARM_NEON__ +# define PNG_ARM_NEON_OPT 2 +# else +# define PNG_ARM_NEON_OPT 0 +# endif +#endif + +#if PNG_ARM_NEON_OPT > 0 + /* NEON optimizations are to be at least considered by libpng, so enable the + * callbacks to do this. + */ +# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_neon + + /* By default the 'intrinsics' code in arm/filter_neon_intrinsics.c is used + * if possible - if __ARM_NEON__ is set and the compiler version is not known + * to be broken. This is control by PNG_ARM_NEON_IMPLEMENTATION which can + * be: + * + * 1 The intrinsics code (the default with __ARM_NEON__) + * 2 The hand coded assembler (the default without __ARM_NEON__) + * + * It is possible to set PNG_ARM_NEON_IMPLEMENTATION in CPPFLAGS, however + * this is *NOT* supported and may cease to work even after a minor revision + * to libpng. It *is* valid to do this for testing purposes, e.g. speed + * testing or a new compiler, but the results should be communicated to the + * libpng implementation list for incorporation in the next minor release. + */ +# ifndef PNG_ARM_NEON_IMPLEMENTATION +# ifdef __ARM_NEON__ +# if defined(__clang__) + /* At present it is unknown by the libpng developers which versions + * of clang support the intrinsics, however some or perhaps all + * versions do not work with the assembler so this may be + * irrelevant, so just use the default (do nothing here.) + */ +# elif defined(__GNUC__) + /* GCC 4.5.4 NEON support is known to be broken. 4.6.3 is known to + * work, so if this *is* GCC, or G++, look for a version >4.5 + */ +# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6) +# define PNG_ARM_NEON_IMPLEMENTATION 2 +# endif /* no GNUC support */ +# endif /* __GNUC__ */ +# else /* !defined __ARM_NEON__ */ + /* The 'intrinsics' code simply won't compile without this -mfpu=neon: + */ +# define PNG_ARM_NEON_IMPLEMENTATION 2 +# endif /* __ARM_NEON__ */ +# endif /* !defined PNG_ARM_NEON_IMPLEMENTATION */ + +# ifndef PNG_ARM_NEON_IMPLEMENTATION + /* Use the intrinsics code by default. */ +# define PNG_ARM_NEON_IMPLEMENTATION 1 +# endif +#endif /* PNG_ARM_NEON_OPT > 0 */ + +/* Is this a build of a DLL where compilation of the object modules requires + * different preprocessor settings to those required for a simple library? If + * so PNG_BUILD_DLL must be set. + * + * If libpng is used inside a DLL but that DLL does not export the libpng APIs + * PNG_BUILD_DLL must not be set. To avoid the code below kicking in build a + * static library of libpng then link the DLL against that. + */ +#ifndef PNG_BUILD_DLL +# ifdef DLL_EXPORT + /* This is set by libtool when files are compiled for a DLL; libtool + * always compiles twice, even on systems where it isn't necessary. Set + * PNG_BUILD_DLL in case it is necessary: + */ +# define PNG_BUILD_DLL +# else +# ifdef _WINDLL + /* This is set by the Microsoft Visual Studio IDE in projects that + * build a DLL. It can't easily be removed from those projects (it + * isn't visible in the Visual Studio UI) so it is a fairly reliable + * indication that PNG_IMPEXP needs to be set to the DLL export + * attributes. + */ +# define PNG_BUILD_DLL +# else +# ifdef __DLL__ + /* This is set by the Borland C system when compiling for a DLL + * (as above.) + */ +# define PNG_BUILD_DLL +# else + /* Add additional compiler cases here. */ +# endif +# endif +# endif +#endif /* Setting PNG_BUILD_DLL if required */ + +/* See pngconf.h for more details: the builder of the library may set this on + * the command line to the right thing for the specific compilation system or it + * may be automagically set above (at present we know of no system where it does + * need to be set on the command line.) + * + * PNG_IMPEXP must be set here when building the library to prevent pngconf.h + * setting it to the "import" setting for a DLL build. + */ +#ifndef PNG_IMPEXP +# ifdef PNG_BUILD_DLL +# define PNG_IMPEXP PNG_DLL_EXPORT +# else + /* Not building a DLL, or the DLL doesn't require specific export + * definitions. + */ +# define PNG_IMPEXP +# endif +#endif + +/* No warnings for private or deprecated functions in the build: */ +#ifndef PNG_DEPRECATED +# define PNG_DEPRECATED +#endif +#ifndef PNG_PRIVATE +# define PNG_PRIVATE +#endif + +/* Symbol preprocessing support. + * + * To enable listing global, but internal, symbols the following macros should + * always be used to declare an extern data or function object in this file. + */ +#ifndef PNG_INTERNAL_DATA +# define PNG_INTERNAL_DATA(type, name, array) extern type name array +#endif + +#ifndef PNG_INTERNAL_FUNCTION +# define PNG_INTERNAL_FUNCTION(type, name, args, attributes)\ + extern PNG_FUNCTION(type, name, args, PNG_EMPTY attributes) +#endif + +/* If floating or fixed point APIs are disabled they may still be compiled + * internally. To handle this make sure they are declared as the appropriate + * internal extern function (otherwise the symbol prefixing stuff won't work and + * the functions will be used without definitions.) + * + * NOTE: although all the API functions are declared here they are not all + * actually built! Because the declarations are still made it is necessary to + * fake out types that they depend on. + */ +#ifndef PNG_FP_EXPORT +# ifndef PNG_FLOATING_POINT_SUPPORTED +# define PNG_FP_EXPORT(ordinal, type, name, args)\ + PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY); +# ifndef PNG_VERSION_INFO_ONLY + typedef struct png_incomplete png_double; + typedef png_double* png_doublep; + typedef const png_double* png_const_doublep; + typedef png_double** png_doublepp; +# endif +# endif +#endif +#ifndef PNG_FIXED_EXPORT +# ifndef PNG_FIXED_POINT_SUPPORTED +# define PNG_FIXED_EXPORT(ordinal, type, name, args)\ + PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY); +# endif +#endif + +#include "png.h" + +/* pngconf.h does not set PNG_DLL_EXPORT unless it is required, so: */ +#ifndef PNG_DLL_EXPORT +# define PNG_DLL_EXPORT +#endif + +/* SECURITY and SAFETY: + * + * By default libpng is built without any internal limits on image size, + * individual heap (png_malloc) allocations or the total amount of memory used. + * If PNG_SAFE_LIMITS_SUPPORTED is defined, however, the limits below are used + * (unless individually overridden). These limits are believed to be fairly + * safe, but builders of secure systems should verify the values against the + * real system capabilities. + */ +#ifdef PNG_SAFE_LIMITS_SUPPORTED + /* 'safe' limits */ +# ifndef PNG_USER_WIDTH_MAX +# define PNG_USER_WIDTH_MAX 1000000 +# endif +# ifndef PNG_USER_HEIGHT_MAX +# define PNG_USER_HEIGHT_MAX 1000000 +# endif +# ifndef PNG_USER_CHUNK_CACHE_MAX +# define PNG_USER_CHUNK_CACHE_MAX 128 +# endif +# ifndef PNG_USER_CHUNK_MALLOC_MAX +# define PNG_USER_CHUNK_MALLOC_MAX 8000000 +# endif +#else + /* values for no limits */ +# ifndef PNG_USER_WIDTH_MAX +# define PNG_USER_WIDTH_MAX 0x7fffffff +# endif +# ifndef PNG_USER_HEIGHT_MAX +# define PNG_USER_HEIGHT_MAX 0x7fffffff +# endif +# ifndef PNG_USER_CHUNK_CACHE_MAX +# define PNG_USER_CHUNK_CACHE_MAX 0 +# endif +# ifndef PNG_USER_CHUNK_MALLOC_MAX +# define PNG_USER_CHUNK_MALLOC_MAX 0 +# endif +#endif + +/* Moved to pngpriv.h at libpng-1.5.0 */ +/* NOTE: some of these may have been used in external applications as + * these definitions were exposed in pngconf.h prior to 1.5. + */ + +/* If you are running on a machine where you cannot allocate more + * than 64K of memory at once, uncomment this. While libpng will not + * normally need that much memory in a chunk (unless you load up a very + * large file), zlib needs to know how big of a chunk it can use, and + * libpng thus makes sure to check any memory allocation to verify it + * will fit into memory. + * + * zlib provides 'MAXSEG_64K' which, if defined, indicates the + * same limit and pngconf.h (already included) sets the limit + * if certain operating systems are detected. + */ +#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) +# define PNG_MAX_MALLOC_64K +#endif + +#ifndef PNG_UNUSED +/* Unused formal parameter warnings are silenced using the following macro + * which is expected to have no bad effects on performance (optimizing + * compilers will probably remove it entirely). Note that if you replace + * it with something other than whitespace, you must include the terminating + * semicolon. + */ +# define PNG_UNUSED(param) (void)param; +#endif + +/* Just a little check that someone hasn't tried to define something + * contradictory. + */ +#if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K) +# undef PNG_ZBUF_SIZE +# define PNG_ZBUF_SIZE 65536L +#endif + +/* If warnings or errors are turned off the code is disabled or redirected here. + * From 1.5.4 functions have been added to allow very limited formatting of + * error and warning messages - this code will also be disabled here. + */ +#ifdef PNG_WARNINGS_SUPPORTED +# define PNG_WARNING_PARAMETERS(p) png_warning_parameters p; +#else +# define png_warning(s1,s2) ((void)(s1)) +# define png_chunk_warning(s1,s2) ((void)(s1)) +# define png_warning_parameter(p,number,string) ((void)0) +# define png_warning_parameter_unsigned(p,number,format,value) ((void)0) +# define png_warning_parameter_signed(p,number,format,value) ((void)0) +# define png_formatted_warning(pp,p,message) ((void)(pp)) +# define PNG_WARNING_PARAMETERS(p) +#endif +#ifndef PNG_ERROR_TEXT_SUPPORTED +# define png_error(s1,s2) png_err(s1) +# define png_chunk_error(s1,s2) png_err(s1) +# define png_fixed_error(s1,s2) png_err(s1) +#endif + +/* C allows up-casts from (void*) to any pointer and (const void*) to any + * pointer to a const object. C++ regards this as a type error and requires an + * explicit, static, cast and provides the static_cast<> rune to ensure that + * const is not cast away. + */ +#ifdef __cplusplus +# define png_voidcast(type, value) static_cast(value) +# define png_constcast(type, value) const_cast(value) +# define png_aligncast(type, value) \ + static_cast(static_cast(value)) +# define png_aligncastconst(type, value) \ + static_cast(static_cast(value)) +#else +# define png_voidcast(type, value) (value) +# define png_constcast(type, value) ((type)(value)) +# define png_aligncast(type, value) ((void*)(value)) +# define png_aligncastconst(type, value) ((const void*)(value)) +#endif /* __cplusplus */ + +/* Some fixed point APIs are still required even if not exported because + * they get used by the corresponding floating point APIs. This magic + * deals with this: + */ +#ifdef PNG_FIXED_POINT_SUPPORTED +# define PNGFAPI PNGAPI +#else +# define PNGFAPI /* PRIVATE */ +#endif + +#ifndef PNG_VERSION_INFO_ONLY +/* Other defines specific to compilers can go here. Try to keep + * them inside an appropriate ifdef/endif pair for portability. + */ +#if defined(PNG_FLOATING_POINT_SUPPORTED) ||\ + defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) + /* png.c requires the following ANSI-C constants if the conversion of + * floating point to ASCII is implemented therein: + * + * DBL_DIG Maximum number of decimal digits (can be set to any constant) + * DBL_MIN Smallest normalized fp number (can be set to an arbitrary value) + * DBL_MAX Maximum floating point number (can be set to an arbitrary value) + */ +# include + +# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \ + defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC) + /* We need to check that hasn't already been included earlier + * as it seems it doesn't agree with , yet we should really use + * if possible. + */ +# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__) +# include +# endif +# else +# include +# endif +# if defined(_AMIGA) && defined(__SASC) && defined(_M68881) + /* Amiga SAS/C: We must include builtin FPU functions when compiling using + * MATH=68881 + */ +# include +# endif +#endif + +/* This provides the non-ANSI (far) memory allocation routines. */ +#if defined(__TURBOC__) && defined(__MSDOS__) +# include +# include +#endif + +#if defined(WIN32) || defined(_Windows) || defined(_WINDOWS) || \ + defined(_WIN32) || defined(__WIN32__) +# include /* defines _WINDOWS_ macro */ +#endif +#endif /* PNG_VERSION_INFO_ONLY */ + +/* Moved here around 1.5.0beta36 from pngconf.h */ +/* Users may want to use these so they are not private. Any library + * functions that are passed far data must be model-independent. + */ + +/* Memory model/platform independent fns */ +#ifndef PNG_ABORT +# ifdef _WINDOWS_ +# define PNG_ABORT() ExitProcess(0) +# else +# define PNG_ABORT() abort() +# endif +#endif + +/* These macros may need to be architecture dependent. */ +#define PNG_ALIGN_NONE 0 /* do not use data alignment */ +#define PNG_ALIGN_ALWAYS 1 /* assume unaligned accesses are OK */ +#ifdef offsetof +# define PNG_ALIGN_OFFSET 2 /* use offsetof to determine alignment */ +#else +# define PNG_ALIGN_OFFSET -1 /* prevent the use of this */ +#endif +#define PNG_ALIGN_SIZE 3 /* use sizeof to determine alignment */ + +#ifndef PNG_ALIGN_TYPE + /* Default to using aligned access optimizations and requiring alignment to a + * multiple of the data type size. Override in a compiler specific fashion + * if necessary by inserting tests here: + */ +# define PNG_ALIGN_TYPE PNG_ALIGN_SIZE +#endif + +#if PNG_ALIGN_TYPE == PNG_ALIGN_SIZE + /* This is used because in some compiler implementations non-aligned + * structure members are supported, so the offsetof approach below fails. + * Set PNG_ALIGN_SIZE=0 for compiler combinations where unaligned access + * is good for performance. Do not do this unless you have tested the result + * and understand it. + */ +# define png_alignof(type) (sizeof (type)) +#else +# if PNG_ALIGN_TYPE == PNG_ALIGN_OFFSET +# define png_alignof(type) offsetof(struct{char c; type t;}, t) +# else +# if PNG_ALIGN_TYPE == PNG_ALIGN_ALWAYS +# define png_alignof(type) (1) +# endif + /* Else leave png_alignof undefined to prevent use thereof */ +# endif +#endif + +/* This implicitly assumes alignment is always to a power of 2. */ +#ifdef png_alignof +# define png_isaligned(ptr, type)\ + ((((const char*)ptr-(const char*)0) & (png_alignof(type)-1)) == 0) +#else +# define png_isaligned(ptr, type) 0 +#endif + +/* End of memory model/platform independent support */ +/* End of 1.5.0beta36 move from pngconf.h */ + +/* CONSTANTS and UTILITY MACROS + * These are used internally by libpng and not exposed in the API + */ + +/* Various modes of operation. Note that after an init, mode is set to + * zero automatically when the structure is created. Three of these + * are defined in png.h because they need to be visible to applications + * that call png_set_unknown_chunk(). + */ +/* #define PNG_HAVE_IHDR 0x01 (defined in png.h) */ +/* #define PNG_HAVE_PLTE 0x02 (defined in png.h) */ +#define PNG_HAVE_IDAT 0x04 +/* #define PNG_AFTER_IDAT 0x08 (defined in png.h) */ +#define PNG_HAVE_IEND 0x10 + /* 0x20 (unused) */ + /* 0x40 (unused) */ + /* 0x80 (unused) */ +#define PNG_HAVE_CHUNK_HEADER 0x100 +#define PNG_WROTE_tIME 0x200 +#define PNG_WROTE_INFO_BEFORE_PLTE 0x400 +#define PNG_BACKGROUND_IS_GRAY 0x800 +#define PNG_HAVE_PNG_SIGNATURE 0x1000 +#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */ + /* 0x4000 (unused) */ +#define PNG_IS_READ_STRUCT 0x8000 /* Else is a write struct */ + +/* Flags for the transformations the PNG library does on the image data */ +#define PNG_BGR 0x0001 +#define PNG_INTERLACE 0x0002 +#define PNG_PACK 0x0004 +#define PNG_SHIFT 0x0008 +#define PNG_SWAP_BYTES 0x0010 +#define PNG_INVERT_MONO 0x0020 +#define PNG_QUANTIZE 0x0040 +#define PNG_COMPOSE 0x0080 /* Was PNG_BACKGROUND */ +#define PNG_BACKGROUND_EXPAND 0x0100 +#define PNG_EXPAND_16 0x0200 /* Added to libpng 1.5.2 */ +#define PNG_16_TO_8 0x0400 /* Becomes 'chop' in 1.5.4 */ +#define PNG_RGBA 0x0800 +#define PNG_EXPAND 0x1000 +#define PNG_GAMMA 0x2000 +#define PNG_GRAY_TO_RGB 0x4000 +#define PNG_FILLER 0x8000 +#define PNG_PACKSWAP 0x10000 +#define PNG_SWAP_ALPHA 0x20000 +#define PNG_STRIP_ALPHA 0x40000 +#define PNG_INVERT_ALPHA 0x80000 +#define PNG_USER_TRANSFORM 0x100000 +#define PNG_RGB_TO_GRAY_ERR 0x200000 +#define PNG_RGB_TO_GRAY_WARN 0x400000 +#define PNG_RGB_TO_GRAY 0x600000 /* two bits, RGB_TO_GRAY_ERR|WARN */ +#define PNG_ENCODE_ALPHA 0x800000 /* Added to libpng-1.5.4 */ +#define PNG_ADD_ALPHA 0x1000000 /* Added to libpng-1.2.7 */ +#define PNG_EXPAND_tRNS 0x2000000 /* Added to libpng-1.2.9 */ +#define PNG_SCALE_16_TO_8 0x4000000 /* Added to libpng-1.5.4 */ + /* 0x8000000 unused */ + /* 0x10000000 unused */ + /* 0x20000000 unused */ + /* 0x40000000 unused */ +/* Flags for png_create_struct */ +#define PNG_STRUCT_PNG 0x0001 +#define PNG_STRUCT_INFO 0x0002 + +/* Scaling factor for filter heuristic weighting calculations */ +#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT)) +#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT)) + +/* Flags for the png_ptr->flags rather than declaring a byte for each one */ +#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001 +#define PNG_FLAG_ZSTREAM_INITIALIZED 0x0002 /* Added to libpng-1.6.0 */ + /* 0x0004 unused */ +#define PNG_FLAG_ZSTREAM_ENDED 0x0008 /* Added to libpng-1.6.0 */ + /* 0x0010 unused */ + /* 0x0020 unused */ +#define PNG_FLAG_ROW_INIT 0x0040 +#define PNG_FLAG_FILLER_AFTER 0x0080 +#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100 +#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200 +#define PNG_FLAG_CRC_CRITICAL_USE 0x0400 +#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 +#define PNG_FLAG_ASSUME_sRGB 0x1000 /* Added to libpng-1.5.4 */ +#define PNG_FLAG_OPTIMIZE_ALPHA 0x2000 /* Added to libpng-1.5.4 */ +#define PNG_FLAG_DETECT_UNINITIALIZED 0x4000 /* Added to libpng-1.5.4 */ +/* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000 */ +/* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000 */ +#define PNG_FLAG_LIBRARY_MISMATCH 0x20000 +#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000 +#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000 +#define PNG_FLAG_BENIGN_ERRORS_WARN 0x100000 /* Added to libpng-1.4.0 */ +#define PNG_FLAG_APP_WARNINGS_WARN 0x200000 /* Added to libpng-1.6.0 */ +#define PNG_FLAG_APP_ERRORS_WARN 0x400000 /* Added to libpng-1.6.0 */ + /* 0x800000 unused */ + /* 0x1000000 unused */ + /* 0x2000000 unused */ + /* 0x4000000 unused */ + /* 0x8000000 unused */ + /* 0x10000000 unused */ + /* 0x20000000 unused */ + /* 0x40000000 unused */ + +#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ + PNG_FLAG_CRC_ANCILLARY_NOWARN) + +#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \ + PNG_FLAG_CRC_CRITICAL_IGNORE) + +#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \ + PNG_FLAG_CRC_CRITICAL_MASK) + +/* Save typing and make code easier to understand */ + +#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \ + abs((int)((c1).green) - (int)((c2).green)) + \ + abs((int)((c1).blue) - (int)((c2).blue))) + +/* Added to libpng-1.6.0: scale a 16-bit value in the range 0..65535 to 0..255 + * by dividing by 257 *with rounding*. This macro is exact for the given range. + * See the discourse in pngrtran.c png_do_scale_16_to_8. The values in the + * macro were established by experiment (modifying the added value). The macro + * has a second variant that takes a value already scaled by 255 and divides by + * 65535 - this has a maximum error of .502. Over the range 0..65535*65535 it + * only gives off-by-one errors and only for 0.5% (1 in 200) of the values. + */ +#define PNG_DIV65535(v24) (((v24) + 32895) >> 16) +#define PNG_DIV257(v16) PNG_DIV65535((png_uint_32)(v16) * 255) + +/* Added to libpng-1.2.6 JB */ +#define PNG_ROWBYTES(pixel_bits, width) \ + ((pixel_bits) >= 8 ? \ + ((png_size_t)(width) * (((png_size_t)(pixel_bits)) >> 3)) : \ + (( ((png_size_t)(width) * ((png_size_t)(pixel_bits))) + 7) >> 3) ) + +/* PNG_OUT_OF_RANGE returns true if value is outside the range + * ideal-delta..ideal+delta. Each argument is evaluated twice. + * "ideal" and "delta" should be constants, normally simple + * integers, "value" a variable. Added to libpng-1.2.6 JB + */ +#define PNG_OUT_OF_RANGE(value, ideal, delta) \ + ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) ) + +/* Conversions between fixed and floating point, only defined if + * required (to make sure the code doesn't accidentally use float + * when it is supposedly disabled.) + */ +#ifdef PNG_FLOATING_POINT_SUPPORTED +/* The floating point conversion can't overflow, though it can and + * does lose accuracy relative to the original fixed point value. + * In practice this doesn't matter because png_fixed_point only + * stores numbers with very low precision. The png_ptr and s + * arguments are unused by default but are there in case error + * checking becomes a requirement. + */ +#define png_float(png_ptr, fixed, s) (.00001 * (fixed)) + +/* The fixed point conversion performs range checking and evaluates + * its argument multiple times, so must be used with care. The + * range checking uses the PNG specification values for a signed + * 32 bit fixed point value except that the values are deliberately + * rounded-to-zero to an integral value - 21474 (21474.83 is roughly + * (2^31-1) * 100000). 's' is a string that describes the value being + * converted. + * + * NOTE: this macro will raise a png_error if the range check fails, + * therefore it is normally only appropriate to use this on values + * that come from API calls or other sources where an out of range + * error indicates a programming error, not a data error! + * + * NOTE: by default this is off - the macro is not used - because the + * function call saves a lot of code. + */ +#ifdef PNG_FIXED_POINT_MACRO_SUPPORTED +#define png_fixed(png_ptr, fp, s) ((fp) <= 21474 && (fp) >= -21474 ?\ + ((png_fixed_point)(100000 * (fp))) : (png_fixed_error(png_ptr, s),0)) +#endif +/* else the corresponding function is defined below, inside the scope of the + * cplusplus test. + */ +#endif + +/* Constants for known chunk types. If you need to add a chunk, define the name + * here. For historical reasons these constants have the form png_; i.e. + * the prefix is lower case. Please use decimal values as the parameters to + * match the ISO PNG specification and to avoid relying on the C locale + * interpretation of character values. + * + * Prior to 1.5.6 these constants were strings, as of 1.5.6 png_uint_32 values + * are computed and a new macro (PNG_STRING_FROM_CHUNK) added to allow a string + * to be generated if required. + * + * PNG_32b correctly produces a value shifted by up to 24 bits, even on + * architectures where (int) is only 16 bits. + */ +#define PNG_32b(b,s) ((png_uint_32)(b) << (s)) +#define PNG_U32(b1,b2,b3,b4) \ + (PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0)) + +/* Constants for known chunk types. + * + * MAINTAINERS: If you need to add a chunk, define the name here. + * For historical reasons these constants have the form png_; i.e. + * the prefix is lower case. Please use decimal values as the parameters to + * match the ISO PNG specification and to avoid relying on the C locale + * interpretation of character values. Please keep the list sorted. + * + * Notice that PNG_U32 is used to define a 32-bit value for the 4 byte chunk + * type. In fact the specification does not express chunk types this way, + * however using a 32-bit value means that the chunk type can be read from the + * stream using exactly the same code as used for a 32-bit unsigned value and + * can be examined far more efficiently (using one arithmetic compare). + * + * Prior to 1.5.6 the chunk type constants were expressed as C strings. The + * libpng API still uses strings for 'unknown' chunks and a macro, + * PNG_STRING_FROM_CHUNK, allows a string to be generated if required. Notice + * that for portable code numeric values must still be used; the string "IHDR" + * is not portable and neither is PNG_U32('I', 'H', 'D', 'R'). + * + * In 1.7.0 the definitions will be made public in png.h to avoid having to + * duplicate the same definitions in application code. + */ +#define png_IDAT PNG_U32( 73, 68, 65, 84) +#define png_IEND PNG_U32( 73, 69, 78, 68) +#define png_IHDR PNG_U32( 73, 72, 68, 82) +#define png_PLTE PNG_U32( 80, 76, 84, 69) +#define png_bKGD PNG_U32( 98, 75, 71, 68) +#define png_cHRM PNG_U32( 99, 72, 82, 77) +#define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */ +#define png_gAMA PNG_U32(103, 65, 77, 65) +#define png_gIFg PNG_U32(103, 73, 70, 103) +#define png_gIFt PNG_U32(103, 73, 70, 116) /* deprecated */ +#define png_gIFx PNG_U32(103, 73, 70, 120) +#define png_hIST PNG_U32(104, 73, 83, 84) +#define png_iCCP PNG_U32(105, 67, 67, 80) +#define png_iTXt PNG_U32(105, 84, 88, 116) +#define png_oFFs PNG_U32(111, 70, 70, 115) +#define png_pCAL PNG_U32(112, 67, 65, 76) +#define png_pHYs PNG_U32(112, 72, 89, 115) +#define png_sBIT PNG_U32(115, 66, 73, 84) +#define png_sCAL PNG_U32(115, 67, 65, 76) +#define png_sPLT PNG_U32(115, 80, 76, 84) +#define png_sRGB PNG_U32(115, 82, 71, 66) +#define png_sTER PNG_U32(115, 84, 69, 82) +#define png_tEXt PNG_U32(116, 69, 88, 116) +#define png_tIME PNG_U32(116, 73, 77, 69) +#define png_tRNS PNG_U32(116, 82, 78, 83) +#define png_zTXt PNG_U32(122, 84, 88, 116) + +/* The following will work on (signed char*) strings, whereas the get_uint_32 + * macro will fail on top-bit-set values because of the sign extension. + */ +#define PNG_CHUNK_FROM_STRING(s)\ + PNG_U32(0xff&(s)[0], 0xff&(s)[1], 0xff&(s)[2], 0xff&(s)[3]) + +/* This uses (char), not (png_byte) to avoid warnings on systems where (char) is + * signed and the argument is a (char[]) This macro will fail miserably on + * systems where (char) is more than 8 bits. + */ +#define PNG_STRING_FROM_CHUNK(s,c)\ + (void)(((char*)(s))[0]=(char)((c)>>24), ((char*)(s))[1]=(char)((c)>>16),\ + ((char*)(s))[2]=(char)((c)>>8), ((char*)(s))[3]=(char)((c))) + +/* Do the same but terminate with a null character. */ +#define PNG_CSTRING_FROM_CHUNK(s,c)\ + (void)(PNG_STRING_FROM_CHUNK(s,c), ((char*)(s))[4] = 0) + +/* Test on flag values as defined in the spec (section 5.4): */ +#define PNG_CHUNK_ANCILLARY(c) (1 & ((c) >> 29)) +#define PNG_CHUNK_CRITICAL(c) (!PNG_CHUNK_ANCILLARY(c)) +#define PNG_CHUNK_PRIVATE(c) (1 & ((c) >> 21)) +#define PNG_CHUNK_RESERVED(c) (1 & ((c) >> 13)) +#define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >> 5)) + +/* Gamma values (new at libpng-1.5.4): */ +#define PNG_GAMMA_MAC_OLD 151724 /* Assume '1.8' is really 2.2/1.45! */ +#define PNG_GAMMA_MAC_INVERSE 65909 +#define PNG_GAMMA_sRGB_INVERSE 45455 + +/* Almost everything below is C specific; the #defines above can be used in + * non-C code (so long as it is C-preprocessed) the rest of this stuff cannot. + */ +#ifndef PNG_VERSION_INFO_ONLY + +#include "pngstruct.h" +#include "pnginfo.h" + +/* Validate the include paths - the include path used to generate pnglibconf.h + * must match that used in the build, or we must be using pnglibconf.h.prebuilt: + */ +#if PNG_ZLIB_VERNUM != 0 && PNG_ZLIB_VERNUM != ZLIB_VERNUM +# error ZLIB_VERNUM != PNG_ZLIB_VERNUM \ + "-I (include path) error: see the notes in pngpriv.h" + /* This means that when pnglibconf.h was built the copy of zlib.h that it + * used is not the same as the one being used here. Because the build of + * libpng makes decisions to use inflateInit2 and inflateReset2 based on the + * zlib version number and because this affects handling of certain broken + * PNG files the -I directives must match. + * + * The most likely explanation is that you passed a -I in CFLAGS, this will + * not work; all the preprocessor directories and in particular all the -I + * directives must be in CPPFLAGS. + */ +#endif + +/* This is used for 16 bit gamma tables -- only the top level pointers are + * const; this could be changed: + */ +typedef const png_uint_16p * png_const_uint_16pp; + +/* Added to libpng-1.5.7: sRGB conversion tables */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +#ifdef PNG_SIMPLIFIED_READ_SUPPORTED +PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_table, [256]); + /* Convert from an sRGB encoded value 0..255 to a 16-bit linear value, + * 0..65535. This table gives the closest 16-bit answers (no errors). + */ +#endif + +PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_base, [512]); +PNG_INTERNAL_DATA(const png_byte, png_sRGB_delta, [512]); + +#define PNG_sRGB_FROM_LINEAR(linear) ((png_byte)((png_sRGB_base[(linear)>>15] +\ + ((((linear)&0x7fff)*png_sRGB_delta[(linear)>>15])>>12)) >> 8)) + /* Given a value 'linear' in the range 0..255*65535 calculate the 8-bit sRGB + * encoded value with maximum error 0.646365. Note that the input is not a + * 16-bit value; it has been multiplied by 255! */ +#endif /* PNG_SIMPLIFIED_READ/WRITE */ + + +/* Inhibit C++ name-mangling for libpng functions but not for system calls. */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Internal functions; these are not exported from a DLL however because they + * are used within several of the C source files they have to be C extern. + * + * All of these functions must be declared with PNG_INTERNAL_FUNCTION. + */ + +/* Zlib support */ +#define PNG_UNEXPECTED_ZLIB_RETURN (-7) +PNG_INTERNAL_FUNCTION(void, png_zstream_error,(png_structrp png_ptr, int ret), + PNG_EMPTY); + /* Used by the zlib handling functions to ensure that z_stream::msg is always + * set before they return. + */ + +#ifdef PNG_WRITE_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr, + png_compression_bufferp *list),PNG_EMPTY); + /* Free the buffer list used by the compressed write code. */ +#endif + +#if defined(PNG_FLOATING_POINT_SUPPORTED) && \ + !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ + (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \ + defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \ + (defined(PNG_sCAL_SUPPORTED) && \ + defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)) +PNG_INTERNAL_FUNCTION(png_fixed_point,png_fixed,(png_const_structrp png_ptr, + double fp, png_const_charp text),PNG_EMPTY); +#endif + +/* Check the user version string for compatibility, returns false if the version + * numbers aren't compatible. + */ +PNG_INTERNAL_FUNCTION(int,png_user_version_check,(png_structrp png_ptr, + png_const_charp user_png_ver),PNG_EMPTY); + +/* Internal base allocator - no messages, NULL on failure to allocate. This + * does, however, call the application provided allocator and that could call + * png_error (although that would be a bug in the application implementation.) + */ +PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_base,(png_const_structrp png_ptr, + png_alloc_size_t size),PNG_ALLOCATED); + +#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\ + defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) +/* Internal array allocator, outputs no error or warning messages on failure, + * just returns NULL. + */ +PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_array,(png_const_structrp png_ptr, + int nelements, size_t element_size),PNG_ALLOCATED); + +/* The same but an existing array is extended by add_elements. This function + * also memsets the new elements to 0 and copies the old elements. The old + * array is not freed or altered. + */ +PNG_INTERNAL_FUNCTION(png_voidp,png_realloc_array,(png_const_structrp png_ptr, + png_const_voidp array, int old_elements, int add_elements, + size_t element_size),PNG_ALLOCATED); +#endif /* text, sPLT or unknown chunks */ + +/* Magic to create a struct when there is no struct to call the user supplied + * memory allocators. Because error handling has not been set up the memory + * handlers can't safely call png_error, but this is an obscure and undocumented + * restriction so libpng has to assume that the 'free' handler, at least, might + * call png_error. + */ +PNG_INTERNAL_FUNCTION(png_structp,png_create_png_struct, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, + png_free_ptr free_fn),PNG_ALLOCATED); + +/* Free memory from internal libpng struct */ +PNG_INTERNAL_FUNCTION(void,png_destroy_png_struct,(png_structrp png_ptr), + PNG_EMPTY); + +/* Free an allocated jmp_buf (always succeeds) */ +PNG_INTERNAL_FUNCTION(void,png_free_jmpbuf,(png_structrp png_ptr),PNG_EMPTY); + +/* Function to allocate memory for zlib. PNGAPI is disallowed. */ +PNG_INTERNAL_FUNCTION(voidpf,png_zalloc,(voidpf png_ptr, uInt items, uInt size), + PNG_ALLOCATED); + +/* Function to free memory for zlib. PNGAPI is disallowed. */ +PNG_INTERNAL_FUNCTION(void,png_zfree,(voidpf png_ptr, voidpf ptr),PNG_EMPTY); + +/* Next four functions are used internally as callbacks. PNGCBAPI is required + * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3, changed to + * PNGCBAPI at 1.5.0 + */ + +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_read_data,(png_structp png_ptr, + png_bytep data, png_size_t length),PNG_EMPTY); + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_push_fill_buffer,(png_structp png_ptr, + png_bytep buffer, png_size_t length),PNG_EMPTY); +#endif + +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_write_data,(png_structp png_ptr, + png_bytep data, png_size_t length),PNG_EMPTY); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +# ifdef PNG_STDIO_SUPPORTED +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_flush,(png_structp png_ptr), + PNG_EMPTY); +# endif +#endif + +/* Reset the CRC variable */ +PNG_INTERNAL_FUNCTION(void,png_reset_crc,(png_structrp png_ptr),PNG_EMPTY); + +/* Write the "data" buffer to whatever output you are using */ +PNG_INTERNAL_FUNCTION(void,png_write_data,(png_structrp png_ptr, + png_const_bytep data, png_size_t length),PNG_EMPTY); + +/* Read and check the PNG file signature */ +PNG_INTERNAL_FUNCTION(void,png_read_sig,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); + +/* Read the chunk header (length + type name) */ +PNG_INTERNAL_FUNCTION(png_uint_32,png_read_chunk_header,(png_structrp png_ptr), + PNG_EMPTY); + +/* Read data from whatever input you are using into the "data" buffer */ +PNG_INTERNAL_FUNCTION(void,png_read_data,(png_structrp png_ptr, png_bytep data, + png_size_t length),PNG_EMPTY); + +/* Read bytes into buf, and update png_ptr->crc */ +PNG_INTERNAL_FUNCTION(void,png_crc_read,(png_structrp png_ptr, png_bytep buf, + png_uint_32 length),PNG_EMPTY); + +/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */ +PNG_INTERNAL_FUNCTION(int,png_crc_finish,(png_structrp png_ptr, + png_uint_32 skip),PNG_EMPTY); + +/* Read the CRC from the file and compare it to the libpng calculated CRC */ +PNG_INTERNAL_FUNCTION(int,png_crc_error,(png_structrp png_ptr),PNG_EMPTY); + +/* Calculate the CRC over a section of data. Note that we are only + * passing a maximum of 64K on systems that have this as a memory limit, + * since this is the maximum buffer size we can specify. + */ +PNG_INTERNAL_FUNCTION(void,png_calculate_crc,(png_structrp png_ptr, + png_const_bytep ptr, png_size_t length),PNG_EMPTY); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_flush,(png_structrp png_ptr),PNG_EMPTY); +#endif + +/* Write various chunks */ + +/* Write the IHDR chunk, and update the png_struct with the necessary + * information. + */ +PNG_INTERNAL_FUNCTION(void,png_write_IHDR,(png_structrp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, + int compression_method, int filter_method, int interlace_method),PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_write_PLTE,(png_structrp png_ptr, + png_const_colorp palette, png_uint_32 num_pal),PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_compress_IDAT,(png_structrp png_ptr, + png_const_bytep row_data, png_alloc_size_t row_data_length, int flush), + PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_write_IEND,(png_structrp png_ptr),PNG_EMPTY); + +#ifdef PNG_WRITE_gAMA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_gAMA_fixed,(png_structrp png_ptr, + png_fixed_point file_gamma),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_sBIT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_sBIT,(png_structrp png_ptr, + png_const_color_8p sbit, int color_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_cHRM_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_cHRM_fixed,(png_structrp png_ptr, + const png_xy *xy), PNG_EMPTY); + /* The xy value must have been previously validated */ +#endif + +#ifdef PNG_WRITE_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr, + int intent),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_iCCP_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_iCCP,(png_structrp png_ptr, + png_const_charp name, png_const_bytep profile), PNG_EMPTY); + /* The profile must have been previously validated for correctness, the + * length comes from the first four bytes. Only the base, deflate, + * compression is supported. + */ +#endif + +#ifdef PNG_WRITE_sPLT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_sPLT,(png_structrp png_ptr, + png_const_sPLT_tp palette),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_tRNS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_tRNS,(png_structrp png_ptr, + png_const_bytep trans, png_const_color_16p values, int number, + int color_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_bKGD_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_bKGD,(png_structrp png_ptr, + png_const_color_16p values, int color_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_hIST_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_hIST,(png_structrp png_ptr, + png_const_uint_16p hist, int num_hist),PNG_EMPTY); +#endif + +/* Chunks that have keywords */ +#ifdef PNG_WRITE_tEXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_tEXt,(png_structrp png_ptr, + png_const_charp key, png_const_charp text, png_size_t text_len),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_zTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_zTXt,(png_structrp png_ptr, png_const_charp + key, png_const_charp text, png_size_t text_len, int compression),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_iTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_iTXt,(png_structrp png_ptr, + int compression, png_const_charp key, png_const_charp lang, + png_const_charp lang_key, png_const_charp text),PNG_EMPTY); +#endif + +#ifdef PNG_TEXT_SUPPORTED /* Added at version 1.0.14 and 1.2.4 */ +PNG_INTERNAL_FUNCTION(int,png_set_text_2,(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_textp text_ptr, int num_text),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_oFFs_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_oFFs,(png_structrp png_ptr, + png_int_32 x_offset, png_int_32 y_offset, int unit_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_pCAL_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_pCAL,(png_structrp png_ptr, + png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, + png_const_charp units, png_charpp params),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_pHYs_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_pHYs,(png_structrp png_ptr, + png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, + int unit_type),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_tIME_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_tIME,(png_structrp png_ptr, + png_const_timep mod_time),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_sCAL_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_write_sCAL_s,(png_structrp png_ptr, + int unit, png_const_charp width, png_const_charp height),PNG_EMPTY); +#endif + +/* Called when finished processing a row of data */ +PNG_INTERNAL_FUNCTION(void,png_write_finish_row,(png_structrp png_ptr), + PNG_EMPTY); + +/* Internal use only. Called before first row of data */ +PNG_INTERNAL_FUNCTION(void,png_write_start_row,(png_structrp png_ptr), + PNG_EMPTY); + +/* Combine a row of data, dealing with alpha, etc. if requested. 'row' is an + * array of png_ptr->width pixels. If the image is not interlaced or this + * is the final pass this just does a memcpy, otherwise the "display" flag + * is used to determine whether to copy pixels that are not in the current pass. + * + * Because 'png_do_read_interlace' (below) replicates pixels this allows this + * function to achieve the documented 'blocky' appearance during interlaced read + * if display is 1 and the 'sparkle' appearance, where existing pixels in 'row' + * are not changed if they are not in the current pass, when display is 0. + * + * 'display' must be 0 or 1, otherwise the memcpy will be done regardless. + * + * The API always reads from the png_struct row buffer and always assumes that + * it is full width (png_do_read_interlace has already been called.) + * + * This function is only ever used to write to row buffers provided by the + * caller of the relevant libpng API and the row must have already been + * transformed by the read transformations. + * + * The PNG_USE_COMPILE_TIME_MASKS option causes generation of pre-computed + * bitmasks for use within the code, otherwise runtime generated masks are used. + * The default is compile time masks. + */ +#ifndef PNG_USE_COMPILE_TIME_MASKS +# define PNG_USE_COMPILE_TIME_MASKS 1 +#endif +PNG_INTERNAL_FUNCTION(void,png_combine_row,(png_const_structrp png_ptr, + png_bytep row, int display),PNG_EMPTY); + +#ifdef PNG_READ_INTERLACING_SUPPORTED +/* Expand an interlaced row: the 'row_info' describes the pass data that has + * been read in and must correspond to the pixels in 'row', the pixels are + * expanded (moved apart) in 'row' to match the final layout, when doing this + * the pixels are *replicated* to the intervening space. This is essential for + * the correct operation of png_combine_row, above. + */ +PNG_INTERNAL_FUNCTION(void,png_do_read_interlace,(png_row_infop row_info, + png_bytep row, int pass, png_uint_32 transformations),PNG_EMPTY); +#endif + +/* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ + +#ifdef PNG_WRITE_INTERLACING_SUPPORTED +/* Grab pixels out of a row for an interlaced pass */ +PNG_INTERNAL_FUNCTION(void,png_do_write_interlace,(png_row_infop row_info, + png_bytep row, int pass),PNG_EMPTY); +#endif + +/* Unfilter a row: check the filter value before calling this, there is no point + * calling it for PNG_FILTER_VALUE_NONE. + */ +PNG_INTERNAL_FUNCTION(void,png_read_filter_row,(png_structrp pp, png_row_infop + row_info, png_bytep row, png_const_bytep prev_row, int filter),PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_neon,(png_row_infop row_info, + png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); + +/* Choose the best filter to use and filter the row data */ +PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); + +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_read_IDAT_data,(png_structrp png_ptr, + png_bytep output, png_alloc_size_t avail_out),PNG_EMPTY); + /* Read 'avail_out' bytes of data from the IDAT stream. If the output buffer + * is NULL the function checks, instead, for the end of the stream. In this + * case a benign error will be issued if the stream end is not found or if + * extra data has to be consumed. + */ +PNG_INTERNAL_FUNCTION(void,png_read_finish_IDAT,(png_structrp png_ptr), + PNG_EMPTY); + /* This cleans up when the IDAT LZ stream does not end when the last image + * byte is read; there is still some pending input. + */ + +PNG_INTERNAL_FUNCTION(void,png_read_finish_row,(png_structrp png_ptr), + PNG_EMPTY); + /* Finish a row while reading, dealing with interlacing passes, etc. */ +#endif + +/* Initialize the row buffers, etc. */ +PNG_INTERNAL_FUNCTION(void,png_read_start_row,(png_structrp png_ptr),PNG_EMPTY); + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +/* Optional call to update the users info structure */ +PNG_INTERNAL_FUNCTION(void,png_read_transform_info,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +#endif + +/* These are the functions that do the transformations */ +#ifdef PNG_READ_FILLER_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_read_filler,(png_row_infop row_info, + png_bytep row, png_uint_32 filler, png_uint_32 flags),PNG_EMPTY); +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_read_swap_alpha,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_write_swap_alpha,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_read_invert_alpha,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_write_invert_alpha,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ + defined(PNG_READ_STRIP_ALPHA_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_strip_channel,(png_row_infop row_info, + png_bytep row, int at_start),PNG_EMPTY); +#endif + +#ifdef PNG_16BIT_SUPPORTED +#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_swap,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif +#endif + +#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ + defined(PNG_WRITE_PACKSWAP_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_packswap,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_do_rgb_to_gray,(png_structrp png_ptr, + png_row_infop row_info, png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_gray_to_rgb,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_PACK_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_unpack,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_unshift,(png_row_infop row_info, + png_bytep row, png_const_color_8p sig_bits),PNG_EMPTY); +#endif + +#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_invert,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_scale_16_to_8,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_chop,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_quantize,(png_row_infop row_info, + png_bytep row, png_const_bytep palette_lookup, + png_const_bytep quantize_lookup),PNG_EMPTY); + +# ifdef PNG_CORRECT_PALETTE_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_correct_palette,(png_structrp png_ptr, + png_colorp palette, int num_palette),PNG_EMPTY); +# endif +#endif + +#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_bgr,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_PACK_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_pack,(png_row_infop row_info, + png_bytep row, png_uint_32 bit_depth),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_shift,(png_row_infop row_info, + png_bytep row, png_const_color_8p bit_depth),PNG_EMPTY); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_compose,(png_row_infop row_info, + png_bytep row, png_structrp png_ptr),PNG_EMPTY); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_gamma,(png_row_infop row_info, + png_bytep row, png_structrp png_ptr),PNG_EMPTY); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_encode_alpha,(png_row_infop row_info, + png_bytep row, png_structrp png_ptr),PNG_EMPTY); +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_expand_palette,(png_row_infop row_info, + png_bytep row, png_const_colorp palette, png_const_bytep trans, + int num_trans),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_do_expand,(png_row_infop row_info, + png_bytep row, png_const_color_16p trans_color),PNG_EMPTY); +#endif + +#ifdef PNG_READ_EXPAND_16_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_expand_16,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +/* The following decodes the appropriate chunks, and does error correction, + * then calls the appropriate callback for the chunk if it is valid. + */ + +/* Decode the IHDR chunk */ +PNG_INTERNAL_FUNCTION(void,png_handle_IHDR,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_handle_PLTE,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_handle_IEND,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); + +#ifdef PNG_READ_bKGD_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_bKGD,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_cHRM_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_cHRM,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_gAMA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_gAMA,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_hIST_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_hIST,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_iCCP_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_iCCP,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif /* PNG_READ_iCCP_SUPPORTED */ + +#ifdef PNG_READ_iTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_iTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_oFFs_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_oFFs,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_pCAL,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_pHYs_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_pHYs,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_sBIT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_sBIT,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_sCAL_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_sCAL,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_sPLT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_sPLT,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif /* PNG_READ_sPLT_SUPPORTED */ + +#ifdef PNG_READ_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_sRGB,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_tEXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_tEXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_tIME_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_tIME,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_tRNS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_tRNS,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_zTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_zTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +PNG_INTERNAL_FUNCTION(void,png_check_chunk_name,(png_structrp png_ptr, + png_uint_32 chunk_name),PNG_EMPTY); + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_unknown,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length, int keep),PNG_EMPTY); + /* This is the function that gets called for unknown chunks. The 'keep' + * argument is either non-zero for a known chunk that has been set to be + * handled as unknown or zero for an unknown chunk. By default the function + * just skips the chunk or errors out if it is critical. + */ + +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\ + defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) +PNG_INTERNAL_FUNCTION(int,png_chunk_unknown_handling, + (png_const_structrp png_ptr, png_uint_32 chunk_name),PNG_EMPTY); + /* Exactly as the API png_handle_as_unknown() except that the argument is a + * 32-bit chunk name, not a string. + */ +#endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */ +#endif /* PNG_SET_UNKNOWN_CHUNKS_SUPPORTED */ + +/* Handle the transformations for reading and writing */ +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_read_transformations,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); +#endif +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_write_transformations,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); +#endif + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_init_read_transformations,(png_structrp png_ptr), + PNG_EMPTY); +#endif + +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_read_chunk,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_sig,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_check_crc,(png_structrp png_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_crc_skip,(png_structrp png_ptr, + png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_crc_finish,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_save_buffer,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_restore_buffer,(png_structrp png_ptr, + png_bytep buffer, png_size_t buffer_length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_IDAT,(png_structrp png_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_process_IDAT_data,(png_structrp png_ptr, + png_bytep buffer, png_size_t buffer_length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_process_row,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_handle_unknown,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_info,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_end,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_row,(png_structrp png_ptr, + png_bytep row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_end,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_process_some_data,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_push_finish_row,(png_structrp png_ptr), + PNG_EMPTY); +# ifdef PNG_READ_tEXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_handle_tEXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_tEXt,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +# endif +# ifdef PNG_READ_zTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_handle_zTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_zTXt,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +# endif +# ifdef PNG_READ_iTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_handle_iTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_iTXt,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +# endif + +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +#ifdef PNG_MNG_FEATURES_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_read_intrapixel,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_do_write_intrapixel,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +/* Added at libpng version 1.6.0 */ +#ifdef PNG_GAMMA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_colorspace_set_gamma,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_fixed_point gAMA), PNG_EMPTY); + /* Set the colorspace gamma with a value provided by the application or by + * the gAMA chunk on read. The value will override anything set by an ICC + * profile. + */ + +PNG_INTERNAL_FUNCTION(void,png_colorspace_sync_info,(png_const_structrp png_ptr, + png_inforp info_ptr), PNG_EMPTY); + /* Synchronize the info 'valid' flags with the colorspace */ + +PNG_INTERNAL_FUNCTION(void,png_colorspace_sync,(png_const_structrp png_ptr, + png_inforp info_ptr), PNG_EMPTY); + /* Copy the png_struct colorspace to the info_struct and call the above to + * synchronize the flags. Checks for NULL info_ptr and does nothing. + */ +#endif + +/* Added at libpng version 1.4.0 */ +#ifdef PNG_COLORSPACE_SUPPORTED +/* These internal functions are for maintaining the colorspace structure within + * a png_info or png_struct (or, indeed, both). + */ +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_chromaticities, + (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_xy *xy, + int preferred), PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_endpoints, + (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_XYZ *XYZ, + int preferred), PNG_EMPTY); + +#ifdef PNG_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_sRGB,(png_const_structrp png_ptr, + png_colorspacerp colorspace, int intent), PNG_EMPTY); + /* This does set the colorspace gAMA and cHRM values too, but doesn't set the + * flags to write them, if it returns false there was a problem and an error + * message has already been output (but the colorspace may still need to be + * synced to record the invalid flag). + */ +#endif /* sRGB */ + +#ifdef PNG_iCCP_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_ICC,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length, png_const_bytep profile, int color_type), + PNG_EMPTY); + /* The 'name' is used for information only */ + +/* Routines for checking parts of an ICC profile. */ +PNG_INTERNAL_FUNCTION(int,png_icc_check_length,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length), PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_icc_check_header,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length, + png_const_bytep profile /* first 132 bytes only */, int color_type), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_icc_check_tag_table,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length, + png_const_bytep profile /* header plus whole tag table */), PNG_EMPTY); +#ifdef PNG_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_icc_set_sRGB,( + png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_bytep profile, uLong adler), PNG_EMPTY); + /* 'adler' is the Adler32 checksum of the uncompressed profile data. It may + * be zero to indicate that it is not available. It is used, if provided, + * as a fast check on the profile when checking to see if it is sRGB. + */ +#endif +#endif /* iCCP */ + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_colorspace_set_rgb_coefficients, + (png_structrp png_ptr), PNG_EMPTY); + /* Set the rgb_to_gray coefficients from the colorspace Y values */ +#endif /* READ_RGB_TO_GRAY */ +#endif /* COLORSPACE */ + +/* Added at libpng version 1.4.0 */ +PNG_INTERNAL_FUNCTION(void,png_check_IHDR,(png_const_structrp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type),PNG_EMPTY); + +/* Added at libpng version 1.5.10 */ +#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ + defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_check_palette_indexes, + (png_structrp png_ptr, png_row_infop row_info),PNG_EMPTY); +#endif + +#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_fixed_error,(png_const_structrp png_ptr, + png_const_charp name),PNG_NORETURN); +#endif + +/* Puts 'string' into 'buffer' at buffer[pos], taking care never to overwrite + * the end. Always leaves the buffer nul terminated. Never errors out (and + * there is no error code.) + */ +PNG_INTERNAL_FUNCTION(size_t,png_safecat,(png_charp buffer, size_t bufsize, + size_t pos, png_const_charp string),PNG_EMPTY); + +/* Various internal functions to handle formatted warning messages, currently + * only implemented for warnings. + */ +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED) +/* Utility to dump an unsigned value into a buffer, given a start pointer and + * and end pointer (which should point just *beyond* the end of the buffer!) + * Returns the pointer to the start of the formatted string. This utility only + * does unsigned values. + */ +PNG_INTERNAL_FUNCTION(png_charp,png_format_number,(png_const_charp start, + png_charp end, int format, png_alloc_size_t number),PNG_EMPTY); + +/* Convenience macro that takes an array: */ +#define PNG_FORMAT_NUMBER(buffer,format,number) \ + png_format_number(buffer, buffer + (sizeof buffer), format, number) + +/* Suggested size for a number buffer (enough for 64 bits and a sign!) */ +#define PNG_NUMBER_BUFFER_SIZE 24 + +/* These are the integer formats currently supported, the name is formed from + * the standard printf(3) format string. + */ +#define PNG_NUMBER_FORMAT_u 1 /* chose unsigned API! */ +#define PNG_NUMBER_FORMAT_02u 2 +#define PNG_NUMBER_FORMAT_d 1 /* chose signed API! */ +#define PNG_NUMBER_FORMAT_02d 2 +#define PNG_NUMBER_FORMAT_x 3 +#define PNG_NUMBER_FORMAT_02x 4 +#define PNG_NUMBER_FORMAT_fixed 5 /* choose the signed API */ +#endif + +#ifdef PNG_WARNINGS_SUPPORTED +/* New defines and members adding in libpng-1.5.4 */ +# define PNG_WARNING_PARAMETER_SIZE 32 +# define PNG_WARNING_PARAMETER_COUNT 8 /* Maximum 9; see pngerror.c */ + +/* An l-value of this type has to be passed to the APIs below to cache the + * values of the parameters to a formatted warning message. + */ +typedef char png_warning_parameters[PNG_WARNING_PARAMETER_COUNT][ + PNG_WARNING_PARAMETER_SIZE]; + +PNG_INTERNAL_FUNCTION(void,png_warning_parameter,(png_warning_parameters p, + int number, png_const_charp string),PNG_EMPTY); + /* Parameters are limited in size to PNG_WARNING_PARAMETER_SIZE characters, + * including the trailing '\0'. + */ +PNG_INTERNAL_FUNCTION(void,png_warning_parameter_unsigned, + (png_warning_parameters p, int number, int format, png_alloc_size_t value), + PNG_EMPTY); + /* Use png_alloc_size_t because it is an unsigned type as big as any we + * need to output. Use the following for a signed value. + */ +PNG_INTERNAL_FUNCTION(void,png_warning_parameter_signed, + (png_warning_parameters p, int number, int format, png_int_32 value), + PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_formatted_warning,(png_const_structrp png_ptr, + png_warning_parameters p, png_const_charp message),PNG_EMPTY); + /* 'message' follows the X/Open approach of using @1, @2 to insert + * parameters previously supplied using the above functions. Errors in + * specifying the parameters will simply result in garbage substitutions. + */ +#endif + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +/* Application errors (new in 1.6); use these functions (declared below) for + * errors in the parameters or order of API function calls on read. The + * 'warning' should be used for an error that can be handled completely; the + * 'error' for one which can be handled safely but which may lose application + * information or settings. + * + * By default these both result in a png_error call prior to release, while in a + * released version the 'warning' is just a warning. However if the application + * explicitly disables benign errors (explicitly permitting the code to lose + * information) they both turn into warnings. + * + * If benign errors aren't supported they end up as the corresponding base call + * (png_warning or png_error.) + */ +PNG_INTERNAL_FUNCTION(void,png_app_warning,(png_const_structrp png_ptr, + png_const_charp message),PNG_EMPTY); + /* The application provided invalid parameters to an API function or called + * an API function at the wrong time, libpng can completely recover. + */ + +PNG_INTERNAL_FUNCTION(void,png_app_error,(png_const_structrp png_ptr, + png_const_charp message),PNG_EMPTY); + /* As above but libpng will ignore the call, or attempt some other partial + * recovery from the error. + */ +#else +# define png_app_warning(pp,s) png_warning(pp,s) +# define png_app_error(pp,s) png_error(pp,s) +#endif + +PNG_INTERNAL_FUNCTION(void,png_chunk_report,(png_const_structrp png_ptr, + png_const_charp message, int error),PNG_EMPTY); + /* Report a recoverable issue in chunk data. On read this is used to report + * a problem found while reading a particular chunk and the + * png_chunk_benign_error or png_chunk_warning function is used as + * appropriate. On write this is used to report an error that comes from + * data set via an application call to a png_set_ API and png_app_error or + * png_app_warning is used as appropriate. + * + * The 'error' parameter must have one of the following values: + */ +#define PNG_CHUNK_WARNING 0 /* never an error */ +#define PNG_CHUNK_WRITE_ERROR 1 /* an error only on write */ +#define PNG_CHUNK_ERROR 2 /* always an error */ + +/* ASCII to FP interfaces, currently only implemented if sCAL + * support is required. + */ +#if defined(PNG_sCAL_SUPPORTED) +/* MAX_DIGITS is actually the maximum number of characters in an sCAL + * width or height, derived from the precision (number of significant + * digits - a build time settable option) and assumptions about the + * maximum ridiculous exponent. + */ +#define PNG_sCAL_MAX_DIGITS (PNG_sCAL_PRECISION+1/*.*/+1/*E*/+10/*exponent*/) + +#ifdef PNG_FLOATING_POINT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_ascii_from_fp,(png_const_structrp png_ptr, + png_charp ascii, png_size_t size, double fp, unsigned int precision), + PNG_EMPTY); +#endif /* FLOATING_POINT */ + +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr, + png_charp ascii, png_size_t size, png_fixed_point fp),PNG_EMPTY); +#endif /* FIXED_POINT */ +#endif /* sCAL */ + +#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) +/* An internal API to validate the format of a floating point number. + * The result is the index of the next character. If the number is + * not valid it will be the index of a character in the supposed number. + * + * The format of a number is defined in the PNG extensions specification + * and this API is strictly conformant to that spec, not anyone elses! + * + * The format as a regular expression is: + * + * [+-]?[0-9]+.?([Ee][+-]?[0-9]+)? + * + * or: + * + * [+-]?.[0-9]+(.[0-9]+)?([Ee][+-]?[0-9]+)? + * + * The complexity is that either integer or fraction must be present and the + * fraction is permitted to have no digits only if the integer is present. + * + * NOTE: The dangling E problem. + * There is a PNG valid floating point number in the following: + * + * PNG floating point numbers are not greedy. + * + * Working this out requires *TWO* character lookahead (because of the + * sign), the parser does not do this - it will fail at the 'r' - this + * doesn't matter for PNG sCAL chunk values, but it requires more care + * if the value were ever to be embedded in something more complex. Use + * ANSI-C strtod if you need the lookahead. + */ +/* State table for the parser. */ +#define PNG_FP_INTEGER 0 /* before or in integer */ +#define PNG_FP_FRACTION 1 /* before or in fraction */ +#define PNG_FP_EXPONENT 2 /* before or in exponent */ +#define PNG_FP_STATE 3 /* mask for the above */ +#define PNG_FP_SAW_SIGN 4 /* Saw +/- in current state */ +#define PNG_FP_SAW_DIGIT 8 /* Saw a digit in current state */ +#define PNG_FP_SAW_DOT 16 /* Saw a dot in current state */ +#define PNG_FP_SAW_E 32 /* Saw an E (or e) in current state */ +#define PNG_FP_SAW_ANY 60 /* Saw any of the above 4 */ + +/* These three values don't affect the parser. They are set but not used. + */ +#define PNG_FP_WAS_VALID 64 /* Preceding substring is a valid fp number */ +#define PNG_FP_NEGATIVE 128 /* A negative number, including "-0" */ +#define PNG_FP_NONZERO 256 /* A non-zero value */ +#define PNG_FP_STICKY 448 /* The above three flags */ + +/* This is available for the caller to store in 'state' if required. Do not + * call the parser after setting it (the parser sometimes clears it.) + */ +#define PNG_FP_INVALID 512 /* Available for callers as a distinct value */ + +/* Result codes for the parser (boolean - true meants ok, false means + * not ok yet.) + */ +#define PNG_FP_MAYBE 0 /* The number may be valid in the future */ +#define PNG_FP_OK 1 /* The number is valid */ + +/* Tests on the sticky non-zero and negative flags. To pass these checks + * the state must also indicate that the whole number is valid - this is + * achieved by testing PNG_FP_SAW_DIGIT (see the implementation for why this + * is equivalent to PNG_FP_OK above.) + */ +#define PNG_FP_NZ_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NEGATIVE | PNG_FP_NONZERO) + /* NZ_MASK: the string is valid and a non-zero negative value */ +#define PNG_FP_Z_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NONZERO) + /* Z MASK: the string is valid and a non-zero value. */ + /* PNG_FP_SAW_DIGIT: the string is valid. */ +#define PNG_FP_IS_ZERO(state) (((state) & PNG_FP_Z_MASK) == PNG_FP_SAW_DIGIT) +#define PNG_FP_IS_POSITIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_Z_MASK) +#define PNG_FP_IS_NEGATIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_NZ_MASK) + +/* The actual parser. This can be called repeatedly. It updates + * the index into the string and the state variable (which must + * be initialized to 0). It returns a result code, as above. There + * is no point calling the parser any more if it fails to advance to + * the end of the string - it is stuck on an invalid character (or + * terminated by '\0'). + * + * Note that the pointer will consume an E or even an E+ and then leave + * a 'maybe' state even though a preceding integer.fraction is valid. + * The PNG_FP_WAS_VALID flag indicates that a preceding substring was + * a valid number. It's possible to recover from this by calling + * the parser again (from the start, with state 0) but with a string + * that omits the last character (i.e. set the size to the index of + * the problem character.) This has not been tested within libpng. + */ +PNG_INTERNAL_FUNCTION(int,png_check_fp_number,(png_const_charp string, + png_size_t size, int *statep, png_size_tp whereami),PNG_EMPTY); + +/* This is the same but it checks a complete string and returns true + * only if it just contains a floating point number. As of 1.5.4 this + * function also returns the state at the end of parsing the number if + * it was valid (otherwise it returns 0.) This can be used for testing + * for negative or zero values using the sticky flag. + */ +PNG_INTERNAL_FUNCTION(int,png_check_fp_string,(png_const_charp string, + png_size_t size),PNG_EMPTY); +#endif /* pCAL || sCAL */ + +#if defined(PNG_READ_GAMMA_SUPPORTED) ||\ + defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED) +/* Added at libpng version 1.5.0 */ +/* This is a utility to provide a*times/div (rounded) and indicate + * if there is an overflow. The result is a boolean - false (0) + * for overflow, true (1) if no overflow, in which case *res + * holds the result. + */ +PNG_INTERNAL_FUNCTION(int,png_muldiv,(png_fixed_point_p res, png_fixed_point a, + png_int_32 multiplied_by, png_int_32 divided_by),PNG_EMPTY); +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED) +/* Same deal, but issue a warning on overflow and return 0. */ +PNG_INTERNAL_FUNCTION(png_fixed_point,png_muldiv_warn, + (png_const_structrp png_ptr, png_fixed_point a, png_int_32 multiplied_by, + png_int_32 divided_by),PNG_EMPTY); +#endif + +#ifdef PNG_GAMMA_SUPPORTED +/* Calculate a reciprocal - used for gamma values. This returns + * 0 if the argument is 0 in order to maintain an undefined value; + * there are no warnings. + */ +PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal,(png_fixed_point a), + PNG_EMPTY); + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* The same but gives a reciprocal of the product of two fixed point + * values. Accuracy is suitable for gamma calculations but this is + * not exact - use png_muldiv for that. Only required at present on read. + */ +PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal2,(png_fixed_point a, + png_fixed_point b),PNG_EMPTY); +#endif + +/* Return true if the gamma value is significantly different from 1.0 */ +PNG_INTERNAL_FUNCTION(int,png_gamma_significant,(png_fixed_point gamma_value), + PNG_EMPTY); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +/* Internal fixed point gamma correction. These APIs are called as + * required to convert single values - they don't need to be fast, + * they are not used when processing image pixel values. + * + * While the input is an 'unsigned' value it must actually be the + * correct bit value - 0..255 or 0..65535 as required. + */ +PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_correct,(png_structrp png_ptr, + unsigned int value, png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_16bit_correct,(unsigned int value, + png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(png_byte,png_gamma_8bit_correct,(unsigned int value, + png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_destroy_gamma_table,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_build_gamma_table,(png_structrp png_ptr, + int bit_depth),PNG_EMPTY); +#endif + +/* SIMPLIFIED READ/WRITE SUPPORT */ +#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) +/* The internal structure that png_image::opaque points to. */ +typedef struct png_control +{ + png_structp png_ptr; + png_infop info_ptr; + png_voidp error_buf; /* Always a jmp_buf at present. */ + + png_const_bytep memory; /* Memory buffer. */ + png_size_t size; /* Size of the memory buffer. */ + + unsigned int for_write :1; /* Otherwise it is a read structure */ + unsigned int owned_file :1; /* We own the file in io_ptr */ +} png_control; + +/* Return the pointer to the jmp_buf from a png_control: necessary because C + * does not reveal the type of the elements of jmp_buf. + */ +#ifdef __cplusplus +# define png_control_jmp_buf(pc) (((jmp_buf*)((pc)->error_buf))[0]) +#else +# define png_control_jmp_buf(pc) ((pc)->error_buf) +#endif + +/* Utility to safely execute a piece of libpng code catching and logging any + * errors that might occur. Returns true on success, false on failure (either + * of the function or as a result of a png_error.) + */ +PNG_INTERNAL_FUNCTION(void,png_safe_error,(png_structp png_ptr, + png_const_charp error_message),PNG_NORETURN); + +#ifdef PNG_WARNINGS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_safe_warning,(png_structp png_ptr, + png_const_charp warning_message),PNG_EMPTY); +#else +# define png_safe_warning 0/*dummy argument*/ +#endif + +PNG_INTERNAL_FUNCTION(int,png_safe_execute,(png_imagep image, + int (*function)(png_voidp), png_voidp arg),PNG_EMPTY); + +/* Utility to log an error; this also cleans up the png_image; the function + * always returns 0 (false). + */ +PNG_INTERNAL_FUNCTION(int,png_image_error,(png_imagep image, + png_const_charp error_message),PNG_EMPTY); + +#ifndef PNG_SIMPLIFIED_READ_SUPPORTED +/* png_image_free is used by the write code but not exported */ +PNG_INTERNAL_FUNCTION(void, png_image_free, (png_imagep image), PNG_EMPTY); +#endif /* !SIMPLIFIED_READ */ + +#endif /* SIMPLIFIED READ/WRITE */ + +/* These are initialization functions for hardware specific PNG filter + * optimizations; list these here then select the appropriate one at compile + * time using the macro PNG_FILTER_OPTIMIZATIONS. If the macro is not defined + * the generic code is used. + */ +#ifdef PNG_FILTER_OPTIMIZATIONS +PNG_INTERNAL_FUNCTION(void, PNG_FILTER_OPTIMIZATIONS, (png_structp png_ptr, + unsigned int bpp), PNG_EMPTY); + /* Just declare the optimization that will be used */ +#else + /* List *all* the possible optimizations here - this branch is required if + * the builder of libpng passes the definition of PNG_FILTER_OPTIMIZATIONS in + * CFLAGS in place of CPPFLAGS *and* uses symbol prefixing. + */ +PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon, + (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); +#endif + +/* Maintainer: Put new private prototypes here ^ */ + +#include "pngdebug.h" + +#ifdef __cplusplus +} +#endif + +#endif /* PNG_VERSION_INFO_ONLY */ +#endif /* PNGPRIV_H */ diff --git a/lib/3rdParty/dlib/include/dlib/external/libpng/pngstruct.h b/lib/3rdParty/dlib/include/dlib/external/libpng/pngstruct.h new file mode 100644 index 00000000..d58c0288 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/libpng/pngstruct.h @@ -0,0 +1,489 @@ + +/* pngstruct.h - header file for PNG reference library + * + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * Last changed in libpng 1.6.1 [March 28, 2013] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +/* The structure that holds the information to read and write PNG files. + * The only people who need to care about what is inside of this are the + * people who will be modifying the library for their own special needs. + * It should NOT be accessed directly by an application. + */ + +#ifndef PNGSTRUCT_H +#define PNGSTRUCT_H +/* zlib.h defines the structure z_stream, an instance of which is included + * in this structure and is required for decompressing the LZ compressed + * data in PNG files. + */ +#ifndef ZLIB_CONST + /* We must ensure that zlib uses 'const' in declarations. */ +# define ZLIB_CONST +#endif +#include "zlib.h" +#ifdef const + /* zlib.h sometimes #defines const to nothing, undo this. */ +# undef const +#endif + +/* zlib.h has mediocre z_const use before 1.2.6, this stuff is for compatibility + * with older builds. + */ +#if ZLIB_VERNUM < 0x1260 +# define PNGZ_MSG_CAST(s) png_constcast(char*,s) +# define PNGZ_INPUT_CAST(b) png_constcast(png_bytep,b) +#else +# define PNGZ_MSG_CAST(s) (s) +# define PNGZ_INPUT_CAST(b) (b) +#endif + +/* zlib.h declares a magic type 'uInt' that limits the amount of data that zlib + * can handle at once. This type need be no larger than 16 bits (so maximum of + * 65535), this define allows us to discover how big it is, but limited by the + * maximuum for png_size_t. The value can be overriden in a library build + * (pngusr.h, or set it in CPPFLAGS) and it works to set it to a considerably + * lower value (e.g. 255 works). A lower value may help memory usage (slightly) + * and may even improve performance on some systems (and degrade it on others.) + */ +#ifndef ZLIB_IO_MAX +# define ZLIB_IO_MAX ((uInt)-1) +#endif + +#ifdef PNG_WRITE_SUPPORTED +/* The type of a compression buffer list used by the write code. */ +typedef struct png_compression_buffer +{ + struct png_compression_buffer *next; + png_byte output[1]; /* actually zbuf_size */ +} png_compression_buffer, *png_compression_bufferp; + +#define PNG_COMPRESSION_BUFFER_SIZE(pp)\ + (offsetof(png_compression_buffer, output) + (pp)->zbuffer_size) +#endif + +/* Colorspace support; structures used in png_struct, png_info and in internal + * functions to hold and communicate information about the color space. + * + * PNG_COLORSPACE_SUPPORTED is only required if the application will perform + * colorspace corrections, otherwise all the colorspace information can be + * skipped and the size of libpng can be reduced (significantly) by compiling + * out the colorspace support. + */ +#ifdef PNG_COLORSPACE_SUPPORTED +/* The chromaticities of the red, green and blue colorants and the chromaticity + * of the corresponding white point (i.e. of rgb(1.0,1.0,1.0)). + */ +typedef struct png_xy +{ + png_fixed_point redx, redy; + png_fixed_point greenx, greeny; + png_fixed_point bluex, bluey; + png_fixed_point whitex, whitey; +} png_xy; + +/* The same data as above but encoded as CIE XYZ values. When this data comes + * from chromaticities the sum of the Y values is assumed to be 1.0 + */ +typedef struct png_XYZ +{ + png_fixed_point red_X, red_Y, red_Z; + png_fixed_point green_X, green_Y, green_Z; + png_fixed_point blue_X, blue_Y, blue_Z; +} png_XYZ; +#endif /* COLORSPACE */ + +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) +/* A colorspace is all the above plus, potentially, profile information, + * however at present libpng does not use the profile internally so it is only + * stored in the png_info struct (if iCCP is supported.) The rendering intent + * is retained here and is checked. + * + * The file gamma encoding information is also stored here and gamma correction + * is done by libpng, whereas color correction must currently be done by the + * application. + */ +typedef struct png_colorspace +{ +#ifdef PNG_GAMMA_SUPPORTED + png_fixed_point gamma; /* File gamma */ +#endif + +#ifdef PNG_COLORSPACE_SUPPORTED + png_xy end_points_xy; /* End points as chromaticities */ + png_XYZ end_points_XYZ; /* End points as CIE XYZ colorant values */ + png_uint_16 rendering_intent; /* Rendering intent of a profile */ +#endif + + /* Flags are always defined to simplify the code. */ + png_uint_16 flags; /* As defined below */ +} png_colorspace, * PNG_RESTRICT png_colorspacerp; + +typedef const png_colorspace * PNG_RESTRICT png_const_colorspacerp; + +/* General flags for the 'flags' field */ +#define PNG_COLORSPACE_HAVE_GAMMA 0x0001 +#define PNG_COLORSPACE_HAVE_ENDPOINTS 0x0002 +#define PNG_COLORSPACE_HAVE_INTENT 0x0004 +#define PNG_COLORSPACE_FROM_gAMA 0x0008 +#define PNG_COLORSPACE_FROM_cHRM 0x0010 +#define PNG_COLORSPACE_FROM_sRGB 0x0020 +#define PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB 0x0040 +#define PNG_COLORSPACE_MATCHES_sRGB 0x0080 /* exact match on profile */ +#define PNG_COLORSPACE_INVALID 0x8000 +#define PNG_COLORSPACE_CANCEL(flags) (0xffff ^ (flags)) +#endif /* COLORSPACE || GAMMA */ + +struct png_struct_def +{ +#ifdef PNG_SETJMP_SUPPORTED + jmp_buf jmp_buf_local; /* New name in 1.6.0 for jmp_buf in png_struct */ + png_longjmp_ptr longjmp_fn;/* setjmp non-local goto function. */ + jmp_buf *jmp_buf_ptr; /* passed to longjmp_fn */ + size_t jmp_buf_size; /* size of the above, if allocated */ +#endif + png_error_ptr error_fn; /* function for printing errors and aborting */ +#ifdef PNG_WARNINGS_SUPPORTED + png_error_ptr warning_fn; /* function for printing warnings */ +#endif + png_voidp error_ptr; /* user supplied struct for error functions */ + png_rw_ptr write_data_fn; /* function for writing output data */ + png_rw_ptr read_data_fn; /* function for reading input data */ + png_voidp io_ptr; /* ptr to application struct for I/O functions */ + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + png_user_transform_ptr read_user_transform_fn; /* user read transform */ +#endif + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + png_user_transform_ptr write_user_transform_fn; /* user write transform */ +#endif + +/* These were added in libpng-1.0.2 */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED +#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ + defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) + png_voidp user_transform_ptr; /* user supplied struct for user transform */ + png_byte user_transform_depth; /* bit depth of user transformed pixels */ + png_byte user_transform_channels; /* channels in user transformed pixels */ +#endif +#endif + + png_uint_32 mode; /* tells us where we are in the PNG file */ + png_uint_32 flags; /* flags indicating various things to libpng */ + png_uint_32 transformations; /* which transformations to perform */ + + png_uint_32 zowner; /* ID (chunk type) of zstream owner, 0 if none */ + z_stream zstream; /* decompression structure */ + +#ifdef PNG_WRITE_SUPPORTED + png_compression_bufferp zbuffer_list; /* Created on demand during write */ + uInt zbuffer_size; /* size of the actual buffer */ + + int zlib_level; /* holds zlib compression level */ + int zlib_method; /* holds zlib compression method */ + int zlib_window_bits; /* holds zlib compression window bits */ + int zlib_mem_level; /* holds zlib compression memory level */ + int zlib_strategy; /* holds zlib compression strategy */ +#endif +/* Added at libpng 1.5.4 */ +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED + int zlib_text_level; /* holds zlib compression level */ + int zlib_text_method; /* holds zlib compression method */ + int zlib_text_window_bits; /* holds zlib compression window bits */ + int zlib_text_mem_level; /* holds zlib compression memory level */ + int zlib_text_strategy; /* holds zlib compression strategy */ +#endif +/* End of material added at libpng 1.5.4 */ +/* Added at libpng 1.6.0 */ +#ifdef PNG_WRITE_SUPPORTED + int zlib_set_level; /* Actual values set into the zstream on write */ + int zlib_set_method; + int zlib_set_window_bits; + int zlib_set_mem_level; + int zlib_set_strategy; +#endif + + png_uint_32 width; /* width of image in pixels */ + png_uint_32 height; /* height of image in pixels */ + png_uint_32 num_rows; /* number of rows in current pass */ + png_uint_32 usr_width; /* width of row at start of write */ + png_size_t rowbytes; /* size of row in bytes */ + png_uint_32 iwidth; /* width of current interlaced row in pixels */ + png_uint_32 row_number; /* current row in interlace pass */ + png_uint_32 chunk_name; /* PNG_CHUNK() id of current chunk */ + png_bytep prev_row; /* buffer to save previous (unfiltered) row. + * This is a pointer into big_prev_row + */ + png_bytep row_buf; /* buffer to save current (unfiltered) row. + * This is a pointer into big_row_buf + */ +#ifdef PNG_WRITE_SUPPORTED + png_bytep sub_row; /* buffer to save "sub" row when filtering */ + png_bytep up_row; /* buffer to save "up" row when filtering */ + png_bytep avg_row; /* buffer to save "avg" row when filtering */ + png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */ +#endif + png_size_t info_rowbytes; /* Added in 1.5.4: cache of updated row bytes */ + + png_uint_32 idat_size; /* current IDAT size for read */ + png_uint_32 crc; /* current chunk CRC value */ + png_colorp palette; /* palette from the input file */ + png_uint_16 num_palette; /* number of color entries in palette */ + +/* Added at libpng-1.5.10 */ +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED + int num_palette_max; /* maximum palette index found in IDAT */ +#endif + + png_uint_16 num_trans; /* number of transparency values */ + png_byte compression; /* file compression type (always 0) */ + png_byte filter; /* file filter type (always 0) */ + png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ + png_byte pass; /* current interlace pass (0 - 6) */ + png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */ + png_byte color_type; /* color type of file */ + png_byte bit_depth; /* bit depth of file */ + png_byte usr_bit_depth; /* bit depth of users row: write only */ + png_byte pixel_depth; /* number of bits per pixel */ + png_byte channels; /* number of channels in file */ +#ifdef PNG_WRITE_SUPPORTED + png_byte usr_channels; /* channels at start of write: write only */ +#endif + png_byte sig_bytes; /* magic bytes read/written from start of file */ + png_byte maximum_pixel_depth; + /* pixel depth used for the row buffers */ + png_byte transformed_pixel_depth; + /* pixel depth after read/write transforms */ +#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) + png_uint_16 filler; /* filler bytes for pixel expansion */ +#endif + +#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + png_byte background_gamma_type; + png_fixed_point background_gamma; + png_color_16 background; /* background color in screen gamma space */ +#ifdef PNG_READ_GAMMA_SUPPORTED + png_color_16 background_1; /* background normalized to gamma 1.0 */ +#endif +#endif /* PNG_bKGD_SUPPORTED */ + +#ifdef PNG_WRITE_FLUSH_SUPPORTED + png_flush_ptr output_flush_fn; /* Function for flushing output */ + png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */ + png_uint_32 flush_rows; /* number of rows written since last flush */ +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED + int gamma_shift; /* number of "insignificant" bits in 16-bit gamma */ + png_fixed_point screen_gamma; /* screen gamma value (display_exponent) */ + + png_bytep gamma_table; /* gamma table for 8-bit depth files */ + png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */ +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + png_bytep gamma_from_1; /* converts from 1.0 to screen */ + png_bytep gamma_to_1; /* converts from file to 1.0 */ + png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */ + png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */ +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED) + png_color_8 sig_bit; /* significant bits in each available channel */ +#endif + +#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) + png_color_8 shift; /* shift for significant bit tranformation */ +#endif + +#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \ + || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) + png_bytep trans_alpha; /* alpha values for paletted files */ + png_color_16 trans_color; /* transparent color for non-paletted files */ +#endif + + png_read_status_ptr read_row_fn; /* called after each row is decoded */ + png_write_status_ptr write_row_fn; /* called after each row is encoded */ +#ifdef PNG_PROGRESSIVE_READ_SUPPORTED + png_progressive_info_ptr info_fn; /* called after header data fully read */ + png_progressive_row_ptr row_fn; /* called after a prog. row is decoded */ + png_progressive_end_ptr end_fn; /* called after image is complete */ + png_bytep save_buffer_ptr; /* current location in save_buffer */ + png_bytep save_buffer; /* buffer for previously read data */ + png_bytep current_buffer_ptr; /* current location in current_buffer */ + png_bytep current_buffer; /* buffer for recently used data */ + png_uint_32 push_length; /* size of current input chunk */ + png_uint_32 skip_length; /* bytes to skip in input data */ + png_size_t save_buffer_size; /* amount of data now in save_buffer */ + png_size_t save_buffer_max; /* total size of save_buffer */ + png_size_t buffer_size; /* total amount of available input data */ + png_size_t current_buffer_size; /* amount of data now in current_buffer */ + int process_mode; /* what push library is currently doing */ + int cur_palette; /* current push library palette index */ + +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) +/* For the Borland special 64K segment handler */ + png_bytepp offset_table_ptr; + png_bytep offset_table; + png_uint_16 offset_table_number; + png_uint_16 offset_table_count; + png_uint_16 offset_table_count_free; +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + png_bytep palette_lookup; /* lookup table for quantizing */ + png_bytep quantize_index; /* index translation for palette files */ +#endif + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + png_byte heuristic_method; /* heuristic for row filter selection */ + png_byte num_prev_filters; /* number of weights for previous rows */ + png_bytep prev_filters; /* filter type(s) of previous row(s) */ + png_uint_16p filter_weights; /* weight(s) for previous line(s) */ + png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */ + png_uint_16p filter_costs; /* relative filter calculation cost */ + png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */ +#endif + + /* Options */ +#ifdef PNG_SET_OPTION_SUPPORTED + png_byte options; /* On/off state (up to 4 options) */ +#endif + +#if PNG_LIBPNG_VER < 10700 +/* To do: remove this from libpng-1.7 */ +#ifdef PNG_TIME_RFC1123_SUPPORTED + char time_buffer[29]; /* String to hold RFC 1123 time text */ +#endif +#endif + +/* New members added in libpng-1.0.6 */ + + png_uint_32 free_me; /* flags items libpng is responsible for freeing */ + +#ifdef PNG_USER_CHUNKS_SUPPORTED + png_voidp user_chunk_ptr; +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */ +#endif +#endif + +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + int unknown_default; /* As PNG_HANDLE_* */ + unsigned int num_chunk_list; /* Number of entries in the list */ + png_bytep chunk_list; /* List of png_byte[5]; the textual chunk name + * followed by a PNG_HANDLE_* byte */ +#endif + +/* New members added in libpng-1.0.3 */ +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + png_byte rgb_to_gray_status; + /* Added in libpng 1.5.5 to record setting of coefficients: */ + png_byte rgb_to_gray_coefficients_set; + /* These were changed from png_byte in libpng-1.0.6 */ + png_uint_16 rgb_to_gray_red_coeff; + png_uint_16 rgb_to_gray_green_coeff; + /* deleted in 1.5.5: rgb_to_gray_blue_coeff; */ +#endif + +/* New member added in libpng-1.0.4 (renamed in 1.0.9) */ +#if defined(PNG_MNG_FEATURES_SUPPORTED) +/* Changed from png_byte to png_uint_32 at version 1.2.0 */ + png_uint_32 mng_features_permitted; +#endif + +/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */ +#ifdef PNG_MNG_FEATURES_SUPPORTED + png_byte filter_type; +#endif + +/* New members added in libpng-1.2.0 */ + +/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */ +#ifdef PNG_USER_MEM_SUPPORTED + png_voidp mem_ptr; /* user supplied struct for mem functions */ + png_malloc_ptr malloc_fn; /* function for allocating memory */ + png_free_ptr free_fn; /* function for freeing memory */ +#endif + +/* New member added in libpng-1.0.13 and 1.2.0 */ + png_bytep big_row_buf; /* buffer to save current (unfiltered) row */ + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +/* The following three members were added at version 1.0.14 and 1.2.4 */ + png_bytep quantize_sort; /* working sort array */ + png_bytep index_to_palette; /* where the original index currently is + in the palette */ + png_bytep palette_to_index; /* which original index points to this + palette color */ +#endif + +/* New members added in libpng-1.0.16 and 1.2.6 */ + png_byte compression_type; + +#ifdef PNG_USER_LIMITS_SUPPORTED + png_uint_32 user_width_max; + png_uint_32 user_height_max; + + /* Added in libpng-1.4.0: Total number of sPLT, text, and unknown + * chunks that can be stored (0 means unlimited). + */ + png_uint_32 user_chunk_cache_max; + + /* Total memory that a zTXt, sPLT, iTXt, iCCP, or unknown chunk + * can occupy when decompressed. 0 means unlimited. + */ + png_alloc_size_t user_chunk_malloc_max; +#endif + +/* New member added in libpng-1.0.25 and 1.2.17 */ +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + /* Temporary storage for unknown chunk that the library doesn't recognize, + * used while reading the chunk. + */ + png_unknown_chunk unknown_chunk; +#endif + +/* New member added in libpng-1.2.26 */ + png_size_t old_big_row_buf_size; + +#ifdef PNG_READ_SUPPORTED +/* New member added in libpng-1.2.30 */ + png_bytep read_buffer; /* buffer for reading chunk data */ + png_alloc_size_t read_buffer_size; /* current size of the buffer */ +#endif +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED + uInt IDAT_read_size; /* limit on read buffer size for IDAT */ +#endif + +#ifdef PNG_IO_STATE_SUPPORTED +/* New member added in libpng-1.4.0 */ + png_uint_32 io_state; +#endif + +/* New member added in libpng-1.5.6 */ + png_bytep big_prev_row; + +/* New member added in libpng-1.5.7 */ + void (*read_filter[PNG_FILTER_VALUE_LAST-1])(png_row_infop row_info, + png_bytep row, png_const_bytep prev_row); + +#ifdef PNG_READ_SUPPORTED +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) + png_colorspace colorspace; +#endif +#endif +}; +#endif /* PNGSTRUCT_H */ diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/attr.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/attr.h new file mode 100644 index 00000000..dce875a6 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/attr.h @@ -0,0 +1,489 @@ +/* + pybind11/attr.h: Infrastructure for processing custom + type and function attributes + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "cast.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +/// \addtogroup annotations +/// @{ + +/// Annotation for methods +struct is_method { handle class_; is_method(const handle &c) : class_(c) { } }; + +/// Annotation for operators +struct is_operator { }; + +/// Annotation for parent scope +struct scope { handle value; scope(const handle &s) : value(s) { } }; + +/// Annotation for documentation +struct doc { const char *value; doc(const char *value) : value(value) { } }; + +/// Annotation for function names +struct name { const char *value; name(const char *value) : value(value) { } }; + +/// Annotation indicating that a function is an overload associated with a given "sibling" +struct sibling { handle value; sibling(const handle &value) : value(value.ptr()) { } }; + +/// Annotation indicating that a class derives from another given type +template struct base { + PYBIND11_DEPRECATED("base() was deprecated in favor of specifying 'T' as a template argument to class_") + base() { } +}; + +/// Keep patient alive while nurse lives +template struct keep_alive { }; + +/// Annotation indicating that a class is involved in a multiple inheritance relationship +struct multiple_inheritance { }; + +/// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class +struct dynamic_attr { }; + +/// Annotation which enables the buffer protocol for a type +struct buffer_protocol { }; + +/// Annotation which requests that a special metaclass is created for a type +struct metaclass { + handle value; + + PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.") + metaclass() {} + + /// Override pybind11's default metaclass + explicit metaclass(handle value) : value(value) { } +}; + +/// Annotation that marks a class as local to the module: +struct module_local { const bool value; constexpr module_local(bool v = true) : value(v) { } }; + +/// Annotation to mark enums as an arithmetic type +struct arithmetic { }; + +/** \rst + A call policy which places one or more guard variables (``Ts...``) around the function call. + + For example, this definition: + + .. code-block:: cpp + + m.def("foo", foo, py::call_guard()); + + is equivalent to the following pseudocode: + + .. code-block:: cpp + + m.def("foo", [](args...) { + T scope_guard; + return foo(args...); // forwarded arguments + }); + \endrst */ +template struct call_guard; + +template <> struct call_guard<> { using type = detail::void_type; }; + +template +struct call_guard { + static_assert(std::is_default_constructible::value, + "The guard type must be default constructible"); + + using type = T; +}; + +template +struct call_guard { + struct type { + T guard{}; // Compose multiple guard types with left-to-right default-constructor order + typename call_guard::type next{}; + }; +}; + +/// @} annotations + +NAMESPACE_BEGIN(detail) +/* Forward declarations */ +enum op_id : int; +enum op_type : int; +struct undefined_t; +template struct op_; +inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret); + +/// Internal data structure which holds metadata about a keyword argument +struct argument_record { + const char *name; ///< Argument name + const char *descr; ///< Human-readable version of the argument value + handle value; ///< Associated Python object + bool convert : 1; ///< True if the argument is allowed to convert when loading + bool none : 1; ///< True if None is allowed when loading + + argument_record(const char *name, const char *descr, handle value, bool convert, bool none) + : name(name), descr(descr), value(value), convert(convert), none(none) { } +}; + +/// Internal data structure which holds metadata about a bound function (signature, overloads, etc.) +struct function_record { + function_record() + : is_constructor(false), is_new_style_constructor(false), is_stateless(false), + is_operator(false), has_args(false), has_kwargs(false), is_method(false) { } + + /// Function name + char *name = nullptr; /* why no C++ strings? They generate heavier code.. */ + + // User-specified documentation string + char *doc = nullptr; + + /// Human-readable version of the function signature + char *signature = nullptr; + + /// List of registered keyword arguments + std::vector args; + + /// Pointer to lambda function which converts arguments and performs the actual call + handle (*impl) (function_call &) = nullptr; + + /// Storage for the wrapped function pointer and captured data, if any + void *data[3] = { }; + + /// Pointer to custom destructor for 'data' (if needed) + void (*free_data) (function_record *ptr) = nullptr; + + /// Return value policy associated with this function + return_value_policy policy = return_value_policy::automatic; + + /// True if name == '__init__' + bool is_constructor : 1; + + /// True if this is a new-style `__init__` defined in `detail/init.h` + bool is_new_style_constructor : 1; + + /// True if this is a stateless function pointer + bool is_stateless : 1; + + /// True if this is an operator (__add__), etc. + bool is_operator : 1; + + /// True if the function has a '*args' argument + bool has_args : 1; + + /// True if the function has a '**kwargs' argument + bool has_kwargs : 1; + + /// True if this is a method + bool is_method : 1; + + /// Number of arguments (including py::args and/or py::kwargs, if present) + std::uint16_t nargs; + + /// Python method object + PyMethodDef *def = nullptr; + + /// Python handle to the parent scope (a class or a module) + handle scope; + + /// Python handle to the sibling function representing an overload chain + handle sibling; + + /// Pointer to next overload + function_record *next = nullptr; +}; + +/// Special data structure which (temporarily) holds metadata about a bound class +struct type_record { + PYBIND11_NOINLINE type_record() + : multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false), module_local(false) { } + + /// Handle to the parent scope + handle scope; + + /// Name of the class + const char *name = nullptr; + + // Pointer to RTTI type_info data structure + const std::type_info *type = nullptr; + + /// How large is the underlying C++ type? + size_t type_size = 0; + + /// How large is the type's holder? + size_t holder_size = 0; + + /// The global operator new can be overridden with a class-specific variant + void *(*operator_new)(size_t) = ::operator new; + + /// Function pointer to class_<..>::init_instance + void (*init_instance)(instance *, const void *) = nullptr; + + /// Function pointer to class_<..>::dealloc + void (*dealloc)(detail::value_and_holder &) = nullptr; + + /// List of base classes of the newly created type + list bases; + + /// Optional docstring + const char *doc = nullptr; + + /// Custom metaclass (optional) + handle metaclass; + + /// Multiple inheritance marker + bool multiple_inheritance : 1; + + /// Does the class manage a __dict__? + bool dynamic_attr : 1; + + /// Does the class implement the buffer protocol? + bool buffer_protocol : 1; + + /// Is the default (unique_ptr) holder type used? + bool default_holder : 1; + + /// Is the class definition local to the module shared object? + bool module_local : 1; + + PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *)) { + auto base_info = detail::get_type_info(base, false); + if (!base_info) { + std::string tname(base.name()); + detail::clean_type_id(tname); + pybind11_fail("generic_type: type \"" + std::string(name) + + "\" referenced unknown base type \"" + tname + "\""); + } + + if (default_holder != base_info->default_holder) { + std::string tname(base.name()); + detail::clean_type_id(tname); + pybind11_fail("generic_type: type \"" + std::string(name) + "\" " + + (default_holder ? "does not have" : "has") + + " a non-default holder type while its base \"" + tname + "\" " + + (base_info->default_holder ? "does not" : "does")); + } + + bases.append((PyObject *) base_info->type); + + if (base_info->type->tp_dictoffset != 0) + dynamic_attr = true; + + if (caster) + base_info->implicit_casts.emplace_back(type, caster); + } +}; + +inline function_call::function_call(function_record &f, handle p) : + func(f), parent(p) { + args.reserve(f.nargs); + args_convert.reserve(f.nargs); +} + +/// Tag for a new-style `__init__` defined in `detail/init.h` +struct is_new_style_constructor { }; + +/** + * Partial template specializations to process custom attributes provided to + * cpp_function_ and class_. These are either used to initialize the respective + * fields in the type_record and function_record data structures or executed at + * runtime to deal with custom call policies (e.g. keep_alive). + */ +template struct process_attribute; + +template struct process_attribute_default { + /// Default implementation: do nothing + static void init(const T &, function_record *) { } + static void init(const T &, type_record *) { } + static void precall(function_call &) { } + static void postcall(function_call &, handle) { } +}; + +/// Process an attribute specifying the function's name +template <> struct process_attribute : process_attribute_default { + static void init(const name &n, function_record *r) { r->name = const_cast(n.value); } +}; + +/// Process an attribute specifying the function's docstring +template <> struct process_attribute : process_attribute_default { + static void init(const doc &n, function_record *r) { r->doc = const_cast(n.value); } +}; + +/// Process an attribute specifying the function's docstring (provided as a C-style string) +template <> struct process_attribute : process_attribute_default { + static void init(const char *d, function_record *r) { r->doc = const_cast(d); } + static void init(const char *d, type_record *r) { r->doc = const_cast(d); } +}; +template <> struct process_attribute : process_attribute { }; + +/// Process an attribute indicating the function's return value policy +template <> struct process_attribute : process_attribute_default { + static void init(const return_value_policy &p, function_record *r) { r->policy = p; } +}; + +/// Process an attribute which indicates that this is an overloaded function associated with a given sibling +template <> struct process_attribute : process_attribute_default { + static void init(const sibling &s, function_record *r) { r->sibling = s.value; } +}; + +/// Process an attribute which indicates that this function is a method +template <> struct process_attribute : process_attribute_default { + static void init(const is_method &s, function_record *r) { r->is_method = true; r->scope = s.class_; } +}; + +/// Process an attribute which indicates the parent scope of a method +template <> struct process_attribute : process_attribute_default { + static void init(const scope &s, function_record *r) { r->scope = s.value; } +}; + +/// Process an attribute which indicates that this function is an operator +template <> struct process_attribute : process_attribute_default { + static void init(const is_operator &, function_record *r) { r->is_operator = true; } +}; + +template <> struct process_attribute : process_attribute_default { + static void init(const is_new_style_constructor &, function_record *r) { r->is_new_style_constructor = true; } +}; + +/// Process a keyword argument attribute (*without* a default value) +template <> struct process_attribute : process_attribute_default { + static void init(const arg &a, function_record *r) { + if (r->is_method && r->args.empty()) + r->args.emplace_back("self", nullptr, handle(), true /*convert*/, false /*none not allowed*/); + r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none); + } +}; + +/// Process a keyword argument attribute (*with* a default value) +template <> struct process_attribute : process_attribute_default { + static void init(const arg_v &a, function_record *r) { + if (r->is_method && r->args.empty()) + r->args.emplace_back("self", nullptr /*descr*/, handle() /*parent*/, true /*convert*/, false /*none not allowed*/); + + if (!a.value) { +#if !defined(NDEBUG) + std::string descr("'"); + if (a.name) descr += std::string(a.name) + ": "; + descr += a.type + "'"; + if (r->is_method) { + if (r->name) + descr += " in method '" + (std::string) str(r->scope) + "." + (std::string) r->name + "'"; + else + descr += " in method of '" + (std::string) str(r->scope) + "'"; + } else if (r->name) { + descr += " in function '" + (std::string) r->name + "'"; + } + pybind11_fail("arg(): could not convert default argument " + + descr + " into a Python object (type not registered yet?)"); +#else + pybind11_fail("arg(): could not convert default argument " + "into a Python object (type not registered yet?). " + "Compile in debug mode for more information."); +#endif + } + r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none); + } +}; + +/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees that) +template +struct process_attribute::value>> : process_attribute_default { + static void init(const handle &h, type_record *r) { r->bases.append(h); } +}; + +/// Process a parent class attribute (deprecated, does not support multiple inheritance) +template +struct process_attribute> : process_attribute_default> { + static void init(const base &, type_record *r) { r->add_base(typeid(T), nullptr); } +}; + +/// Process a multiple inheritance attribute +template <> +struct process_attribute : process_attribute_default { + static void init(const multiple_inheritance &, type_record *r) { r->multiple_inheritance = true; } +}; + +template <> +struct process_attribute : process_attribute_default { + static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; } +}; + +template <> +struct process_attribute : process_attribute_default { + static void init(const buffer_protocol &, type_record *r) { r->buffer_protocol = true; } +}; + +template <> +struct process_attribute : process_attribute_default { + static void init(const metaclass &m, type_record *r) { r->metaclass = m.value; } +}; + +template <> +struct process_attribute : process_attribute_default { + static void init(const module_local &l, type_record *r) { r->module_local = l.value; } +}; + +/// Process an 'arithmetic' attribute for enums (does nothing here) +template <> +struct process_attribute : process_attribute_default {}; + +template +struct process_attribute> : process_attribute_default> { }; + +/** + * Process a keep_alive call policy -- invokes keep_alive_impl during the + * pre-call handler if both Nurse, Patient != 0 and use the post-call handler + * otherwise + */ +template struct process_attribute> : public process_attribute_default> { + template = 0> + static void precall(function_call &call) { keep_alive_impl(Nurse, Patient, call, handle()); } + template = 0> + static void postcall(function_call &, handle) { } + template = 0> + static void precall(function_call &) { } + template = 0> + static void postcall(function_call &call, handle ret) { keep_alive_impl(Nurse, Patient, call, ret); } +}; + +/// Recursively iterate over variadic template arguments +template struct process_attributes { + static void init(const Args&... args, function_record *r) { + int unused[] = { 0, (process_attribute::type>::init(args, r), 0) ... }; + ignore_unused(unused); + } + static void init(const Args&... args, type_record *r) { + int unused[] = { 0, (process_attribute::type>::init(args, r), 0) ... }; + ignore_unused(unused); + } + static void precall(function_call &call) { + int unused[] = { 0, (process_attribute::type>::precall(call), 0) ... }; + ignore_unused(unused); + } + static void postcall(function_call &call, handle fn_ret) { + int unused[] = { 0, (process_attribute::type>::postcall(call, fn_ret), 0) ... }; + ignore_unused(unused); + } +}; + +template +using is_call_guard = is_instantiation; + +/// Extract the ``type`` from the first `call_guard` in `Extras...` (or `void_type` if none found) +template +using extract_guard_t = typename exactly_one_t, Extra...>::type; + +/// Check the number of named arguments at compile time +template ::value...), + size_t self = constexpr_sum(std::is_same::value...)> +constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) { + return named == 0 || (self + named + has_args + has_kwargs) == nargs; +} + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/buffer_info.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/buffer_info.h new file mode 100644 index 00000000..9f072fa7 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/buffer_info.h @@ -0,0 +1,108 @@ +/* + pybind11/buffer_info.h: Python buffer object interface + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "detail/common.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +/// Information record describing a Python buffer object +struct buffer_info { + void *ptr = nullptr; // Pointer to the underlying storage + ssize_t itemsize = 0; // Size of individual items in bytes + ssize_t size = 0; // Total number of entries + std::string format; // For homogeneous buffers, this should be set to format_descriptor::format() + ssize_t ndim = 0; // Number of dimensions + std::vector shape; // Shape of the tensor (1 entry per dimension) + std::vector strides; // Number of entries between adjacent entries (for each per dimension) + + buffer_info() { } + + buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim, + detail::any_container shape_in, detail::any_container strides_in) + : ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim), + shape(std::move(shape_in)), strides(std::move(strides_in)) { + if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) + pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length"); + for (size_t i = 0; i < (size_t) ndim; ++i) + size *= shape[i]; + } + + template + buffer_info(T *ptr, detail::any_container shape_in, detail::any_container strides_in) + : buffer_info(private_ctr_tag(), ptr, sizeof(T), format_descriptor::format(), static_cast(shape_in->size()), std::move(shape_in), std::move(strides_in)) { } + + buffer_info(void *ptr, ssize_t itemsize, const std::string &format, ssize_t size) + : buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}) { } + + template + buffer_info(T *ptr, ssize_t size) + : buffer_info(ptr, sizeof(T), format_descriptor::format(), size) { } + + explicit buffer_info(Py_buffer *view, bool ownview = true) + : buffer_info(view->buf, view->itemsize, view->format, view->ndim, + {view->shape, view->shape + view->ndim}, {view->strides, view->strides + view->ndim}) { + this->view = view; + this->ownview = ownview; + } + + buffer_info(const buffer_info &) = delete; + buffer_info& operator=(const buffer_info &) = delete; + + buffer_info(buffer_info &&other) { + (*this) = std::move(other); + } + + buffer_info& operator=(buffer_info &&rhs) { + ptr = rhs.ptr; + itemsize = rhs.itemsize; + size = rhs.size; + format = std::move(rhs.format); + ndim = rhs.ndim; + shape = std::move(rhs.shape); + strides = std::move(rhs.strides); + std::swap(view, rhs.view); + std::swap(ownview, rhs.ownview); + return *this; + } + + ~buffer_info() { + if (view && ownview) { PyBuffer_Release(view); delete view; } + } + +private: + struct private_ctr_tag { }; + + buffer_info(private_ctr_tag, void *ptr, ssize_t itemsize, const std::string &format, ssize_t ndim, + detail::any_container &&shape_in, detail::any_container &&strides_in) + : buffer_info(ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in)) { } + + Py_buffer *view = nullptr; + bool ownview = false; +}; + +NAMESPACE_BEGIN(detail) + +template struct compare_buffer_info { + static bool compare(const buffer_info& b) { + return b.format == format_descriptor::format() && b.itemsize == (ssize_t) sizeof(T); + } +}; + +template struct compare_buffer_info::value>> { + static bool compare(const buffer_info& b) { + return (size_t) b.itemsize == sizeof(T) && (b.format == format_descriptor::value || + ((sizeof(T) == sizeof(long)) && b.format == (std::is_unsigned::value ? "L" : "l")) || + ((sizeof(T) == sizeof(size_t)) && b.format == (std::is_unsigned::value ? "N" : "n"))); + } +}; + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/cast.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/cast.h new file mode 100644 index 00000000..a722a9e8 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/cast.h @@ -0,0 +1,2063 @@ +/* + pybind11/cast.h: Partial template specializations to cast between + C++ and Python types + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pytypes.h" +#include "detail/typeid.h" +#include "detail/descr.h" +#include "detail/internals.h" +#include +#include +#include + +#if defined(PYBIND11_CPP17) +# if defined(__has_include) +# if __has_include() +# define PYBIND11_HAS_STRING_VIEW +# endif +# elif defined(_MSC_VER) +# define PYBIND11_HAS_STRING_VIEW +# endif +#endif +#ifdef PYBIND11_HAS_STRING_VIEW +#include +#endif + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +/// A life support system for temporary objects created by `type_caster::load()`. +/// Adding a patient will keep it alive up until the enclosing function returns. +class loader_life_support { +public: + /// A new patient frame is created when a function is entered + loader_life_support() { + get_internals().loader_patient_stack.push_back(nullptr); + } + + /// ... and destroyed after it returns + ~loader_life_support() { + auto &stack = get_internals().loader_patient_stack; + if (stack.empty()) + pybind11_fail("loader_life_support: internal error"); + + auto ptr = stack.back(); + stack.pop_back(); + Py_CLEAR(ptr); + + // A heuristic to reduce the stack's capacity (e.g. after long recursive calls) + if (stack.capacity() > 16 && stack.size() != 0 && stack.capacity() / stack.size() > 2) + stack.shrink_to_fit(); + } + + /// This can only be used inside a pybind11-bound function, either by `argument_loader` + /// at argument preparation time or by `py::cast()` at execution time. + PYBIND11_NOINLINE static void add_patient(handle h) { + auto &stack = get_internals().loader_patient_stack; + if (stack.empty()) + throw cast_error("When called outside a bound function, py::cast() cannot " + "do Python -> C++ conversions which require the creation " + "of temporary values"); + + auto &list_ptr = stack.back(); + if (list_ptr == nullptr) { + list_ptr = PyList_New(1); + if (!list_ptr) + pybind11_fail("loader_life_support: error allocating list"); + PyList_SET_ITEM(list_ptr, 0, h.inc_ref().ptr()); + } else { + auto result = PyList_Append(list_ptr, h.ptr()); + if (result == -1) + pybind11_fail("loader_life_support: error adding patient"); + } + } +}; + +// Gets the cache entry for the given type, creating it if necessary. The return value is the pair +// returned by emplace, i.e. an iterator for the entry and a bool set to `true` if the entry was +// just created. +inline std::pair all_type_info_get_cache(PyTypeObject *type); + +// Populates a just-created cache entry. +PYBIND11_NOINLINE inline void all_type_info_populate(PyTypeObject *t, std::vector &bases) { + std::vector check; + for (handle parent : reinterpret_borrow(t->tp_bases)) + check.push_back((PyTypeObject *) parent.ptr()); + + auto const &type_dict = get_internals().registered_types_py; + for (size_t i = 0; i < check.size(); i++) { + auto type = check[i]; + // Ignore Python2 old-style class super type: + if (!PyType_Check((PyObject *) type)) continue; + + // Check `type` in the current set of registered python types: + auto it = type_dict.find(type); + if (it != type_dict.end()) { + // We found a cache entry for it, so it's either pybind-registered or has pre-computed + // pybind bases, but we have to make sure we haven't already seen the type(s) before: we + // want to follow Python/virtual C++ rules that there should only be one instance of a + // common base. + for (auto *tinfo : it->second) { + // NB: Could use a second set here, rather than doing a linear search, but since + // having a large number of immediate pybind11-registered types seems fairly + // unlikely, that probably isn't worthwhile. + bool found = false; + for (auto *known : bases) { + if (known == tinfo) { found = true; break; } + } + if (!found) bases.push_back(tinfo); + } + } + else if (type->tp_bases) { + // It's some python type, so keep follow its bases classes to look for one or more + // registered types + if (i + 1 == check.size()) { + // When we're at the end, we can pop off the current element to avoid growing + // `check` when adding just one base (which is typical--i.e. when there is no + // multiple inheritance) + check.pop_back(); + i--; + } + for (handle parent : reinterpret_borrow(type->tp_bases)) + check.push_back((PyTypeObject *) parent.ptr()); + } + } +} + +/** + * Extracts vector of type_info pointers of pybind-registered roots of the given Python type. Will + * be just 1 pybind type for the Python type of a pybind-registered class, or for any Python-side + * derived class that uses single inheritance. Will contain as many types as required for a Python + * class that uses multiple inheritance to inherit (directly or indirectly) from multiple + * pybind-registered classes. Will be empty if neither the type nor any base classes are + * pybind-registered. + * + * The value is cached for the lifetime of the Python type. + */ +inline const std::vector &all_type_info(PyTypeObject *type) { + auto ins = all_type_info_get_cache(type); + if (ins.second) + // New cache entry: populate it + all_type_info_populate(type, ins.first->second); + + return ins.first->second; +} + +/** + * Gets a single pybind11 type info for a python type. Returns nullptr if neither the type nor any + * ancestors are pybind11-registered. Throws an exception if there are multiple bases--use + * `all_type_info` instead if you want to support multiple bases. + */ +PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) { + auto &bases = all_type_info(type); + if (bases.size() == 0) + return nullptr; + if (bases.size() > 1) + pybind11_fail("pybind11::detail::get_type_info: type has multiple pybind11-registered bases"); + return bases.front(); +} + +inline detail::type_info *get_local_type_info(const std::type_index &tp) { + auto &locals = registered_local_types_cpp(); + auto it = locals.find(tp); + if (it != locals.end()) + return it->second; + return nullptr; +} + +inline detail::type_info *get_global_type_info(const std::type_index &tp) { + auto &types = get_internals().registered_types_cpp; + auto it = types.find(tp); + if (it != types.end()) + return it->second; + return nullptr; +} + +/// Return the type info for a given C++ type; on lookup failure can either throw or return nullptr. +PYBIND11_NOINLINE inline detail::type_info *get_type_info(const std::type_index &tp, + bool throw_if_missing = false) { + if (auto ltype = get_local_type_info(tp)) + return ltype; + if (auto gtype = get_global_type_info(tp)) + return gtype; + + if (throw_if_missing) { + std::string tname = tp.name(); + detail::clean_type_id(tname); + pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \"" + tname + "\""); + } + return nullptr; +} + +PYBIND11_NOINLINE inline handle get_type_handle(const std::type_info &tp, bool throw_if_missing) { + detail::type_info *type_info = get_type_info(tp, throw_if_missing); + return handle(type_info ? ((PyObject *) type_info->type) : nullptr); +} + +struct value_and_holder { + instance *inst; + size_t index; + const detail::type_info *type; + void **vh; + + // Main constructor for a found value/holder: + value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index) : + inst{i}, index{index}, type{type}, + vh{inst->simple_layout ? inst->simple_value_holder : &inst->nonsimple.values_and_holders[vpos]} + {} + + // Default constructor (used to signal a value-and-holder not found by get_value_and_holder()) + value_and_holder() : inst{nullptr} {} + + // Used for past-the-end iterator + value_and_holder(size_t index) : index{index} {} + + template V *&value_ptr() const { + return reinterpret_cast(vh[0]); + } + // True if this `value_and_holder` has a non-null value pointer + explicit operator bool() const { return value_ptr(); } + + template H &holder() const { + return reinterpret_cast(vh[1]); + } + bool holder_constructed() const { + return inst->simple_layout + ? inst->simple_holder_constructed + : inst->nonsimple.status[index] & instance::status_holder_constructed; + } + void set_holder_constructed(bool v = true) { + if (inst->simple_layout) + inst->simple_holder_constructed = v; + else if (v) + inst->nonsimple.status[index] |= instance::status_holder_constructed; + else + inst->nonsimple.status[index] &= (uint8_t) ~instance::status_holder_constructed; + } + bool instance_registered() const { + return inst->simple_layout + ? inst->simple_instance_registered + : inst->nonsimple.status[index] & instance::status_instance_registered; + } + void set_instance_registered(bool v = true) { + if (inst->simple_layout) + inst->simple_instance_registered = v; + else if (v) + inst->nonsimple.status[index] |= instance::status_instance_registered; + else + inst->nonsimple.status[index] &= (uint8_t) ~instance::status_instance_registered; + } +}; + +// Container for accessing and iterating over an instance's values/holders +struct values_and_holders { +private: + instance *inst; + using type_vec = std::vector; + const type_vec &tinfo; + +public: + values_and_holders(instance *inst) : inst{inst}, tinfo(all_type_info(Py_TYPE(inst))) {} + + struct iterator { + private: + instance *inst; + const type_vec *types; + value_and_holder curr; + friend struct values_and_holders; + iterator(instance *inst, const type_vec *tinfo) + : inst{inst}, types{tinfo}, + curr(inst /* instance */, + types->empty() ? nullptr : (*types)[0] /* type info */, + 0, /* vpos: (non-simple types only): the first vptr comes first */ + 0 /* index */) + {} + // Past-the-end iterator: + iterator(size_t end) : curr(end) {} + public: + bool operator==(const iterator &other) { return curr.index == other.curr.index; } + bool operator!=(const iterator &other) { return curr.index != other.curr.index; } + iterator &operator++() { + if (!inst->simple_layout) + curr.vh += 1 + (*types)[curr.index]->holder_size_in_ptrs; + ++curr.index; + curr.type = curr.index < types->size() ? (*types)[curr.index] : nullptr; + return *this; + } + value_and_holder &operator*() { return curr; } + value_and_holder *operator->() { return &curr; } + }; + + iterator begin() { return iterator(inst, &tinfo); } + iterator end() { return iterator(tinfo.size()); } + + iterator find(const type_info *find_type) { + auto it = begin(), endit = end(); + while (it != endit && it->type != find_type) ++it; + return it; + } + + size_t size() { return tinfo.size(); } +}; + +/** + * Extracts C++ value and holder pointer references from an instance (which may contain multiple + * values/holders for python-side multiple inheritance) that match the given type. Throws an error + * if the given type (or ValueType, if omitted) is not a pybind11 base of the given instance. If + * `find_type` is omitted (or explicitly specified as nullptr) the first value/holder are returned, + * regardless of type (and the resulting .type will be nullptr). + * + * The returned object should be short-lived: in particular, it must not outlive the called-upon + * instance. + */ +PYBIND11_NOINLINE inline value_and_holder instance::get_value_and_holder(const type_info *find_type /*= nullptr default in common.h*/, bool throw_if_missing /*= true in common.h*/) { + // Optimize common case: + if (!find_type || Py_TYPE(this) == find_type->type) + return value_and_holder(this, find_type, 0, 0); + + detail::values_and_holders vhs(this); + auto it = vhs.find(find_type); + if (it != vhs.end()) + return *it; + + if (!throw_if_missing) + return value_and_holder(); + +#if defined(NDEBUG) + pybind11_fail("pybind11::detail::instance::get_value_and_holder: " + "type is not a pybind11 base of the given instance " + "(compile in debug mode for type details)"); +#else + pybind11_fail("pybind11::detail::instance::get_value_and_holder: `" + + std::string(find_type->type->tp_name) + "' is not a pybind11 base of the given `" + + std::string(Py_TYPE(this)->tp_name) + "' instance"); +#endif +} + +PYBIND11_NOINLINE inline void instance::allocate_layout() { + auto &tinfo = all_type_info(Py_TYPE(this)); + + const size_t n_types = tinfo.size(); + + if (n_types == 0) + pybind11_fail("instance allocation failed: new instance has no pybind11-registered base types"); + + simple_layout = + n_types == 1 && tinfo.front()->holder_size_in_ptrs <= instance_simple_holder_in_ptrs(); + + // Simple path: no python-side multiple inheritance, and a small-enough holder + if (simple_layout) { + simple_value_holder[0] = nullptr; + simple_holder_constructed = false; + simple_instance_registered = false; + } + else { // multiple base types or a too-large holder + // Allocate space to hold: [v1*][h1][v2*][h2]...[bb...] where [vN*] is a value pointer, + // [hN] is the (uninitialized) holder instance for value N, and [bb...] is a set of bool + // values that tracks whether each associated holder has been initialized. Each [block] is + // padded, if necessary, to an integer multiple of sizeof(void *). + size_t space = 0; + for (auto t : tinfo) { + space += 1; // value pointer + space += t->holder_size_in_ptrs; // holder instance + } + size_t flags_at = space; + space += size_in_ptrs(n_types); // status bytes (holder_constructed and instance_registered) + + // Allocate space for flags, values, and holders, and initialize it to 0 (flags and values, + // in particular, need to be 0). Use Python's memory allocation functions: in Python 3.6 + // they default to using pymalloc, which is designed to be efficient for small allocations + // like the one we're doing here; in earlier versions (and for larger allocations) they are + // just wrappers around malloc. +#if PY_VERSION_HEX >= 0x03050000 + nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *)); + if (!nonsimple.values_and_holders) throw std::bad_alloc(); +#else + nonsimple.values_and_holders = (void **) PyMem_New(void *, space); + if (!nonsimple.values_and_holders) throw std::bad_alloc(); + std::memset(nonsimple.values_and_holders, 0, space * sizeof(void *)); +#endif + nonsimple.status = reinterpret_cast(&nonsimple.values_and_holders[flags_at]); + } + owned = true; +} + +PYBIND11_NOINLINE inline void instance::deallocate_layout() { + if (!simple_layout) + PyMem_Free(nonsimple.values_and_holders); +} + +PYBIND11_NOINLINE inline bool isinstance_generic(handle obj, const std::type_info &tp) { + handle type = detail::get_type_handle(tp, false); + if (!type) + return false; + return isinstance(obj, type); +} + +PYBIND11_NOINLINE inline std::string error_string() { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_RuntimeError, "Unknown internal error occurred"); + return "Unknown internal error occurred"; + } + + error_scope scope; // Preserve error state + + std::string errorString; + if (scope.type) { + errorString += handle(scope.type).attr("__name__").cast(); + errorString += ": "; + } + if (scope.value) + errorString += (std::string) str(scope.value); + + PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace); + +#if PY_MAJOR_VERSION >= 3 + if (scope.trace != nullptr) + PyException_SetTraceback(scope.value, scope.trace); +#endif + +#if !defined(PYPY_VERSION) + if (scope.trace) { + PyTracebackObject *trace = (PyTracebackObject *) scope.trace; + + /* Get the deepest trace possible */ + while (trace->tb_next) + trace = trace->tb_next; + + PyFrameObject *frame = trace->tb_frame; + errorString += "\n\nAt:\n"; + while (frame) { + int lineno = PyFrame_GetLineNumber(frame); + errorString += + " " + handle(frame->f_code->co_filename).cast() + + "(" + std::to_string(lineno) + "): " + + handle(frame->f_code->co_name).cast() + "\n"; + frame = frame->f_back; + } + } +#endif + + return errorString; +} + +PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr, const detail::type_info *type ) { + auto &instances = get_internals().registered_instances; + auto range = instances.equal_range(ptr); + for (auto it = range.first; it != range.second; ++it) { + for (auto vh : values_and_holders(it->second)) { + if (vh.type == type) + return handle((PyObject *) it->second); + } + } + return handle(); +} + +inline PyThreadState *get_thread_state_unchecked() { +#if defined(PYPY_VERSION) + return PyThreadState_GET(); +#elif PY_VERSION_HEX < 0x03000000 + return _PyThreadState_Current; +#elif PY_VERSION_HEX < 0x03050000 + return (PyThreadState*) _Py_atomic_load_relaxed(&_PyThreadState_Current); +#elif PY_VERSION_HEX < 0x03050200 + return (PyThreadState*) _PyThreadState_Current.value; +#else + return _PyThreadState_UncheckedGet(); +#endif +} + +// Forward declarations +inline void keep_alive_impl(handle nurse, handle patient); +inline PyObject *make_new_instance(PyTypeObject *type); + +class type_caster_generic { +public: + PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info) + : typeinfo(get_type_info(type_info)), cpptype(&type_info) { } + + type_caster_generic(const type_info *typeinfo) + : typeinfo(typeinfo), cpptype(typeinfo ? typeinfo->cpptype : nullptr) { } + + bool load(handle src, bool convert) { + return load_impl(src, convert); + } + + PYBIND11_NOINLINE static handle cast(const void *_src, return_value_policy policy, handle parent, + const detail::type_info *tinfo, + void *(*copy_constructor)(const void *), + void *(*move_constructor)(const void *), + const void *existing_holder = nullptr) { + if (!tinfo) // no type info: error will be set already + return handle(); + + void *src = const_cast(_src); + if (src == nullptr) + return none().release(); + + auto it_instances = get_internals().registered_instances.equal_range(src); + for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) { + for (auto instance_type : detail::all_type_info(Py_TYPE(it_i->second))) { + if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype)) + return handle((PyObject *) it_i->second).inc_ref(); + } + } + + auto inst = reinterpret_steal(make_new_instance(tinfo->type)); + auto wrapper = reinterpret_cast(inst.ptr()); + wrapper->owned = false; + void *&valueptr = values_and_holders(wrapper).begin()->value_ptr(); + + switch (policy) { + case return_value_policy::automatic: + case return_value_policy::take_ownership: + valueptr = src; + wrapper->owned = true; + break; + + case return_value_policy::automatic_reference: + case return_value_policy::reference: + valueptr = src; + wrapper->owned = false; + break; + + case return_value_policy::copy: + if (copy_constructor) + valueptr = copy_constructor(src); + else + throw cast_error("return_value_policy = copy, but the " + "object is non-copyable!"); + wrapper->owned = true; + break; + + case return_value_policy::move: + if (move_constructor) + valueptr = move_constructor(src); + else if (copy_constructor) + valueptr = copy_constructor(src); + else + throw cast_error("return_value_policy = move, but the " + "object is neither movable nor copyable!"); + wrapper->owned = true; + break; + + case return_value_policy::reference_internal: + valueptr = src; + wrapper->owned = false; + keep_alive_impl(inst, parent); + break; + + default: + throw cast_error("unhandled return_value_policy: should not happen!"); + } + + tinfo->init_instance(wrapper, existing_holder); + + return inst.release(); + } + + // Base methods for generic caster; there are overridden in copyable_holder_caster + void load_value(value_and_holder &&v_h) { + auto *&vptr = v_h.value_ptr(); + // Lazy allocation for unallocated values: + if (vptr == nullptr) { + auto *type = v_h.type ? v_h.type : typeinfo; + vptr = type->operator_new(type->type_size); + } + value = vptr; + } + bool try_implicit_casts(handle src, bool convert) { + for (auto &cast : typeinfo->implicit_casts) { + type_caster_generic sub_caster(*cast.first); + if (sub_caster.load(src, convert)) { + value = cast.second(sub_caster.value); + return true; + } + } + return false; + } + bool try_direct_conversions(handle src) { + for (auto &converter : *typeinfo->direct_conversions) { + if (converter(src.ptr(), value)) + return true; + } + return false; + } + void check_holder_compat() {} + + PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) { + auto caster = type_caster_generic(ti); + if (caster.load(src, false)) + return caster.value; + return nullptr; + } + + /// Try to load with foreign typeinfo, if available. Used when there is no + /// native typeinfo, or when the native one wasn't able to produce a value. + PYBIND11_NOINLINE bool try_load_foreign_module_local(handle src) { + constexpr auto *local_key = PYBIND11_MODULE_LOCAL_ID; + const auto pytype = src.get_type(); + if (!hasattr(pytype, local_key)) + return false; + + type_info *foreign_typeinfo = reinterpret_borrow(getattr(pytype, local_key)); + // Only consider this foreign loader if actually foreign and is a loader of the correct cpp type + if (foreign_typeinfo->module_local_load == &local_load + || (cpptype && !same_type(*cpptype, *foreign_typeinfo->cpptype))) + return false; + + if (auto result = foreign_typeinfo->module_local_load(src.ptr(), foreign_typeinfo)) { + value = result; + return true; + } + return false; + } + + // Implementation of `load`; this takes the type of `this` so that it can dispatch the relevant + // bits of code between here and copyable_holder_caster where the two classes need different + // logic (without having to resort to virtual inheritance). + template + PYBIND11_NOINLINE bool load_impl(handle src, bool convert) { + if (!src) return false; + if (!typeinfo) return try_load_foreign_module_local(src); + if (src.is_none()) { + // Defer accepting None to other overloads (if we aren't in convert mode): + if (!convert) return false; + value = nullptr; + return true; + } + + auto &this_ = static_cast(*this); + this_.check_holder_compat(); + + PyTypeObject *srctype = Py_TYPE(src.ptr()); + + // Case 1: If src is an exact type match for the target type then we can reinterpret_cast + // the instance's value pointer to the target type: + if (srctype == typeinfo->type) { + this_.load_value(reinterpret_cast(src.ptr())->get_value_and_holder()); + return true; + } + // Case 2: We have a derived class + else if (PyType_IsSubtype(srctype, typeinfo->type)) { + auto &bases = all_type_info(srctype); + bool no_cpp_mi = typeinfo->simple_type; + + // Case 2a: the python type is a Python-inherited derived class that inherits from just + // one simple (no MI) pybind11 class, or is an exact match, so the C++ instance is of + // the right type and we can use reinterpret_cast. + // (This is essentially the same as case 2b, but because not using multiple inheritance + // is extremely common, we handle it specially to avoid the loop iterator and type + // pointer lookup overhead) + if (bases.size() == 1 && (no_cpp_mi || bases.front()->type == typeinfo->type)) { + this_.load_value(reinterpret_cast(src.ptr())->get_value_and_holder()); + return true; + } + // Case 2b: the python type inherits from multiple C++ bases. Check the bases to see if + // we can find an exact match (or, for a simple C++ type, an inherited match); if so, we + // can safely reinterpret_cast to the relevant pointer. + else if (bases.size() > 1) { + for (auto base : bases) { + if (no_cpp_mi ? PyType_IsSubtype(base->type, typeinfo->type) : base->type == typeinfo->type) { + this_.load_value(reinterpret_cast(src.ptr())->get_value_and_holder(base)); + return true; + } + } + } + + // Case 2c: C++ multiple inheritance is involved and we couldn't find an exact type match + // in the registered bases, above, so try implicit casting (needed for proper C++ casting + // when MI is involved). + if (this_.try_implicit_casts(src, convert)) + return true; + } + + // Perform an implicit conversion + if (convert) { + for (auto &converter : typeinfo->implicit_conversions) { + auto temp = reinterpret_steal(converter(src.ptr(), typeinfo->type)); + if (load_impl(temp, false)) { + loader_life_support::add_patient(temp); + return true; + } + } + if (this_.try_direct_conversions(src)) + return true; + } + + // Failed to match local typeinfo. Try again with global. + if (typeinfo->module_local) { + if (auto gtype = get_global_type_info(*typeinfo->cpptype)) { + typeinfo = gtype; + return load(src, false); + } + } + + // Global typeinfo has precedence over foreign module_local + return try_load_foreign_module_local(src); + } + + + // Called to do type lookup and wrap the pointer and type in a pair when a dynamic_cast + // isn't needed or can't be used. If the type is unknown, sets the error and returns a pair + // with .second = nullptr. (p.first = nullptr is not an error: it becomes None). + PYBIND11_NOINLINE static std::pair src_and_type( + const void *src, const std::type_info &cast_type, const std::type_info *rtti_type = nullptr) { + if (auto *tpi = get_type_info(cast_type)) + return {src, const_cast(tpi)}; + + // Not found, set error: + std::string tname = rtti_type ? rtti_type->name() : cast_type.name(); + detail::clean_type_id(tname); + std::string msg = "Unregistered type : " + tname; + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return {nullptr, nullptr}; + } + + const type_info *typeinfo = nullptr; + const std::type_info *cpptype = nullptr; + void *value = nullptr; +}; + +/** + * Determine suitable casting operator for pointer-or-lvalue-casting type casters. The type caster + * needs to provide `operator T*()` and `operator T&()` operators. + * + * If the type supports moving the value away via an `operator T&&() &&` method, it should use + * `movable_cast_op_type` instead. + */ +template +using cast_op_type = + conditional_t>::value, + typename std::add_pointer>::type, + typename std::add_lvalue_reference>::type>; + +/** + * Determine suitable casting operator for a type caster with a movable value. Such a type caster + * needs to provide `operator T*()`, `operator T&()`, and `operator T&&() &&`. The latter will be + * called in appropriate contexts where the value can be moved rather than copied. + * + * These operator are automatically provided when using the PYBIND11_TYPE_CASTER macro. + */ +template +using movable_cast_op_type = + conditional_t::type>::value, + typename std::add_pointer>::type, + conditional_t::value, + typename std::add_rvalue_reference>::type, + typename std::add_lvalue_reference>::type>>; + +// std::is_copy_constructible isn't quite enough: it lets std::vector (and similar) through when +// T is non-copyable, but code containing such a copy constructor fails to actually compile. +template struct is_copy_constructible : std::is_copy_constructible {}; + +// Specialization for types that appear to be copy constructible but also look like stl containers +// (we specifically check for: has `value_type` and `reference` with `reference = value_type&`): if +// so, copy constructability depends on whether the value_type is copy constructible. +template struct is_copy_constructible, + std::is_same + >::value>> : is_copy_constructible {}; + +#if !defined(PYBIND11_CPP17) +// Likewise for std::pair before C++17 (which mandates that the copy constructor not exist when the +// two types aren't themselves copy constructible). +template struct is_copy_constructible> + : all_of, is_copy_constructible> {}; +#endif + +/// Generic type caster for objects stored on the heap +template class type_caster_base : public type_caster_generic { + using itype = intrinsic_t; +public: + static PYBIND11_DESCR name() { return type_descr(_()); } + + type_caster_base() : type_caster_base(typeid(type)) { } + explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) { } + + static handle cast(const itype &src, return_value_policy policy, handle parent) { + if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference) + policy = return_value_policy::copy; + return cast(&src, policy, parent); + } + + static handle cast(itype &&src, return_value_policy, handle parent) { + return cast(&src, return_value_policy::move, parent); + } + + // Returns a (pointer, type_info) pair taking care of necessary RTTI type lookup for a + // polymorphic type. If the instance isn't derived, returns the non-RTTI base version. + template ::value, int> = 0> + static std::pair src_and_type(const itype *src) { + const void *vsrc = src; + auto &cast_type = typeid(itype); + const std::type_info *instance_type = nullptr; + if (vsrc) { + instance_type = &typeid(*src); + if (!same_type(cast_type, *instance_type)) { + // This is a base pointer to a derived type; if it is a pybind11-registered type, we + // can get the correct derived pointer (which may be != base pointer) by a + // dynamic_cast to most derived type: + if (auto *tpi = get_type_info(*instance_type)) + return {dynamic_cast(src), const_cast(tpi)}; + } + } + // Otherwise we have either a nullptr, an `itype` pointer, or an unknown derived pointer, so + // don't do a cast + return type_caster_generic::src_and_type(vsrc, cast_type, instance_type); + } + + // Non-polymorphic type, so no dynamic casting; just call the generic version directly + template ::value, int> = 0> + static std::pair src_and_type(const itype *src) { + return type_caster_generic::src_and_type(src, typeid(itype)); + } + + static handle cast(const itype *src, return_value_policy policy, handle parent) { + auto st = src_and_type(src); + return type_caster_generic::cast( + st.first, policy, parent, st.second, + make_copy_constructor(src), make_move_constructor(src)); + } + + static handle cast_holder(const itype *src, const void *holder) { + auto st = src_and_type(src); + return type_caster_generic::cast( + st.first, return_value_policy::take_ownership, {}, st.second, + nullptr, nullptr, holder); + } + + template using cast_op_type = cast_op_type; + + operator itype*() { return (type *) value; } + operator itype&() { if (!value) throw reference_cast_error(); return *((itype *) value); } + +protected: + using Constructor = void *(*)(const void *); + + /* Only enabled when the types are {copy,move}-constructible *and* when the type + does not have a private operator new implementation. */ + template ::value>> + static auto make_copy_constructor(const T *x) -> decltype(new T(*x), Constructor{}) { + return [](const void *arg) -> void * { + return new T(*reinterpret_cast(arg)); + }; + } + + template ::value>> + static auto make_move_constructor(const T *x) -> decltype(new T(std::move(*const_cast(x))), Constructor{}) { + return [](const void *arg) -> void * { + return new T(std::move(*const_cast(reinterpret_cast(arg)))); + }; + } + + static Constructor make_copy_constructor(...) { return nullptr; } + static Constructor make_move_constructor(...) { return nullptr; } +}; + +template class type_caster : public type_caster_base { }; +template using make_caster = type_caster>; + +// Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T +template typename make_caster::template cast_op_type cast_op(make_caster &caster) { + return caster.operator typename make_caster::template cast_op_type(); +} +template typename make_caster::template cast_op_type::type> +cast_op(make_caster &&caster) { + return std::move(caster).operator + typename make_caster::template cast_op_type::type>(); +} + +template class type_caster> { +private: + using caster_t = make_caster; + caster_t subcaster; + using subcaster_cast_op_type = typename caster_t::template cast_op_type; + static_assert(std::is_same::type &, subcaster_cast_op_type>::value, + "std::reference_wrapper caster requires T to have a caster with an `T &` operator"); +public: + bool load(handle src, bool convert) { return subcaster.load(src, convert); } + static PYBIND11_DESCR name() { return caster_t::name(); } + static handle cast(const std::reference_wrapper &src, return_value_policy policy, handle parent) { + // It is definitely wrong to take ownership of this pointer, so mask that rvp + if (policy == return_value_policy::take_ownership || policy == return_value_policy::automatic) + policy = return_value_policy::automatic_reference; + return caster_t::cast(&src.get(), policy, parent); + } + template using cast_op_type = std::reference_wrapper; + operator std::reference_wrapper() { return subcaster.operator subcaster_cast_op_type&(); } +}; + +#define PYBIND11_TYPE_CASTER(type, py_name) \ + protected: \ + type value; \ + public: \ + static PYBIND11_DESCR name() { return type_descr(py_name); } \ + template >::value, int> = 0> \ + static handle cast(T_ *src, return_value_policy policy, handle parent) { \ + if (!src) return none().release(); \ + if (policy == return_value_policy::take_ownership) { \ + auto h = cast(std::move(*src), policy, parent); delete src; return h; \ + } else { \ + return cast(*src, policy, parent); \ + } \ + } \ + operator type*() { return &value; } \ + operator type&() { return value; } \ + operator type&&() && { return std::move(value); } \ + template using cast_op_type = pybind11::detail::movable_cast_op_type + + +template using is_std_char_type = any_of< + std::is_same, /* std::string */ + std::is_same, /* std::u16string */ + std::is_same, /* std::u32string */ + std::is_same /* std::wstring */ +>; + +template +struct type_caster::value && !is_std_char_type::value>> { + using _py_type_0 = conditional_t; + using _py_type_1 = conditional_t::value, _py_type_0, typename std::make_unsigned<_py_type_0>::type>; + using py_type = conditional_t::value, double, _py_type_1>; +public: + + bool load(handle src, bool convert) { + py_type py_value; + + if (!src) + return false; + + if (std::is_floating_point::value) { + if (convert || PyFloat_Check(src.ptr())) + py_value = (py_type) PyFloat_AsDouble(src.ptr()); + else + return false; + } else if (PyFloat_Check(src.ptr())) { + return false; + } else if (std::is_unsigned::value) { + py_value = as_unsigned(src.ptr()); + } else { // signed integer: + py_value = sizeof(T) <= sizeof(long) + ? (py_type) PyLong_AsLong(src.ptr()) + : (py_type) PYBIND11_LONG_AS_LONGLONG(src.ptr()); + } + + bool py_err = py_value == (py_type) -1 && PyErr_Occurred(); + if (py_err || (std::is_integral::value && sizeof(py_type) != sizeof(T) && + (py_value < (py_type) std::numeric_limits::min() || + py_value > (py_type) std::numeric_limits::max()))) { + bool type_error = py_err && PyErr_ExceptionMatches( +#if PY_VERSION_HEX < 0x03000000 && !defined(PYPY_VERSION) + PyExc_SystemError +#else + PyExc_TypeError +#endif + ); + PyErr_Clear(); + if (type_error && convert && PyNumber_Check(src.ptr())) { + auto tmp = reinterpret_steal(std::is_floating_point::value + ? PyNumber_Float(src.ptr()) + : PyNumber_Long(src.ptr())); + PyErr_Clear(); + return load(tmp, false); + } + return false; + } + + value = (T) py_value; + return true; + } + + static handle cast(T src, return_value_policy /* policy */, handle /* parent */) { + if (std::is_floating_point::value) { + return PyFloat_FromDouble((double) src); + } else if (sizeof(T) <= sizeof(long)) { + if (std::is_signed::value) + return PyLong_FromLong((long) src); + else + return PyLong_FromUnsignedLong((unsigned long) src); + } else { + if (std::is_signed::value) + return PyLong_FromLongLong((long long) src); + else + return PyLong_FromUnsignedLongLong((unsigned long long) src); + } + } + + PYBIND11_TYPE_CASTER(T, _::value>("int", "float")); +}; + +template struct void_caster { +public: + bool load(handle src, bool) { + if (src && src.is_none()) + return true; + return false; + } + static handle cast(T, return_value_policy /* policy */, handle /* parent */) { + return none().inc_ref(); + } + PYBIND11_TYPE_CASTER(T, _("None")); +}; + +template <> class type_caster : public void_caster {}; + +template <> class type_caster : public type_caster { +public: + using type_caster::cast; + + bool load(handle h, bool) { + if (!h) { + return false; + } else if (h.is_none()) { + value = nullptr; + return true; + } + + /* Check if this is a capsule */ + if (isinstance(h)) { + value = reinterpret_borrow(h); + return true; + } + + /* Check if this is a C++ type */ + auto &bases = all_type_info((PyTypeObject *) h.get_type().ptr()); + if (bases.size() == 1) { // Only allowing loading from a single-value type + value = values_and_holders(reinterpret_cast(h.ptr())).begin()->value_ptr(); + return true; + } + + /* Fail */ + return false; + } + + static handle cast(const void *ptr, return_value_policy /* policy */, handle /* parent */) { + if (ptr) + return capsule(ptr).release(); + else + return none().inc_ref(); + } + + template using cast_op_type = void*&; + operator void *&() { return value; } + static PYBIND11_DESCR name() { return type_descr(_("capsule")); } +private: + void *value = nullptr; +}; + +template <> class type_caster : public void_caster { }; + +template <> class type_caster { +public: + bool load(handle src, bool convert) { + if (!src) return false; + else if (src.ptr() == Py_True) { value = true; return true; } + else if (src.ptr() == Py_False) { value = false; return true; } + else if (convert || !strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name)) { + // (allow non-implicit conversion for numpy booleans) + + Py_ssize_t res = -1; + if (src.is_none()) { + res = 0; // None is implicitly converted to False + } + #if defined(PYPY_VERSION) + // On PyPy, check that "__bool__" (or "__nonzero__" on Python 2.7) attr exists + else if (hasattr(src, PYBIND11_BOOL_ATTR)) { + res = PyObject_IsTrue(src.ptr()); + } + #else + // Alternate approach for CPython: this does the same as the above, but optimized + // using the CPython API so as to avoid an unneeded attribute lookup. + else if (auto tp_as_number = src.ptr()->ob_type->tp_as_number) { + if (PYBIND11_NB_BOOL(tp_as_number)) { + res = (*PYBIND11_NB_BOOL(tp_as_number))(src.ptr()); + } + } + #endif + if (res == 0 || res == 1) { + value = (bool) res; + return true; + } + } + return false; + } + static handle cast(bool src, return_value_policy /* policy */, handle /* parent */) { + return handle(src ? Py_True : Py_False).inc_ref(); + } + PYBIND11_TYPE_CASTER(bool, _("bool")); +}; + +// Helper class for UTF-{8,16,32} C++ stl strings: +template struct string_caster { + using CharT = typename StringType::value_type; + + // Simplify life by being able to assume standard char sizes (the standard only guarantees + // minimums, but Python requires exact sizes) + static_assert(!std::is_same::value || sizeof(CharT) == 1, "Unsupported char size != 1"); + static_assert(!std::is_same::value || sizeof(CharT) == 2, "Unsupported char16_t size != 2"); + static_assert(!std::is_same::value || sizeof(CharT) == 4, "Unsupported char32_t size != 4"); + // wchar_t can be either 16 bits (Windows) or 32 (everywhere else) + static_assert(!std::is_same::value || sizeof(CharT) == 2 || sizeof(CharT) == 4, + "Unsupported wchar_t size != 2/4"); + static constexpr size_t UTF_N = 8 * sizeof(CharT); + + bool load(handle src, bool) { +#if PY_MAJOR_VERSION < 3 + object temp; +#endif + handle load_src = src; + if (!src) { + return false; + } else if (!PyUnicode_Check(load_src.ptr())) { +#if PY_MAJOR_VERSION >= 3 + return load_bytes(load_src); +#else + if (sizeof(CharT) == 1) { + return load_bytes(load_src); + } + + // The below is a guaranteed failure in Python 3 when PyUnicode_Check returns false + if (!PYBIND11_BYTES_CHECK(load_src.ptr())) + return false; + + temp = reinterpret_steal(PyUnicode_FromObject(load_src.ptr())); + if (!temp) { PyErr_Clear(); return false; } + load_src = temp; +#endif + } + + object utfNbytes = reinterpret_steal(PyUnicode_AsEncodedString( + load_src.ptr(), UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr)); + if (!utfNbytes) { PyErr_Clear(); return false; } + + const CharT *buffer = reinterpret_cast(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr())); + size_t length = (size_t) PYBIND11_BYTES_SIZE(utfNbytes.ptr()) / sizeof(CharT); + if (UTF_N > 8) { buffer++; length--; } // Skip BOM for UTF-16/32 + value = StringType(buffer, length); + + // If we're loading a string_view we need to keep the encoded Python object alive: + if (IsView) + loader_life_support::add_patient(utfNbytes); + + return true; + } + + static handle cast(const StringType &src, return_value_policy /* policy */, handle /* parent */) { + const char *buffer = reinterpret_cast(src.data()); + ssize_t nbytes = ssize_t(src.size() * sizeof(CharT)); + handle s = decode_utfN(buffer, nbytes); + if (!s) throw error_already_set(); + return s; + } + + PYBIND11_TYPE_CASTER(StringType, _(PYBIND11_STRING_NAME)); + +private: + static handle decode_utfN(const char *buffer, ssize_t nbytes) { +#if !defined(PYPY_VERSION) + return + UTF_N == 8 ? PyUnicode_DecodeUTF8(buffer, nbytes, nullptr) : + UTF_N == 16 ? PyUnicode_DecodeUTF16(buffer, nbytes, nullptr, nullptr) : + PyUnicode_DecodeUTF32(buffer, nbytes, nullptr, nullptr); +#else + // PyPy seems to have multiple problems related to PyUnicode_UTF*: the UTF8 version + // sometimes segfaults for unknown reasons, while the UTF16 and 32 versions require a + // non-const char * arguments, which is also a nuissance, so bypass the whole thing by just + // passing the encoding as a string value, which works properly: + return PyUnicode_Decode(buffer, nbytes, UTF_N == 8 ? "utf-8" : UTF_N == 16 ? "utf-16" : "utf-32", nullptr); +#endif + } + + // When loading into a std::string or char*, accept a bytes object as-is (i.e. + // without any encoding/decoding attempt). For other C++ char sizes this is a no-op. + // which supports loading a unicode from a str, doesn't take this path. + template + bool load_bytes(enable_if_t src) { + if (PYBIND11_BYTES_CHECK(src.ptr())) { + // We were passed a Python 3 raw bytes; accept it into a std::string or char* + // without any encoding attempt. + const char *bytes = PYBIND11_BYTES_AS_STRING(src.ptr()); + if (bytes) { + value = StringType(bytes, (size_t) PYBIND11_BYTES_SIZE(src.ptr())); + return true; + } + } + + return false; + } + + template + bool load_bytes(enable_if_t) { return false; } +}; + +template +struct type_caster, enable_if_t::value>> + : string_caster> {}; + +#ifdef PYBIND11_HAS_STRING_VIEW +template +struct type_caster, enable_if_t::value>> + : string_caster, true> {}; +#endif + +// Type caster for C-style strings. We basically use a std::string type caster, but also add the +// ability to use None as a nullptr char* (which the string caster doesn't allow). +template struct type_caster::value>> { + using StringType = std::basic_string; + using StringCaster = type_caster; + StringCaster str_caster; + bool none = false; + CharT one_char = 0; +public: + bool load(handle src, bool convert) { + if (!src) return false; + if (src.is_none()) { + // Defer accepting None to other overloads (if we aren't in convert mode): + if (!convert) return false; + none = true; + return true; + } + return str_caster.load(src, convert); + } + + static handle cast(const CharT *src, return_value_policy policy, handle parent) { + if (src == nullptr) return pybind11::none().inc_ref(); + return StringCaster::cast(StringType(src), policy, parent); + } + + static handle cast(CharT src, return_value_policy policy, handle parent) { + if (std::is_same::value) { + handle s = PyUnicode_DecodeLatin1((const char *) &src, 1, nullptr); + if (!s) throw error_already_set(); + return s; + } + return StringCaster::cast(StringType(1, src), policy, parent); + } + + operator CharT*() { return none ? nullptr : const_cast(static_cast(str_caster).c_str()); } + operator CharT&() { + if (none) + throw value_error("Cannot convert None to a character"); + + auto &value = static_cast(str_caster); + size_t str_len = value.size(); + if (str_len == 0) + throw value_error("Cannot convert empty string to a character"); + + // If we're in UTF-8 mode, we have two possible failures: one for a unicode character that + // is too high, and one for multiple unicode characters (caught later), so we need to figure + // out how long the first encoded character is in bytes to distinguish between these two + // errors. We also allow want to allow unicode characters U+0080 through U+00FF, as those + // can fit into a single char value. + if (StringCaster::UTF_N == 8 && str_len > 1 && str_len <= 4) { + unsigned char v0 = static_cast(value[0]); + size_t char0_bytes = !(v0 & 0x80) ? 1 : // low bits only: 0-127 + (v0 & 0xE0) == 0xC0 ? 2 : // 0b110xxxxx - start of 2-byte sequence + (v0 & 0xF0) == 0xE0 ? 3 : // 0b1110xxxx - start of 3-byte sequence + 4; // 0b11110xxx - start of 4-byte sequence + + if (char0_bytes == str_len) { + // If we have a 128-255 value, we can decode it into a single char: + if (char0_bytes == 2 && (v0 & 0xFC) == 0xC0) { // 0x110000xx 0x10xxxxxx + one_char = static_cast(((v0 & 3) << 6) + (static_cast(value[1]) & 0x3F)); + return one_char; + } + // Otherwise we have a single character, but it's > U+00FF + throw value_error("Character code point not in range(0x100)"); + } + } + + // UTF-16 is much easier: we can only have a surrogate pair for values above U+FFFF, thus a + // surrogate pair with total length 2 instantly indicates a range error (but not a "your + // string was too long" error). + else if (StringCaster::UTF_N == 16 && str_len == 2) { + one_char = static_cast(value[0]); + if (one_char >= 0xD800 && one_char < 0xE000) + throw value_error("Character code point not in range(0x10000)"); + } + + if (str_len != 1) + throw value_error("Expected a character, but multi-character string found"); + + one_char = value[0]; + return one_char; + } + + static PYBIND11_DESCR name() { return type_descr(_(PYBIND11_STRING_NAME)); } + template using cast_op_type = pybind11::detail::cast_op_type<_T>; +}; + +// Base implementation for std::tuple and std::pair +template class Tuple, typename... Ts> class tuple_caster { + using type = Tuple; + static constexpr auto size = sizeof...(Ts); + using indices = make_index_sequence; +public: + + bool load(handle src, bool convert) { + if (!isinstance(src)) + return false; + const auto seq = reinterpret_borrow(src); + if (seq.size() != size) + return false; + return load_impl(seq, convert, indices{}); + } + + template + static handle cast(T &&src, return_value_policy policy, handle parent) { + return cast_impl(std::forward(src), policy, parent, indices{}); + } + + static PYBIND11_DESCR name() { + return type_descr(_("Tuple[") + detail::concat(make_caster::name()...) + _("]")); + } + + template using cast_op_type = type; + + operator type() & { return implicit_cast(indices{}); } + operator type() && { return std::move(*this).implicit_cast(indices{}); } + +protected: + template + type implicit_cast(index_sequence) & { return type(cast_op(std::get(subcasters))...); } + template + type implicit_cast(index_sequence) && { return type(cast_op(std::move(std::get(subcasters)))...); } + + static constexpr bool load_impl(const sequence &, bool, index_sequence<>) { return true; } + + template + bool load_impl(const sequence &seq, bool convert, index_sequence) { + for (bool r : {std::get(subcasters).load(seq[Is], convert)...}) + if (!r) + return false; + return true; + } + + /* Implementation: Convert a C++ tuple into a Python tuple */ + template + static handle cast_impl(T &&src, return_value_policy policy, handle parent, index_sequence) { + std::array entries{{ + reinterpret_steal(make_caster::cast(std::get(std::forward(src)), policy, parent))... + }}; + for (const auto &entry: entries) + if (!entry) + return handle(); + tuple result(size); + int counter = 0; + for (auto & entry: entries) + PyTuple_SET_ITEM(result.ptr(), counter++, entry.release().ptr()); + return result.release(); + } + + Tuple...> subcasters; +}; + +template class type_caster> + : public tuple_caster {}; + +template class type_caster> + : public tuple_caster {}; + +/// Helper class which abstracts away certain actions. Users can provide specializations for +/// custom holders, but it's only necessary if the type has a non-standard interface. +template +struct holder_helper { + static auto get(const T &p) -> decltype(p.get()) { return p.get(); } +}; + +/// Type caster for holder types like std::shared_ptr, etc. +template +struct copyable_holder_caster : public type_caster_base { +public: + using base = type_caster_base; + static_assert(std::is_base_of>::value, + "Holder classes are only supported for custom types"); + using base::base; + using base::cast; + using base::typeinfo; + using base::value; + + bool load(handle src, bool convert) { + return base::template load_impl>(src, convert); + } + + explicit operator type*() { return this->value; } + explicit operator type&() { return *(this->value); } + explicit operator holder_type*() { return &holder; } + + // Workaround for Intel compiler bug + // see pybind11 issue 94 + #if defined(__ICC) || defined(__INTEL_COMPILER) + operator holder_type&() { return holder; } + #else + explicit operator holder_type&() { return holder; } + #endif + + static handle cast(const holder_type &src, return_value_policy, handle) { + const auto *ptr = holder_helper::get(src); + return type_caster_base::cast_holder(ptr, &src); + } + +protected: + friend class type_caster_generic; + void check_holder_compat() { + if (typeinfo->default_holder) + throw cast_error("Unable to load a custom holder type from a default-holder instance"); + } + + bool load_value(value_and_holder &&v_h) { + if (v_h.holder_constructed()) { + value = v_h.value_ptr(); + holder = v_h.template holder(); + return true; + } else { + throw cast_error("Unable to cast from non-held to held instance (T& to Holder) " +#if defined(NDEBUG) + "(compile in debug mode for type information)"); +#else + "of type '" + type_id() + "''"); +#endif + } + } + + template ::value, int> = 0> + bool try_implicit_casts(handle, bool) { return false; } + + template ::value, int> = 0> + bool try_implicit_casts(handle src, bool convert) { + for (auto &cast : typeinfo->implicit_casts) { + copyable_holder_caster sub_caster(*cast.first); + if (sub_caster.load(src, convert)) { + value = cast.second(sub_caster.value); + holder = holder_type(sub_caster.holder, (type *) value); + return true; + } + } + return false; + } + + static bool try_direct_conversions(handle) { return false; } + + + holder_type holder; +}; + +/// Specialize for the common std::shared_ptr, so users don't need to +template +class type_caster> : public copyable_holder_caster> { }; + +template +struct move_only_holder_caster { + static_assert(std::is_base_of, type_caster>::value, + "Holder classes are only supported for custom types"); + + static handle cast(holder_type &&src, return_value_policy, handle) { + auto *ptr = holder_helper::get(src); + return type_caster_base::cast_holder(ptr, &src); + } + static PYBIND11_DESCR name() { return type_caster_base::name(); } +}; + +template +class type_caster> + : public move_only_holder_caster> { }; + +template +using type_caster_holder = conditional_t::value, + copyable_holder_caster, + move_only_holder_caster>; + +template struct always_construct_holder { static constexpr bool value = Value; }; + +/// Create a specialization for custom holder types (silently ignores std::shared_ptr) +#define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type, ...) \ + namespace pybind11 { namespace detail { \ + template \ + struct always_construct_holder : always_construct_holder { }; \ + template \ + class type_caster::value>> \ + : public type_caster_holder { }; \ + }} + +// PYBIND11_DECLARE_HOLDER_TYPE holder types: +template struct is_holder_type : + std::is_base_of, detail::type_caster> {}; +// Specialization for always-supported unique_ptr holders: +template struct is_holder_type> : + std::true_type {}; + +template struct handle_type_name { static PYBIND11_DESCR name() { return _(); } }; +template <> struct handle_type_name { static PYBIND11_DESCR name() { return _(PYBIND11_BYTES_NAME); } }; +template <> struct handle_type_name { static PYBIND11_DESCR name() { return _("*args"); } }; +template <> struct handle_type_name { static PYBIND11_DESCR name() { return _("**kwargs"); } }; + +template +struct pyobject_caster { + template ::value, int> = 0> + bool load(handle src, bool /* convert */) { value = src; return static_cast(value); } + + template ::value, int> = 0> + bool load(handle src, bool /* convert */) { + if (!isinstance(src)) + return false; + value = reinterpret_borrow(src); + return true; + } + + static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) { + return src.inc_ref(); + } + PYBIND11_TYPE_CASTER(type, handle_type_name::name()); +}; + +template +class type_caster::value>> : public pyobject_caster { }; + +// Our conditions for enabling moving are quite restrictive: +// At compile time: +// - T needs to be a non-const, non-pointer, non-reference type +// - type_caster::operator T&() must exist +// - the type must be move constructible (obviously) +// At run-time: +// - if the type is non-copy-constructible, the object must be the sole owner of the type (i.e. it +// must have ref_count() == 1)h +// If any of the above are not satisfied, we fall back to copying. +template using move_is_plain_type = satisfies_none_of; +template struct move_always : std::false_type {}; +template struct move_always, + negation>, + std::is_move_constructible, + std::is_same>().operator T&()), T&> +>::value>> : std::true_type {}; +template struct move_if_unreferenced : std::false_type {}; +template struct move_if_unreferenced, + negation>, + std::is_move_constructible, + std::is_same>().operator T&()), T&> +>::value>> : std::true_type {}; +template using move_never = none_of, move_if_unreferenced>; + +// Detect whether returning a `type` from a cast on type's type_caster is going to result in a +// reference or pointer to a local variable of the type_caster. Basically, only +// non-reference/pointer `type`s and reference/pointers from a type_caster_generic are safe; +// everything else returns a reference/pointer to a local variable. +template using cast_is_temporary_value_reference = bool_constant< + (std::is_reference::value || std::is_pointer::value) && + !std::is_base_of>::value +>; + +// When a value returned from a C++ function is being cast back to Python, we almost always want to +// force `policy = move`, regardless of the return value policy the function/method was declared +// with. Some classes (most notably Eigen::Ref and related) need to avoid this, and so can do so by +// specializing this struct. +template struct return_value_policy_override { + static return_value_policy policy(return_value_policy p) { + return !std::is_lvalue_reference::value && !std::is_pointer::value + ? return_value_policy::move : p; + } +}; + +// Basic python -> C++ casting; throws if casting fails +template type_caster &load_type(type_caster &conv, const handle &handle) { + if (!conv.load(handle, true)) { +#if defined(NDEBUG) + throw cast_error("Unable to cast Python instance to C++ type (compile in debug mode for details)"); +#else + throw cast_error("Unable to cast Python instance of type " + + (std::string) str(handle.get_type()) + " to C++ type '" + type_id() + "'"); +#endif + } + return conv; +} +// Wrapper around the above that also constructs and returns a type_caster +template make_caster load_type(const handle &handle) { + make_caster conv; + load_type(conv, handle); + return conv; +} + +NAMESPACE_END(detail) + +// pytype -> C++ type +template ::value, int> = 0> +T cast(const handle &handle) { + using namespace detail; + static_assert(!cast_is_temporary_value_reference::value, + "Unable to cast type to reference: value is local to type caster"); + return cast_op(load_type(handle)); +} + +// pytype -> pytype (calls converting constructor) +template ::value, int> = 0> +T cast(const handle &handle) { return T(reinterpret_borrow(handle)); } + +// C++ type -> py::object +template ::value, int> = 0> +object cast(const T &value, return_value_policy policy = return_value_policy::automatic_reference, + handle parent = handle()) { + if (policy == return_value_policy::automatic) + policy = std::is_pointer::value ? return_value_policy::take_ownership : return_value_policy::copy; + else if (policy == return_value_policy::automatic_reference) + policy = std::is_pointer::value ? return_value_policy::reference : return_value_policy::copy; + return reinterpret_steal(detail::make_caster::cast(value, policy, parent)); +} + +template T handle::cast() const { return pybind11::cast(*this); } +template <> inline void handle::cast() const { return; } + +template +detail::enable_if_t::value, T> move(object &&obj) { + if (obj.ref_count() > 1) +#if defined(NDEBUG) + throw cast_error("Unable to cast Python instance to C++ rvalue: instance has multiple references" + " (compile in debug mode for details)"); +#else + throw cast_error("Unable to move from Python " + (std::string) str(obj.get_type()) + + " instance to C++ " + type_id() + " instance: instance has multiple references"); +#endif + + // Move into a temporary and return that, because the reference may be a local value of `conv` + T ret = std::move(detail::load_type(obj).operator T&()); + return ret; +} + +// Calling cast() on an rvalue calls pybind::cast with the object rvalue, which does: +// - If we have to move (because T has no copy constructor), do it. This will fail if the moved +// object has multiple references, but trying to copy will fail to compile. +// - If both movable and copyable, check ref count: if 1, move; otherwise copy +// - Otherwise (not movable), copy. +template detail::enable_if_t::value, T> cast(object &&object) { + return move(std::move(object)); +} +template detail::enable_if_t::value, T> cast(object &&object) { + if (object.ref_count() > 1) + return cast(object); + else + return move(std::move(object)); +} +template detail::enable_if_t::value, T> cast(object &&object) { + return cast(object); +} + +template T object::cast() const & { return pybind11::cast(*this); } +template T object::cast() && { return pybind11::cast(std::move(*this)); } +template <> inline void object::cast() const & { return; } +template <> inline void object::cast() && { return; } + +NAMESPACE_BEGIN(detail) + +// Declared in pytypes.h: +template ::value, int>> +object object_or_cast(T &&o) { return pybind11::cast(std::forward(o)); } + +struct overload_unused {}; // Placeholder type for the unneeded (and dead code) static variable in the OVERLOAD_INT macro +template using overload_caster_t = conditional_t< + cast_is_temporary_value_reference::value, make_caster, overload_unused>; + +// Trampoline use: for reference/pointer types to value-converted values, we do a value cast, then +// store the result in the given variable. For other types, this is a no-op. +template enable_if_t::value, T> cast_ref(object &&o, make_caster &caster) { + return cast_op(load_type(caster, o)); +} +template enable_if_t::value, T> cast_ref(object &&, overload_unused &) { + pybind11_fail("Internal error: cast_ref fallback invoked"); } + +// Trampoline use: Having a pybind11::cast with an invalid reference type is going to static_assert, even +// though if it's in dead code, so we provide a "trampoline" to pybind11::cast that only does anything in +// cases where pybind11::cast is valid. +template enable_if_t::value, T> cast_safe(object &&o) { + return pybind11::cast(std::move(o)); } +template enable_if_t::value, T> cast_safe(object &&) { + pybind11_fail("Internal error: cast_safe fallback invoked"); } +template <> inline void cast_safe(object &&) {} + +NAMESPACE_END(detail) + +template +tuple make_tuple() { return tuple(0); } + +template tuple make_tuple(Args&&... args_) { + constexpr size_t size = sizeof...(Args); + std::array args { + { reinterpret_steal(detail::make_caster::cast( + std::forward(args_), policy, nullptr))... } + }; + for (size_t i = 0; i < args.size(); i++) { + if (!args[i]) { +#if defined(NDEBUG) + throw cast_error("make_tuple(): unable to convert arguments to Python object (compile in debug mode for details)"); +#else + std::array argtypes { {type_id()...} }; + throw cast_error("make_tuple(): unable to convert argument of type '" + + argtypes[i] + "' to Python object"); +#endif + } + } + tuple result(size); + int counter = 0; + for (auto &arg_value : args) + PyTuple_SET_ITEM(result.ptr(), counter++, arg_value.release().ptr()); + return result; +} + +/// \ingroup annotations +/// Annotation for arguments +struct arg { + /// Constructs an argument with the name of the argument; if null or omitted, this is a positional argument. + constexpr explicit arg(const char *name = nullptr) : name(name), flag_noconvert(false), flag_none(true) { } + /// Assign a value to this argument + template arg_v operator=(T &&value) const; + /// Indicate that the type should not be converted in the type caster + arg &noconvert(bool flag = true) { flag_noconvert = flag; return *this; } + /// Indicates that the argument should/shouldn't allow None (e.g. for nullable pointer args) + arg &none(bool flag = true) { flag_none = flag; return *this; } + + const char *name; ///< If non-null, this is a named kwargs argument + bool flag_noconvert : 1; ///< If set, do not allow conversion (requires a supporting type caster!) + bool flag_none : 1; ///< If set (the default), allow None to be passed to this argument +}; + +/// \ingroup annotations +/// Annotation for arguments with values +struct arg_v : arg { +private: + template + arg_v(arg &&base, T &&x, const char *descr = nullptr) + : arg(base), + value(reinterpret_steal( + detail::make_caster::cast(x, return_value_policy::automatic, {}) + )), + descr(descr) +#if !defined(NDEBUG) + , type(type_id()) +#endif + { } + +public: + /// Direct construction with name, default, and description + template + arg_v(const char *name, T &&x, const char *descr = nullptr) + : arg_v(arg(name), std::forward(x), descr) { } + + /// Called internally when invoking `py::arg("a") = value` + template + arg_v(const arg &base, T &&x, const char *descr = nullptr) + : arg_v(arg(base), std::forward(x), descr) { } + + /// Same as `arg::noconvert()`, but returns *this as arg_v&, not arg& + arg_v &noconvert(bool flag = true) { arg::noconvert(flag); return *this; } + + /// Same as `arg::nonone()`, but returns *this as arg_v&, not arg& + arg_v &none(bool flag = true) { arg::none(flag); return *this; } + + /// The default value + object value; + /// The (optional) description of the default value + const char *descr; +#if !defined(NDEBUG) + /// The C++ type name of the default value (only available when compiled in debug mode) + std::string type; +#endif +}; + +template +arg_v arg::operator=(T &&value) const { return {std::move(*this), std::forward(value)}; } + +/// Alias for backward compatibility -- to be removed in version 2.0 +template using arg_t = arg_v; + +inline namespace literals { +/** \rst + String literal version of `arg` + \endrst */ +constexpr arg operator"" _a(const char *name, size_t) { return arg(name); } +} + +NAMESPACE_BEGIN(detail) + +// forward declaration (definition in attr.h) +struct function_record; + +/// Internal data associated with a single function call +struct function_call { + function_call(function_record &f, handle p); // Implementation in attr.h + + /// The function data: + const function_record &func; + + /// Arguments passed to the function: + std::vector args; + + /// The `convert` value the arguments should be loaded with + std::vector args_convert; + + /// Extra references for the optional `py::args` and/or `py::kwargs` arguments (which, if + /// present, are also in `args` but without a reference). + object args_ref, kwargs_ref; + + /// The parent, if any + handle parent; + + /// If this is a call to an initializer, this argument contains `self` + handle init_self; +}; + + +/// Helper class which loads arguments for C++ functions called from Python +template +class argument_loader { + using indices = make_index_sequence; + + template using argument_is_args = std::is_same, args>; + template using argument_is_kwargs = std::is_same, kwargs>; + // Get args/kwargs argument positions relative to the end of the argument list: + static constexpr auto args_pos = constexpr_first() - (int) sizeof...(Args), + kwargs_pos = constexpr_first() - (int) sizeof...(Args); + + static constexpr bool args_kwargs_are_last = kwargs_pos >= - 1 && args_pos >= kwargs_pos - 1; + + static_assert(args_kwargs_are_last, "py::args/py::kwargs are only permitted as the last argument(s) of a function"); + +public: + static constexpr bool has_kwargs = kwargs_pos < 0; + static constexpr bool has_args = args_pos < 0; + + static PYBIND11_DESCR arg_names() { return detail::concat(make_caster::name()...); } + + bool load_args(function_call &call) { + return load_impl_sequence(call, indices{}); + } + + template + enable_if_t::value, Return> call(Func &&f) && { + return std::move(*this).template call_impl(std::forward(f), indices{}, Guard{}); + } + + template + enable_if_t::value, void_type> call(Func &&f) && { + std::move(*this).template call_impl(std::forward(f), indices{}, Guard{}); + return void_type(); + } + +private: + + static bool load_impl_sequence(function_call &, index_sequence<>) { return true; } + + template + bool load_impl_sequence(function_call &call, index_sequence) { + for (bool r : {std::get(argcasters).load(call.args[Is], call.args_convert[Is])...}) + if (!r) + return false; + return true; + } + + template + Return call_impl(Func &&f, index_sequence, Guard &&) { + return std::forward(f)(cast_op(std::move(std::get(argcasters)))...); + } + + std::tuple...> argcasters; +}; + +/// Helper class which collects only positional arguments for a Python function call. +/// A fancier version below can collect any argument, but this one is optimal for simple calls. +template +class simple_collector { +public: + template + explicit simple_collector(Ts &&...values) + : m_args(pybind11::make_tuple(std::forward(values)...)) { } + + const tuple &args() const & { return m_args; } + dict kwargs() const { return {}; } + + tuple args() && { return std::move(m_args); } + + /// Call a Python function and pass the collected arguments + object call(PyObject *ptr) const { + PyObject *result = PyObject_CallObject(ptr, m_args.ptr()); + if (!result) + throw error_already_set(); + return reinterpret_steal(result); + } + +private: + tuple m_args; +}; + +/// Helper class which collects positional, keyword, * and ** arguments for a Python function call +template +class unpacking_collector { +public: + template + explicit unpacking_collector(Ts &&...values) { + // Tuples aren't (easily) resizable so a list is needed for collection, + // but the actual function call strictly requires a tuple. + auto args_list = list(); + int _[] = { 0, (process(args_list, std::forward(values)), 0)... }; + ignore_unused(_); + + m_args = std::move(args_list); + } + + const tuple &args() const & { return m_args; } + const dict &kwargs() const & { return m_kwargs; } + + tuple args() && { return std::move(m_args); } + dict kwargs() && { return std::move(m_kwargs); } + + /// Call a Python function and pass the collected arguments + object call(PyObject *ptr) const { + PyObject *result = PyObject_Call(ptr, m_args.ptr(), m_kwargs.ptr()); + if (!result) + throw error_already_set(); + return reinterpret_steal(result); + } + +private: + template + void process(list &args_list, T &&x) { + auto o = reinterpret_steal(detail::make_caster::cast(std::forward(x), policy, {})); + if (!o) { +#if defined(NDEBUG) + argument_cast_error(); +#else + argument_cast_error(std::to_string(args_list.size()), type_id()); +#endif + } + args_list.append(o); + } + + void process(list &args_list, detail::args_proxy ap) { + for (const auto &a : ap) + args_list.append(a); + } + + void process(list &/*args_list*/, arg_v a) { + if (!a.name) +#if defined(NDEBUG) + nameless_argument_error(); +#else + nameless_argument_error(a.type); +#endif + + if (m_kwargs.contains(a.name)) { +#if defined(NDEBUG) + multiple_values_error(); +#else + multiple_values_error(a.name); +#endif + } + if (!a.value) { +#if defined(NDEBUG) + argument_cast_error(); +#else + argument_cast_error(a.name, a.type); +#endif + } + m_kwargs[a.name] = a.value; + } + + void process(list &/*args_list*/, detail::kwargs_proxy kp) { + if (!kp) + return; + for (const auto &k : reinterpret_borrow(kp)) { + if (m_kwargs.contains(k.first)) { +#if defined(NDEBUG) + multiple_values_error(); +#else + multiple_values_error(str(k.first)); +#endif + } + m_kwargs[k.first] = k.second; + } + } + + [[noreturn]] static void nameless_argument_error() { + throw type_error("Got kwargs without a name; only named arguments " + "may be passed via py::arg() to a python function call. " + "(compile in debug mode for details)"); + } + [[noreturn]] static void nameless_argument_error(std::string type) { + throw type_error("Got kwargs without a name of type '" + type + "'; only named " + "arguments may be passed via py::arg() to a python function call. "); + } + [[noreturn]] static void multiple_values_error() { + throw type_error("Got multiple values for keyword argument " + "(compile in debug mode for details)"); + } + + [[noreturn]] static void multiple_values_error(std::string name) { + throw type_error("Got multiple values for keyword argument '" + name + "'"); + } + + [[noreturn]] static void argument_cast_error() { + throw cast_error("Unable to convert call argument to Python object " + "(compile in debug mode for details)"); + } + + [[noreturn]] static void argument_cast_error(std::string name, std::string type) { + throw cast_error("Unable to convert call argument '" + name + + "' of type '" + type + "' to Python object"); + } + +private: + tuple m_args; + dict m_kwargs; +}; + +/// Collect only positional arguments for a Python function call +template ...>::value>> +simple_collector collect_arguments(Args &&...args) { + return simple_collector(std::forward(args)...); +} + +/// Collect all arguments, including keywords and unpacking (only instantiated when needed) +template ...>::value>> +unpacking_collector collect_arguments(Args &&...args) { + // Following argument order rules for generalized unpacking according to PEP 448 + static_assert( + constexpr_last() < constexpr_first() + && constexpr_last() < constexpr_first(), + "Invalid function call: positional args must precede keywords and ** unpacking; " + "* unpacking must precede ** unpacking" + ); + return unpacking_collector(std::forward(args)...); +} + +template +template +object object_api::operator()(Args &&...args) const { + return detail::collect_arguments(std::forward(args)...).call(derived().ptr()); +} + +template +template +object object_api::call(Args &&...args) const { + return operator()(std::forward(args)...); +} + +NAMESPACE_END(detail) + +#define PYBIND11_MAKE_OPAQUE(Type) \ + namespace pybind11 { namespace detail { \ + template<> class type_caster : public type_caster_base { }; \ + }} + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/chrono.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/chrono.h new file mode 100644 index 00000000..95ada76e --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/chrono.h @@ -0,0 +1,162 @@ +/* + pybind11/chrono.h: Transparent conversion between std::chrono and python's datetime + + Copyright (c) 2016 Trent Houliston and + Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include +#include +#include +#include + +// Backport the PyDateTime_DELTA functions from Python3.3 if required +#ifndef PyDateTime_DELTA_GET_DAYS +#define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta*)o)->days) +#endif +#ifndef PyDateTime_DELTA_GET_SECONDS +#define PyDateTime_DELTA_GET_SECONDS(o) (((PyDateTime_Delta*)o)->seconds) +#endif +#ifndef PyDateTime_DELTA_GET_MICROSECONDS +#define PyDateTime_DELTA_GET_MICROSECONDS(o) (((PyDateTime_Delta*)o)->microseconds) +#endif + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +template class duration_caster { +public: + typedef typename type::rep rep; + typedef typename type::period period; + + typedef std::chrono::duration> days; + + bool load(handle src, bool) { + using namespace std::chrono; + + // Lazy initialise the PyDateTime import + if (!PyDateTimeAPI) { PyDateTime_IMPORT; } + + if (!src) return false; + // If invoked with datetime.delta object + if (PyDelta_Check(src.ptr())) { + value = type(duration_cast>( + days(PyDateTime_DELTA_GET_DAYS(src.ptr())) + + seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr())) + + microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr())))); + return true; + } + // If invoked with a float we assume it is seconds and convert + else if (PyFloat_Check(src.ptr())) { + value = type(duration_cast>(duration(PyFloat_AsDouble(src.ptr())))); + return true; + } + else return false; + } + + // If this is a duration just return it back + static const std::chrono::duration& get_duration(const std::chrono::duration &src) { + return src; + } + + // If this is a time_point get the time_since_epoch + template static std::chrono::duration get_duration(const std::chrono::time_point> &src) { + return src.time_since_epoch(); + } + + static handle cast(const type &src, return_value_policy /* policy */, handle /* parent */) { + using namespace std::chrono; + + // Use overloaded function to get our duration from our source + // Works out if it is a duration or time_point and get the duration + auto d = get_duration(src); + + // Lazy initialise the PyDateTime import + if (!PyDateTimeAPI) { PyDateTime_IMPORT; } + + // Declare these special duration types so the conversions happen with the correct primitive types (int) + using dd_t = duration>; + using ss_t = duration>; + using us_t = duration; + + auto dd = duration_cast(d); + auto subd = d - dd; + auto ss = duration_cast(subd); + auto us = duration_cast(subd - ss); + return PyDelta_FromDSU(dd.count(), ss.count(), us.count()); + } + + PYBIND11_TYPE_CASTER(type, _("datetime.timedelta")); +}; + +// This is for casting times on the system clock into datetime.datetime instances +template class type_caster> { +public: + typedef std::chrono::time_point type; + bool load(handle src, bool) { + using namespace std::chrono; + + // Lazy initialise the PyDateTime import + if (!PyDateTimeAPI) { PyDateTime_IMPORT; } + + if (!src) return false; + if (PyDateTime_Check(src.ptr())) { + std::tm cal; + cal.tm_sec = PyDateTime_DATE_GET_SECOND(src.ptr()); + cal.tm_min = PyDateTime_DATE_GET_MINUTE(src.ptr()); + cal.tm_hour = PyDateTime_DATE_GET_HOUR(src.ptr()); + cal.tm_mday = PyDateTime_GET_DAY(src.ptr()); + cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1; + cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900; + cal.tm_isdst = -1; + + value = system_clock::from_time_t(std::mktime(&cal)) + microseconds(PyDateTime_DATE_GET_MICROSECOND(src.ptr())); + return true; + } + else return false; + } + + static handle cast(const std::chrono::time_point &src, return_value_policy /* policy */, handle /* parent */) { + using namespace std::chrono; + + // Lazy initialise the PyDateTime import + if (!PyDateTimeAPI) { PyDateTime_IMPORT; } + + std::time_t tt = system_clock::to_time_t(src); + // this function uses static memory so it's best to copy it out asap just in case + // otherwise other code that is using localtime may break this (not just python code) + std::tm localtime = *std::localtime(&tt); + + // Declare these special duration types so the conversions happen with the correct primitive types (int) + using us_t = duration; + + return PyDateTime_FromDateAndTime(localtime.tm_year + 1900, + localtime.tm_mon + 1, + localtime.tm_mday, + localtime.tm_hour, + localtime.tm_min, + localtime.tm_sec, + (duration_cast(src.time_since_epoch() % seconds(1))).count()); + } + PYBIND11_TYPE_CASTER(type, _("datetime.datetime")); +}; + +// Other clocks that are not the system clock are not measured as datetime.datetime objects +// since they are not measured on calendar time. So instead we just make them timedeltas +// Or if they have passed us a time as a float we convert that +template class type_caster> +: public duration_caster> { +}; + +template class type_caster> +: public duration_caster> { +}; + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/common.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/common.h new file mode 100644 index 00000000..6c8a4f1e --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/common.h @@ -0,0 +1,2 @@ +#include "detail/common.h" +#warning "Including 'common.h' is deprecated. It will be removed in v3.0. Use 'pybind11.h'." diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/complex.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/complex.h new file mode 100644 index 00000000..5dac27cc --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/complex.h @@ -0,0 +1,61 @@ +/* + pybind11/complex.h: Complex number support + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include + +/// glibc defines I as a macro which breaks things, e.g., boost template names +#ifdef I +# undef I +#endif + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +template struct format_descriptor, detail::enable_if_t::value>> { + static constexpr const char c = format_descriptor::c; + static constexpr const char value[3] = { 'Z', c, '\0' }; + static std::string format() { return std::string(value); } +}; + +template constexpr const char format_descriptor< + std::complex, detail::enable_if_t::value>>::value[3]; + +NAMESPACE_BEGIN(detail) + +template struct is_fmt_numeric, detail::enable_if_t::value>> { + static constexpr bool value = true; + static constexpr int index = is_fmt_numeric::index + 3; +}; + +template class type_caster> { +public: + bool load(handle src, bool convert) { + if (!src) + return false; + if (!convert && !PyComplex_Check(src.ptr())) + return false; + Py_complex result = PyComplex_AsCComplex(src.ptr()); + if (result.real == -1.0 && PyErr_Occurred()) { + PyErr_Clear(); + return false; + } + value = std::complex((T) result.real, (T) result.imag); + return true; + } + + static handle cast(const std::complex &src, return_value_policy /* policy */, handle /* parent */) { + return PyComplex_FromDoubles((double) src.real(), (double) src.imag()); + } + + PYBIND11_TYPE_CASTER(std::complex, _("complex")); +}; +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/detail/class.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/detail/class.h new file mode 100644 index 00000000..ff06370f --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/detail/class.h @@ -0,0 +1,626 @@ +/* + pybind11/detail/class.h: Python C API implementation details for py::class_ + + Copyright (c) 2017 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "../attr.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +#if PY_VERSION_HEX >= 0x03030000 +# define PYBIND11_BUILTIN_QUALNAME +# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) +#else +// In pre-3.3 Python, we still set __qualname__ so that we can produce reliable function type +// signatures; in 3.3+ this macro expands to nothing: +# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) setattr((PyObject *) obj, "__qualname__", nameobj) +#endif + +inline PyTypeObject *type_incref(PyTypeObject *type) { + Py_INCREF(type); + return type; +} + +#if !defined(PYPY_VERSION) + +/// `pybind11_static_property.__get__()`: Always pass the class instead of the instance. +extern "C" inline PyObject *pybind11_static_get(PyObject *self, PyObject * /*ob*/, PyObject *cls) { + return PyProperty_Type.tp_descr_get(self, cls, cls); +} + +/// `pybind11_static_property.__set__()`: Just like the above `__get__()`. +extern "C" inline int pybind11_static_set(PyObject *self, PyObject *obj, PyObject *value) { + PyObject *cls = PyType_Check(obj) ? obj : (PyObject *) Py_TYPE(obj); + return PyProperty_Type.tp_descr_set(self, cls, value); +} + +/** A `static_property` is the same as a `property` but the `__get__()` and `__set__()` + methods are modified to always use the object type instead of a concrete instance. + Return value: New reference. */ +inline PyTypeObject *make_static_property_type() { + constexpr auto *name = "pybind11_static_property"; + auto name_obj = reinterpret_steal(PYBIND11_FROM_STRING(name)); + + /* Danger zone: from now (and until PyType_Ready), make sure to + issue no Python C API calls which could potentially invoke the + garbage collector (the GC will call type_traverse(), which will in + turn find the newly constructed type in an invalid state) */ + auto heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0); + if (!heap_type) + pybind11_fail("make_static_property_type(): error allocating type!"); + + heap_type->ht_name = name_obj.inc_ref().ptr(); +#ifdef PYBIND11_BUILTIN_QUALNAME + heap_type->ht_qualname = name_obj.inc_ref().ptr(); +#endif + + auto type = &heap_type->ht_type; + type->tp_name = name; + type->tp_base = type_incref(&PyProperty_Type); + type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; + type->tp_descr_get = pybind11_static_get; + type->tp_descr_set = pybind11_static_set; + + if (PyType_Ready(type) < 0) + pybind11_fail("make_static_property_type(): failure in PyType_Ready()!"); + + setattr((PyObject *) type, "__module__", str("pybind11_builtins")); + PYBIND11_SET_OLDPY_QUALNAME(type, name_obj); + + return type; +} + +#else // PYPY + +/** PyPy has some issues with the above C API, so we evaluate Python code instead. + This function will only be called once so performance isn't really a concern. + Return value: New reference. */ +inline PyTypeObject *make_static_property_type() { + auto d = dict(); + PyObject *result = PyRun_String(R"(\ + class pybind11_static_property(property): + def __get__(self, obj, cls): + return property.__get__(self, cls, cls) + + def __set__(self, obj, value): + cls = obj if isinstance(obj, type) else type(obj) + property.__set__(self, cls, value) + )", Py_file_input, d.ptr(), d.ptr() + ); + if (result == nullptr) + throw error_already_set(); + Py_DECREF(result); + return (PyTypeObject *) d["pybind11_static_property"].cast().release().ptr(); +} + +#endif // PYPY + +/** Types with static properties need to handle `Type.static_prop = x` in a specific way. + By default, Python replaces the `static_property` itself, but for wrapped C++ types + we need to call `static_property.__set__()` in order to propagate the new value to + the underlying C++ data structure. */ +extern "C" inline int pybind11_meta_setattro(PyObject* obj, PyObject* name, PyObject* value) { + // Use `_PyType_Lookup()` instead of `PyObject_GetAttr()` in order to get the raw + // descriptor (`property`) instead of calling `tp_descr_get` (`property.__get__()`). + PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name); + + // The following assignment combinations are possible: + // 1. `Type.static_prop = value` --> descr_set: `Type.static_prop.__set__(value)` + // 2. `Type.static_prop = other_static_prop` --> setattro: replace existing `static_prop` + // 3. `Type.regular_attribute = value` --> setattro: regular attribute assignment + const auto static_prop = (PyObject *) get_internals().static_property_type; + const auto call_descr_set = descr && PyObject_IsInstance(descr, static_prop) + && !PyObject_IsInstance(value, static_prop); + if (call_descr_set) { + // Call `static_property.__set__()` instead of replacing the `static_property`. +#if !defined(PYPY_VERSION) + return Py_TYPE(descr)->tp_descr_set(descr, obj, value); +#else + if (PyObject *result = PyObject_CallMethod(descr, "__set__", "OO", obj, value)) { + Py_DECREF(result); + return 0; + } else { + return -1; + } +#endif + } else { + // Replace existing attribute. + return PyType_Type.tp_setattro(obj, name, value); + } +} + +#if PY_MAJOR_VERSION >= 3 +/** + * Python 3's PyInstanceMethod_Type hides itself via its tp_descr_get, which prevents aliasing + * methods via cls.attr("m2") = cls.attr("m1"): instead the tp_descr_get returns a plain function, + * when called on a class, or a PyMethod, when called on an instance. Override that behaviour here + * to do a special case bypass for PyInstanceMethod_Types. + */ +extern "C" inline PyObject *pybind11_meta_getattro(PyObject *obj, PyObject *name) { + PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name); + if (descr && PyInstanceMethod_Check(descr)) { + Py_INCREF(descr); + return descr; + } + else { + return PyType_Type.tp_getattro(obj, name); + } +} +#endif + +/** This metaclass is assigned by default to all pybind11 types and is required in order + for static properties to function correctly. Users may override this using `py::metaclass`. + Return value: New reference. */ +inline PyTypeObject* make_default_metaclass() { + constexpr auto *name = "pybind11_type"; + auto name_obj = reinterpret_steal(PYBIND11_FROM_STRING(name)); + + /* Danger zone: from now (and until PyType_Ready), make sure to + issue no Python C API calls which could potentially invoke the + garbage collector (the GC will call type_traverse(), which will in + turn find the newly constructed type in an invalid state) */ + auto heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0); + if (!heap_type) + pybind11_fail("make_default_metaclass(): error allocating metaclass!"); + + heap_type->ht_name = name_obj.inc_ref().ptr(); +#ifdef PYBIND11_BUILTIN_QUALNAME + heap_type->ht_qualname = name_obj.inc_ref().ptr(); +#endif + + auto type = &heap_type->ht_type; + type->tp_name = name; + type->tp_base = type_incref(&PyType_Type); + type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; + + type->tp_setattro = pybind11_meta_setattro; +#if PY_MAJOR_VERSION >= 3 + type->tp_getattro = pybind11_meta_getattro; +#endif + + if (PyType_Ready(type) < 0) + pybind11_fail("make_default_metaclass(): failure in PyType_Ready()!"); + + setattr((PyObject *) type, "__module__", str("pybind11_builtins")); + PYBIND11_SET_OLDPY_QUALNAME(type, name_obj); + + return type; +} + +/// For multiple inheritance types we need to recursively register/deregister base pointers for any +/// base classes with pointers that are difference from the instance value pointer so that we can +/// correctly recognize an offset base class pointer. This calls a function with any offset base ptrs. +inline void traverse_offset_bases(void *valueptr, const detail::type_info *tinfo, instance *self, + bool (*f)(void * /*parentptr*/, instance * /*self*/)) { + for (handle h : reinterpret_borrow(tinfo->type->tp_bases)) { + if (auto parent_tinfo = get_type_info((PyTypeObject *) h.ptr())) { + for (auto &c : parent_tinfo->implicit_casts) { + if (c.first == tinfo->cpptype) { + auto *parentptr = c.second(valueptr); + if (parentptr != valueptr) + f(parentptr, self); + traverse_offset_bases(parentptr, parent_tinfo, self, f); + break; + } + } + } + } +} + +inline bool register_instance_impl(void *ptr, instance *self) { + get_internals().registered_instances.emplace(ptr, self); + return true; // unused, but gives the same signature as the deregister func +} +inline bool deregister_instance_impl(void *ptr, instance *self) { + auto ®istered_instances = get_internals().registered_instances; + auto range = registered_instances.equal_range(ptr); + for (auto it = range.first; it != range.second; ++it) { + if (Py_TYPE(self) == Py_TYPE(it->second)) { + registered_instances.erase(it); + return true; + } + } + return false; +} + +inline void register_instance(instance *self, void *valptr, const type_info *tinfo) { + register_instance_impl(valptr, self); + if (!tinfo->simple_ancestors) + traverse_offset_bases(valptr, tinfo, self, register_instance_impl); +} + +inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo) { + bool ret = deregister_instance_impl(valptr, self); + if (!tinfo->simple_ancestors) + traverse_offset_bases(valptr, tinfo, self, deregister_instance_impl); + return ret; +} + +/// Instance creation function for all pybind11 types. It allocates the internal instance layout for +/// holding C++ objects and holders. Allocation is done lazily (the first time the instance is cast +/// to a reference or pointer), and initialization is done by an `__init__` function. +inline PyObject *make_new_instance(PyTypeObject *type) { +#if defined(PYPY_VERSION) + // PyPy gets tp_basicsize wrong (issue 2482) under multiple inheritance when the first inherited + // object is a a plain Python type (i.e. not derived from an extension type). Fix it. + ssize_t instance_size = static_cast(sizeof(instance)); + if (type->tp_basicsize < instance_size) { + type->tp_basicsize = instance_size; + } +#endif + PyObject *self = type->tp_alloc(type, 0); + auto inst = reinterpret_cast(self); + // Allocate the value/holder internals: + inst->allocate_layout(); + + inst->owned = true; + + return self; +} + +/// Instance creation function for all pybind11 types. It only allocates space for the +/// C++ object, but doesn't call the constructor -- an `__init__` function must do that. +extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *) { + return make_new_instance(type); +} + +/// An `__init__` function constructs the C++ object. Users should provide at least one +/// of these using `py::init` or directly with `.def(__init__, ...)`. Otherwise, the +/// following default function will be used which simply throws an exception. +extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject *) { + PyTypeObject *type = Py_TYPE(self); + std::string msg; +#if defined(PYPY_VERSION) + msg += handle((PyObject *) type).attr("__module__").cast() + "."; +#endif + msg += type->tp_name; + msg += ": No constructor defined!"; + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return -1; +} + +inline void add_patient(PyObject *nurse, PyObject *patient) { + auto &internals = get_internals(); + auto instance = reinterpret_cast(nurse); + auto ¤t_patients = internals.patients[nurse]; + instance->has_patients = true; + for (auto &p : current_patients) + if (p == patient) + return; + Py_INCREF(patient); + current_patients.push_back(patient); +} + +inline void clear_patients(PyObject *self) { + auto instance = reinterpret_cast(self); + auto &internals = get_internals(); + auto pos = internals.patients.find(self); + assert(pos != internals.patients.end()); + // Clearing the patients can cause more Python code to run, which + // can invalidate the iterator. Extract the vector of patients + // from the unordered_map first. + auto patients = std::move(pos->second); + internals.patients.erase(pos); + instance->has_patients = false; + for (PyObject *&patient : patients) + Py_CLEAR(patient); +} + +/// Clears all internal data from the instance and removes it from registered instances in +/// preparation for deallocation. +inline void clear_instance(PyObject *self) { + auto instance = reinterpret_cast(self); + + // Deallocate any values/holders, if present: + for (auto &v_h : values_and_holders(instance)) { + if (v_h) { + + // We have to deregister before we call dealloc because, for virtual MI types, we still + // need to be able to get the parent pointers. + if (v_h.instance_registered() && !deregister_instance(instance, v_h.value_ptr(), v_h.type)) + pybind11_fail("pybind11_object_dealloc(): Tried to deallocate unregistered instance!"); + + if (instance->owned || v_h.holder_constructed()) + v_h.type->dealloc(v_h); + } + } + // Deallocate the value/holder layout internals: + instance->deallocate_layout(); + + if (instance->weakrefs) + PyObject_ClearWeakRefs(self); + + PyObject **dict_ptr = _PyObject_GetDictPtr(self); + if (dict_ptr) + Py_CLEAR(*dict_ptr); + + if (instance->has_patients) + clear_patients(self); +} + +/// Instance destructor function for all pybind11 types. It calls `type_info.dealloc` +/// to destroy the C++ object itself, while the rest is Python bookkeeping. +extern "C" inline void pybind11_object_dealloc(PyObject *self) { + clear_instance(self); + + auto type = Py_TYPE(self); + type->tp_free(self); + + // `type->tp_dealloc != pybind11_object_dealloc` means that we're being called + // as part of a derived type's dealloc, in which case we're not allowed to decref + // the type here. For cross-module compatibility, we shouldn't compare directly + // with `pybind11_object_dealloc`, but with the common one stashed in internals. + auto pybind11_object_type = (PyTypeObject *) get_internals().instance_base; + if (type->tp_dealloc == pybind11_object_type->tp_dealloc) + Py_DECREF(type); +} + +/** Create the type which can be used as a common base for all classes. This is + needed in order to satisfy Python's requirements for multiple inheritance. + Return value: New reference. */ +inline PyObject *make_object_base_type(PyTypeObject *metaclass) { + constexpr auto *name = "pybind11_object"; + auto name_obj = reinterpret_steal(PYBIND11_FROM_STRING(name)); + + /* Danger zone: from now (and until PyType_Ready), make sure to + issue no Python C API calls which could potentially invoke the + garbage collector (the GC will call type_traverse(), which will in + turn find the newly constructed type in an invalid state) */ + auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0); + if (!heap_type) + pybind11_fail("make_object_base_type(): error allocating type!"); + + heap_type->ht_name = name_obj.inc_ref().ptr(); +#ifdef PYBIND11_BUILTIN_QUALNAME + heap_type->ht_qualname = name_obj.inc_ref().ptr(); +#endif + + auto type = &heap_type->ht_type; + type->tp_name = name; + type->tp_base = type_incref(&PyBaseObject_Type); + type->tp_basicsize = static_cast(sizeof(instance)); + type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; + + type->tp_new = pybind11_object_new; + type->tp_init = pybind11_object_init; + type->tp_dealloc = pybind11_object_dealloc; + + /* Support weak references (needed for the keep_alive feature) */ + type->tp_weaklistoffset = offsetof(instance, weakrefs); + + if (PyType_Ready(type) < 0) + pybind11_fail("PyType_Ready failed in make_object_base_type():" + error_string()); + + setattr((PyObject *) type, "__module__", str("pybind11_builtins")); + PYBIND11_SET_OLDPY_QUALNAME(type, name_obj); + + assert(!PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC)); + return (PyObject *) heap_type; +} + +/// dynamic_attr: Support for `d = instance.__dict__`. +extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) { + PyObject *&dict = *_PyObject_GetDictPtr(self); + if (!dict) + dict = PyDict_New(); + Py_XINCREF(dict); + return dict; +} + +/// dynamic_attr: Support for `instance.__dict__ = dict()`. +extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void *) { + if (!PyDict_Check(new_dict)) { + PyErr_Format(PyExc_TypeError, "__dict__ must be set to a dictionary, not a '%.200s'", + Py_TYPE(new_dict)->tp_name); + return -1; + } + PyObject *&dict = *_PyObject_GetDictPtr(self); + Py_INCREF(new_dict); + Py_CLEAR(dict); + dict = new_dict; + return 0; +} + +/// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`. +extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) { + PyObject *&dict = *_PyObject_GetDictPtr(self); + Py_VISIT(dict); + return 0; +} + +/// dynamic_attr: Allow the GC to clear the dictionary. +extern "C" inline int pybind11_clear(PyObject *self) { + PyObject *&dict = *_PyObject_GetDictPtr(self); + Py_CLEAR(dict); + return 0; +} + +/// Give instances of this type a `__dict__` and opt into garbage collection. +inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) { + auto type = &heap_type->ht_type; +#if defined(PYPY_VERSION) + pybind11_fail(std::string(type->tp_name) + ": dynamic attributes are " + "currently not supported in " + "conjunction with PyPy!"); +#endif + type->tp_flags |= Py_TPFLAGS_HAVE_GC; + type->tp_dictoffset = type->tp_basicsize; // place dict at the end + type->tp_basicsize += (ssize_t)sizeof(PyObject *); // and allocate enough space for it + type->tp_traverse = pybind11_traverse; + type->tp_clear = pybind11_clear; + + static PyGetSetDef getset[] = { + {const_cast("__dict__"), pybind11_get_dict, pybind11_set_dict, nullptr, nullptr}, + {nullptr, nullptr, nullptr, nullptr, nullptr} + }; + type->tp_getset = getset; +} + +/// buffer_protocol: Fill in the view as specified by flags. +extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int flags) { + // Look for a `get_buffer` implementation in this type's info or any bases (following MRO). + type_info *tinfo = nullptr; + for (auto type : reinterpret_borrow(Py_TYPE(obj)->tp_mro)) { + tinfo = get_type_info((PyTypeObject *) type.ptr()); + if (tinfo && tinfo->get_buffer) + break; + } + if (view == nullptr || obj == nullptr || !tinfo || !tinfo->get_buffer) { + if (view) + view->obj = nullptr; + PyErr_SetString(PyExc_BufferError, "pybind11_getbuffer(): Internal error"); + return -1; + } + std::memset(view, 0, sizeof(Py_buffer)); + buffer_info *info = tinfo->get_buffer(obj, tinfo->get_buffer_data); + view->obj = obj; + view->ndim = 1; + view->internal = info; + view->buf = info->ptr; + view->itemsize = info->itemsize; + view->len = view->itemsize; + for (auto s : info->shape) + view->len *= s; + if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) + view->format = const_cast(info->format.c_str()); + if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) { + view->ndim = (int) info->ndim; + view->strides = &info->strides[0]; + view->shape = &info->shape[0]; + } + Py_INCREF(view->obj); + return 0; +} + +/// buffer_protocol: Release the resources of the buffer. +extern "C" inline void pybind11_releasebuffer(PyObject *, Py_buffer *view) { + delete (buffer_info *) view->internal; +} + +/// Give this type a buffer interface. +inline void enable_buffer_protocol(PyHeapTypeObject *heap_type) { + heap_type->ht_type.tp_as_buffer = &heap_type->as_buffer; +#if PY_MAJOR_VERSION < 3 + heap_type->ht_type.tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; +#endif + + heap_type->as_buffer.bf_getbuffer = pybind11_getbuffer; + heap_type->as_buffer.bf_releasebuffer = pybind11_releasebuffer; +} + +/** Create a brand new Python type according to the `type_record` specification. + Return value: New reference. */ +inline PyObject* make_new_python_type(const type_record &rec) { + auto name = reinterpret_steal(PYBIND11_FROM_STRING(rec.name)); + + auto qualname = name; + if (rec.scope && !PyModule_Check(rec.scope.ptr()) && hasattr(rec.scope, "__qualname__")) { +#if PY_MAJOR_VERSION >= 3 + qualname = reinterpret_steal( + PyUnicode_FromFormat("%U.%U", rec.scope.attr("__qualname__").ptr(), name.ptr())); +#else + qualname = str(rec.scope.attr("__qualname__").cast() + "." + rec.name); +#endif + } + + object module; + if (rec.scope) { + if (hasattr(rec.scope, "__module__")) + module = rec.scope.attr("__module__"); + else if (hasattr(rec.scope, "__name__")) + module = rec.scope.attr("__name__"); + } + + auto full_name = c_str( +#if !defined(PYPY_VERSION) + module ? str(module).cast() + "." + rec.name : +#endif + rec.name); + + char *tp_doc = nullptr; + if (rec.doc && options::show_user_defined_docstrings()) { + /* Allocate memory for docstring (using PyObject_MALLOC, since + Python will free this later on) */ + size_t size = strlen(rec.doc) + 1; + tp_doc = (char *) PyObject_MALLOC(size); + memcpy((void *) tp_doc, rec.doc, size); + } + + auto &internals = get_internals(); + auto bases = tuple(rec.bases); + auto base = (bases.size() == 0) ? internals.instance_base + : bases[0].ptr(); + + /* Danger zone: from now (and until PyType_Ready), make sure to + issue no Python C API calls which could potentially invoke the + garbage collector (the GC will call type_traverse(), which will in + turn find the newly constructed type in an invalid state) */ + auto metaclass = rec.metaclass.ptr() ? (PyTypeObject *) rec.metaclass.ptr() + : internals.default_metaclass; + + auto heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0); + if (!heap_type) + pybind11_fail(std::string(rec.name) + ": Unable to create type object!"); + + heap_type->ht_name = name.release().ptr(); +#ifdef PYBIND11_BUILTIN_QUALNAME + heap_type->ht_qualname = qualname.inc_ref().ptr(); +#endif + + auto type = &heap_type->ht_type; + type->tp_name = full_name; + type->tp_doc = tp_doc; + type->tp_base = type_incref((PyTypeObject *)base); + type->tp_basicsize = static_cast(sizeof(instance)); + if (bases.size() > 0) + type->tp_bases = bases.release().ptr(); + + /* Don't inherit base __init__ */ + type->tp_init = pybind11_object_init; + + /* Supported protocols */ + type->tp_as_number = &heap_type->as_number; + type->tp_as_sequence = &heap_type->as_sequence; + type->tp_as_mapping = &heap_type->as_mapping; + + /* Flags */ + type->tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE; +#if PY_MAJOR_VERSION < 3 + type->tp_flags |= Py_TPFLAGS_CHECKTYPES; +#endif + + if (rec.dynamic_attr) + enable_dynamic_attributes(heap_type); + + if (rec.buffer_protocol) + enable_buffer_protocol(heap_type); + + if (PyType_Ready(type) < 0) + pybind11_fail(std::string(rec.name) + ": PyType_Ready failed (" + error_string() + ")!"); + + assert(rec.dynamic_attr ? PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC) + : !PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC)); + + /* Register type with the parent scope */ + if (rec.scope) + setattr(rec.scope, rec.name, (PyObject *) type); + else + Py_INCREF(type); // Keep it alive forever (reference leak) + + if (module) // Needed by pydoc + setattr((PyObject *) type, "__module__", module); + + PYBIND11_SET_OLDPY_QUALNAME(type, qualname); + + return (PyObject *) type; +} + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/detail/common.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/detail/common.h new file mode 100644 index 00000000..7d41cd63 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/detail/common.h @@ -0,0 +1,802 @@ +/* + pybind11/detail/common.h -- Basic macros + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#if !defined(NAMESPACE_BEGIN) +# define NAMESPACE_BEGIN(name) namespace name { +#endif +#if !defined(NAMESPACE_END) +# define NAMESPACE_END(name) } +#endif + +// Robust support for some features and loading modules compiled against different pybind versions +// requires forcing hidden visibility on pybind code, so we enforce this by setting the attribute on +// the main `pybind11` namespace. +#if !defined(PYBIND11_NAMESPACE) +# ifdef __GNUG__ +# define PYBIND11_NAMESPACE pybind11 __attribute__((visibility("hidden"))) +# else +# define PYBIND11_NAMESPACE pybind11 +# endif +#endif + +#if !defined(_MSC_VER) && !defined(__INTEL_COMPILER) +# if __cplusplus >= 201402L +# define PYBIND11_CPP14 +# if __cplusplus > 201402L /* Temporary: should be updated to >= the final C++17 value once known */ +# define PYBIND11_CPP17 +# endif +# endif +#elif defined(_MSC_VER) +// MSVC sets _MSVC_LANG rather than __cplusplus (supposedly until the standard is fully implemented) +# if _MSVC_LANG >= 201402L +# define PYBIND11_CPP14 +# if _MSVC_LANG > 201402L && _MSC_VER >= 1910 +# define PYBIND11_CPP17 +# endif +# endif +#endif + +// Compiler version assertions +#if defined(__INTEL_COMPILER) +# if __INTEL_COMPILER < 1500 +# error pybind11 requires Intel C++ compiler v15 or newer +# endif +#elif defined(__clang__) && !defined(__apple_build_version__) +# if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 3) +# error pybind11 requires clang 3.3 or newer +# endif +#elif defined(__clang__) +// Apple changes clang version macros to its Xcode version; the first Xcode release based on +// (upstream) clang 3.3 was Xcode 5: +# if __clang_major__ < 5 +# error pybind11 requires Xcode/clang 5.0 or newer +# endif +#elif defined(__GNUG__) +# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8) +# error pybind11 requires gcc 4.8 or newer +# endif +#elif defined(_MSC_VER) +// Pybind hits various compiler bugs in 2015u2 and earlier, and also makes use of some stl features +// (e.g. std::negation) added in 2015u3: +# if _MSC_FULL_VER < 190024210 +# error pybind11 requires MSVC 2015 update 3 or newer +# endif +#endif + +#if !defined(PYBIND11_EXPORT) +# if defined(WIN32) || defined(_WIN32) +# define PYBIND11_EXPORT __declspec(dllexport) +# else +# define PYBIND11_EXPORT __attribute__ ((visibility("default"))) +# endif +#endif + +#if defined(_MSC_VER) +# define PYBIND11_NOINLINE __declspec(noinline) +#else +# define PYBIND11_NOINLINE __attribute__ ((noinline)) +#endif + +#if defined(PYBIND11_CPP14) +# define PYBIND11_DEPRECATED(reason) [[deprecated(reason)]] +#else +# define PYBIND11_DEPRECATED(reason) __attribute__((deprecated(reason))) +#endif + +#define PYBIND11_VERSION_MAJOR 2 +#define PYBIND11_VERSION_MINOR 2 +#define PYBIND11_VERSION_PATCH 2 + +/// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode +#if defined(_MSC_VER) +# if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 4) +# define HAVE_ROUND 1 +# endif +# pragma warning(push) +# pragma warning(disable: 4510 4610 4512 4005) +# if defined(_DEBUG) +# define PYBIND11_DEBUG_MARKER +# undef _DEBUG +# endif +#endif + +#include +#include +#include + +#if defined(_WIN32) && (defined(min) || defined(max)) +# error Macro clash with min and max -- define NOMINMAX when compiling your program on Windows +#endif + +#if defined(isalnum) +# undef isalnum +# undef isalpha +# undef islower +# undef isspace +# undef isupper +# undef tolower +# undef toupper +#endif + +#if defined(_MSC_VER) +# if defined(PYBIND11_DEBUG_MARKER) +# define _DEBUG +# undef PYBIND11_DEBUG_MARKER +# endif +# pragma warning(pop) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions +#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr) +#define PYBIND11_INSTANCE_METHOD_CHECK PyInstanceMethod_Check +#define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyInstanceMethod_GET_FUNCTION +#define PYBIND11_BYTES_CHECK PyBytes_Check +#define PYBIND11_BYTES_FROM_STRING PyBytes_FromString +#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize +#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize +#define PYBIND11_BYTES_AS_STRING PyBytes_AsString +#define PYBIND11_BYTES_SIZE PyBytes_Size +#define PYBIND11_LONG_CHECK(o) PyLong_Check(o) +#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o) +#define PYBIND11_BYTES_NAME "bytes" +#define PYBIND11_STRING_NAME "str" +#define PYBIND11_SLICE_OBJECT PyObject +#define PYBIND11_FROM_STRING PyUnicode_FromString +#define PYBIND11_STR_TYPE ::pybind11::str +#define PYBIND11_BOOL_ATTR "__bool__" +#define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_bool) +#define PYBIND11_PLUGIN_IMPL(name) \ + extern "C" PYBIND11_EXPORT PyObject *PyInit_##name() + +#else +#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyMethod_New(ptr, nullptr, class_) +#define PYBIND11_INSTANCE_METHOD_CHECK PyMethod_Check +#define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyMethod_GET_FUNCTION +#define PYBIND11_BYTES_CHECK PyString_Check +#define PYBIND11_BYTES_FROM_STRING PyString_FromString +#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyString_FromStringAndSize +#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyString_AsStringAndSize +#define PYBIND11_BYTES_AS_STRING PyString_AsString +#define PYBIND11_BYTES_SIZE PyString_Size +#define PYBIND11_LONG_CHECK(o) (PyInt_Check(o) || PyLong_Check(o)) +#define PYBIND11_LONG_AS_LONGLONG(o) (PyInt_Check(o) ? (long long) PyLong_AsLong(o) : PyLong_AsLongLong(o)) +#define PYBIND11_BYTES_NAME "str" +#define PYBIND11_STRING_NAME "unicode" +#define PYBIND11_SLICE_OBJECT PySliceObject +#define PYBIND11_FROM_STRING PyString_FromString +#define PYBIND11_STR_TYPE ::pybind11::bytes +#define PYBIND11_BOOL_ATTR "__nonzero__" +#define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_nonzero) +#define PYBIND11_PLUGIN_IMPL(name) \ + static PyObject *pybind11_init_wrapper(); \ + extern "C" PYBIND11_EXPORT void init##name() { \ + (void)pybind11_init_wrapper(); \ + } \ + PyObject *pybind11_init_wrapper() +#endif + +#if PY_VERSION_HEX >= 0x03050000 && PY_VERSION_HEX < 0x03050200 +extern "C" { + struct _Py_atomic_address { void *value; }; + PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current; +} +#endif + +#define PYBIND11_TRY_NEXT_OVERLOAD ((PyObject *) 1) // special failure return code +#define PYBIND11_STRINGIFY(x) #x +#define PYBIND11_TOSTRING(x) PYBIND11_STRINGIFY(x) +#define PYBIND11_CONCAT(first, second) first##second + +/** \rst + ***Deprecated in favor of PYBIND11_MODULE*** + + This macro creates the entry point that will be invoked when the Python interpreter + imports a plugin library. Please create a `module` in the function body and return + the pointer to its underlying Python object at the end. + + .. code-block:: cpp + + PYBIND11_PLUGIN(example) { + pybind11::module m("example", "pybind11 example plugin"); + /// Set up bindings here + return m.ptr(); + } +\endrst */ +#define PYBIND11_PLUGIN(name) \ + PYBIND11_DEPRECATED("PYBIND11_PLUGIN is deprecated, use PYBIND11_MODULE") \ + static PyObject *pybind11_init(); \ + PYBIND11_PLUGIN_IMPL(name) { \ + int major, minor; \ + if (sscanf(Py_GetVersion(), "%i.%i", &major, &minor) != 2) { \ + PyErr_SetString(PyExc_ImportError, "Can't parse Python version."); \ + return nullptr; \ + } else if (major != PY_MAJOR_VERSION || minor != PY_MINOR_VERSION) { \ + PyErr_Format(PyExc_ImportError, \ + "Python version mismatch: module was compiled for " \ + "version %i.%i, while the interpreter is running " \ + "version %i.%i.", PY_MAJOR_VERSION, PY_MINOR_VERSION, \ + major, minor); \ + return nullptr; \ + } \ + try { \ + return pybind11_init(); \ + } catch (pybind11::error_already_set &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } catch (const std::exception &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } \ + } \ + PyObject *pybind11_init() + +/** \rst + This macro creates the entry point that will be invoked when the Python interpreter + imports an extension module. The module name is given as the fist argument and it + should not be in quotes. The second macro argument defines a variable of type + `py::module` which can be used to initialize the module. + + .. code-block:: cpp + + PYBIND11_MODULE(example, m) { + m.doc() = "pybind11 example module"; + + // Add bindings here + m.def("foo", []() { + return "Hello, World!"; + }); + } +\endrst */ +#define PYBIND11_MODULE(name, variable) \ + static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &); \ + PYBIND11_PLUGIN_IMPL(name) { \ + int major, minor; \ + if (sscanf(Py_GetVersion(), "%i.%i", &major, &minor) != 2) { \ + PyErr_SetString(PyExc_ImportError, "Can't parse Python version."); \ + return nullptr; \ + } else if (major != PY_MAJOR_VERSION || minor != PY_MINOR_VERSION) { \ + PyErr_Format(PyExc_ImportError, \ + "Python version mismatch: module was compiled for " \ + "version %i.%i, while the interpreter is running " \ + "version %i.%i.", PY_MAJOR_VERSION, PY_MINOR_VERSION, \ + major, minor); \ + return nullptr; \ + } \ + auto m = pybind11::module(PYBIND11_TOSTRING(name)); \ + try { \ + PYBIND11_CONCAT(pybind11_init_, name)(m); \ + return m.ptr(); \ + } catch (pybind11::error_already_set &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } catch (const std::exception &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } \ + } \ + void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &variable) + + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +using ssize_t = Py_ssize_t; +using size_t = std::size_t; + +/// Approach used to cast a previously unknown C++ instance into a Python object +enum class return_value_policy : uint8_t { + /** This is the default return value policy, which falls back to the policy + return_value_policy::take_ownership when the return value is a pointer. + Otherwise, it uses return_value::move or return_value::copy for rvalue + and lvalue references, respectively. See below for a description of what + all of these different policies do. */ + automatic = 0, + + /** As above, but use policy return_value_policy::reference when the return + value is a pointer. This is the default conversion policy for function + arguments when calling Python functions manually from C++ code (i.e. via + handle::operator()). You probably won't need to use this. */ + automatic_reference, + + /** Reference an existing object (i.e. do not create a new copy) and take + ownership. Python will call the destructor and delete operator when the + object’s reference count reaches zero. Undefined behavior ensues when + the C++ side does the same.. */ + take_ownership, + + /** Create a new copy of the returned object, which will be owned by + Python. This policy is comparably safe because the lifetimes of the two + instances are decoupled. */ + copy, + + /** Use std::move to move the return value contents into a new instance + that will be owned by Python. This policy is comparably safe because the + lifetimes of the two instances (move source and destination) are + decoupled. */ + move, + + /** Reference an existing object, but do not take ownership. The C++ side + is responsible for managing the object’s lifetime and deallocating it + when it is no longer used. Warning: undefined behavior will ensue when + the C++ side deletes an object that is still referenced and used by + Python. */ + reference, + + /** This policy only applies to methods and properties. It references the + object without taking ownership similar to the above + return_value_policy::reference policy. In contrast to that policy, the + function or property’s implicit this argument (called the parent) is + considered to be the the owner of the return value (the child). + pybind11 then couples the lifetime of the parent to the child via a + reference relationship that ensures that the parent cannot be garbage + collected while Python is still using the child. More advanced + variations of this scheme are also possible using combinations of + return_value_policy::reference and the keep_alive call policy */ + reference_internal +}; + +NAMESPACE_BEGIN(detail) + +inline static constexpr int log2(size_t n, int k = 0) { return (n <= 1) ? k : log2(n >> 1, k + 1); } + +// Returns the size as a multiple of sizeof(void *), rounded up. +inline static constexpr size_t size_in_ptrs(size_t s) { return 1 + ((s - 1) >> log2(sizeof(void *))); } + +/** + * The space to allocate for simple layout instance holders (see below) in multiple of the size of + * a pointer (e.g. 2 means 16 bytes on 64-bit architectures). The default is the minimum required + * to holder either a std::unique_ptr or std::shared_ptr (which is almost always + * sizeof(std::shared_ptr)). + */ +constexpr size_t instance_simple_holder_in_ptrs() { + static_assert(sizeof(std::shared_ptr) >= sizeof(std::unique_ptr), + "pybind assumes std::shared_ptrs are at least as big as std::unique_ptrs"); + return size_in_ptrs(sizeof(std::shared_ptr)); +} + +// Forward declarations +struct type_info; +struct value_and_holder; + +struct nonsimple_values_and_holders { + void **values_and_holders; + uint8_t *status; +}; + +/// The 'instance' type which needs to be standard layout (need to be able to use 'offsetof') +struct instance { + PyObject_HEAD + /// Storage for pointers and holder; see simple_layout, below, for a description + union { + void *simple_value_holder[1 + instance_simple_holder_in_ptrs()]; + nonsimple_values_and_holders nonsimple; + }; + /// Weak references (needed for keep alive): + PyObject *weakrefs; + /// If true, the pointer is owned which means we're free to manage it with a holder. + bool owned : 1; + /** + * An instance has two possible value/holder layouts. + * + * Simple layout (when this flag is true), means the `simple_value_holder` is set with a pointer + * and the holder object governing that pointer, i.e. [val1*][holder]. This layout is applied + * whenever there is no python-side multiple inheritance of bound C++ types *and* the type's + * holder will fit in the default space (which is large enough to hold either a std::unique_ptr + * or std::shared_ptr). + * + * Non-simple layout applies when using custom holders that require more space than `shared_ptr` + * (which is typically the size of two pointers), or when multiple inheritance is used on the + * python side. Non-simple layout allocates the required amount of memory to have multiple + * bound C++ classes as parents. Under this layout, `nonsimple.values_and_holders` is set to a + * pointer to allocated space of the required space to hold a a sequence of value pointers and + * holders followed `status`, a set of bit flags (1 byte each), i.e. + * [val1*][holder1][val2*][holder2]...[bb...] where each [block] is rounded up to a multiple of + * `sizeof(void *)`. `nonsimple.holder_constructed` is, for convenience, a pointer to the + * beginning of the [bb...] block (but not independently allocated). + * + * Status bits indicate whether the associated holder is constructed (& + * status_holder_constructed) and whether the value pointer is registered (& + * status_instance_registered) in `registered_instances`. + */ + bool simple_layout : 1; + /// For simple layout, tracks whether the holder has been constructed + bool simple_holder_constructed : 1; + /// For simple layout, tracks whether the instance is registered in `registered_instances` + bool simple_instance_registered : 1; + /// If true, get_internals().patients has an entry for this object + bool has_patients : 1; + + /// Initializes all of the above type/values/holders data (but not the instance values themselves) + void allocate_layout(); + + /// Destroys/deallocates all of the above + void deallocate_layout(); + + /// Returns the value_and_holder wrapper for the given type (or the first, if `find_type` + /// omitted). Returns a default-constructed (with `.inst = nullptr`) object on failure if + /// `throw_if_missing` is false. + value_and_holder get_value_and_holder(const type_info *find_type = nullptr, bool throw_if_missing = true); + + /// Bit values for the non-simple status flags + static constexpr uint8_t status_holder_constructed = 1; + static constexpr uint8_t status_instance_registered = 2; +}; + +static_assert(std::is_standard_layout::value, "Internal error: `pybind11::detail::instance` is not standard layout!"); + +/// from __cpp_future__ import (convenient aliases from C++14/17) +#if defined(PYBIND11_CPP14) && (!defined(_MSC_VER) || _MSC_VER >= 1910) +using std::enable_if_t; +using std::conditional_t; +using std::remove_cv_t; +using std::remove_reference_t; +#else +template using enable_if_t = typename std::enable_if::type; +template using conditional_t = typename std::conditional::type; +template using remove_cv_t = typename std::remove_cv::type; +template using remove_reference_t = typename std::remove_reference::type; +#endif + +/// Index sequences +#if defined(PYBIND11_CPP14) +using std::index_sequence; +using std::make_index_sequence; +#else +template struct index_sequence { }; +template struct make_index_sequence_impl : make_index_sequence_impl { }; +template struct make_index_sequence_impl <0, S...> { typedef index_sequence type; }; +template using make_index_sequence = typename make_index_sequence_impl::type; +#endif + +/// Make an index sequence of the indices of true arguments +template struct select_indices_impl { using type = ISeq; }; +template struct select_indices_impl, I, B, Bs...> + : select_indices_impl, index_sequence>, I + 1, Bs...> {}; +template using select_indices = typename select_indices_impl, 0, Bs...>::type; + +/// Backports of std::bool_constant and std::negation to accommodate older compilers +template using bool_constant = std::integral_constant; +template struct negation : bool_constant { }; + +template struct void_t_impl { using type = void; }; +template using void_t = typename void_t_impl::type; + +/// Compile-time all/any/none of that check the boolean value of all template types +#ifdef __cpp_fold_expressions +template using all_of = bool_constant<(Ts::value && ...)>; +template using any_of = bool_constant<(Ts::value || ...)>; +#elif !defined(_MSC_VER) +template struct bools {}; +template using all_of = std::is_same< + bools, + bools>; +template using any_of = negation...>>; +#else +// MSVC has trouble with the above, but supports std::conjunction, which we can use instead (albeit +// at a slight loss of compilation efficiency). +template using all_of = std::conjunction; +template using any_of = std::disjunction; +#endif +template using none_of = negation>; + +template class... Predicates> using satisfies_all_of = all_of...>; +template class... Predicates> using satisfies_any_of = any_of...>; +template class... Predicates> using satisfies_none_of = none_of...>; + +/// Strip the class from a method type +template struct remove_class { }; +template struct remove_class { typedef R type(A...); }; +template struct remove_class { typedef R type(A...); }; + +/// Helper template to strip away type modifiers +template struct intrinsic_type { typedef T type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template struct intrinsic_type { typedef typename intrinsic_type::type type; }; +template using intrinsic_t = typename intrinsic_type::type; + +/// Helper type to replace 'void' in some expressions +struct void_type { }; + +/// Helper template which holds a list of types +template struct type_list { }; + +/// Compile-time integer sum +#ifdef __cpp_fold_expressions +template constexpr size_t constexpr_sum(Ts... ns) { return (0 + ... + size_t{ns}); } +#else +constexpr size_t constexpr_sum() { return 0; } +template +constexpr size_t constexpr_sum(T n, Ts... ns) { return size_t{n} + constexpr_sum(ns...); } +#endif + +NAMESPACE_BEGIN(constexpr_impl) +/// Implementation details for constexpr functions +constexpr int first(int i) { return i; } +template +constexpr int first(int i, T v, Ts... vs) { return v ? i : first(i + 1, vs...); } + +constexpr int last(int /*i*/, int result) { return result; } +template +constexpr int last(int i, int result, T v, Ts... vs) { return last(i + 1, v ? i : result, vs...); } +NAMESPACE_END(constexpr_impl) + +/// Return the index of the first type in Ts which satisfies Predicate. Returns sizeof...(Ts) if +/// none match. +template class Predicate, typename... Ts> +constexpr int constexpr_first() { return constexpr_impl::first(0, Predicate::value...); } + +/// Return the index of the last type in Ts which satisfies Predicate, or -1 if none match. +template class Predicate, typename... Ts> +constexpr int constexpr_last() { return constexpr_impl::last(0, -1, Predicate::value...); } + +/// Return the Nth element from the parameter pack +template +struct pack_element { using type = typename pack_element::type; }; +template +struct pack_element<0, T, Ts...> { using type = T; }; + +/// Return the one and only type which matches the predicate, or Default if none match. +/// If more than one type matches the predicate, fail at compile-time. +template class Predicate, typename Default, typename... Ts> +struct exactly_one { + static constexpr auto found = constexpr_sum(Predicate::value...); + static_assert(found <= 1, "Found more than one type matching the predicate"); + + static constexpr auto index = found ? constexpr_first() : 0; + using type = conditional_t::type, Default>; +}; +template class P, typename Default> +struct exactly_one { using type = Default; }; + +template class Predicate, typename Default, typename... Ts> +using exactly_one_t = typename exactly_one::type; + +/// Defer the evaluation of type T until types Us are instantiated +template struct deferred_type { using type = T; }; +template using deferred_t = typename deferred_type::type; + +/// Like is_base_of, but requires a strict base (i.e. `is_strict_base_of::value == false`, +/// unlike `std::is_base_of`) +template using is_strict_base_of = bool_constant< + std::is_base_of::value && !std::is_same::value>; + +template class Base> +struct is_template_base_of_impl { + template static std::true_type check(Base *); + static std::false_type check(...); +}; + +/// Check if a template is the base of a type. For example: +/// `is_template_base_of` is true if `struct T : Base {}` where U can be anything +template class Base, typename T> +#if !defined(_MSC_VER) +using is_template_base_of = decltype(is_template_base_of_impl::check((intrinsic_t*)nullptr)); +#else // MSVC2015 has trouble with decltype in template aliases +struct is_template_base_of : decltype(is_template_base_of_impl::check((intrinsic_t*)nullptr)) { }; +#endif + +/// Check if T is an instantiation of the template `Class`. For example: +/// `is_instantiation` is true if `T == shared_ptr` where U can be anything. +template class Class, typename T> +struct is_instantiation : std::false_type { }; +template class Class, typename... Us> +struct is_instantiation> : std::true_type { }; + +/// Check if T is std::shared_ptr where U can be anything +template using is_shared_ptr = is_instantiation; + +/// Check if T looks like an input iterator +template struct is_input_iterator : std::false_type {}; +template +struct is_input_iterator()), decltype(++std::declval())>> + : std::true_type {}; + +template using is_function_pointer = bool_constant< + std::is_pointer::value && std::is_function::type>::value>; + +template struct strip_function_object { + using type = typename remove_class::type; +}; + +// Extracts the function signature from a function, function pointer or lambda. +template > +using function_signature_t = conditional_t< + std::is_function::value, + F, + typename conditional_t< + std::is_pointer::value || std::is_member_pointer::value, + std::remove_pointer, + strip_function_object + >::type +>; + +/// Returns true if the type looks like a lambda: that is, isn't a function, pointer or member +/// pointer. Note that this can catch all sorts of other things, too; this is intended to be used +/// in a place where passing a lambda makes sense. +template using is_lambda = satisfies_none_of, + std::is_function, std::is_pointer, std::is_member_pointer>; + +/// Ignore that a variable is unused in compiler warnings +inline void ignore_unused(const int *) { } + +/// Apply a function over each element of a parameter pack +#ifdef __cpp_fold_expressions +#define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN) (((PATTERN), void()), ...) +#else +using expand_side_effects = bool[]; +#define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN) pybind11::detail::expand_side_effects{ ((PATTERN), void(), false)..., false } +#endif + +NAMESPACE_END(detail) + +/// C++ bindings of builtin Python exceptions +class builtin_exception : public std::runtime_error { +public: + using std::runtime_error::runtime_error; + /// Set the error using the Python C API + virtual void set_error() const = 0; +}; + +#define PYBIND11_RUNTIME_EXCEPTION(name, type) \ + class name : public builtin_exception { public: \ + using builtin_exception::builtin_exception; \ + name() : name("") { } \ + void set_error() const override { PyErr_SetString(type, what()); } \ + }; + +PYBIND11_RUNTIME_EXCEPTION(stop_iteration, PyExc_StopIteration) +PYBIND11_RUNTIME_EXCEPTION(index_error, PyExc_IndexError) +PYBIND11_RUNTIME_EXCEPTION(key_error, PyExc_KeyError) +PYBIND11_RUNTIME_EXCEPTION(value_error, PyExc_ValueError) +PYBIND11_RUNTIME_EXCEPTION(type_error, PyExc_TypeError) +PYBIND11_RUNTIME_EXCEPTION(cast_error, PyExc_RuntimeError) /// Thrown when pybind11::cast or handle::call fail due to a type casting error +PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used internally + +[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const char *reason) { throw std::runtime_error(reason); } +[[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const std::string &reason) { throw std::runtime_error(reason); } + +template struct format_descriptor { }; + +NAMESPACE_BEGIN(detail) +// Returns the index of the given type in the type char array below, and in the list in numpy.h +// The order here is: bool; 8 ints ((signed,unsigned)x(8,16,32,64)bits); float,double,long double; +// complex float,double,long double. Note that the long double types only participate when long +// double is actually longer than double (it isn't under MSVC). +// NB: not only the string below but also complex.h and numpy.h rely on this order. +template struct is_fmt_numeric { static constexpr bool value = false; }; +template struct is_fmt_numeric::value>> { + static constexpr bool value = true; + static constexpr int index = std::is_same::value ? 0 : 1 + ( + std::is_integral::value ? detail::log2(sizeof(T))*2 + std::is_unsigned::value : 8 + ( + std::is_same::value ? 1 : std::is_same::value ? 2 : 0)); +}; +NAMESPACE_END(detail) + +template struct format_descriptor::value>> { + static constexpr const char c = "?bBhHiIqQfdg"[detail::is_fmt_numeric::index]; + static constexpr const char value[2] = { c, '\0' }; + static std::string format() { return std::string(1, c); } +}; + +template constexpr const char format_descriptor< + T, detail::enable_if_t::value>>::value[2]; + +/// RAII wrapper that temporarily clears any Python error state +struct error_scope { + PyObject *type, *value, *trace; + error_scope() { PyErr_Fetch(&type, &value, &trace); } + ~error_scope() { PyErr_Restore(type, value, trace); } +}; + +/// Dummy destructor wrapper that can be used to expose classes with a private destructor +struct nodelete { template void operator()(T*) { } }; + +// overload_cast requires variable templates: C++14 +#if defined(PYBIND11_CPP14) +#define PYBIND11_OVERLOAD_CAST 1 + +NAMESPACE_BEGIN(detail) +template +struct overload_cast_impl { + constexpr overload_cast_impl() {} // MSVC 2015 needs this + + template + constexpr auto operator()(Return (*pf)(Args...)) const noexcept + -> decltype(pf) { return pf; } + + template + constexpr auto operator()(Return (Class::*pmf)(Args...), std::false_type = {}) const noexcept + -> decltype(pmf) { return pmf; } + + template + constexpr auto operator()(Return (Class::*pmf)(Args...) const, std::true_type) const noexcept + -> decltype(pmf) { return pmf; } +}; +NAMESPACE_END(detail) + +/// Syntax sugar for resolving overloaded function pointers: +/// - regular: static_cast(&Class::func) +/// - sweet: overload_cast(&Class::func) +template +static constexpr detail::overload_cast_impl overload_cast = {}; +// MSVC 2015 only accepts this particular initialization syntax for this variable template. + +/// Const member function selector for overload_cast +/// - regular: static_cast(&Class::func) +/// - sweet: overload_cast(&Class::func, const_) +static constexpr auto const_ = std::true_type{}; + +#else // no overload_cast: providing something that static_assert-fails: +template struct overload_cast { + static_assert(detail::deferred_t::value, + "pybind11::overload_cast<...> requires compiling in C++14 mode"); +}; +#endif // overload_cast + +NAMESPACE_BEGIN(detail) + +// Adaptor for converting arbitrary container arguments into a vector; implicitly convertible from +// any standard container (or C-style array) supporting std::begin/std::end, any singleton +// arithmetic type (if T is arithmetic), or explicitly constructible from an iterator pair. +template +class any_container { + std::vector v; +public: + any_container() = default; + + // Can construct from a pair of iterators + template ::value>> + any_container(It first, It last) : v(first, last) { } + + // Implicit conversion constructor from any arbitrary container type with values convertible to T + template ())), T>::value>> + any_container(const Container &c) : any_container(std::begin(c), std::end(c)) { } + + // initializer_list's aren't deducible, so don't get matched by the above template; we need this + // to explicitly allow implicit conversion from one: + template ::value>> + any_container(const std::initializer_list &c) : any_container(c.begin(), c.end()) { } + + // Avoid copying if given an rvalue vector of the correct type. + any_container(std::vector &&v) : v(std::move(v)) { } + + // Moves the vector out of an rvalue any_container + operator std::vector &&() && { return std::move(v); } + + // Dereferencing obtains a reference to the underlying vector + std::vector &operator*() { return v; } + const std::vector &operator*() const { return v; } + + // -> lets you call methods on the underlying vector + std::vector *operator->() { return &v; } + const std::vector *operator->() const { return &v; } +}; + +NAMESPACE_END(detail) + + + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/detail/descr.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/detail/descr.h new file mode 100644 index 00000000..e3bf2ba9 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/detail/descr.h @@ -0,0 +1,185 @@ +/* + pybind11/detail/descr.h: Helper type for concatenating type signatures + either at runtime (C++11) or compile time (C++14) + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "common.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +/* Concatenate type signatures at compile time using C++14 */ +#if defined(PYBIND11_CPP14) && !defined(_MSC_VER) +#define PYBIND11_CONSTEXPR_DESCR + +template class descr { + template friend class descr; +public: + constexpr descr(char const (&text) [Size1+1], const std::type_info * const (&types)[Size2+1]) + : descr(text, types, + make_index_sequence(), + make_index_sequence()) { } + + constexpr const char *text() const { return m_text; } + constexpr const std::type_info * const * types() const { return m_types; } + + template + constexpr descr operator+(const descr &other) const { + return concat(other, + make_index_sequence(), + make_index_sequence(), + make_index_sequence(), + make_index_sequence()); + } + +protected: + template + constexpr descr( + char const (&text) [Size1+1], + const std::type_info * const (&types) [Size2+1], + index_sequence, index_sequence) + : m_text{text[Indices1]..., '\0'}, + m_types{types[Indices2]..., nullptr } {} + + template + constexpr descr + concat(const descr &other, + index_sequence, index_sequence, + index_sequence, index_sequence) const { + return descr( + { m_text[Indices1]..., other.m_text[OtherIndices1]..., '\0' }, + { m_types[Indices2]..., other.m_types[OtherIndices2]..., nullptr } + ); + } + +protected: + char m_text[Size1 + 1]; + const std::type_info * m_types[Size2 + 1]; +}; + +template constexpr descr _(char const(&text)[Size]) { + return descr(text, { nullptr }); +} + +template struct int_to_str : int_to_str { }; +template struct int_to_str<0, Digits...> { + static constexpr auto digits = descr({ ('0' + Digits)..., '\0' }, { nullptr }); +}; + +// Ternary description (like std::conditional) +template +constexpr enable_if_t> _(char const(&text1)[Size1], char const(&)[Size2]) { + return _(text1); +} +template +constexpr enable_if_t> _(char const(&)[Size1], char const(&text2)[Size2]) { + return _(text2); +} +template +constexpr enable_if_t> _(descr d, descr) { return d; } +template +constexpr enable_if_t> _(descr, descr d) { return d; } + +template auto constexpr _() -> decltype(int_to_str::digits) { + return int_to_str::digits; +} + +template constexpr descr<1, 1> _() { + return descr<1, 1>({ '%', '\0' }, { &typeid(Type), nullptr }); +} + +inline constexpr descr<0, 0> concat() { return _(""); } +template auto constexpr concat(descr descr) { return descr; } +template auto constexpr concat(descr descr, Args&&... args) { return descr + _(", ") + concat(args...); } +template auto constexpr type_descr(descr descr) { return _("{") + descr + _("}"); } + +#define PYBIND11_DESCR constexpr auto + +#else /* Simpler C++11 implementation based on run-time memory allocation and copying */ + +class descr { +public: + PYBIND11_NOINLINE descr(const char *text, const std::type_info * const * types) { + size_t nChars = len(text), nTypes = len(types); + m_text = new char[nChars]; + m_types = new const std::type_info *[nTypes]; + memcpy(m_text, text, nChars * sizeof(char)); + memcpy(m_types, types, nTypes * sizeof(const std::type_info *)); + } + + PYBIND11_NOINLINE descr operator+(descr &&d2) && { + descr r; + + size_t nChars1 = len(m_text), nTypes1 = len(m_types); + size_t nChars2 = len(d2.m_text), nTypes2 = len(d2.m_types); + + r.m_text = new char[nChars1 + nChars2 - 1]; + r.m_types = new const std::type_info *[nTypes1 + nTypes2 - 1]; + memcpy(r.m_text, m_text, (nChars1-1) * sizeof(char)); + memcpy(r.m_text + nChars1 - 1, d2.m_text, nChars2 * sizeof(char)); + memcpy(r.m_types, m_types, (nTypes1-1) * sizeof(std::type_info *)); + memcpy(r.m_types + nTypes1 - 1, d2.m_types, nTypes2 * sizeof(std::type_info *)); + + delete[] m_text; delete[] m_types; + delete[] d2.m_text; delete[] d2.m_types; + + return r; + } + + char *text() { return m_text; } + const std::type_info * * types() { return m_types; } + +protected: + PYBIND11_NOINLINE descr() { } + + template static size_t len(const T *ptr) { // return length including null termination + const T *it = ptr; + while (*it++ != (T) 0) + ; + return static_cast(it - ptr); + } + + const std::type_info **m_types = nullptr; + char *m_text = nullptr; +}; + +/* The 'PYBIND11_NOINLINE inline' combinations below are intentional to get the desired linkage while producing as little object code as possible */ + +PYBIND11_NOINLINE inline descr _(const char *text) { + const std::type_info *types[1] = { nullptr }; + return descr(text, types); +} + +template PYBIND11_NOINLINE enable_if_t _(const char *text1, const char *) { return _(text1); } +template PYBIND11_NOINLINE enable_if_t _(char const *, const char *text2) { return _(text2); } +template PYBIND11_NOINLINE enable_if_t _(descr d, descr) { return d; } +template PYBIND11_NOINLINE enable_if_t _(descr, descr d) { return d; } + +template PYBIND11_NOINLINE descr _() { + const std::type_info *types[2] = { &typeid(Type), nullptr }; + return descr("%", types); +} + +template PYBIND11_NOINLINE descr _() { + const std::type_info *types[1] = { nullptr }; + return descr(std::to_string(Size).c_str(), types); +} + +PYBIND11_NOINLINE inline descr concat() { return _(""); } +PYBIND11_NOINLINE inline descr concat(descr &&d) { return d; } +template PYBIND11_NOINLINE descr concat(descr &&d, Args&&... args) { return std::move(d) + _(", ") + concat(std::forward(args)...); } +PYBIND11_NOINLINE inline descr type_descr(descr&& d) { return _("{") + std::move(d) + _("}"); } + +#define PYBIND11_DESCR ::pybind11::detail::descr +#endif + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/detail/init.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/detail/init.h new file mode 100644 index 00000000..82f74076 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/detail/init.h @@ -0,0 +1,335 @@ +/* + pybind11/detail/init.h: init factory function implementation and support code. + + Copyright (c) 2017 Jason Rhinelander + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "class.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +template <> +class type_caster { +public: + bool load(handle h, bool) { + value = reinterpret_cast(h.ptr()); + return true; + } + + template using cast_op_type = value_and_holder &; + operator value_and_holder &() { return *value; } + static PYBIND11_DESCR name() { return type_descr(_()); } + +private: + value_and_holder *value = nullptr; +}; + +NAMESPACE_BEGIN(initimpl) + +inline void no_nullptr(void *ptr) { + if (!ptr) throw type_error("pybind11::init(): factory function returned nullptr"); +} + +// Implementing functions for all forms of py::init<...> and py::init(...) +template using Cpp = typename Class::type; +template using Alias = typename Class::type_alias; +template using Holder = typename Class::holder_type; + +template using is_alias_constructible = std::is_constructible, Cpp &&>; + +// Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance. +template = 0> +bool is_alias(Cpp *ptr) { + return dynamic_cast *>(ptr) != nullptr; +} +// Failing fallback version of the above for a no-alias class (always returns false) +template +constexpr bool is_alias(void *) { return false; } + +// Constructs and returns a new object; if the given arguments don't map to a constructor, we fall +// back to brace aggregate initiailization so that for aggregate initialization can be used with +// py::init, e.g. `py::init` to initialize a `struct T { int a; int b; }`. For +// non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually +// works, but will not do the expected thing when `T` has an `initializer_list` constructor). +template ::value, int> = 0> +inline Class *construct_or_initialize(Args &&...args) { return new Class(std::forward(args)...); } +template ::value, int> = 0> +inline Class *construct_or_initialize(Args &&...args) { return new Class{std::forward(args)...}; } + +// Attempts to constructs an alias using a `Alias(Cpp &&)` constructor. This allows types with +// an alias to provide only a single Cpp factory function as long as the Alias can be +// constructed from an rvalue reference of the base Cpp type. This means that Alias classes +// can, when appropriate, simply define a `Alias(Cpp &&)` constructor rather than needing to +// inherit all the base class constructors. +template +void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/, + value_and_holder &v_h, Cpp &&base) { + v_h.value_ptr() = new Alias(std::move(base)); +} +template +[[noreturn]] void construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/, + value_and_holder &, Cpp &&) { + throw type_error("pybind11::init(): unable to convert returned instance to required " + "alias class: no `Alias(Class &&)` constructor available"); +} + +// Error-generating fallback for factories that don't match one of the below construction +// mechanisms. +template +void construct(...) { + static_assert(!std::is_same::value /* always false */, + "pybind11::init(): init function must return a compatible pointer, " + "holder, or value"); +} + +// Pointer return v1: the factory function returns a class pointer for a registered class. +// If we don't need an alias (because this class doesn't have one, or because the final type is +// inherited on the Python side) we can simply take over ownership. Otherwise we need to try to +// construct an Alias from the returned base instance. +template +void construct(value_and_holder &v_h, Cpp *ptr, bool need_alias) { + no_nullptr(ptr); + if (Class::has_alias && need_alias && !is_alias(ptr)) { + // We're going to try to construct an alias by moving the cpp type. Whether or not + // that succeeds, we still need to destroy the original cpp pointer (either the + // moved away leftover, if the alias construction works, or the value itself if we + // throw an error), but we can't just call `delete ptr`: it might have a special + // deleter, or might be shared_from_this. So we construct a holder around it as if + // it was a normal instance, then steal the holder away into a local variable; thus + // the holder and destruction happens when we leave the C++ scope, and the holder + // class gets to handle the destruction however it likes. + v_h.value_ptr() = ptr; + v_h.set_instance_registered(true); // To prevent init_instance from registering it + v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder + Holder temp_holder(std::move(v_h.holder>())); // Steal the holder + v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null + v_h.set_instance_registered(false); + + construct_alias_from_cpp(is_alias_constructible{}, v_h, std::move(*ptr)); + } else { + // Otherwise the type isn't inherited, so we don't need an Alias + v_h.value_ptr() = ptr; + } +} + +// Pointer return v2: a factory that always returns an alias instance ptr. We simply take over +// ownership of the pointer. +template = 0> +void construct(value_and_holder &v_h, Alias *alias_ptr, bool) { + no_nullptr(alias_ptr); + v_h.value_ptr() = static_cast *>(alias_ptr); +} + +// Holder return: copy its pointer, and move or copy the returned holder into the new instance's +// holder. This also handles types like std::shared_ptr and std::unique_ptr where T is a +// derived type (through those holder's implicit conversion from derived class holder constructors). +template +void construct(value_and_holder &v_h, Holder holder, bool need_alias) { + auto *ptr = holder_helper>::get(holder); + // If we need an alias, check that the held pointer is actually an alias instance + if (Class::has_alias && need_alias && !is_alias(ptr)) + throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance " + "is not an alias instance"); + + v_h.value_ptr() = ptr; + v_h.type->init_instance(v_h.inst, &holder); +} + +// return-by-value version 1: returning a cpp class by value. If the class has an alias and an +// alias is required the alias must have an `Alias(Cpp &&)` constructor so that we can construct +// the alias from the base when needed (i.e. because of Python-side inheritance). When we don't +// need it, we simply move-construct the cpp value into a new instance. +template +void construct(value_and_holder &v_h, Cpp &&result, bool need_alias) { + static_assert(std::is_move_constructible>::value, + "pybind11::init() return-by-value factory function requires a movable class"); + if (Class::has_alias && need_alias) + construct_alias_from_cpp(is_alias_constructible{}, v_h, std::move(result)); + else + v_h.value_ptr() = new Cpp(std::move(result)); +} + +// return-by-value version 2: returning a value of the alias type itself. We move-construct an +// Alias instance (even if no the python-side inheritance is involved). The is intended for +// cases where Alias initialization is always desired. +template +void construct(value_and_holder &v_h, Alias &&result, bool) { + static_assert(std::is_move_constructible>::value, + "pybind11::init() return-by-alias-value factory function requires a movable alias class"); + v_h.value_ptr() = new Alias(std::move(result)); +} + +// Implementing class for py::init<...>() +template +struct constructor { + template = 0> + static void execute(Class &cl, const Extra&... extra) { + cl.def("__init__", [](value_and_holder &v_h, Args... args) { + v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); + }, is_new_style_constructor(), extra...); + } + + template , Args...>::value, int> = 0> + static void execute(Class &cl, const Extra&... extra) { + cl.def("__init__", [](value_and_holder &v_h, Args... args) { + if (Py_TYPE(v_h.inst) == v_h.type->type) + v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); + else + v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); + }, is_new_style_constructor(), extra...); + } + + template , Args...>::value, int> = 0> + static void execute(Class &cl, const Extra&... extra) { + cl.def("__init__", [](value_and_holder &v_h, Args... args) { + v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); + }, is_new_style_constructor(), extra...); + } +}; + +// Implementing class for py::init_alias<...>() +template struct alias_constructor { + template , Args...>::value, int> = 0> + static void execute(Class &cl, const Extra&... extra) { + cl.def("__init__", [](value_and_holder &v_h, Args... args) { + v_h.value_ptr() = construct_or_initialize>(std::forward(args)...); + }, is_new_style_constructor(), extra...); + } +}; + +// Implementation class for py::init(Func) and py::init(Func, AliasFunc) +template , typename = function_signature_t> +struct factory; + +// Specialization for py::init(Func) +template +struct factory { + remove_reference_t class_factory; + + factory(Func &&f) : class_factory(std::forward(f)) { } + + // The given class either has no alias or has no separate alias factory; + // this always constructs the class itself. If the class is registered with an alias + // type and an alias instance is needed (i.e. because the final type is a Python class + // inheriting from the C++ type) the returned value needs to either already be an alias + // instance, or the alias needs to be constructible from a `Class &&` argument. + template + void execute(Class &cl, const Extra &...extra) && { + #if defined(PYBIND11_CPP14) + cl.def("__init__", [func = std::move(class_factory)] + #else + auto &func = class_factory; + cl.def("__init__", [func] + #endif + (value_and_holder &v_h, Args... args) { + construct(v_h, func(std::forward(args)...), + Py_TYPE(v_h.inst) != v_h.type->type); + }, is_new_style_constructor(), extra...); + } +}; + +// Specialization for py::init(Func, AliasFunc) +template +struct factory { + static_assert(sizeof...(CArgs) == sizeof...(AArgs), + "pybind11::init(class_factory, alias_factory): class and alias factories " + "must have identical argument signatures"); + static_assert(all_of...>::value, + "pybind11::init(class_factory, alias_factory): class and alias factories " + "must have identical argument signatures"); + + remove_reference_t class_factory; + remove_reference_t alias_factory; + + factory(CFunc &&c, AFunc &&a) + : class_factory(std::forward(c)), alias_factory(std::forward(a)) { } + + // The class factory is called when the `self` type passed to `__init__` is the direct + // class (i.e. not inherited), the alias factory when `self` is a Python-side subtype. + template + void execute(Class &cl, const Extra&... extra) && { + static_assert(Class::has_alias, "The two-argument version of `py::init()` can " + "only be used if the class has an alias"); + #if defined(PYBIND11_CPP14) + cl.def("__init__", [class_func = std::move(class_factory), alias_func = std::move(alias_factory)] + #else + auto &class_func = class_factory; + auto &alias_func = alias_factory; + cl.def("__init__", [class_func, alias_func] + #endif + (value_and_holder &v_h, CArgs... args) { + if (Py_TYPE(v_h.inst) == v_h.type->type) + // If the instance type equals the registered type we don't have inheritance, so + // don't need the alias and can construct using the class function: + construct(v_h, class_func(std::forward(args)...), false); + else + construct(v_h, alias_func(std::forward(args)...), true); + }, is_new_style_constructor(), extra...); + } +}; + +/// Set just the C++ state. Same as `__init__`. +template +void setstate(value_and_holder &v_h, T &&result, bool need_alias) { + construct(v_h, std::forward(result), need_alias); +} + +/// Set both the C++ and Python states +template ::value, int> = 0> +void setstate(value_and_holder &v_h, std::pair &&result, bool need_alias) { + construct(v_h, std::move(result.first), need_alias); + setattr((PyObject *) v_h.inst, "__dict__", result.second); +} + +/// Implementation for py::pickle(GetState, SetState) +template , typename = function_signature_t> +struct pickle_factory; + +template +struct pickle_factory { + static_assert(std::is_same, intrinsic_t>::value, + "The type returned by `__getstate__` must be the same " + "as the argument accepted by `__setstate__`"); + + remove_reference_t get; + remove_reference_t set; + + pickle_factory(Get get, Set set) + : get(std::forward(get)), set(std::forward(set)) { } + + template + void execute(Class &cl, const Extra &...extra) && { + cl.def("__getstate__", std::move(get)); + +#if defined(PYBIND11_CPP14) + cl.def("__setstate__", [func = std::move(set)] +#else + auto &func = set; + cl.def("__setstate__", [func] +#endif + (value_and_holder &v_h, ArgState state) { + setstate(v_h, func(std::forward(state)), + Py_TYPE(v_h.inst) != v_h.type->type); + }, is_new_style_constructor(), extra...); + } +}; + +NAMESPACE_END(initimpl) +NAMESPACE_END(detail) +NAMESPACE_END(pybind11) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/detail/internals.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/detail/internals.h new file mode 100644 index 00000000..e39f3869 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/detail/internals.h @@ -0,0 +1,249 @@ +/* + pybind11/detail/internals.h: Internal data structure and related functions + + Copyright (c) 2017 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "../pytypes.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) +// Forward declarations +inline PyTypeObject *make_static_property_type(); +inline PyTypeObject *make_default_metaclass(); +inline PyObject *make_object_base_type(PyTypeObject *metaclass); + +// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly +// other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module +// even when `A` is the same, non-hidden-visibility type (e.g. from a common include). Under +// libstdc++, this doesn't happen: equality and the type_index hash are based on the type name, +// which works. If not under a known-good stl, provide our own name-based hash and equality +// functions that use the type name. +#if defined(__GLIBCXX__) +inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { return lhs == rhs; } +using type_hash = std::hash; +using type_equal_to = std::equal_to; +#else +inline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { + return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0; +} + +struct type_hash { + size_t operator()(const std::type_index &t) const { + size_t hash = 5381; + const char *ptr = t.name(); + while (auto c = static_cast(*ptr++)) + hash = (hash * 33) ^ c; + return hash; + } +}; + +struct type_equal_to { + bool operator()(const std::type_index &lhs, const std::type_index &rhs) const { + return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0; + } +}; +#endif + +template +using type_map = std::unordered_map; + +struct overload_hash { + inline size_t operator()(const std::pair& v) const { + size_t value = std::hash()(v.first); + value ^= std::hash()(v.second) + 0x9e3779b9 + (value<<6) + (value>>2); + return value; + } +}; + +/// Internal data structure used to track registered instances and types. +/// Whenever binary incompatible changes are made to this structure, +/// `PYBIND11_INTERNALS_VERSION` must be incremented. +struct internals { + type_map registered_types_cpp; // std::type_index -> pybind11's type information + std::unordered_map> registered_types_py; // PyTypeObject* -> base type_info(s) + std::unordered_multimap registered_instances; // void * -> instance* + std::unordered_set, overload_hash> inactive_overload_cache; + type_map> direct_conversions; + std::unordered_map> patients; + std::forward_list registered_exception_translators; + std::unordered_map shared_data; // Custom data to be shared across extensions + std::vector loader_patient_stack; // Used by `loader_life_support` + std::forward_list static_strings; // Stores the std::strings backing detail::c_str() + PyTypeObject *static_property_type; + PyTypeObject *default_metaclass; + PyObject *instance_base; +#if defined(WITH_THREAD) + decltype(PyThread_create_key()) tstate = 0; // Usually an int but a long on Cygwin64 with Python 3.x + PyInterpreterState *istate = nullptr; +#endif +}; + +/// Additional type information which does not fit into the PyTypeObject. +/// Changes to this struct also require bumping `PYBIND11_INTERNALS_VERSION`. +struct type_info { + PyTypeObject *type; + const std::type_info *cpptype; + size_t type_size, holder_size_in_ptrs; + void *(*operator_new)(size_t); + void (*init_instance)(instance *, const void *); + void (*dealloc)(value_and_holder &v_h); + std::vector implicit_conversions; + std::vector> implicit_casts; + std::vector *direct_conversions; + buffer_info *(*get_buffer)(PyObject *, void *) = nullptr; + void *get_buffer_data = nullptr; + void *(*module_local_load)(PyObject *, const type_info *) = nullptr; + /* A simple type never occurs as a (direct or indirect) parent + * of a class that makes use of multiple inheritance */ + bool simple_type : 1; + /* True if there is no multiple inheritance in this type's inheritance tree */ + bool simple_ancestors : 1; + /* for base vs derived holder_type checks */ + bool default_holder : 1; + /* true if this is a type registered with py::module_local */ + bool module_local : 1; +}; + +/// Tracks the `internals` and `type_info` ABI version independent of the main library version +#define PYBIND11_INTERNALS_VERSION 1 + +#if defined(WITH_THREAD) +# define PYBIND11_INTERNALS_KIND "" +#else +# define PYBIND11_INTERNALS_KIND "_without_thread" +#endif + +#define PYBIND11_INTERNALS_ID "__pybind11_internals_v" \ + PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND "__" + +#define PYBIND11_MODULE_LOCAL_ID "__pybind11_module_local_v" \ + PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) PYBIND11_INTERNALS_KIND "__" + +/// Each module locally stores a pointer to the `internals` data. The data +/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`. +inline internals **&get_internals_pp() { + static internals **internals_pp = nullptr; + return internals_pp; +} + +/// Return a reference to the current `internals` data +PYBIND11_NOINLINE inline internals &get_internals() { + auto **&internals_pp = get_internals_pp(); + if (internals_pp && *internals_pp) + return **internals_pp; + + constexpr auto *id = PYBIND11_INTERNALS_ID; + auto builtins = handle(PyEval_GetBuiltins()); + if (builtins.contains(id) && isinstance(builtins[id])) { + internals_pp = static_cast(capsule(builtins[id])); + + // We loaded builtins through python's builtins, which means that our `error_already_set` + // and `builtin_exception` may be different local classes than the ones set up in the + // initial exception translator, below, so add another for our local exception classes. + // + // libstdc++ doesn't require this (types there are identified only by name) +#if !defined(__GLIBCXX__) + (*internals_pp)->registered_exception_translators.push_front( + [](std::exception_ptr p) -> void { + try { + if (p) std::rethrow_exception(p); + } catch (error_already_set &e) { e.restore(); return; + } catch (const builtin_exception &e) { e.set_error(); return; + } + } + ); +#endif + } else { + if (!internals_pp) internals_pp = new internals*(); + auto *&internals_ptr = *internals_pp; + internals_ptr = new internals(); +#if defined(WITH_THREAD) + PyEval_InitThreads(); + PyThreadState *tstate = PyThreadState_Get(); + internals_ptr->tstate = PyThread_create_key(); + PyThread_set_key_value(internals_ptr->tstate, tstate); + internals_ptr->istate = tstate->interp; +#endif + builtins[id] = capsule(internals_pp); + internals_ptr->registered_exception_translators.push_front( + [](std::exception_ptr p) -> void { + try { + if (p) std::rethrow_exception(p); + } catch (error_already_set &e) { e.restore(); return; + } catch (const builtin_exception &e) { e.set_error(); return; + } catch (const std::bad_alloc &e) { PyErr_SetString(PyExc_MemoryError, e.what()); return; + } catch (const std::domain_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; + } catch (const std::invalid_argument &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; + } catch (const std::length_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; + } catch (const std::out_of_range &e) { PyErr_SetString(PyExc_IndexError, e.what()); return; + } catch (const std::range_error &e) { PyErr_SetString(PyExc_ValueError, e.what()); return; + } catch (const std::exception &e) { PyErr_SetString(PyExc_RuntimeError, e.what()); return; + } catch (...) { + PyErr_SetString(PyExc_RuntimeError, "Caught an unknown exception!"); + return; + } + } + ); + internals_ptr->static_property_type = make_static_property_type(); + internals_ptr->default_metaclass = make_default_metaclass(); + internals_ptr->instance_base = make_object_base_type(internals_ptr->default_metaclass); + } + return **internals_pp; +} + +/// Works like `internals.registered_types_cpp`, but for module-local registered types: +inline type_map ®istered_local_types_cpp() { + static type_map locals{}; + return locals; +} + +/// Constructs a std::string with the given arguments, stores it in `internals`, and returns its +/// `c_str()`. Such strings objects have a long storage duration -- the internal strings are only +/// cleared when the program exits or after interpreter shutdown (when embedding), and so are +/// suitable for c-style strings needed by Python internals (such as PyTypeObject's tp_name). +template +const char *c_str(Args &&...args) { + auto &strings = get_internals().static_strings; + strings.emplace_front(std::forward(args)...); + return strings.front().c_str(); +} + +NAMESPACE_END(detail) + +/// Returns a named pointer that is shared among all extension modules (using the same +/// pybind11 version) running in the current interpreter. Names starting with underscores +/// are reserved for internal usage. Returns `nullptr` if no matching entry was found. +inline PYBIND11_NOINLINE void *get_shared_data(const std::string &name) { + auto &internals = detail::get_internals(); + auto it = internals.shared_data.find(name); + return it != internals.shared_data.end() ? it->second : nullptr; +} + +/// Set the shared data that can be later recovered by `get_shared_data()`. +inline PYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) { + detail::get_internals().shared_data[name] = data; + return data; +} + +/// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if +/// such entry exists. Otherwise, a new object of default-constructible type `T` is +/// added to the shared data under the given name and a reference to it is returned. +template +T &get_or_create_shared_data(const std::string &name) { + auto &internals = detail::get_internals(); + auto it = internals.shared_data.find(name); + T *ptr = (T *) (it != internals.shared_data.end() ? it->second : nullptr); + if (!ptr) { + ptr = new T(); + internals.shared_data[name] = ptr; + } + return *ptr; +} + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/detail/typeid.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/detail/typeid.h new file mode 100644 index 00000000..6f36aab7 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/detail/typeid.h @@ -0,0 +1,53 @@ +/* + pybind11/detail/typeid.h: Compiler-independent access to type identifiers + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include +#include + +#if defined(__GNUG__) +#include +#endif + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) +/// Erase all occurrences of a substring +inline void erase_all(std::string &string, const std::string &search) { + for (size_t pos = 0;;) { + pos = string.find(search, pos); + if (pos == std::string::npos) break; + string.erase(pos, search.length()); + } +} + +PYBIND11_NOINLINE inline void clean_type_id(std::string &name) { +#if defined(__GNUG__) + int status = 0; + std::unique_ptr res { + abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free }; + if (status == 0) + name = res.get(); +#else + detail::erase_all(name, "class "); + detail::erase_all(name, "struct "); + detail::erase_all(name, "enum "); +#endif + detail::erase_all(name, "pybind11::"); +} +NAMESPACE_END(detail) + +/// Return a string representation of a C++ type +template static std::string type_id() { + std::string name(typeid(T).name()); + detail::clean_type_id(name); + return name; +} + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/eigen.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/eigen.h new file mode 100644 index 00000000..693a484d --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/eigen.h @@ -0,0 +1,612 @@ +/* + pybind11/eigen.h: Transparent conversion for dense and sparse Eigen matrices + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "numpy.h" + +#if defined(__INTEL_COMPILER) +# pragma warning(disable: 1682) // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem) +#elif defined(__GNUG__) || defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +# if __GNUC__ >= 7 +# pragma GCC diagnostic ignored "-Wint-in-bool-context" +# endif +#endif + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +# pragma warning(disable: 4996) // warning C4996: std::unary_negate is deprecated in C++17 +#endif + +#include +#include + +// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit +// move constructors that break things. We could detect this an explicitly copy, but an extra copy +// of matrices seems highly undesirable. +static_assert(EIGEN_VERSION_AT_LEAST(3,2,7), "Eigen support in pybind11 requires Eigen >= 3.2.7"); + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +// Provide a convenience alias for easier pass-by-ref usage with fully dynamic strides: +using EigenDStride = Eigen::Stride; +template using EigenDRef = Eigen::Ref; +template using EigenDMap = Eigen::Map; + +NAMESPACE_BEGIN(detail) + +#if EIGEN_VERSION_AT_LEAST(3,3,0) +using EigenIndex = Eigen::Index; +#else +using EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE; +#endif + +// Matches Eigen::Map, Eigen::Ref, blocks, etc: +template using is_eigen_dense_map = all_of, std::is_base_of, T>>; +template using is_eigen_mutable_map = std::is_base_of, T>; +template using is_eigen_dense_plain = all_of>, is_template_base_of>; +template using is_eigen_sparse = is_template_base_of; +// Test for objects inheriting from EigenBase that aren't captured by the above. This +// basically covers anything that can be assigned to a dense matrix but that don't have a typical +// matrix data layout that can be copied from their .data(). For example, DiagonalMatrix and +// SelfAdjointView fall into this category. +template using is_eigen_other = all_of< + is_template_base_of, + negation, is_eigen_dense_plain, is_eigen_sparse>> +>; + +// Captures numpy/eigen conformability status (returned by EigenProps::conformable()): +template struct EigenConformable { + bool conformable = false; + EigenIndex rows = 0, cols = 0; + EigenDStride stride{0, 0}; // Only valid if negativestrides is false! + bool negativestrides = false; // If true, do not use stride! + + EigenConformable(bool fits = false) : conformable{fits} {} + // Matrix type: + EigenConformable(EigenIndex r, EigenIndex c, + EigenIndex rstride, EigenIndex cstride) : + conformable{true}, rows{r}, cols{c} { + // TODO: when Eigen bug #747 is fixed, remove the tests for non-negativity. http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747 + if (rstride < 0 || cstride < 0) { + negativestrides = true; + } else { + stride = {EigenRowMajor ? rstride : cstride /* outer stride */, + EigenRowMajor ? cstride : rstride /* inner stride */ }; + } + } + // Vector type: + EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride) + : EigenConformable(r, c, r == 1 ? c*stride : stride, c == 1 ? r : r*stride) {} + + template bool stride_compatible() const { + // To have compatible strides, we need (on both dimensions) one of fully dynamic strides, + // matching strides, or a dimension size of 1 (in which case the stride value is irrelevant) + return + !negativestrides && + (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner() || + (EigenRowMajor ? cols : rows) == 1) && + (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer() || + (EigenRowMajor ? rows : cols) == 1); + } + operator bool() const { return conformable; } +}; + +template struct eigen_extract_stride { using type = Type; }; +template +struct eigen_extract_stride> { using type = StrideType; }; +template +struct eigen_extract_stride> { using type = StrideType; }; + +// Helper struct for extracting information from an Eigen type +template struct EigenProps { + using Type = Type_; + using Scalar = typename Type::Scalar; + using StrideType = typename eigen_extract_stride::type; + static constexpr EigenIndex + rows = Type::RowsAtCompileTime, + cols = Type::ColsAtCompileTime, + size = Type::SizeAtCompileTime; + static constexpr bool + row_major = Type::IsRowMajor, + vector = Type::IsVectorAtCompileTime, // At least one dimension has fixed size 1 + fixed_rows = rows != Eigen::Dynamic, + fixed_cols = cols != Eigen::Dynamic, + fixed = size != Eigen::Dynamic, // Fully-fixed size + dynamic = !fixed_rows && !fixed_cols; // Fully-dynamic size + + template using if_zero = std::integral_constant; + static constexpr EigenIndex inner_stride = if_zero::value, + outer_stride = if_zero::value; + static constexpr bool dynamic_stride = inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic; + static constexpr bool requires_row_major = !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1; + static constexpr bool requires_col_major = !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1; + + // Takes an input array and determines whether we can make it fit into the Eigen type. If + // the array is a vector, we attempt to fit it into either an Eigen 1xN or Nx1 vector + // (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type). + static EigenConformable conformable(const array &a) { + const auto dims = a.ndim(); + if (dims < 1 || dims > 2) + return false; + + if (dims == 2) { // Matrix type: require exact match (or dynamic) + + EigenIndex + np_rows = a.shape(0), + np_cols = a.shape(1), + np_rstride = a.strides(0) / static_cast(sizeof(Scalar)), + np_cstride = a.strides(1) / static_cast(sizeof(Scalar)); + if ((fixed_rows && np_rows != rows) || (fixed_cols && np_cols != cols)) + return false; + + return {np_rows, np_cols, np_rstride, np_cstride}; + } + + // Otherwise we're storing an n-vector. Only one of the strides will be used, but whichever + // is used, we want the (single) numpy stride value. + const EigenIndex n = a.shape(0), + stride = a.strides(0) / static_cast(sizeof(Scalar)); + + if (vector) { // Eigen type is a compile-time vector + if (fixed && size != n) + return false; // Vector size mismatch + return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride}; + } + else if (fixed) { + // The type has a fixed size, but is not a vector: abort + return false; + } + else if (fixed_cols) { + // Since this isn't a vector, cols must be != 1. We allow this only if it exactly + // equals the number of elements (rows is Dynamic, and so 1 row is allowed). + if (cols != n) return false; + return {1, n, stride}; + } + else { + // Otherwise it's either fully dynamic, or column dynamic; both become a column vector + if (fixed_rows && rows != n) return false; + return {n, 1, stride}; + } + } + + static PYBIND11_DESCR descriptor() { + constexpr bool show_writeable = is_eigen_dense_map::value && is_eigen_mutable_map::value; + constexpr bool show_order = is_eigen_dense_map::value; + constexpr bool show_c_contiguous = show_order && requires_row_major; + constexpr bool show_f_contiguous = !show_c_contiguous && show_order && requires_col_major; + + return type_descr(_("numpy.ndarray[") + npy_format_descriptor::name() + + _("[") + _(_<(size_t) rows>(), _("m")) + + _(", ") + _(_<(size_t) cols>(), _("n")) + + _("]") + + // For a reference type (e.g. Ref) we have other constraints that might need to be + // satisfied: writeable=True (for a mutable reference), and, depending on the map's stride + // options, possibly f_contiguous or c_contiguous. We include them in the descriptor output + // to provide some hint as to why a TypeError is occurring (otherwise it can be confusing to + // see that a function accepts a 'numpy.ndarray[float64[3,2]]' and an error message that you + // *gave* a numpy.ndarray of the right type and dimensions. + _(", flags.writeable", "") + + _(", flags.c_contiguous", "") + + _(", flags.f_contiguous", "") + + _("]") + ); + } +}; + +// Casts an Eigen type to numpy array. If given a base, the numpy array references the src data, +// otherwise it'll make a copy. writeable lets you turn off the writeable flag for the array. +template handle eigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) { + constexpr ssize_t elem_size = sizeof(typename props::Scalar); + array a; + if (props::vector) + a = array({ src.size() }, { elem_size * src.innerStride() }, src.data(), base); + else + a = array({ src.rows(), src.cols() }, { elem_size * src.rowStride(), elem_size * src.colStride() }, + src.data(), base); + + if (!writeable) + array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_; + + return a.release(); +} + +// Takes an lvalue ref to some Eigen type and a (python) base object, creating a numpy array that +// reference the Eigen object's data with `base` as the python-registered base class (if omitted, +// the base will be set to None, and lifetime management is up to the caller). The numpy array is +// non-writeable if the given type is const. +template +handle eigen_ref_array(Type &src, handle parent = none()) { + // none here is to get past array's should-we-copy detection, which currently always + // copies when there is no base. Setting the base to None should be harmless. + return eigen_array_cast(src, parent, !std::is_const::value); +} + +// Takes a pointer to some dense, plain Eigen type, builds a capsule around it, then returns a numpy +// array that references the encapsulated data with a python-side reference to the capsule to tie +// its destruction to that of any dependent python objects. Const-ness is determined by whether or +// not the Type of the pointer given is const. +template ::value>> +handle eigen_encapsulate(Type *src) { + capsule base(src, [](void *o) { delete static_cast(o); }); + return eigen_ref_array(*src, base); +} + +// Type caster for regular, dense matrix types (e.g. MatrixXd), but not maps/refs/etc. of dense +// types. +template +struct type_caster::value>> { + using Scalar = typename Type::Scalar; + using props = EigenProps; + + bool load(handle src, bool convert) { + // If we're in no-convert mode, only load if given an array of the correct type + if (!convert && !isinstance>(src)) + return false; + + // Coerce into an array, but don't do type conversion yet; the copy below handles it. + auto buf = array::ensure(src); + + if (!buf) + return false; + + auto dims = buf.ndim(); + if (dims < 1 || dims > 2) + return false; + + auto fits = props::conformable(buf); + if (!fits) + return false; + + // Allocate the new type, then build a numpy reference into it + value = Type(fits.rows, fits.cols); + auto ref = reinterpret_steal(eigen_ref_array(value)); + if (dims == 1) ref = ref.squeeze(); + else if (ref.ndim() == 1) buf = buf.squeeze(); + + int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr()); + + if (result < 0) { // Copy failed! + PyErr_Clear(); + return false; + } + + return true; + } + +private: + + // Cast implementation + template + static handle cast_impl(CType *src, return_value_policy policy, handle parent) { + switch (policy) { + case return_value_policy::take_ownership: + case return_value_policy::automatic: + return eigen_encapsulate(src); + case return_value_policy::move: + return eigen_encapsulate(new CType(std::move(*src))); + case return_value_policy::copy: + return eigen_array_cast(*src); + case return_value_policy::reference: + case return_value_policy::automatic_reference: + return eigen_ref_array(*src); + case return_value_policy::reference_internal: + return eigen_ref_array(*src, parent); + default: + throw cast_error("unhandled return_value_policy: should not happen!"); + }; + } + +public: + + // Normal returned non-reference, non-const value: + static handle cast(Type &&src, return_value_policy /* policy */, handle parent) { + return cast_impl(&src, return_value_policy::move, parent); + } + // If you return a non-reference const, we mark the numpy array readonly: + static handle cast(const Type &&src, return_value_policy /* policy */, handle parent) { + return cast_impl(&src, return_value_policy::move, parent); + } + // lvalue reference return; default (automatic) becomes copy + static handle cast(Type &src, return_value_policy policy, handle parent) { + if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference) + policy = return_value_policy::copy; + return cast_impl(&src, policy, parent); + } + // const lvalue reference return; default (automatic) becomes copy + static handle cast(const Type &src, return_value_policy policy, handle parent) { + if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference) + policy = return_value_policy::copy; + return cast(&src, policy, parent); + } + // non-const pointer return + static handle cast(Type *src, return_value_policy policy, handle parent) { + return cast_impl(src, policy, parent); + } + // const pointer return + static handle cast(const Type *src, return_value_policy policy, handle parent) { + return cast_impl(src, policy, parent); + } + + static PYBIND11_DESCR name() { return props::descriptor(); } + + operator Type*() { return &value; } + operator Type&() { return value; } + operator Type&&() && { return std::move(value); } + template using cast_op_type = movable_cast_op_type; + +private: + Type value; +}; + +// Eigen Ref/Map classes have slightly different policy requirements, meaning we don't want to force +// `move` when a Ref/Map rvalue is returned; we treat Ref<> sort of like a pointer (we care about +// the underlying data, not the outer shell). +template +struct return_value_policy_override::value>> { + static return_value_policy policy(return_value_policy p) { return p; } +}; + +// Base class for casting reference/map/block/etc. objects back to python. +template struct eigen_map_caster { +private: + using props = EigenProps; + +public: + + // Directly referencing a ref/map's data is a bit dangerous (whatever the map/ref points to has + // to stay around), but we'll allow it under the assumption that you know what you're doing (and + // have an appropriate keep_alive in place). We return a numpy array pointing directly at the + // ref's data (The numpy array ends up read-only if the ref was to a const matrix type.) Note + // that this means you need to ensure you don't destroy the object in some other way (e.g. with + // an appropriate keep_alive, or with a reference to a statically allocated matrix). + static handle cast(const MapType &src, return_value_policy policy, handle parent) { + switch (policy) { + case return_value_policy::copy: + return eigen_array_cast(src); + case return_value_policy::reference_internal: + return eigen_array_cast(src, parent, is_eigen_mutable_map::value); + case return_value_policy::reference: + case return_value_policy::automatic: + case return_value_policy::automatic_reference: + return eigen_array_cast(src, none(), is_eigen_mutable_map::value); + default: + // move, take_ownership don't make any sense for a ref/map: + pybind11_fail("Invalid return_value_policy for Eigen Map/Ref/Block type"); + } + } + + static PYBIND11_DESCR name() { return props::descriptor(); } + + // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return + // types but not bound arguments). We still provide them (with an explicitly delete) so that + // you end up here if you try anyway. + bool load(handle, bool) = delete; + operator MapType() = delete; + template using cast_op_type = MapType; +}; + +// We can return any map-like object (but can only load Refs, specialized next): +template struct type_caster::value>> + : eigen_map_caster {}; + +// Loader for Ref<...> arguments. See the documentation for info on how to make this work without +// copying (it requires some extra effort in many cases). +template +struct type_caster< + Eigen::Ref, + enable_if_t>::value> +> : public eigen_map_caster> { +private: + using Type = Eigen::Ref; + using props = EigenProps; + using Scalar = typename props::Scalar; + using MapType = Eigen::Map; + using Array = array_t; + static constexpr bool need_writeable = is_eigen_mutable_map::value; + // Delay construction (these have no default constructor) + std::unique_ptr map; + std::unique_ptr ref; + // Our array. When possible, this is just a numpy array pointing to the source data, but + // sometimes we can't avoid copying (e.g. input is not a numpy array at all, has an incompatible + // layout, or is an array of a type that needs to be converted). Using a numpy temporary + // (rather than an Eigen temporary) saves an extra copy when we need both type conversion and + // storage order conversion. (Note that we refuse to use this temporary copy when loading an + // argument for a Ref with M non-const, i.e. a read-write reference). + Array copy_or_ref; +public: + bool load(handle src, bool convert) { + // First check whether what we have is already an array of the right type. If not, we can't + // avoid a copy (because the copy is also going to do type conversion). + bool need_copy = !isinstance(src); + + EigenConformable fits; + if (!need_copy) { + // We don't need a converting copy, but we also need to check whether the strides are + // compatible with the Ref's stride requirements + Array aref = reinterpret_borrow(src); + + if (aref && (!need_writeable || aref.writeable())) { + fits = props::conformable(aref); + if (!fits) return false; // Incompatible dimensions + if (!fits.template stride_compatible()) + need_copy = true; + else + copy_or_ref = std::move(aref); + } + else { + need_copy = true; + } + } + + if (need_copy) { + // We need to copy: If we need a mutable reference, or we're not supposed to convert + // (either because we're in the no-convert overload pass, or because we're explicitly + // instructed not to copy (via `py::arg().noconvert()`) we have to fail loading. + if (!convert || need_writeable) return false; + + Array copy = Array::ensure(src); + if (!copy) return false; + fits = props::conformable(copy); + if (!fits || !fits.template stride_compatible()) + return false; + copy_or_ref = std::move(copy); + loader_life_support::add_patient(copy_or_ref); + } + + ref.reset(); + map.reset(new MapType(data(copy_or_ref), fits.rows, fits.cols, make_stride(fits.stride.outer(), fits.stride.inner()))); + ref.reset(new Type(*map)); + + return true; + } + + operator Type*() { return ref.get(); } + operator Type&() { return *ref; } + template using cast_op_type = pybind11::detail::cast_op_type<_T>; + +private: + template ::value, int> = 0> + Scalar *data(Array &a) { return a.mutable_data(); } + + template ::value, int> = 0> + const Scalar *data(Array &a) { return a.data(); } + + // Attempt to figure out a constructor of `Stride` that will work. + // If both strides are fixed, use a default constructor: + template using stride_ctor_default = bool_constant< + S::InnerStrideAtCompileTime != Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic && + std::is_default_constructible::value>; + // Otherwise, if there is a two-index constructor, assume it is (outer,inner) like + // Eigen::Stride, and use it: + template using stride_ctor_dual = bool_constant< + !stride_ctor_default::value && std::is_constructible::value>; + // Otherwise, if there is a one-index constructor, and just one of the strides is dynamic, use + // it (passing whichever stride is dynamic). + template using stride_ctor_outer = bool_constant< + !any_of, stride_ctor_dual>::value && + S::OuterStrideAtCompileTime == Eigen::Dynamic && S::InnerStrideAtCompileTime != Eigen::Dynamic && + std::is_constructible::value>; + template using stride_ctor_inner = bool_constant< + !any_of, stride_ctor_dual>::value && + S::InnerStrideAtCompileTime == Eigen::Dynamic && S::OuterStrideAtCompileTime != Eigen::Dynamic && + std::is_constructible::value>; + + template ::value, int> = 0> + static S make_stride(EigenIndex, EigenIndex) { return S(); } + template ::value, int> = 0> + static S make_stride(EigenIndex outer, EigenIndex inner) { return S(outer, inner); } + template ::value, int> = 0> + static S make_stride(EigenIndex outer, EigenIndex) { return S(outer); } + template ::value, int> = 0> + static S make_stride(EigenIndex, EigenIndex inner) { return S(inner); } + +}; + +// type_caster for special matrix types (e.g. DiagonalMatrix), which are EigenBase, but not +// EigenDense (i.e. they don't have a data(), at least not with the usual matrix layout). +// load() is not supported, but we can cast them into the python domain by first copying to a +// regular Eigen::Matrix, then casting that. +template +struct type_caster::value>> { +protected: + using Matrix = Eigen::Matrix; + using props = EigenProps; +public: + static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) { + handle h = eigen_encapsulate(new Matrix(src)); + return h; + } + static handle cast(const Type *src, return_value_policy policy, handle parent) { return cast(*src, policy, parent); } + + static PYBIND11_DESCR name() { return props::descriptor(); } + + // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return + // types but not bound arguments). We still provide them (with an explicitly delete) so that + // you end up here if you try anyway. + bool load(handle, bool) = delete; + operator Type() = delete; + template using cast_op_type = Type; +}; + +template +struct type_caster::value>> { + typedef typename Type::Scalar Scalar; + typedef remove_reference_t().outerIndexPtr())> StorageIndex; + typedef typename Type::Index Index; + static constexpr bool rowMajor = Type::IsRowMajor; + + bool load(handle src, bool) { + if (!src) + return false; + + auto obj = reinterpret_borrow(src); + object sparse_module = module::import("scipy.sparse"); + object matrix_type = sparse_module.attr( + rowMajor ? "csr_matrix" : "csc_matrix"); + + if (!obj.get_type().is(matrix_type)) { + try { + obj = matrix_type(obj); + } catch (const error_already_set &) { + return false; + } + } + + auto values = array_t((object) obj.attr("data")); + auto innerIndices = array_t((object) obj.attr("indices")); + auto outerIndices = array_t((object) obj.attr("indptr")); + auto shape = pybind11::tuple((pybind11::object) obj.attr("shape")); + auto nnz = obj.attr("nnz").cast(); + + if (!values || !innerIndices || !outerIndices) + return false; + + value = Eigen::MappedSparseMatrix( + shape[0].cast(), shape[1].cast(), nnz, + outerIndices.mutable_data(), innerIndices.mutable_data(), values.mutable_data()); + + return true; + } + + static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) { + const_cast(src).makeCompressed(); + + object matrix_type = module::import("scipy.sparse").attr( + rowMajor ? "csr_matrix" : "csc_matrix"); + + array data(src.nonZeros(), src.valuePtr()); + array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr()); + array innerIndices(src.nonZeros(), src.innerIndexPtr()); + + return matrix_type( + std::make_tuple(data, innerIndices, outerIndices), + std::make_pair(src.rows(), src.cols()) + ).release(); + } + + PYBIND11_TYPE_CASTER(Type, _<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[") + + npy_format_descriptor::name() + _("]")); +}; + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) + +#if defined(__GNUG__) || defined(__clang__) +# pragma GCC diagnostic pop +#elif defined(_MSC_VER) +# pragma warning(pop) +#endif diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/embed.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/embed.h new file mode 100644 index 00000000..9abc61c3 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/embed.h @@ -0,0 +1,194 @@ +/* + pybind11/embed.h: Support for embedding the interpreter + + Copyright (c) 2017 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include "eval.h" + +#if defined(PYPY_VERSION) +# error Embedding the interpreter is not supported with PyPy +#endif + +#if PY_MAJOR_VERSION >= 3 +# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \ + extern "C" PyObject *pybind11_init_impl_##name() { \ + return pybind11_init_wrapper_##name(); \ + } +#else +# define PYBIND11_EMBEDDED_MODULE_IMPL(name) \ + extern "C" void pybind11_init_impl_##name() { \ + pybind11_init_wrapper_##name(); \ + } +#endif + +/** \rst + Add a new module to the table of builtins for the interpreter. Must be + defined in global scope. The first macro parameter is the name of the + module (without quotes). The second parameter is the variable which will + be used as the interface to add functions and classes to the module. + + .. code-block:: cpp + + PYBIND11_EMBEDDED_MODULE(example, m) { + // ... initialize functions and classes here + m.def("foo", []() { + return "Hello, World!"; + }); + } + \endrst */ +#define PYBIND11_EMBEDDED_MODULE(name, variable) \ + static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &); \ + static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \ + auto m = pybind11::module(PYBIND11_TOSTRING(name)); \ + try { \ + PYBIND11_CONCAT(pybind11_init_, name)(m); \ + return m.ptr(); \ + } catch (pybind11::error_already_set &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } catch (const std::exception &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } \ + } \ + PYBIND11_EMBEDDED_MODULE_IMPL(name) \ + pybind11::detail::embedded_module name(PYBIND11_TOSTRING(name), \ + PYBIND11_CONCAT(pybind11_init_impl_, name)); \ + void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &variable) + + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks. +struct embedded_module { +#if PY_MAJOR_VERSION >= 3 + using init_t = PyObject *(*)(); +#else + using init_t = void (*)(); +#endif + embedded_module(const char *name, init_t init) { + if (Py_IsInitialized()) + pybind11_fail("Can't add new modules after the interpreter has been initialized"); + + auto result = PyImport_AppendInittab(name, init); + if (result == -1) + pybind11_fail("Insufficient memory to add a new module"); + } +}; + +NAMESPACE_END(detail) + +/** \rst + Initialize the Python interpreter. No other pybind11 or CPython API functions can be + called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The + optional parameter can be used to skip the registration of signal handlers (see the + Python documentation for details). Calling this function again after the interpreter + has already been initialized is a fatal error. + \endrst */ +inline void initialize_interpreter(bool init_signal_handlers = true) { + if (Py_IsInitialized()) + pybind11_fail("The interpreter is already running"); + + Py_InitializeEx(init_signal_handlers ? 1 : 0); + + // Make .py files in the working directory available by default + module::import("sys").attr("path").cast().append("."); +} + +/** \rst + Shut down the Python interpreter. No pybind11 or CPython API functions can be called + after this. In addition, pybind11 objects must not outlive the interpreter: + + .. code-block:: cpp + + { // BAD + py::initialize_interpreter(); + auto hello = py::str("Hello, World!"); + py::finalize_interpreter(); + } // <-- BOOM, hello's destructor is called after interpreter shutdown + + { // GOOD + py::initialize_interpreter(); + { // scoped + auto hello = py::str("Hello, World!"); + } // <-- OK, hello is cleaned up properly + py::finalize_interpreter(); + } + + { // BETTER + py::scoped_interpreter guard{}; + auto hello = py::str("Hello, World!"); + } + + .. warning:: + + The interpreter can be restarted by calling `initialize_interpreter` again. + Modules created using pybind11 can be safely re-initialized. However, Python + itself cannot completely unload binary extension modules and there are several + caveats with regard to interpreter restarting. All the details can be found + in the CPython documentation. In short, not all interpreter memory may be + freed, either due to reference cycles or user-created global data. + + \endrst */ +inline void finalize_interpreter() { + handle builtins(PyEval_GetBuiltins()); + const char *id = PYBIND11_INTERNALS_ID; + + // Get the internals pointer (without creating it if it doesn't exist). It's possible for the + // internals to be created during Py_Finalize() (e.g. if a py::capsule calls `get_internals()` + // during destruction), so we get the pointer-pointer here and check it after Py_Finalize(). + detail::internals **internals_ptr_ptr = detail::get_internals_pp(); + // It could also be stashed in builtins, so look there too: + if (builtins.contains(id) && isinstance(builtins[id])) + internals_ptr_ptr = capsule(builtins[id]); + + Py_Finalize(); + + if (internals_ptr_ptr) { + delete *internals_ptr_ptr; + *internals_ptr_ptr = nullptr; + } +} + +/** \rst + Scope guard version of `initialize_interpreter` and `finalize_interpreter`. + This a move-only guard and only a single instance can exist. + + .. code-block:: cpp + + #include + + int main() { + py::scoped_interpreter guard{}; + py::print(Hello, World!); + } // <-- interpreter shutdown + \endrst */ +class scoped_interpreter { +public: + scoped_interpreter(bool init_signal_handlers = true) { + initialize_interpreter(init_signal_handlers); + } + + scoped_interpreter(const scoped_interpreter &) = delete; + scoped_interpreter(scoped_interpreter &&other) noexcept { other.is_valid = false; } + scoped_interpreter &operator=(const scoped_interpreter &) = delete; + scoped_interpreter &operator=(scoped_interpreter &&) = delete; + + ~scoped_interpreter() { + if (is_valid) + finalize_interpreter(); + } + +private: + bool is_valid = true; +}; + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/eval.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/eval.h new file mode 100644 index 00000000..ea85ba1d --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/eval.h @@ -0,0 +1,117 @@ +/* + pybind11/exec.h: Support for evaluating Python expressions and statements + from strings and files + + Copyright (c) 2016 Klemens Morgenstern and + Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +enum eval_mode { + /// Evaluate a string containing an isolated expression + eval_expr, + + /// Evaluate a string containing a single statement. Returns \c none + eval_single_statement, + + /// Evaluate a string containing a sequence of statement. Returns \c none + eval_statements +}; + +template +object eval(str expr, object global = globals(), object local = object()) { + if (!local) + local = global; + + /* PyRun_String does not accept a PyObject / encoding specifier, + this seems to be the only alternative */ + std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr; + + int start; + switch (mode) { + case eval_expr: start = Py_eval_input; break; + case eval_single_statement: start = Py_single_input; break; + case eval_statements: start = Py_file_input; break; + default: pybind11_fail("invalid evaluation mode"); + } + + PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr()); + if (!result) + throw error_already_set(); + return reinterpret_steal(result); +} + +template +object eval(const char (&s)[N], object global = globals(), object local = object()) { + /* Support raw string literals by removing common leading whitespace */ + auto expr = (s[0] == '\n') ? str(module::import("textwrap").attr("dedent")(s)) + : str(s); + return eval(expr, global, local); +} + +inline void exec(str expr, object global = globals(), object local = object()) { + eval(expr, global, local); +} + +template +void exec(const char (&s)[N], object global = globals(), object local = object()) { + eval(s, global, local); +} + +template +object eval_file(str fname, object global = globals(), object local = object()) { + if (!local) + local = global; + + int start; + switch (mode) { + case eval_expr: start = Py_eval_input; break; + case eval_single_statement: start = Py_single_input; break; + case eval_statements: start = Py_file_input; break; + default: pybind11_fail("invalid evaluation mode"); + } + + int closeFile = 1; + std::string fname_str = (std::string) fname; +#if PY_VERSION_HEX >= 0x03040000 + FILE *f = _Py_fopen_obj(fname.ptr(), "r"); +#elif PY_VERSION_HEX >= 0x03000000 + FILE *f = _Py_fopen(fname.ptr(), "r"); +#else + /* No unicode support in open() :( */ + auto fobj = reinterpret_steal(PyFile_FromString( + const_cast(fname_str.c_str()), + const_cast("r"))); + FILE *f = nullptr; + if (fobj) + f = PyFile_AsFile(fobj.ptr()); + closeFile = 0; +#endif + if (!f) { + PyErr_Clear(); + pybind11_fail("File \"" + fname_str + "\" could not be opened!"); + } + +#if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION) + PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(), + local.ptr()); + (void) closeFile; +#else + PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), + local.ptr(), closeFile); +#endif + + if (!result) + throw error_already_set(); + return reinterpret_steal(result); +} + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/functional.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/functional.h new file mode 100644 index 00000000..eda14ba5 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/functional.h @@ -0,0 +1,85 @@ +/* + pybind11/functional.h: std::function<> support + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +template +struct type_caster> { + using type = std::function; + using retval_type = conditional_t::value, void_type, Return>; + using function_type = Return (*) (Args...); + +public: + bool load(handle src, bool convert) { + if (src.is_none()) { + // Defer accepting None to other overloads (if we aren't in convert mode): + if (!convert) return false; + return true; + } + + if (!isinstance(src)) + return false; + + auto func = reinterpret_borrow(src); + + /* + When passing a C++ function as an argument to another C++ + function via Python, every function call would normally involve + a full C++ -> Python -> C++ roundtrip, which can be prohibitive. + Here, we try to at least detect the case where the function is + stateless (i.e. function pointer or lambda function without + captured variables), in which case the roundtrip can be avoided. + */ + if (auto cfunc = func.cpp_function()) { + auto c = reinterpret_borrow(PyCFunction_GET_SELF(cfunc.ptr())); + auto rec = (function_record *) c; + + if (rec && rec->is_stateless && + same_type(typeid(function_type), *reinterpret_cast(rec->data[1]))) { + struct capture { function_type f; }; + value = ((capture *) &rec->data)->f; + return true; + } + } + + value = [func](Args... args) -> Return { + gil_scoped_acquire acq; + object retval(func(std::forward(args)...)); + /* Visual studio 2015 parser issue: need parentheses around this expression */ + return (retval.template cast()); + }; + return true; + } + + template + static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) { + if (!f_) + return none().inc_ref(); + + auto result = f_.template target(); + if (result) + return cpp_function(*result, policy).release(); + else + return cpp_function(std::forward(f_), policy).release(); + } + + PYBIND11_TYPE_CASTER(type, _("Callable[[") + + argument_loader::arg_names() + _("], ") + + make_caster::name() + + _("]")); +}; + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/iostream.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/iostream.h new file mode 100644 index 00000000..a9c27aac --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/iostream.h @@ -0,0 +1,200 @@ +/* + pybind11/iostream.h -- Tools to assist with redirecting cout and cerr to Python + + Copyright (c) 2017 Henry F. Schreiner + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" + +#include +#include +#include +#include +#include + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +// Buffer that writes to Python instead of C++ +class pythonbuf : public std::streambuf { +private: + using traits_type = std::streambuf::traits_type; + + char d_buffer[1024]; + object pywrite; + object pyflush; + + int overflow(int c) { + if (!traits_type::eq_int_type(c, traits_type::eof())) { + *pptr() = traits_type::to_char_type(c); + pbump(1); + } + return sync() ? traits_type::not_eof(c) : traits_type::eof(); + } + + int sync() { + if (pbase() != pptr()) { + // This subtraction cannot be negative, so dropping the sign + str line(pbase(), static_cast(pptr() - pbase())); + + pywrite(line); + pyflush(); + + setp(pbase(), epptr()); + } + return 0; + } + +public: + pythonbuf(object pyostream) + : pywrite(pyostream.attr("write")), + pyflush(pyostream.attr("flush")) { + setp(d_buffer, d_buffer + sizeof(d_buffer) - 1); + } + + /// Sync before destroy + ~pythonbuf() { + sync(); + } +}; + +NAMESPACE_END(detail) + + +/** \rst + This a move-only guard that redirects output. + + .. code-block:: cpp + + #include + + ... + + { + py::scoped_ostream_redirect output; + std::cout << "Hello, World!"; // Python stdout + } // <-- return std::cout to normal + + You can explicitly pass the c++ stream and the python object, + for example to guard stderr instead. + + .. code-block:: cpp + + { + py::scoped_ostream_redirect output{std::cerr, py::module::import("sys").attr("stderr")}; + std::cerr << "Hello, World!"; + } + \endrst */ +class scoped_ostream_redirect { +protected: + std::streambuf *old; + std::ostream &costream; + detail::pythonbuf buffer; + +public: + scoped_ostream_redirect( + std::ostream &costream = std::cout, + object pyostream = module::import("sys").attr("stdout")) + : costream(costream), buffer(pyostream) { + old = costream.rdbuf(&buffer); + } + + ~scoped_ostream_redirect() { + costream.rdbuf(old); + } + + scoped_ostream_redirect(const scoped_ostream_redirect &) = delete; + scoped_ostream_redirect(scoped_ostream_redirect &&other) = default; + scoped_ostream_redirect &operator=(const scoped_ostream_redirect &) = delete; + scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete; +}; + + +/** \rst + Like `scoped_ostream_redirect`, but redirects cerr by default. This class + is provided primary to make ``py::call_guard`` easier to make. + + .. code-block:: cpp + + m.def("noisy_func", &noisy_func, + py::call_guard()); + +\endrst */ +class scoped_estream_redirect : public scoped_ostream_redirect { +public: + scoped_estream_redirect( + std::ostream &costream = std::cerr, + object pyostream = module::import("sys").attr("stderr")) + : scoped_ostream_redirect(costream,pyostream) {} +}; + + +NAMESPACE_BEGIN(detail) + +// Class to redirect output as a context manager. C++ backend. +class OstreamRedirect { + bool do_stdout_; + bool do_stderr_; + std::unique_ptr redirect_stdout; + std::unique_ptr redirect_stderr; + +public: + OstreamRedirect(bool do_stdout = true, bool do_stderr = true) + : do_stdout_(do_stdout), do_stderr_(do_stderr) {} + + void enter() { + if (do_stdout_) + redirect_stdout.reset(new scoped_ostream_redirect()); + if (do_stderr_) + redirect_stderr.reset(new scoped_estream_redirect()); + } + + void exit() { + redirect_stdout.reset(); + redirect_stderr.reset(); + } +}; + +NAMESPACE_END(detail) + +/** \rst + This is a helper function to add a C++ redirect context manager to Python + instead of using a C++ guard. To use it, add the following to your binding code: + + .. code-block:: cpp + + #include + + ... + + py::add_ostream_redirect(m, "ostream_redirect"); + + You now have a Python context manager that redirects your output: + + .. code-block:: python + + with m.ostream_redirect(): + m.print_to_cout_function() + + This manager can optionally be told which streams to operate on: + + .. code-block:: python + + with m.ostream_redirect(stdout=true, stderr=true): + m.noisy_function_with_error_printing() + + \endrst */ +inline class_ add_ostream_redirect(module m, std::string name = "ostream_redirect") { + return class_(m, name.c_str(), module_local()) + .def(init(), arg("stdout")=true, arg("stderr")=true) + .def("__enter__", &detail::OstreamRedirect::enter) + .def("__exit__", [](detail::OstreamRedirect &self, args) { self.exit(); }); +} + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/numpy.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/numpy.h new file mode 100644 index 00000000..b1600dc2 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/numpy.h @@ -0,0 +1,1600 @@ +/* + pybind11/numpy.h: Basic NumPy support, vectorize() wrapper + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include "complex.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +#endif + +/* This will be true on all flat address space platforms and allows us to reduce the + whole npy_intp / ssize_t / Py_intptr_t business down to just ssize_t for all size + and dimension types (e.g. shape, strides, indexing), instead of inflicting this + upon the library user. */ +static_assert(sizeof(ssize_t) == sizeof(Py_intptr_t), "ssize_t != Py_intptr_t"); + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +class array; // Forward declaration + +NAMESPACE_BEGIN(detail) +template struct npy_format_descriptor; + +struct PyArrayDescr_Proxy { + PyObject_HEAD + PyObject *typeobj; + char kind; + char type; + char byteorder; + char flags; + int type_num; + int elsize; + int alignment; + char *subarray; + PyObject *fields; + PyObject *names; +}; + +struct PyArray_Proxy { + PyObject_HEAD + char *data; + int nd; + ssize_t *dimensions; + ssize_t *strides; + PyObject *base; + PyObject *descr; + int flags; +}; + +struct PyVoidScalarObject_Proxy { + PyObject_VAR_HEAD + char *obval; + PyArrayDescr_Proxy *descr; + int flags; + PyObject *base; +}; + +struct numpy_type_info { + PyObject* dtype_ptr; + std::string format_str; +}; + +struct numpy_internals { + std::unordered_map registered_dtypes; + + numpy_type_info *get_type_info(const std::type_info& tinfo, bool throw_if_missing = true) { + auto it = registered_dtypes.find(std::type_index(tinfo)); + if (it != registered_dtypes.end()) + return &(it->second); + if (throw_if_missing) + pybind11_fail(std::string("NumPy type info missing for ") + tinfo.name()); + return nullptr; + } + + template numpy_type_info *get_type_info(bool throw_if_missing = true) { + return get_type_info(typeid(typename std::remove_cv::type), throw_if_missing); + } +}; + +inline PYBIND11_NOINLINE void load_numpy_internals(numpy_internals* &ptr) { + ptr = &get_or_create_shared_data("_numpy_internals"); +} + +inline numpy_internals& get_numpy_internals() { + static numpy_internals* ptr = nullptr; + if (!ptr) + load_numpy_internals(ptr); + return *ptr; +} + +struct npy_api { + enum constants { + NPY_ARRAY_C_CONTIGUOUS_ = 0x0001, + NPY_ARRAY_F_CONTIGUOUS_ = 0x0002, + NPY_ARRAY_OWNDATA_ = 0x0004, + NPY_ARRAY_FORCECAST_ = 0x0010, + NPY_ARRAY_ENSUREARRAY_ = 0x0040, + NPY_ARRAY_ALIGNED_ = 0x0100, + NPY_ARRAY_WRITEABLE_ = 0x0400, + NPY_BOOL_ = 0, + NPY_BYTE_, NPY_UBYTE_, + NPY_SHORT_, NPY_USHORT_, + NPY_INT_, NPY_UINT_, + NPY_LONG_, NPY_ULONG_, + NPY_LONGLONG_, NPY_ULONGLONG_, + NPY_FLOAT_, NPY_DOUBLE_, NPY_LONGDOUBLE_, + NPY_CFLOAT_, NPY_CDOUBLE_, NPY_CLONGDOUBLE_, + NPY_OBJECT_ = 17, + NPY_STRING_, NPY_UNICODE_, NPY_VOID_ + }; + + typedef struct { + Py_intptr_t *ptr; + int len; + } PyArray_Dims; + + static npy_api& get() { + static npy_api api = lookup(); + return api; + } + + bool PyArray_Check_(PyObject *obj) const { + return (bool) PyObject_TypeCheck(obj, PyArray_Type_); + } + bool PyArrayDescr_Check_(PyObject *obj) const { + return (bool) PyObject_TypeCheck(obj, PyArrayDescr_Type_); + } + + unsigned int (*PyArray_GetNDArrayCFeatureVersion_)(); + PyObject *(*PyArray_DescrFromType_)(int); + PyObject *(*PyArray_NewFromDescr_) + (PyTypeObject *, PyObject *, int, Py_intptr_t *, + Py_intptr_t *, void *, int, PyObject *); + PyObject *(*PyArray_DescrNewFromType_)(int); + int (*PyArray_CopyInto_)(PyObject *, PyObject *); + PyObject *(*PyArray_NewCopy_)(PyObject *, int); + PyTypeObject *PyArray_Type_; + PyTypeObject *PyVoidArrType_Type_; + PyTypeObject *PyArrayDescr_Type_; + PyObject *(*PyArray_DescrFromScalar_)(PyObject *); + PyObject *(*PyArray_FromAny_) (PyObject *, PyObject *, int, int, int, PyObject *); + int (*PyArray_DescrConverter_) (PyObject *, PyObject **); + bool (*PyArray_EquivTypes_) (PyObject *, PyObject *); + int (*PyArray_GetArrayParamsFromObject_)(PyObject *, PyObject *, char, PyObject **, int *, + Py_ssize_t *, PyObject **, PyObject *); + PyObject *(*PyArray_Squeeze_)(PyObject *); + int (*PyArray_SetBaseObject_)(PyObject *, PyObject *); + PyObject* (*PyArray_Resize_)(PyObject*, PyArray_Dims*, int, int); +private: + enum functions { + API_PyArray_GetNDArrayCFeatureVersion = 211, + API_PyArray_Type = 2, + API_PyArrayDescr_Type = 3, + API_PyVoidArrType_Type = 39, + API_PyArray_DescrFromType = 45, + API_PyArray_DescrFromScalar = 57, + API_PyArray_FromAny = 69, + API_PyArray_Resize = 80, + API_PyArray_CopyInto = 82, + API_PyArray_NewCopy = 85, + API_PyArray_NewFromDescr = 94, + API_PyArray_DescrNewFromType = 9, + API_PyArray_DescrConverter = 174, + API_PyArray_EquivTypes = 182, + API_PyArray_GetArrayParamsFromObject = 278, + API_PyArray_Squeeze = 136, + API_PyArray_SetBaseObject = 282 + }; + + static npy_api lookup() { + module m = module::import("numpy.core.multiarray"); + auto c = m.attr("_ARRAY_API"); +#if PY_MAJOR_VERSION >= 3 + void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), NULL); +#else + void **api_ptr = (void **) PyCObject_AsVoidPtr(c.ptr()); +#endif + npy_api api; +#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func]; + DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion); + if (api.PyArray_GetNDArrayCFeatureVersion_() < 0x7) + pybind11_fail("pybind11 numpy support requires numpy >= 1.7.0"); + DECL_NPY_API(PyArray_Type); + DECL_NPY_API(PyVoidArrType_Type); + DECL_NPY_API(PyArrayDescr_Type); + DECL_NPY_API(PyArray_DescrFromType); + DECL_NPY_API(PyArray_DescrFromScalar); + DECL_NPY_API(PyArray_FromAny); + DECL_NPY_API(PyArray_Resize); + DECL_NPY_API(PyArray_CopyInto); + DECL_NPY_API(PyArray_NewCopy); + DECL_NPY_API(PyArray_NewFromDescr); + DECL_NPY_API(PyArray_DescrNewFromType); + DECL_NPY_API(PyArray_DescrConverter); + DECL_NPY_API(PyArray_EquivTypes); + DECL_NPY_API(PyArray_GetArrayParamsFromObject); + DECL_NPY_API(PyArray_Squeeze); + DECL_NPY_API(PyArray_SetBaseObject); +#undef DECL_NPY_API + return api; + } +}; + +inline PyArray_Proxy* array_proxy(void* ptr) { + return reinterpret_cast(ptr); +} + +inline const PyArray_Proxy* array_proxy(const void* ptr) { + return reinterpret_cast(ptr); +} + +inline PyArrayDescr_Proxy* array_descriptor_proxy(PyObject* ptr) { + return reinterpret_cast(ptr); +} + +inline const PyArrayDescr_Proxy* array_descriptor_proxy(const PyObject* ptr) { + return reinterpret_cast(ptr); +} + +inline bool check_flags(const void* ptr, int flag) { + return (flag == (array_proxy(ptr)->flags & flag)); +} + +template struct is_std_array : std::false_type { }; +template struct is_std_array> : std::true_type { }; +template struct is_complex : std::false_type { }; +template struct is_complex> : std::true_type { }; + +template struct array_info_scalar { + typedef T type; + static constexpr bool is_array = false; + static constexpr bool is_empty = false; + static PYBIND11_DESCR extents() { return _(""); } + static void append_extents(list& /* shape */) { } +}; +// Computes underlying type and a comma-separated list of extents for array +// types (any mix of std::array and built-in arrays). An array of char is +// treated as scalar because it gets special handling. +template struct array_info : array_info_scalar { }; +template struct array_info> { + using type = typename array_info::type; + static constexpr bool is_array = true; + static constexpr bool is_empty = (N == 0) || array_info::is_empty; + static constexpr size_t extent = N; + + // appends the extents to shape + static void append_extents(list& shape) { + shape.append(N); + array_info::append_extents(shape); + } + + template::is_array, int> = 0> + static PYBIND11_DESCR extents() { + return _(); + } + + template::is_array, int> = 0> + static PYBIND11_DESCR extents() { + return concat(_(), array_info::extents()); + } +}; +// For numpy we have special handling for arrays of characters, so we don't include +// the size in the array extents. +template struct array_info : array_info_scalar { }; +template struct array_info> : array_info_scalar> { }; +template struct array_info : array_info> { }; +template using remove_all_extents_t = typename array_info::type; + +template using is_pod_struct = all_of< + std::is_standard_layout, // since we're accessing directly in memory we need a standard layout type +#if !defined(__GNUG__) || defined(_LIBCPP_VERSION) || defined(_GLIBCXX_USE_CXX11_ABI) + // _GLIBCXX_USE_CXX11_ABI indicates that we're using libstdc++ from GCC 5 or newer, independent + // of the actual compiler (Clang can also use libstdc++, but it always defines __GNUC__ == 4). + std::is_trivially_copyable, +#else + // GCC 4 doesn't implement is_trivially_copyable, so approximate it + std::is_trivially_destructible, + satisfies_any_of, +#endif + satisfies_none_of +>; + +template ssize_t byte_offset_unsafe(const Strides &) { return 0; } +template +ssize_t byte_offset_unsafe(const Strides &strides, ssize_t i, Ix... index) { + return i * strides[Dim] + byte_offset_unsafe(strides, index...); +} + +/** + * Proxy class providing unsafe, unchecked const access to array data. This is constructed through + * the `unchecked()` method of `array` or the `unchecked()` method of `array_t`. `Dims` + * will be -1 for dimensions determined at runtime. + */ +template +class unchecked_reference { +protected: + static constexpr bool Dynamic = Dims < 0; + const unsigned char *data_; + // Storing the shape & strides in local variables (i.e. these arrays) allows the compiler to + // make large performance gains on big, nested loops, but requires compile-time dimensions + conditional_t> + shape_, strides_; + const ssize_t dims_; + + friend class pybind11::array; + // Constructor for compile-time dimensions: + template + unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t) + : data_{reinterpret_cast(data)}, dims_{Dims} { + for (size_t i = 0; i < (size_t) dims_; i++) { + shape_[i] = shape[i]; + strides_[i] = strides[i]; + } + } + // Constructor for runtime dimensions: + template + unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t dims) + : data_{reinterpret_cast(data)}, shape_{shape}, strides_{strides}, dims_{dims} {} + +public: + /** + * Unchecked const reference access to data at the given indices. For a compile-time known + * number of dimensions, this requires the correct number of arguments; for run-time + * dimensionality, this is not checked (and so is up to the caller to use safely). + */ + template const T &operator()(Ix... index) const { + static_assert(ssize_t{sizeof...(Ix)} == Dims || Dynamic, + "Invalid number of indices for unchecked array reference"); + return *reinterpret_cast(data_ + byte_offset_unsafe(strides_, ssize_t(index)...)); + } + /** + * Unchecked const reference access to data; this operator only participates if the reference + * is to a 1-dimensional array. When present, this is exactly equivalent to `obj(index)`. + */ + template > + const T &operator[](ssize_t index) const { return operator()(index); } + + /// Pointer access to the data at the given indices. + template const T *data(Ix... ix) const { return &operator()(ssize_t(ix)...); } + + /// Returns the item size, i.e. sizeof(T) + constexpr static ssize_t itemsize() { return sizeof(T); } + + /// Returns the shape (i.e. size) of dimension `dim` + ssize_t shape(ssize_t dim) const { return shape_[(size_t) dim]; } + + /// Returns the number of dimensions of the array + ssize_t ndim() const { return dims_; } + + /// Returns the total number of elements in the referenced array, i.e. the product of the shapes + template + enable_if_t size() const { + return std::accumulate(shape_.begin(), shape_.end(), (ssize_t) 1, std::multiplies()); + } + template + enable_if_t size() const { + return std::accumulate(shape_, shape_ + ndim(), (ssize_t) 1, std::multiplies()); + } + + /// Returns the total number of bytes used by the referenced data. Note that the actual span in + /// memory may be larger if the referenced array has non-contiguous strides (e.g. for a slice). + ssize_t nbytes() const { + return size() * itemsize(); + } +}; + +template +class unchecked_mutable_reference : public unchecked_reference { + friend class pybind11::array; + using ConstBase = unchecked_reference; + using ConstBase::ConstBase; + using ConstBase::Dynamic; +public: + /// Mutable, unchecked access to data at the given indices. + template T& operator()(Ix... index) { + static_assert(ssize_t{sizeof...(Ix)} == Dims || Dynamic, + "Invalid number of indices for unchecked array reference"); + return const_cast(ConstBase::operator()(index...)); + } + /** + * Mutable, unchecked access data at the given index; this operator only participates if the + * reference is to a 1-dimensional array (or has runtime dimensions). When present, this is + * exactly equivalent to `obj(index)`. + */ + template > + T &operator[](ssize_t index) { return operator()(index); } + + /// Mutable pointer access to the data at the given indices. + template T *mutable_data(Ix... ix) { return &operator()(ssize_t(ix)...); } +}; + +template +struct type_caster> { + static_assert(Dim == 0 && Dim > 0 /* always fail */, "unchecked array proxy object is not castable"); +}; +template +struct type_caster> : type_caster> {}; + +NAMESPACE_END(detail) + +class dtype : public object { +public: + PYBIND11_OBJECT_DEFAULT(dtype, object, detail::npy_api::get().PyArrayDescr_Check_); + + explicit dtype(const buffer_info &info) { + dtype descr(_dtype_from_pep3118()(PYBIND11_STR_TYPE(info.format))); + // If info.itemsize == 0, use the value calculated from the format string + m_ptr = descr.strip_padding(info.itemsize ? info.itemsize : descr.itemsize()).release().ptr(); + } + + explicit dtype(const std::string &format) { + m_ptr = from_args(pybind11::str(format)).release().ptr(); + } + + dtype(const char *format) : dtype(std::string(format)) { } + + dtype(list names, list formats, list offsets, ssize_t itemsize) { + dict args; + args["names"] = names; + args["formats"] = formats; + args["offsets"] = offsets; + args["itemsize"] = pybind11::int_(itemsize); + m_ptr = from_args(args).release().ptr(); + } + + /// This is essentially the same as calling numpy.dtype(args) in Python. + static dtype from_args(object args) { + PyObject *ptr = nullptr; + if (!detail::npy_api::get().PyArray_DescrConverter_(args.release().ptr(), &ptr) || !ptr) + throw error_already_set(); + return reinterpret_steal(ptr); + } + + /// Return dtype associated with a C++ type. + template static dtype of() { + return detail::npy_format_descriptor::type>::dtype(); + } + + /// Size of the data type in bytes. + ssize_t itemsize() const { + return detail::array_descriptor_proxy(m_ptr)->elsize; + } + + /// Returns true for structured data types. + bool has_fields() const { + return detail::array_descriptor_proxy(m_ptr)->names != nullptr; + } + + /// Single-character type code. + char kind() const { + return detail::array_descriptor_proxy(m_ptr)->kind; + } + +private: + static object _dtype_from_pep3118() { + static PyObject *obj = module::import("numpy.core._internal") + .attr("_dtype_from_pep3118").cast().release().ptr(); + return reinterpret_borrow(obj); + } + + dtype strip_padding(ssize_t itemsize) { + // Recursively strip all void fields with empty names that are generated for + // padding fields (as of NumPy v1.11). + if (!has_fields()) + return *this; + + struct field_descr { PYBIND11_STR_TYPE name; object format; pybind11::int_ offset; }; + std::vector field_descriptors; + + for (auto field : attr("fields").attr("items")()) { + auto spec = field.cast(); + auto name = spec[0].cast(); + auto format = spec[1].cast()[0].cast(); + auto offset = spec[1].cast()[1].cast(); + if (!len(name) && format.kind() == 'V') + continue; + field_descriptors.push_back({(PYBIND11_STR_TYPE) name, format.strip_padding(format.itemsize()), offset}); + } + + std::sort(field_descriptors.begin(), field_descriptors.end(), + [](const field_descr& a, const field_descr& b) { + return a.offset.cast() < b.offset.cast(); + }); + + list names, formats, offsets; + for (auto& descr : field_descriptors) { + names.append(descr.name); + formats.append(descr.format); + offsets.append(descr.offset); + } + return dtype(names, formats, offsets, itemsize); + } +}; + +class array : public buffer { +public: + PYBIND11_OBJECT_CVT(array, buffer, detail::npy_api::get().PyArray_Check_, raw_array) + + enum { + c_style = detail::npy_api::NPY_ARRAY_C_CONTIGUOUS_, + f_style = detail::npy_api::NPY_ARRAY_F_CONTIGUOUS_, + forcecast = detail::npy_api::NPY_ARRAY_FORCECAST_ + }; + + array() : array({{0}}, static_cast(nullptr)) {} + + using ShapeContainer = detail::any_container; + using StridesContainer = detail::any_container; + + // Constructs an array taking shape/strides from arbitrary container types + array(const pybind11::dtype &dt, ShapeContainer shape, StridesContainer strides, + const void *ptr = nullptr, handle base = handle()) { + + if (strides->empty()) + *strides = c_strides(*shape, dt.itemsize()); + + auto ndim = shape->size(); + if (ndim != strides->size()) + pybind11_fail("NumPy: shape ndim doesn't match strides ndim"); + auto descr = dt; + + int flags = 0; + if (base && ptr) { + if (isinstance(base)) + /* Copy flags from base (except ownership bit) */ + flags = reinterpret_borrow(base).flags() & ~detail::npy_api::NPY_ARRAY_OWNDATA_; + else + /* Writable by default, easy to downgrade later on if needed */ + flags = detail::npy_api::NPY_ARRAY_WRITEABLE_; + } + + auto &api = detail::npy_api::get(); + auto tmp = reinterpret_steal(api.PyArray_NewFromDescr_( + api.PyArray_Type_, descr.release().ptr(), (int) ndim, shape->data(), strides->data(), + const_cast(ptr), flags, nullptr)); + if (!tmp) + throw error_already_set(); + if (ptr) { + if (base) { + api.PyArray_SetBaseObject_(tmp.ptr(), base.inc_ref().ptr()); + } else { + tmp = reinterpret_steal(api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */)); + } + } + m_ptr = tmp.release().ptr(); + } + + array(const pybind11::dtype &dt, ShapeContainer shape, const void *ptr = nullptr, handle base = handle()) + : array(dt, std::move(shape), {}, ptr, base) { } + + template ::value && !std::is_same::value>> + array(const pybind11::dtype &dt, T count, const void *ptr = nullptr, handle base = handle()) + : array(dt, {{count}}, ptr, base) { } + + template + array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle()) + : array(pybind11::dtype::of(), std::move(shape), std::move(strides), ptr, base) { } + + template + array(ShapeContainer shape, const T *ptr, handle base = handle()) + : array(std::move(shape), {}, ptr, base) { } + + template + explicit array(ssize_t count, const T *ptr, handle base = handle()) : array({count}, {}, ptr, base) { } + + explicit array(const buffer_info &info) + : array(pybind11::dtype(info), info.shape, info.strides, info.ptr) { } + + /// Array descriptor (dtype) + pybind11::dtype dtype() const { + return reinterpret_borrow(detail::array_proxy(m_ptr)->descr); + } + + /// Total number of elements + ssize_t size() const { + return std::accumulate(shape(), shape() + ndim(), (ssize_t) 1, std::multiplies()); + } + + /// Byte size of a single element + ssize_t itemsize() const { + return detail::array_descriptor_proxy(detail::array_proxy(m_ptr)->descr)->elsize; + } + + /// Total number of bytes + ssize_t nbytes() const { + return size() * itemsize(); + } + + /// Number of dimensions + ssize_t ndim() const { + return detail::array_proxy(m_ptr)->nd; + } + + /// Base object + object base() const { + return reinterpret_borrow(detail::array_proxy(m_ptr)->base); + } + + /// Dimensions of the array + const ssize_t* shape() const { + return detail::array_proxy(m_ptr)->dimensions; + } + + /// Dimension along a given axis + ssize_t shape(ssize_t dim) const { + if (dim >= ndim()) + fail_dim_check(dim, "invalid axis"); + return shape()[dim]; + } + + /// Strides of the array + const ssize_t* strides() const { + return detail::array_proxy(m_ptr)->strides; + } + + /// Stride along a given axis + ssize_t strides(ssize_t dim) const { + if (dim >= ndim()) + fail_dim_check(dim, "invalid axis"); + return strides()[dim]; + } + + /// Return the NumPy array flags + int flags() const { + return detail::array_proxy(m_ptr)->flags; + } + + /// If set, the array is writeable (otherwise the buffer is read-only) + bool writeable() const { + return detail::check_flags(m_ptr, detail::npy_api::NPY_ARRAY_WRITEABLE_); + } + + /// If set, the array owns the data (will be freed when the array is deleted) + bool owndata() const { + return detail::check_flags(m_ptr, detail::npy_api::NPY_ARRAY_OWNDATA_); + } + + /// Pointer to the contained data. If index is not provided, points to the + /// beginning of the buffer. May throw if the index would lead to out of bounds access. + template const void* data(Ix... index) const { + return static_cast(detail::array_proxy(m_ptr)->data + offset_at(index...)); + } + + /// Mutable pointer to the contained data. If index is not provided, points to the + /// beginning of the buffer. May throw if the index would lead to out of bounds access. + /// May throw if the array is not writeable. + template void* mutable_data(Ix... index) { + check_writeable(); + return static_cast(detail::array_proxy(m_ptr)->data + offset_at(index...)); + } + + /// Byte offset from beginning of the array to a given index (full or partial). + /// May throw if the index would lead to out of bounds access. + template ssize_t offset_at(Ix... index) const { + if ((ssize_t) sizeof...(index) > ndim()) + fail_dim_check(sizeof...(index), "too many indices for an array"); + return byte_offset(ssize_t(index)...); + } + + ssize_t offset_at() const { return 0; } + + /// Item count from beginning of the array to a given index (full or partial). + /// May throw if the index would lead to out of bounds access. + template ssize_t index_at(Ix... index) const { + return offset_at(index...) / itemsize(); + } + + /** + * Returns a proxy object that provides access to the array's data without bounds or + * dimensionality checking. Will throw if the array is missing the `writeable` flag. Use with + * care: the array must not be destroyed or reshaped for the duration of the returned object, + * and the caller must take care not to access invalid dimensions or dimension indices. + */ + template detail::unchecked_mutable_reference mutable_unchecked() & { + if (Dims >= 0 && ndim() != Dims) + throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) + + "; expected " + std::to_string(Dims)); + return detail::unchecked_mutable_reference(mutable_data(), shape(), strides(), ndim()); + } + + /** + * Returns a proxy object that provides const access to the array's data without bounds or + * dimensionality checking. Unlike `mutable_unchecked()`, this does not require that the + * underlying array have the `writable` flag. Use with care: the array must not be destroyed or + * reshaped for the duration of the returned object, and the caller must take care not to access + * invalid dimensions or dimension indices. + */ + template detail::unchecked_reference unchecked() const & { + if (Dims >= 0 && ndim() != Dims) + throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) + + "; expected " + std::to_string(Dims)); + return detail::unchecked_reference(data(), shape(), strides(), ndim()); + } + + /// Return a new view with all of the dimensions of length 1 removed + array squeeze() { + auto& api = detail::npy_api::get(); + return reinterpret_steal(api.PyArray_Squeeze_(m_ptr)); + } + + /// Resize array to given shape + /// If refcheck is true and more that one reference exist to this array + /// then resize will succeed only if it makes a reshape, i.e. original size doesn't change + void resize(ShapeContainer new_shape, bool refcheck = true) { + detail::npy_api::PyArray_Dims d = { + new_shape->data(), int(new_shape->size()) + }; + // try to resize, set ordering param to -1 cause it's not used anyway + object new_array = reinterpret_steal( + detail::npy_api::get().PyArray_Resize_(m_ptr, &d, int(refcheck), -1) + ); + if (!new_array) throw error_already_set(); + if (isinstance(new_array)) { *this = std::move(new_array); } + } + + /// Ensure that the argument is a NumPy array + /// In case of an error, nullptr is returned and the Python error is cleared. + static array ensure(handle h, int ExtraFlags = 0) { + auto result = reinterpret_steal(raw_array(h.ptr(), ExtraFlags)); + if (!result) + PyErr_Clear(); + return result; + } + +protected: + template friend struct detail::npy_format_descriptor; + + void fail_dim_check(ssize_t dim, const std::string& msg) const { + throw index_error(msg + ": " + std::to_string(dim) + + " (ndim = " + std::to_string(ndim()) + ")"); + } + + template ssize_t byte_offset(Ix... index) const { + check_dimensions(index...); + return detail::byte_offset_unsafe(strides(), ssize_t(index)...); + } + + void check_writeable() const { + if (!writeable()) + throw std::domain_error("array is not writeable"); + } + + // Default, C-style strides + static std::vector c_strides(const std::vector &shape, ssize_t itemsize) { + auto ndim = shape.size(); + std::vector strides(ndim, itemsize); + for (size_t i = ndim - 1; i > 0; --i) + strides[i - 1] = strides[i] * shape[i]; + return strides; + } + + // F-style strides; default when constructing an array_t with `ExtraFlags & f_style` + static std::vector f_strides(const std::vector &shape, ssize_t itemsize) { + auto ndim = shape.size(); + std::vector strides(ndim, itemsize); + for (size_t i = 1; i < ndim; ++i) + strides[i] = strides[i - 1] * shape[i - 1]; + return strides; + } + + template void check_dimensions(Ix... index) const { + check_dimensions_impl(ssize_t(0), shape(), ssize_t(index)...); + } + + void check_dimensions_impl(ssize_t, const ssize_t*) const { } + + template void check_dimensions_impl(ssize_t axis, const ssize_t* shape, ssize_t i, Ix... index) const { + if (i >= *shape) { + throw index_error(std::string("index ") + std::to_string(i) + + " is out of bounds for axis " + std::to_string(axis) + + " with size " + std::to_string(*shape)); + } + check_dimensions_impl(axis + 1, shape + 1, index...); + } + + /// Create array from any object -- always returns a new reference + static PyObject *raw_array(PyObject *ptr, int ExtraFlags = 0) { + if (ptr == nullptr) { + PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array from a nullptr"); + return nullptr; + } + return detail::npy_api::get().PyArray_FromAny_( + ptr, nullptr, 0, 0, detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr); + } +}; + +template class array_t : public array { +private: + struct private_ctor {}; + // Delegating constructor needed when both moving and accessing in the same constructor + array_t(private_ctor, ShapeContainer &&shape, StridesContainer &&strides, const T *ptr, handle base) + : array(std::move(shape), std::move(strides), ptr, base) {} +public: + static_assert(!detail::array_info::is_array, "Array types cannot be used with array_t"); + + using value_type = T; + + array_t() : array(0, static_cast(nullptr)) {} + array_t(handle h, borrowed_t) : array(h, borrowed_t{}) { } + array_t(handle h, stolen_t) : array(h, stolen_t{}) { } + + PYBIND11_DEPRECATED("Use array_t::ensure() instead") + array_t(handle h, bool is_borrowed) : array(raw_array_t(h.ptr()), stolen_t{}) { + if (!m_ptr) PyErr_Clear(); + if (!is_borrowed) Py_XDECREF(h.ptr()); + } + + array_t(const object &o) : array(raw_array_t(o.ptr()), stolen_t{}) { + if (!m_ptr) throw error_already_set(); + } + + explicit array_t(const buffer_info& info) : array(info) { } + + array_t(ShapeContainer shape, StridesContainer strides, const T *ptr = nullptr, handle base = handle()) + : array(std::move(shape), std::move(strides), ptr, base) { } + + explicit array_t(ShapeContainer shape, const T *ptr = nullptr, handle base = handle()) + : array_t(private_ctor{}, std::move(shape), + ExtraFlags & f_style ? f_strides(*shape, itemsize()) : c_strides(*shape, itemsize()), + ptr, base) { } + + explicit array_t(size_t count, const T *ptr = nullptr, handle base = handle()) + : array({count}, {}, ptr, base) { } + + constexpr ssize_t itemsize() const { + return sizeof(T); + } + + template ssize_t index_at(Ix... index) const { + return offset_at(index...) / itemsize(); + } + + template const T* data(Ix... index) const { + return static_cast(array::data(index...)); + } + + template T* mutable_data(Ix... index) { + return static_cast(array::mutable_data(index...)); + } + + // Reference to element at a given index + template const T& at(Ix... index) const { + if (sizeof...(index) != ndim()) + fail_dim_check(sizeof...(index), "index dimension mismatch"); + return *(static_cast(array::data()) + byte_offset(ssize_t(index)...) / itemsize()); + } + + // Mutable reference to element at a given index + template T& mutable_at(Ix... index) { + if (sizeof...(index) != ndim()) + fail_dim_check(sizeof...(index), "index dimension mismatch"); + return *(static_cast(array::mutable_data()) + byte_offset(ssize_t(index)...) / itemsize()); + } + + /** + * Returns a proxy object that provides access to the array's data without bounds or + * dimensionality checking. Will throw if the array is missing the `writeable` flag. Use with + * care: the array must not be destroyed or reshaped for the duration of the returned object, + * and the caller must take care not to access invalid dimensions or dimension indices. + */ + template detail::unchecked_mutable_reference mutable_unchecked() & { + return array::mutable_unchecked(); + } + + /** + * Returns a proxy object that provides const access to the array's data without bounds or + * dimensionality checking. Unlike `unchecked()`, this does not require that the underlying + * array have the `writable` flag. Use with care: the array must not be destroyed or reshaped + * for the duration of the returned object, and the caller must take care not to access invalid + * dimensions or dimension indices. + */ + template detail::unchecked_reference unchecked() const & { + return array::unchecked(); + } + + /// Ensure that the argument is a NumPy array of the correct dtype (and if not, try to convert + /// it). In case of an error, nullptr is returned and the Python error is cleared. + static array_t ensure(handle h) { + auto result = reinterpret_steal(raw_array_t(h.ptr())); + if (!result) + PyErr_Clear(); + return result; + } + + static bool check_(handle h) { + const auto &api = detail::npy_api::get(); + return api.PyArray_Check_(h.ptr()) + && api.PyArray_EquivTypes_(detail::array_proxy(h.ptr())->descr, dtype::of().ptr()); + } + +protected: + /// Create array from any object -- always returns a new reference + static PyObject *raw_array_t(PyObject *ptr) { + if (ptr == nullptr) { + PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array_t from a nullptr"); + return nullptr; + } + return detail::npy_api::get().PyArray_FromAny_( + ptr, dtype::of().release().ptr(), 0, 0, + detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr); + } +}; + +template +struct format_descriptor::value>> { + static std::string format() { + return detail::npy_format_descriptor::type>::format(); + } +}; + +template struct format_descriptor { + static std::string format() { return std::to_string(N) + "s"; } +}; +template struct format_descriptor> { + static std::string format() { return std::to_string(N) + "s"; } +}; + +template +struct format_descriptor::value>> { + static std::string format() { + return format_descriptor< + typename std::remove_cv::type>::type>::format(); + } +}; + +template +struct format_descriptor::is_array>> { + static std::string format() { + using namespace detail; + PYBIND11_DESCR extents = _("(") + array_info::extents() + _(")"); + return extents.text() + format_descriptor>::format(); + } +}; + +NAMESPACE_BEGIN(detail) +template +struct pyobject_caster> { + using type = array_t; + + bool load(handle src, bool convert) { + if (!convert && !type::check_(src)) + return false; + value = type::ensure(src); + return static_cast(value); + } + + static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) { + return src.inc_ref(); + } + PYBIND11_TYPE_CASTER(type, handle_type_name::name()); +}; + +template +struct compare_buffer_info::value>> { + static bool compare(const buffer_info& b) { + return npy_api::get().PyArray_EquivTypes_(dtype::of().ptr(), dtype(b).ptr()); + } +}; + +template struct npy_format_descriptor::value>> { +private: + // NB: the order here must match the one in common.h + constexpr static const int values[15] = { + npy_api::NPY_BOOL_, + npy_api::NPY_BYTE_, npy_api::NPY_UBYTE_, npy_api::NPY_SHORT_, npy_api::NPY_USHORT_, + npy_api::NPY_INT_, npy_api::NPY_UINT_, npy_api::NPY_LONGLONG_, npy_api::NPY_ULONGLONG_, + npy_api::NPY_FLOAT_, npy_api::NPY_DOUBLE_, npy_api::NPY_LONGDOUBLE_, + npy_api::NPY_CFLOAT_, npy_api::NPY_CDOUBLE_, npy_api::NPY_CLONGDOUBLE_ + }; + +public: + static constexpr int value = values[detail::is_fmt_numeric::index]; + + static pybind11::dtype dtype() { + if (auto ptr = npy_api::get().PyArray_DescrFromType_(value)) + return reinterpret_borrow(ptr); + pybind11_fail("Unsupported buffer format!"); + } + template ::value, int> = 0> + static PYBIND11_DESCR name() { + return _::value>(_("bool"), + _::value>("int", "uint") + _()); + } + template ::value, int> = 0> + static PYBIND11_DESCR name() { + return _::value || std::is_same::value>( + _("float") + _(), _("longdouble")); + } + template ::value, int> = 0> + static PYBIND11_DESCR name() { + return _::value || std::is_same::value>( + _("complex") + _(), _("longcomplex")); + } +}; + +#define PYBIND11_DECL_CHAR_FMT \ + static PYBIND11_DESCR name() { return _("S") + _(); } \ + static pybind11::dtype dtype() { return pybind11::dtype(std::string("S") + std::to_string(N)); } +template struct npy_format_descriptor { PYBIND11_DECL_CHAR_FMT }; +template struct npy_format_descriptor> { PYBIND11_DECL_CHAR_FMT }; +#undef PYBIND11_DECL_CHAR_FMT + +template struct npy_format_descriptor::is_array>> { +private: + using base_descr = npy_format_descriptor::type>; +public: + static_assert(!array_info::is_empty, "Zero-sized arrays are not supported"); + + static PYBIND11_DESCR name() { return _("(") + array_info::extents() + _(")") + base_descr::name(); } + static pybind11::dtype dtype() { + list shape; + array_info::append_extents(shape); + return pybind11::dtype::from_args(pybind11::make_tuple(base_descr::dtype(), shape)); + } +}; + +template struct npy_format_descriptor::value>> { +private: + using base_descr = npy_format_descriptor::type>; +public: + static PYBIND11_DESCR name() { return base_descr::name(); } + static pybind11::dtype dtype() { return base_descr::dtype(); } +}; + +struct field_descriptor { + const char *name; + ssize_t offset; + ssize_t size; + std::string format; + dtype descr; +}; + +inline PYBIND11_NOINLINE void register_structured_dtype( + const std::initializer_list& fields, + const std::type_info& tinfo, ssize_t itemsize, + bool (*direct_converter)(PyObject *, void *&)) { + + auto& numpy_internals = get_numpy_internals(); + if (numpy_internals.get_type_info(tinfo, false)) + pybind11_fail("NumPy: dtype is already registered"); + + list names, formats, offsets; + for (auto field : fields) { + if (!field.descr) + pybind11_fail(std::string("NumPy: unsupported field dtype: `") + + field.name + "` @ " + tinfo.name()); + names.append(PYBIND11_STR_TYPE(field.name)); + formats.append(field.descr); + offsets.append(pybind11::int_(field.offset)); + } + auto dtype_ptr = pybind11::dtype(names, formats, offsets, itemsize).release().ptr(); + + // There is an existing bug in NumPy (as of v1.11): trailing bytes are + // not encoded explicitly into the format string. This will supposedly + // get fixed in v1.12; for further details, see these: + // - https://github.com/numpy/numpy/issues/7797 + // - https://github.com/numpy/numpy/pull/7798 + // Because of this, we won't use numpy's logic to generate buffer format + // strings and will just do it ourselves. + std::vector ordered_fields(fields); + std::sort(ordered_fields.begin(), ordered_fields.end(), + [](const field_descriptor &a, const field_descriptor &b) { return a.offset < b.offset; }); + ssize_t offset = 0; + std::ostringstream oss; + // mark the structure as unaligned with '^', because numpy and C++ don't + // always agree about alignment (particularly for complex), and we're + // explicitly listing all our padding. This depends on none of the fields + // overriding the endianness. Putting the ^ in front of individual fields + // isn't guaranteed to work due to https://github.com/numpy/numpy/issues/9049 + oss << "^T{"; + for (auto& field : ordered_fields) { + if (field.offset > offset) + oss << (field.offset - offset) << 'x'; + oss << field.format << ':' << field.name << ':'; + offset = field.offset + field.size; + } + if (itemsize > offset) + oss << (itemsize - offset) << 'x'; + oss << '}'; + auto format_str = oss.str(); + + // Sanity check: verify that NumPy properly parses our buffer format string + auto& api = npy_api::get(); + auto arr = array(buffer_info(nullptr, itemsize, format_str, 1)); + if (!api.PyArray_EquivTypes_(dtype_ptr, arr.dtype().ptr())) + pybind11_fail("NumPy: invalid buffer descriptor!"); + + auto tindex = std::type_index(tinfo); + numpy_internals.registered_dtypes[tindex] = { dtype_ptr, format_str }; + get_internals().direct_conversions[tindex].push_back(direct_converter); +} + +template struct npy_format_descriptor { + static_assert(is_pod_struct::value, "Attempt to use a non-POD or unimplemented POD type as a numpy dtype"); + + static PYBIND11_DESCR name() { return make_caster::name(); } + + static pybind11::dtype dtype() { + return reinterpret_borrow(dtype_ptr()); + } + + static std::string format() { + static auto format_str = get_numpy_internals().get_type_info(true)->format_str; + return format_str; + } + + static void register_dtype(const std::initializer_list& fields) { + register_structured_dtype(fields, typeid(typename std::remove_cv::type), + sizeof(T), &direct_converter); + } + +private: + static PyObject* dtype_ptr() { + static PyObject* ptr = get_numpy_internals().get_type_info(true)->dtype_ptr; + return ptr; + } + + static bool direct_converter(PyObject *obj, void*& value) { + auto& api = npy_api::get(); + if (!PyObject_TypeCheck(obj, api.PyVoidArrType_Type_)) + return false; + if (auto descr = reinterpret_steal(api.PyArray_DescrFromScalar_(obj))) { + if (api.PyArray_EquivTypes_(dtype_ptr(), descr.ptr())) { + value = ((PyVoidScalarObject_Proxy *) obj)->obval; + return true; + } + } + return false; + } +}; + +#ifdef __CLION_IDE__ // replace heavy macro with dummy code for the IDE (doesn't affect code) +# define PYBIND11_NUMPY_DTYPE(Type, ...) ((void)0) +# define PYBIND11_NUMPY_DTYPE_EX(Type, ...) ((void)0) +#else + +#define PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, Name) \ + ::pybind11::detail::field_descriptor { \ + Name, offsetof(T, Field), sizeof(decltype(std::declval().Field)), \ + ::pybind11::format_descriptor().Field)>::format(), \ + ::pybind11::detail::npy_format_descriptor().Field)>::dtype() \ + } + +// Extract name, offset and format descriptor for a struct field +#define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, #Field) + +// The main idea of this macro is borrowed from https://github.com/swansontec/map-macro +// (C) William Swanson, Paul Fultz +#define PYBIND11_EVAL0(...) __VA_ARGS__ +#define PYBIND11_EVAL1(...) PYBIND11_EVAL0 (PYBIND11_EVAL0 (PYBIND11_EVAL0 (__VA_ARGS__))) +#define PYBIND11_EVAL2(...) PYBIND11_EVAL1 (PYBIND11_EVAL1 (PYBIND11_EVAL1 (__VA_ARGS__))) +#define PYBIND11_EVAL3(...) PYBIND11_EVAL2 (PYBIND11_EVAL2 (PYBIND11_EVAL2 (__VA_ARGS__))) +#define PYBIND11_EVAL4(...) PYBIND11_EVAL3 (PYBIND11_EVAL3 (PYBIND11_EVAL3 (__VA_ARGS__))) +#define PYBIND11_EVAL(...) PYBIND11_EVAL4 (PYBIND11_EVAL4 (PYBIND11_EVAL4 (__VA_ARGS__))) +#define PYBIND11_MAP_END(...) +#define PYBIND11_MAP_OUT +#define PYBIND11_MAP_COMMA , +#define PYBIND11_MAP_GET_END() 0, PYBIND11_MAP_END +#define PYBIND11_MAP_NEXT0(test, next, ...) next PYBIND11_MAP_OUT +#define PYBIND11_MAP_NEXT1(test, next) PYBIND11_MAP_NEXT0 (test, next, 0) +#define PYBIND11_MAP_NEXT(test, next) PYBIND11_MAP_NEXT1 (PYBIND11_MAP_GET_END test, next) +#ifdef _MSC_VER // MSVC is not as eager to expand macros, hence this workaround +#define PYBIND11_MAP_LIST_NEXT1(test, next) \ + PYBIND11_EVAL0 (PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0)) +#else +#define PYBIND11_MAP_LIST_NEXT1(test, next) \ + PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0) +#endif +#define PYBIND11_MAP_LIST_NEXT(test, next) \ + PYBIND11_MAP_LIST_NEXT1 (PYBIND11_MAP_GET_END test, next) +#define PYBIND11_MAP_LIST0(f, t, x, peek, ...) \ + f(t, x) PYBIND11_MAP_LIST_NEXT (peek, PYBIND11_MAP_LIST1) (f, t, peek, __VA_ARGS__) +#define PYBIND11_MAP_LIST1(f, t, x, peek, ...) \ + f(t, x) PYBIND11_MAP_LIST_NEXT (peek, PYBIND11_MAP_LIST0) (f, t, peek, __VA_ARGS__) +// PYBIND11_MAP_LIST(f, t, a1, a2, ...) expands to f(t, a1), f(t, a2), ... +#define PYBIND11_MAP_LIST(f, t, ...) \ + PYBIND11_EVAL (PYBIND11_MAP_LIST1 (f, t, __VA_ARGS__, (), 0)) + +#define PYBIND11_NUMPY_DTYPE(Type, ...) \ + ::pybind11::detail::npy_format_descriptor::register_dtype \ + ({PYBIND11_MAP_LIST (PYBIND11_FIELD_DESCRIPTOR, Type, __VA_ARGS__)}) + +#ifdef _MSC_VER +#define PYBIND11_MAP2_LIST_NEXT1(test, next) \ + PYBIND11_EVAL0 (PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0)) +#else +#define PYBIND11_MAP2_LIST_NEXT1(test, next) \ + PYBIND11_MAP_NEXT0 (test, PYBIND11_MAP_COMMA next, 0) +#endif +#define PYBIND11_MAP2_LIST_NEXT(test, next) \ + PYBIND11_MAP2_LIST_NEXT1 (PYBIND11_MAP_GET_END test, next) +#define PYBIND11_MAP2_LIST0(f, t, x1, x2, peek, ...) \ + f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT (peek, PYBIND11_MAP2_LIST1) (f, t, peek, __VA_ARGS__) +#define PYBIND11_MAP2_LIST1(f, t, x1, x2, peek, ...) \ + f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT (peek, PYBIND11_MAP2_LIST0) (f, t, peek, __VA_ARGS__) +// PYBIND11_MAP2_LIST(f, t, a1, a2, ...) expands to f(t, a1, a2), f(t, a3, a4), ... +#define PYBIND11_MAP2_LIST(f, t, ...) \ + PYBIND11_EVAL (PYBIND11_MAP2_LIST1 (f, t, __VA_ARGS__, (), 0)) + +#define PYBIND11_NUMPY_DTYPE_EX(Type, ...) \ + ::pybind11::detail::npy_format_descriptor::register_dtype \ + ({PYBIND11_MAP2_LIST (PYBIND11_FIELD_DESCRIPTOR_EX, Type, __VA_ARGS__)}) + +#endif // __CLION_IDE__ + +template +using array_iterator = typename std::add_pointer::type; + +template +array_iterator array_begin(const buffer_info& buffer) { + return array_iterator(reinterpret_cast(buffer.ptr)); +} + +template +array_iterator array_end(const buffer_info& buffer) { + return array_iterator(reinterpret_cast(buffer.ptr) + buffer.size); +} + +class common_iterator { +public: + using container_type = std::vector; + using value_type = container_type::value_type; + using size_type = container_type::size_type; + + common_iterator() : p_ptr(0), m_strides() {} + + common_iterator(void* ptr, const container_type& strides, const container_type& shape) + : p_ptr(reinterpret_cast(ptr)), m_strides(strides.size()) { + m_strides.back() = static_cast(strides.back()); + for (size_type i = m_strides.size() - 1; i != 0; --i) { + size_type j = i - 1; + value_type s = static_cast(shape[i]); + m_strides[j] = strides[j] + m_strides[i] - strides[i] * s; + } + } + + void increment(size_type dim) { + p_ptr += m_strides[dim]; + } + + void* data() const { + return p_ptr; + } + +private: + char* p_ptr; + container_type m_strides; +}; + +template class multi_array_iterator { +public: + using container_type = std::vector; + + multi_array_iterator(const std::array &buffers, + const container_type &shape) + : m_shape(shape.size()), m_index(shape.size(), 0), + m_common_iterator() { + + // Manual copy to avoid conversion warning if using std::copy + for (size_t i = 0; i < shape.size(); ++i) + m_shape[i] = shape[i]; + + container_type strides(shape.size()); + for (size_t i = 0; i < N; ++i) + init_common_iterator(buffers[i], shape, m_common_iterator[i], strides); + } + + multi_array_iterator& operator++() { + for (size_t j = m_index.size(); j != 0; --j) { + size_t i = j - 1; + if (++m_index[i] != m_shape[i]) { + increment_common_iterator(i); + break; + } else { + m_index[i] = 0; + } + } + return *this; + } + + template T* data() const { + return reinterpret_cast(m_common_iterator[K].data()); + } + +private: + + using common_iter = common_iterator; + + void init_common_iterator(const buffer_info &buffer, + const container_type &shape, + common_iter &iterator, + container_type &strides) { + auto buffer_shape_iter = buffer.shape.rbegin(); + auto buffer_strides_iter = buffer.strides.rbegin(); + auto shape_iter = shape.rbegin(); + auto strides_iter = strides.rbegin(); + + while (buffer_shape_iter != buffer.shape.rend()) { + if (*shape_iter == *buffer_shape_iter) + *strides_iter = *buffer_strides_iter; + else + *strides_iter = 0; + + ++buffer_shape_iter; + ++buffer_strides_iter; + ++shape_iter; + ++strides_iter; + } + + std::fill(strides_iter, strides.rend(), 0); + iterator = common_iter(buffer.ptr, strides, shape); + } + + void increment_common_iterator(size_t dim) { + for (auto &iter : m_common_iterator) + iter.increment(dim); + } + + container_type m_shape; + container_type m_index; + std::array m_common_iterator; +}; + +enum class broadcast_trivial { non_trivial, c_trivial, f_trivial }; + +// Populates the shape and number of dimensions for the set of buffers. Returns a broadcast_trivial +// enum value indicating whether the broadcast is "trivial"--that is, has each buffer being either a +// singleton or a full-size, C-contiguous (`c_trivial`) or Fortran-contiguous (`f_trivial`) storage +// buffer; returns `non_trivial` otherwise. +template +broadcast_trivial broadcast(const std::array &buffers, ssize_t &ndim, std::vector &shape) { + ndim = std::accumulate(buffers.begin(), buffers.end(), ssize_t(0), [](ssize_t res, const buffer_info &buf) { + return std::max(res, buf.ndim); + }); + + shape.clear(); + shape.resize((size_t) ndim, 1); + + // Figure out the output size, and make sure all input arrays conform (i.e. are either size 1 or + // the full size). + for (size_t i = 0; i < N; ++i) { + auto res_iter = shape.rbegin(); + auto end = buffers[i].shape.rend(); + for (auto shape_iter = buffers[i].shape.rbegin(); shape_iter != end; ++shape_iter, ++res_iter) { + const auto &dim_size_in = *shape_iter; + auto &dim_size_out = *res_iter; + + // Each input dimension can either be 1 or `n`, but `n` values must match across buffers + if (dim_size_out == 1) + dim_size_out = dim_size_in; + else if (dim_size_in != 1 && dim_size_in != dim_size_out) + pybind11_fail("pybind11::vectorize: incompatible size/dimension of inputs!"); + } + } + + bool trivial_broadcast_c = true; + bool trivial_broadcast_f = true; + for (size_t i = 0; i < N && (trivial_broadcast_c || trivial_broadcast_f); ++i) { + if (buffers[i].size == 1) + continue; + + // Require the same number of dimensions: + if (buffers[i].ndim != ndim) + return broadcast_trivial::non_trivial; + + // Require all dimensions be full-size: + if (!std::equal(buffers[i].shape.cbegin(), buffers[i].shape.cend(), shape.cbegin())) + return broadcast_trivial::non_trivial; + + // Check for C contiguity (but only if previous inputs were also C contiguous) + if (trivial_broadcast_c) { + ssize_t expect_stride = buffers[i].itemsize; + auto end = buffers[i].shape.crend(); + for (auto shape_iter = buffers[i].shape.crbegin(), stride_iter = buffers[i].strides.crbegin(); + trivial_broadcast_c && shape_iter != end; ++shape_iter, ++stride_iter) { + if (expect_stride == *stride_iter) + expect_stride *= *shape_iter; + else + trivial_broadcast_c = false; + } + } + + // Check for Fortran contiguity (if previous inputs were also F contiguous) + if (trivial_broadcast_f) { + ssize_t expect_stride = buffers[i].itemsize; + auto end = buffers[i].shape.cend(); + for (auto shape_iter = buffers[i].shape.cbegin(), stride_iter = buffers[i].strides.cbegin(); + trivial_broadcast_f && shape_iter != end; ++shape_iter, ++stride_iter) { + if (expect_stride == *stride_iter) + expect_stride *= *shape_iter; + else + trivial_broadcast_f = false; + } + } + } + + return + trivial_broadcast_c ? broadcast_trivial::c_trivial : + trivial_broadcast_f ? broadcast_trivial::f_trivial : + broadcast_trivial::non_trivial; +} + +template +struct vectorize_arg { + static_assert(!std::is_rvalue_reference::value, "Functions with rvalue reference arguments cannot be vectorized"); + // The wrapped function gets called with this type: + using call_type = remove_reference_t; + // Is this a vectorized argument? + static constexpr bool vectorize = + satisfies_any_of::value && + satisfies_none_of::value && + (!std::is_reference::value || + (std::is_lvalue_reference::value && std::is_const::value)); + // Accept this type: an array for vectorized types, otherwise the type as-is: + using type = conditional_t, array::forcecast>, T>; +}; + +template +struct vectorize_helper { +private: + static constexpr size_t N = sizeof...(Args); + static constexpr size_t NVectorized = constexpr_sum(vectorize_arg::vectorize...); + static_assert(NVectorized >= 1, + "pybind11::vectorize(...) requires a function with at least one vectorizable argument"); + +public: + template + explicit vectorize_helper(T &&f) : f(std::forward(f)) { } + + object operator()(typename vectorize_arg::type... args) { + return run(args..., + make_index_sequence(), + select_indices::vectorize...>(), + make_index_sequence()); + } + +private: + remove_reference_t f; + + template using param_n_t = typename pack_element::call_type...>::type; + + // Runs a vectorized function given arguments tuple and three index sequences: + // - Index is the full set of 0 ... (N-1) argument indices; + // - VIndex is the subset of argument indices with vectorized parameters, letting us access + // vectorized arguments (anything not in this sequence is passed through) + // - BIndex is a incremental sequence (beginning at 0) of the same size as VIndex, so that + // we can store vectorized buffer_infos in an array (argument VIndex has its buffer at + // index BIndex in the array). + template object run( + typename vectorize_arg::type &...args, + index_sequence i_seq, index_sequence vi_seq, index_sequence bi_seq) { + + // Pointers to values the function was called with; the vectorized ones set here will start + // out as array_t pointers, but they will be changed them to T pointers before we make + // call the wrapped function. Non-vectorized pointers are left as-is. + std::array params{{ &args... }}; + + // The array of `buffer_info`s of vectorized arguments: + std::array buffers{{ reinterpret_cast(params[VIndex])->request()... }}; + + /* Determine dimensions parameters of output array */ + ssize_t nd = 0; + std::vector shape(0); + auto trivial = broadcast(buffers, nd, shape); + size_t ndim = (size_t) nd; + + size_t size = std::accumulate(shape.begin(), shape.end(), (size_t) 1, std::multiplies()); + + // If all arguments are 0-dimension arrays (i.e. single values) return a plain value (i.e. + // not wrapped in an array). + if (size == 1 && ndim == 0) { + PYBIND11_EXPAND_SIDE_EFFECTS(params[VIndex] = buffers[BIndex].ptr); + return cast(f(*reinterpret_cast *>(params[Index])...)); + } + + array_t result; + if (trivial == broadcast_trivial::f_trivial) result = array_t(shape); + else result = array_t(shape); + + if (size == 0) return result; + + /* Call the function */ + if (trivial == broadcast_trivial::non_trivial) + apply_broadcast(buffers, params, result, i_seq, vi_seq, bi_seq); + else + apply_trivial(buffers, params, result.mutable_data(), size, i_seq, vi_seq, bi_seq); + + return result; + } + + template + void apply_trivial(std::array &buffers, + std::array ¶ms, + Return *out, + size_t size, + index_sequence, index_sequence, index_sequence) { + + // Initialize an array of mutable byte references and sizes with references set to the + // appropriate pointer in `params`; as we iterate, we'll increment each pointer by its size + // (except for singletons, which get an increment of 0). + std::array, NVectorized> vecparams{{ + std::pair( + reinterpret_cast(params[VIndex] = buffers[BIndex].ptr), + buffers[BIndex].size == 1 ? 0 : sizeof(param_n_t) + )... + }}; + + for (size_t i = 0; i < size; ++i) { + out[i] = f(*reinterpret_cast *>(params[Index])...); + for (auto &x : vecparams) x.first += x.second; + } + } + + template + void apply_broadcast(std::array &buffers, + std::array ¶ms, + array_t &output_array, + index_sequence, index_sequence, index_sequence) { + + buffer_info output = output_array.request(); + multi_array_iterator input_iter(buffers, output.shape); + + for (array_iterator iter = array_begin(output), end = array_end(output); + iter != end; + ++iter, ++input_iter) { + PYBIND11_EXPAND_SIDE_EFFECTS(( + params[VIndex] = input_iter.template data() + )); + *iter = f(*reinterpret_cast *>(std::get(params))...); + } + } +}; + +template +vectorize_helper +vectorize_extractor(const Func &f, Return (*) (Args ...)) { + return detail::vectorize_helper(f); +} + +template struct handle_type_name> { + static PYBIND11_DESCR name() { + return _("numpy.ndarray[") + npy_format_descriptor::name() + _("]"); + } +}; + +NAMESPACE_END(detail) + +// Vanilla pointer vectorizer: +template +detail::vectorize_helper +vectorize(Return (*f) (Args ...)) { + return detail::vectorize_helper(f); +} + +// lambda vectorizer: +template ::value, int> = 0> +auto vectorize(Func &&f) -> decltype( + detail::vectorize_extractor(std::forward(f), (detail::function_signature_t *) nullptr)) { + return detail::vectorize_extractor(std::forward(f), (detail::function_signature_t *) nullptr); +} + +// Vectorize a class method (non-const): +template ())), Return, Class *, Args...>> +Helper vectorize(Return (Class::*f)(Args...)) { + return Helper(std::mem_fn(f)); +} + +// Vectorize a class method (non-const): +template ())), Return, const Class *, Args...>> +Helper vectorize(Return (Class::*f)(Args...) const) { + return Helper(std::mem_fn(f)); +} + +NAMESPACE_END(PYBIND11_NAMESPACE) + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/operators.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/operators.h new file mode 100644 index 00000000..b3dd62c3 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/operators.h @@ -0,0 +1,168 @@ +/* + pybind11/operator.h: Metatemplates for operator overloading + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" + +#if defined(__clang__) && !defined(__INTEL_COMPILER) +# pragma clang diagnostic ignored "-Wunsequenced" // multiple unsequenced modifications to 'self' (when using def(py::self OP Type())) +#elif defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +#endif + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +/// Enumeration with all supported operator types +enum op_id : int { + op_add, op_sub, op_mul, op_div, op_mod, op_divmod, op_pow, op_lshift, + op_rshift, op_and, op_xor, op_or, op_neg, op_pos, op_abs, op_invert, + op_int, op_long, op_float, op_str, op_cmp, op_gt, op_ge, op_lt, op_le, + op_eq, op_ne, op_iadd, op_isub, op_imul, op_idiv, op_imod, op_ilshift, + op_irshift, op_iand, op_ixor, op_ior, op_complex, op_bool, op_nonzero, + op_repr, op_truediv, op_itruediv, op_hash +}; + +enum op_type : int { + op_l, /* base type on left */ + op_r, /* base type on right */ + op_u /* unary operator */ +}; + +struct self_t { }; +static const self_t self = self_t(); + +/// Type for an unused type slot +struct undefined_t { }; + +/// Don't warn about an unused variable +inline self_t __self() { return self; } + +/// base template of operator implementations +template struct op_impl { }; + +/// Operator implementation generator +template struct op_ { + template void execute(Class &cl, const Extra&... extra) const { + using Base = typename Class::type; + using L_type = conditional_t::value, Base, L>; + using R_type = conditional_t::value, Base, R>; + using op = op_impl; + cl.def(op::name(), &op::execute, is_operator(), extra...); + #if PY_MAJOR_VERSION < 3 + if (id == op_truediv || id == op_itruediv) + cl.def(id == op_itruediv ? "__idiv__" : ot == op_l ? "__div__" : "__rdiv__", + &op::execute, is_operator(), extra...); + #endif + } + template void execute_cast(Class &cl, const Extra&... extra) const { + using Base = typename Class::type; + using L_type = conditional_t::value, Base, L>; + using R_type = conditional_t::value, Base, R>; + using op = op_impl; + cl.def(op::name(), &op::execute_cast, is_operator(), extra...); + #if PY_MAJOR_VERSION < 3 + if (id == op_truediv || id == op_itruediv) + cl.def(id == op_itruediv ? "__idiv__" : ot == op_l ? "__div__" : "__rdiv__", + &op::execute, is_operator(), extra...); + #endif + } +}; + +#define PYBIND11_BINARY_OPERATOR(id, rid, op, expr) \ +template struct op_impl { \ + static char const* name() { return "__" #id "__"; } \ + static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); } \ + static B execute_cast(const L &l, const R &r) { return B(expr); } \ +}; \ +template struct op_impl { \ + static char const* name() { return "__" #rid "__"; } \ + static auto execute(const R &r, const L &l) -> decltype(expr) { return (expr); } \ + static B execute_cast(const R &r, const L &l) { return B(expr); } \ +}; \ +inline op_ op(const self_t &, const self_t &) { \ + return op_(); \ +} \ +template op_ op(const self_t &, const T &) { \ + return op_(); \ +} \ +template op_ op(const T &, const self_t &) { \ + return op_(); \ +} + +#define PYBIND11_INPLACE_OPERATOR(id, op, expr) \ +template struct op_impl { \ + static char const* name() { return "__" #id "__"; } \ + static auto execute(L &l, const R &r) -> decltype(expr) { return expr; } \ + static B execute_cast(L &l, const R &r) { return B(expr); } \ +}; \ +template op_ op(const self_t &, const T &) { \ + return op_(); \ +} + +#define PYBIND11_UNARY_OPERATOR(id, op, expr) \ +template struct op_impl { \ + static char const* name() { return "__" #id "__"; } \ + static auto execute(const L &l) -> decltype(expr) { return expr; } \ + static B execute_cast(const L &l) { return B(expr); } \ +}; \ +inline op_ op(const self_t &) { \ + return op_(); \ +} + +PYBIND11_BINARY_OPERATOR(sub, rsub, operator-, l - r) +PYBIND11_BINARY_OPERATOR(add, radd, operator+, l + r) +PYBIND11_BINARY_OPERATOR(mul, rmul, operator*, l * r) +PYBIND11_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r) +PYBIND11_BINARY_OPERATOR(mod, rmod, operator%, l % r) +PYBIND11_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r) +PYBIND11_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r) +PYBIND11_BINARY_OPERATOR(and, rand, operator&, l & r) +PYBIND11_BINARY_OPERATOR(xor, rxor, operator^, l ^ r) +PYBIND11_BINARY_OPERATOR(eq, eq, operator==, l == r) +PYBIND11_BINARY_OPERATOR(ne, ne, operator!=, l != r) +PYBIND11_BINARY_OPERATOR(or, ror, operator|, l | r) +PYBIND11_BINARY_OPERATOR(gt, lt, operator>, l > r) +PYBIND11_BINARY_OPERATOR(ge, le, operator>=, l >= r) +PYBIND11_BINARY_OPERATOR(lt, gt, operator<, l < r) +PYBIND11_BINARY_OPERATOR(le, ge, operator<=, l <= r) +//PYBIND11_BINARY_OPERATOR(pow, rpow, pow, std::pow(l, r)) +PYBIND11_INPLACE_OPERATOR(iadd, operator+=, l += r) +PYBIND11_INPLACE_OPERATOR(isub, operator-=, l -= r) +PYBIND11_INPLACE_OPERATOR(imul, operator*=, l *= r) +PYBIND11_INPLACE_OPERATOR(itruediv, operator/=, l /= r) +PYBIND11_INPLACE_OPERATOR(imod, operator%=, l %= r) +PYBIND11_INPLACE_OPERATOR(ilshift, operator<<=, l <<= r) +PYBIND11_INPLACE_OPERATOR(irshift, operator>>=, l >>= r) +PYBIND11_INPLACE_OPERATOR(iand, operator&=, l &= r) +PYBIND11_INPLACE_OPERATOR(ixor, operator^=, l ^= r) +PYBIND11_INPLACE_OPERATOR(ior, operator|=, l |= r) +PYBIND11_UNARY_OPERATOR(neg, operator-, -l) +PYBIND11_UNARY_OPERATOR(pos, operator+, +l) +PYBIND11_UNARY_OPERATOR(abs, abs, std::abs(l)) +PYBIND11_UNARY_OPERATOR(hash, hash, std::hash()(l)) +PYBIND11_UNARY_OPERATOR(invert, operator~, (~l)) +PYBIND11_UNARY_OPERATOR(bool, operator!, !!l) +PYBIND11_UNARY_OPERATOR(int, int_, (int) l) +PYBIND11_UNARY_OPERATOR(float, float_, (double) l) + +#undef PYBIND11_BINARY_OPERATOR +#undef PYBIND11_INPLACE_OPERATOR +#undef PYBIND11_UNARY_OPERATOR +NAMESPACE_END(detail) + +using detail::self; + +NAMESPACE_END(PYBIND11_NAMESPACE) + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/options.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/options.h new file mode 100644 index 00000000..cc1e1f6f --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/options.h @@ -0,0 +1,65 @@ +/* + pybind11/options.h: global settings that are configurable at runtime. + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "detail/common.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +class options { +public: + + // Default RAII constructor, which leaves settings as they currently are. + options() : previous_state(global_state()) {} + + // Class is non-copyable. + options(const options&) = delete; + options& operator=(const options&) = delete; + + // Destructor, which restores settings that were in effect before. + ~options() { + global_state() = previous_state; + } + + // Setter methods (affect the global state): + + options& disable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = false; return *this; } + + options& enable_user_defined_docstrings() & { global_state().show_user_defined_docstrings = true; return *this; } + + options& disable_function_signatures() & { global_state().show_function_signatures = false; return *this; } + + options& enable_function_signatures() & { global_state().show_function_signatures = true; return *this; } + + // Getter methods (return the global state): + + static bool show_user_defined_docstrings() { return global_state().show_user_defined_docstrings; } + + static bool show_function_signatures() { return global_state().show_function_signatures; } + + // This type is not meant to be allocated on the heap. + void* operator new(size_t) = delete; + +private: + + struct state { + bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings. + bool show_function_signatures = true; //< Include auto-generated function signatures in docstrings. + }; + + static state &global_state() { + static state instance; + return instance; + } + + state previous_state; +}; + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/pybind11.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/pybind11.h new file mode 100644 index 00000000..7723d2a8 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/pybind11.h @@ -0,0 +1,1963 @@ +/* + pybind11/pybind11.h: Main header file of the C++11 python + binding generator library + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4100) // warning C4100: Unreferenced formal parameter +# pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +# pragma warning(disable: 4512) // warning C4512: Assignment operator was implicitly defined as deleted +# pragma warning(disable: 4800) // warning C4800: 'int': forcing value to bool 'true' or 'false' (performance warning) +# pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name +# pragma warning(disable: 4702) // warning C4702: unreachable code +# pragma warning(disable: 4522) // warning C4522: multiple assignment operators specified +#elif defined(__INTEL_COMPILER) +# pragma warning(push) +# pragma warning(disable: 68) // integer conversion resulted in a change of sign +# pragma warning(disable: 186) // pointless comparison of unsigned integer with zero +# pragma warning(disable: 878) // incompatible exception specifications +# pragma warning(disable: 1334) // the "template" keyword used for syntactic disambiguation may only be used within a template +# pragma warning(disable: 1682) // implicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem) +# pragma warning(disable: 1875) // offsetof applied to non-POD (Plain Old Data) types is nonstandard +# pragma warning(disable: 2196) // warning #2196: routine is both "inline" and "noinline" +#elif defined(__GNUG__) && !defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-but-set-parameter" +# pragma GCC diagnostic ignored "-Wunused-but-set-variable" +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +# pragma GCC diagnostic ignored "-Wstrict-aliasing" +# pragma GCC diagnostic ignored "-Wattributes" +# if __GNUC__ >= 7 +# pragma GCC diagnostic ignored "-Wnoexcept-type" +# endif +#endif + +#include "attr.h" +#include "options.h" +#include "detail/class.h" +#include "detail/init.h" + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +/// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object +class cpp_function : public function { +public: + cpp_function() { } + + /// Construct a cpp_function from a vanilla function pointer + template + cpp_function(Return (*f)(Args...), const Extra&... extra) { + initialize(f, f, extra...); + } + + /// Construct a cpp_function from a lambda function (possibly with internal state) + template ::value>> + cpp_function(Func &&f, const Extra&... extra) { + initialize(std::forward(f), + (detail::function_signature_t *) nullptr, extra...); + } + + /// Construct a cpp_function from a class method (non-const) + template + cpp_function(Return (Class::*f)(Arg...), const Extra&... extra) { + initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); }, + (Return (*) (Class *, Arg...)) nullptr, extra...); + } + + /// Construct a cpp_function from a class method (const) + template + cpp_function(Return (Class::*f)(Arg...) const, const Extra&... extra) { + initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(args...); }, + (Return (*)(const Class *, Arg ...)) nullptr, extra...); + } + + /// Return the function name + object name() const { return attr("__name__"); } + +protected: + /// Space optimization: don't inline this frequently instantiated fragment + PYBIND11_NOINLINE detail::function_record *make_function_record() { + return new detail::function_record(); + } + + /// Special internal constructor for functors, lambda functions, etc. + template + void initialize(Func &&f, Return (*)(Args...), const Extra&... extra) { + using namespace detail; + + struct capture { remove_reference_t f; }; + + /* Store the function including any extra state it might have (e.g. a lambda capture object) */ + auto rec = make_function_record(); + + /* Store the capture object directly in the function record if there is enough space */ + if (sizeof(capture) <= sizeof(rec->data)) { + /* Without these pragmas, GCC warns that there might not be + enough space to use the placement new operator. However, the + 'if' statement above ensures that this is the case. */ +#if defined(__GNUG__) && !defined(__clang__) && __GNUC__ >= 6 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wplacement-new" +#endif + new ((capture *) &rec->data) capture { std::forward(f) }; +#if defined(__GNUG__) && !defined(__clang__) && __GNUC__ >= 6 +# pragma GCC diagnostic pop +#endif + if (!std::is_trivially_destructible::value) + rec->free_data = [](function_record *r) { ((capture *) &r->data)->~capture(); }; + } else { + rec->data[0] = new capture { std::forward(f) }; + rec->free_data = [](function_record *r) { delete ((capture *) r->data[0]); }; + } + + /* Type casters for the function arguments and return value */ + using cast_in = argument_loader; + using cast_out = make_caster< + conditional_t::value, void_type, Return> + >; + + static_assert(expected_num_args(sizeof...(Args), cast_in::has_args, cast_in::has_kwargs), + "The number of argument annotations does not match the number of function arguments"); + + /* Dispatch code which converts function arguments and performs the actual function call */ + rec->impl = [](function_call &call) -> handle { + cast_in args_converter; + + /* Try to cast the function arguments into the C++ domain */ + if (!args_converter.load_args(call)) + return PYBIND11_TRY_NEXT_OVERLOAD; + + /* Invoke call policy pre-call hook */ + process_attributes::precall(call); + + /* Get a pointer to the capture object */ + auto data = (sizeof(capture) <= sizeof(call.func.data) + ? &call.func.data : call.func.data[0]); + capture *cap = const_cast(reinterpret_cast(data)); + + /* Override policy for rvalues -- usually to enforce rvp::move on an rvalue */ + const auto policy = return_value_policy_override::policy(call.func.policy); + + /* Function scope guard -- defaults to the compile-to-nothing `void_type` */ + using Guard = extract_guard_t; + + /* Perform the function call */ + handle result = cast_out::cast( + std::move(args_converter).template call(cap->f), policy, call.parent); + + /* Invoke call policy post-call hook */ + process_attributes::postcall(call, result); + + return result; + }; + + /* Process any user-provided function attributes */ + process_attributes::init(extra..., rec); + + /* Generate a readable signature describing the function's arguments and return value types */ + PYBIND11_DESCR signature = _("(") + cast_in::arg_names() + _(") -> ") + cast_out::name(); + + /* Register the function with Python from generic (non-templated) code */ + initialize_generic(rec, signature.text(), signature.types(), sizeof...(Args)); + + if (cast_in::has_args) rec->has_args = true; + if (cast_in::has_kwargs) rec->has_kwargs = true; + + /* Stash some additional information used by an important optimization in 'functional.h' */ + using FunctionType = Return (*)(Args...); + constexpr bool is_function_ptr = + std::is_convertible::value && + sizeof(capture) == sizeof(void *); + if (is_function_ptr) { + rec->is_stateless = true; + rec->data[1] = const_cast(reinterpret_cast(&typeid(FunctionType))); + } + } + + /// Register a function call with Python (generic non-templated code goes here) + void initialize_generic(detail::function_record *rec, const char *text, + const std::type_info *const *types, size_t args) { + + /* Create copies of all referenced C-style strings */ + rec->name = strdup(rec->name ? rec->name : ""); + if (rec->doc) rec->doc = strdup(rec->doc); + for (auto &a: rec->args) { + if (a.name) + a.name = strdup(a.name); + if (a.descr) + a.descr = strdup(a.descr); + else if (a.value) + a.descr = strdup(a.value.attr("__repr__")().cast().c_str()); + } + + rec->is_constructor = !strcmp(rec->name, "__init__") || !strcmp(rec->name, "__setstate__"); + +#if !defined(NDEBUG) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING) + if (rec->is_constructor && !rec->is_new_style_constructor) { + const auto class_name = std::string(((PyTypeObject *) rec->scope.ptr())->tp_name); + const auto func_name = std::string(rec->name); + PyErr_WarnEx( + PyExc_FutureWarning, + ("pybind11-bound class '" + class_name + "' is using an old-style " + "placement-new '" + func_name + "' which has been deprecated. See " + "the upgrade guide in pybind11's docs. This message is only visible " + "when compiled in debug mode.").c_str(), 0 + ); + } +#endif + + /* Generate a proper function signature */ + std::string signature; + size_t type_depth = 0, char_index = 0, type_index = 0, arg_index = 0; + while (true) { + char c = text[char_index++]; + if (c == '\0') + break; + + if (c == '{') { + // Write arg name for everything except *args, **kwargs and return type. + if (type_depth == 0 && text[char_index] != '*' && arg_index < args) { + if (!rec->args.empty() && rec->args[arg_index].name) { + signature += rec->args[arg_index].name; + } else if (arg_index == 0 && rec->is_method) { + signature += "self"; + } else { + signature += "arg" + std::to_string(arg_index - (rec->is_method ? 1 : 0)); + } + signature += ": "; + } + ++type_depth; + } else if (c == '}') { + --type_depth; + if (type_depth == 0) { + if (arg_index < rec->args.size() && rec->args[arg_index].descr) { + signature += "="; + signature += rec->args[arg_index].descr; + } + arg_index++; + } + } else if (c == '%') { + const std::type_info *t = types[type_index++]; + if (!t) + pybind11_fail("Internal error while parsing type signature (1)"); + if (auto tinfo = detail::get_type_info(*t)) { + handle th((PyObject *) tinfo->type); + signature += + th.attr("__module__").cast() + "." + + th.attr("__qualname__").cast(); // Python 3.3+, but we backport it to earlier versions + } else if (rec->is_new_style_constructor && arg_index == 0) { + // A new-style `__init__` takes `self` as `value_and_holder`. + // Rewrite it to the proper class type. + signature += + rec->scope.attr("__module__").cast() + "." + + rec->scope.attr("__qualname__").cast(); + } else { + std::string tname(t->name()); + detail::clean_type_id(tname); + signature += tname; + } + } else { + signature += c; + } + } + if (type_depth != 0 || types[type_index] != nullptr) + pybind11_fail("Internal error while parsing type signature (2)"); + + #if !defined(PYBIND11_CONSTEXPR_DESCR) + delete[] types; + delete[] text; + #endif + +#if PY_MAJOR_VERSION < 3 + if (strcmp(rec->name, "__next__") == 0) { + std::free(rec->name); + rec->name = strdup("next"); + } else if (strcmp(rec->name, "__bool__") == 0) { + std::free(rec->name); + rec->name = strdup("__nonzero__"); + } +#endif + rec->signature = strdup(signature.c_str()); + rec->args.shrink_to_fit(); + rec->nargs = (std::uint16_t) args; + + if (rec->sibling && PYBIND11_INSTANCE_METHOD_CHECK(rec->sibling.ptr())) + rec->sibling = PYBIND11_INSTANCE_METHOD_GET_FUNCTION(rec->sibling.ptr()); + + detail::function_record *chain = nullptr, *chain_start = rec; + if (rec->sibling) { + if (PyCFunction_Check(rec->sibling.ptr())) { + auto rec_capsule = reinterpret_borrow(PyCFunction_GET_SELF(rec->sibling.ptr())); + chain = (detail::function_record *) rec_capsule; + /* Never append a method to an overload chain of a parent class; + instead, hide the parent's overloads in this case */ + if (!chain->scope.is(rec->scope)) + chain = nullptr; + } + // Don't trigger for things like the default __init__, which are wrapper_descriptors that we are intentionally replacing + else if (!rec->sibling.is_none() && rec->name[0] != '_') + pybind11_fail("Cannot overload existing non-function object \"" + std::string(rec->name) + + "\" with a function of the same name"); + } + + if (!chain) { + /* No existing overload was found, create a new function object */ + rec->def = new PyMethodDef(); + std::memset(rec->def, 0, sizeof(PyMethodDef)); + rec->def->ml_name = rec->name; + rec->def->ml_meth = reinterpret_cast(*dispatcher); + rec->def->ml_flags = METH_VARARGS | METH_KEYWORDS; + + capsule rec_capsule(rec, [](void *ptr) { + destruct((detail::function_record *) ptr); + }); + + object scope_module; + if (rec->scope) { + if (hasattr(rec->scope, "__module__")) { + scope_module = rec->scope.attr("__module__"); + } else if (hasattr(rec->scope, "__name__")) { + scope_module = rec->scope.attr("__name__"); + } + } + + m_ptr = PyCFunction_NewEx(rec->def, rec_capsule.ptr(), scope_module.ptr()); + if (!m_ptr) + pybind11_fail("cpp_function::cpp_function(): Could not allocate function object"); + } else { + /* Append at the end of the overload chain */ + m_ptr = rec->sibling.ptr(); + inc_ref(); + chain_start = chain; + if (chain->is_method != rec->is_method) + pybind11_fail("overloading a method with both static and instance methods is not supported; " + #if defined(NDEBUG) + "compile in debug mode for more details" + #else + "error while attempting to bind " + std::string(rec->is_method ? "instance" : "static") + " method " + + std::string(pybind11::str(rec->scope.attr("__name__"))) + "." + std::string(rec->name) + signature + #endif + ); + while (chain->next) + chain = chain->next; + chain->next = rec; + } + + std::string signatures; + int index = 0; + /* Create a nice pydoc rec including all signatures and + docstrings of the functions in the overload chain */ + if (chain && options::show_function_signatures()) { + // First a generic signature + signatures += rec->name; + signatures += "(*args, **kwargs)\n"; + signatures += "Overloaded function.\n\n"; + } + // Then specific overload signatures + bool first_user_def = true; + for (auto it = chain_start; it != nullptr; it = it->next) { + if (options::show_function_signatures()) { + if (index > 0) signatures += "\n"; + if (chain) + signatures += std::to_string(++index) + ". "; + signatures += rec->name; + signatures += it->signature; + signatures += "\n"; + } + if (it->doc && strlen(it->doc) > 0 && options::show_user_defined_docstrings()) { + // If we're appending another docstring, and aren't printing function signatures, we + // need to append a newline first: + if (!options::show_function_signatures()) { + if (first_user_def) first_user_def = false; + else signatures += "\n"; + } + if (options::show_function_signatures()) signatures += "\n"; + signatures += it->doc; + if (options::show_function_signatures()) signatures += "\n"; + } + } + + /* Install docstring */ + PyCFunctionObject *func = (PyCFunctionObject *) m_ptr; + if (func->m_ml->ml_doc) + std::free(const_cast(func->m_ml->ml_doc)); + func->m_ml->ml_doc = strdup(signatures.c_str()); + + if (rec->is_method) { + m_ptr = PYBIND11_INSTANCE_METHOD_NEW(m_ptr, rec->scope.ptr()); + if (!m_ptr) + pybind11_fail("cpp_function::cpp_function(): Could not allocate instance method object"); + Py_DECREF(func); + } + } + + /// When a cpp_function is GCed, release any memory allocated by pybind11 + static void destruct(detail::function_record *rec) { + while (rec) { + detail::function_record *next = rec->next; + if (rec->free_data) + rec->free_data(rec); + std::free((char *) rec->name); + std::free((char *) rec->doc); + std::free((char *) rec->signature); + for (auto &arg: rec->args) { + std::free(const_cast(arg.name)); + std::free(const_cast(arg.descr)); + arg.value.dec_ref(); + } + if (rec->def) { + std::free(const_cast(rec->def->ml_doc)); + delete rec->def; + } + delete rec; + rec = next; + } + } + + /// Main dispatch logic for calls to functions bound using pybind11 + static PyObject *dispatcher(PyObject *self, PyObject *args_in, PyObject *kwargs_in) { + using namespace detail; + + /* Iterator over the list of potentially admissible overloads */ + function_record *overloads = (function_record *) PyCapsule_GetPointer(self, nullptr), + *it = overloads; + + /* Need to know how many arguments + keyword arguments there are to pick the right overload */ + const size_t n_args_in = (size_t) PyTuple_GET_SIZE(args_in); + + handle parent = n_args_in > 0 ? PyTuple_GET_ITEM(args_in, 0) : nullptr, + result = PYBIND11_TRY_NEXT_OVERLOAD; + + auto self_value_and_holder = value_and_holder(); + if (overloads->is_constructor) { + const auto tinfo = get_type_info((PyTypeObject *) overloads->scope.ptr()); + const auto pi = reinterpret_cast(parent.ptr()); + self_value_and_holder = pi->get_value_and_holder(tinfo, false); + + if (!self_value_and_holder.type || !self_value_and_holder.inst) { + PyErr_SetString(PyExc_TypeError, "__init__(self, ...) called with invalid `self` argument"); + return nullptr; + } + + // If this value is already registered it must mean __init__ is invoked multiple times; + // we really can't support that in C++, so just ignore the second __init__. + if (self_value_and_holder.instance_registered()) + return none().release().ptr(); + } + + try { + // We do this in two passes: in the first pass, we load arguments with `convert=false`; + // in the second, we allow conversion (except for arguments with an explicit + // py::arg().noconvert()). This lets us prefer calls without conversion, with + // conversion as a fallback. + std::vector second_pass; + + // However, if there are no overloads, we can just skip the no-convert pass entirely + const bool overloaded = it != nullptr && it->next != nullptr; + + for (; it != nullptr; it = it->next) { + + /* For each overload: + 1. Copy all positional arguments we were given, also checking to make sure that + named positional arguments weren't *also* specified via kwarg. + 2. If we weren't given enough, try to make up the omitted ones by checking + whether they were provided by a kwarg matching the `py::arg("name")` name. If + so, use it (and remove it from kwargs; if not, see if the function binding + provided a default that we can use. + 3. Ensure that either all keyword arguments were "consumed", or that the function + takes a kwargs argument to accept unconsumed kwargs. + 4. Any positional arguments still left get put into a tuple (for args), and any + leftover kwargs get put into a dict. + 5. Pack everything into a vector; if we have py::args or py::kwargs, they are an + extra tuple or dict at the end of the positional arguments. + 6. Call the function call dispatcher (function_record::impl) + + If one of these fail, move on to the next overload and keep trying until we get a + result other than PYBIND11_TRY_NEXT_OVERLOAD. + */ + + function_record &func = *it; + size_t pos_args = func.nargs; // Number of positional arguments that we need + if (func.has_args) --pos_args; // (but don't count py::args + if (func.has_kwargs) --pos_args; // or py::kwargs) + + if (!func.has_args && n_args_in > pos_args) + continue; // Too many arguments for this overload + + if (n_args_in < pos_args && func.args.size() < pos_args) + continue; // Not enough arguments given, and not enough defaults to fill in the blanks + + function_call call(func, parent); + + size_t args_to_copy = std::min(pos_args, n_args_in); + size_t args_copied = 0; + + // 0. Inject new-style `self` argument + if (func.is_new_style_constructor) { + // The `value` may have been preallocated by an old-style `__init__` + // if it was a preceding candidate for overload resolution. + if (self_value_and_holder) + self_value_and_holder.type->dealloc(self_value_and_holder); + + call.init_self = PyTuple_GET_ITEM(args_in, 0); + call.args.push_back(reinterpret_cast(&self_value_and_holder)); + call.args_convert.push_back(false); + ++args_copied; + } + + // 1. Copy any position arguments given. + bool bad_arg = false; + for (; args_copied < args_to_copy; ++args_copied) { + argument_record *arg_rec = args_copied < func.args.size() ? &func.args[args_copied] : nullptr; + if (kwargs_in && arg_rec && arg_rec->name && PyDict_GetItemString(kwargs_in, arg_rec->name)) { + bad_arg = true; + break; + } + + handle arg(PyTuple_GET_ITEM(args_in, args_copied)); + if (arg_rec && !arg_rec->none && arg.is_none()) { + bad_arg = true; + break; + } + call.args.push_back(arg); + call.args_convert.push_back(arg_rec ? arg_rec->convert : true); + } + if (bad_arg) + continue; // Maybe it was meant for another overload (issue #688) + + // We'll need to copy this if we steal some kwargs for defaults + dict kwargs = reinterpret_borrow(kwargs_in); + + // 2. Check kwargs and, failing that, defaults that may help complete the list + if (args_copied < pos_args) { + bool copied_kwargs = false; + + for (; args_copied < pos_args; ++args_copied) { + const auto &arg = func.args[args_copied]; + + handle value; + if (kwargs_in && arg.name) + value = PyDict_GetItemString(kwargs.ptr(), arg.name); + + if (value) { + // Consume a kwargs value + if (!copied_kwargs) { + kwargs = reinterpret_steal(PyDict_Copy(kwargs.ptr())); + copied_kwargs = true; + } + PyDict_DelItemString(kwargs.ptr(), arg.name); + } else if (arg.value) { + value = arg.value; + } + + if (value) { + call.args.push_back(value); + call.args_convert.push_back(arg.convert); + } + else + break; + } + + if (args_copied < pos_args) + continue; // Not enough arguments, defaults, or kwargs to fill the positional arguments + } + + // 3. Check everything was consumed (unless we have a kwargs arg) + if (kwargs && kwargs.size() > 0 && !func.has_kwargs) + continue; // Unconsumed kwargs, but no py::kwargs argument to accept them + + // 4a. If we have a py::args argument, create a new tuple with leftovers + if (func.has_args) { + tuple extra_args; + if (args_to_copy == 0) { + // We didn't copy out any position arguments from the args_in tuple, so we + // can reuse it directly without copying: + extra_args = reinterpret_borrow(args_in); + } else if (args_copied >= n_args_in) { + extra_args = tuple(0); + } else { + size_t args_size = n_args_in - args_copied; + extra_args = tuple(args_size); + for (size_t i = 0; i < args_size; ++i) { + extra_args[i] = PyTuple_GET_ITEM(args_in, args_copied + i); + } + } + call.args.push_back(extra_args); + call.args_convert.push_back(false); + call.args_ref = std::move(extra_args); + } + + // 4b. If we have a py::kwargs, pass on any remaining kwargs + if (func.has_kwargs) { + if (!kwargs.ptr()) + kwargs = dict(); // If we didn't get one, send an empty one + call.args.push_back(kwargs); + call.args_convert.push_back(false); + call.kwargs_ref = std::move(kwargs); + } + + // 5. Put everything in a vector. Not technically step 5, we've been building it + // in `call.args` all along. + #if !defined(NDEBUG) + if (call.args.size() != func.nargs || call.args_convert.size() != func.nargs) + pybind11_fail("Internal error: function call dispatcher inserted wrong number of arguments!"); + #endif + + std::vector second_pass_convert; + if (overloaded) { + // We're in the first no-convert pass, so swap out the conversion flags for a + // set of all-false flags. If the call fails, we'll swap the flags back in for + // the conversion-allowed call below. + second_pass_convert.resize(func.nargs, false); + call.args_convert.swap(second_pass_convert); + } + + // 6. Call the function. + try { + loader_life_support guard{}; + result = func.impl(call); + } catch (reference_cast_error &) { + result = PYBIND11_TRY_NEXT_OVERLOAD; + } + + if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) + break; + + if (overloaded) { + // The (overloaded) call failed; if the call has at least one argument that + // permits conversion (i.e. it hasn't been explicitly specified `.noconvert()`) + // then add this call to the list of second pass overloads to try. + for (size_t i = func.is_method ? 1 : 0; i < pos_args; i++) { + if (second_pass_convert[i]) { + // Found one: swap the converting flags back in and store the call for + // the second pass. + call.args_convert.swap(second_pass_convert); + second_pass.push_back(std::move(call)); + break; + } + } + } + } + + if (overloaded && !second_pass.empty() && result.ptr() == PYBIND11_TRY_NEXT_OVERLOAD) { + // The no-conversion pass finished without success, try again with conversion allowed + for (auto &call : second_pass) { + try { + loader_life_support guard{}; + result = call.func.impl(call); + } catch (reference_cast_error &) { + result = PYBIND11_TRY_NEXT_OVERLOAD; + } + + if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) + break; + } + } + } catch (error_already_set &e) { + e.restore(); + return nullptr; + } catch (...) { + /* When an exception is caught, give each registered exception + translator a chance to translate it to a Python exception + in reverse order of registration. + + A translator may choose to do one of the following: + + - catch the exception and call PyErr_SetString or PyErr_SetObject + to set a standard (or custom) Python exception, or + - do nothing and let the exception fall through to the next translator, or + - delegate translation to the next translator by throwing a new type of exception. */ + + auto last_exception = std::current_exception(); + auto ®istered_exception_translators = get_internals().registered_exception_translators; + for (auto& translator : registered_exception_translators) { + try { + translator(last_exception); + } catch (...) { + last_exception = std::current_exception(); + continue; + } + return nullptr; + } + PyErr_SetString(PyExc_SystemError, "Exception escaped from default exception translator!"); + return nullptr; + } + + auto append_note_if_missing_header_is_suspected = [](std::string &msg) { + if (msg.find("std::") != std::string::npos) { + msg += "\n\n" + "Did you forget to `#include `? Or ,\n" + ", , etc. Some automatic\n" + "conversions are optional and require extra headers to be included\n" + "when compiling your pybind11 module."; + } + }; + + if (result.ptr() == PYBIND11_TRY_NEXT_OVERLOAD) { + if (overloads->is_operator) + return handle(Py_NotImplemented).inc_ref().ptr(); + + std::string msg = std::string(overloads->name) + "(): incompatible " + + std::string(overloads->is_constructor ? "constructor" : "function") + + " arguments. The following argument types are supported:\n"; + + int ctr = 0; + for (function_record *it2 = overloads; it2 != nullptr; it2 = it2->next) { + msg += " "+ std::to_string(++ctr) + ". "; + + bool wrote_sig = false; + if (overloads->is_constructor) { + // For a constructor, rewrite `(self: Object, arg0, ...) -> NoneType` as `Object(arg0, ...)` + std::string sig = it2->signature; + size_t start = sig.find('(') + 7; // skip "(self: " + if (start < sig.size()) { + // End at the , for the next argument + size_t end = sig.find(", "), next = end + 2; + size_t ret = sig.rfind(" -> "); + // Or the ), if there is no comma: + if (end >= sig.size()) next = end = sig.find(')'); + if (start < end && next < sig.size()) { + msg.append(sig, start, end - start); + msg += '('; + msg.append(sig, next, ret - next); + wrote_sig = true; + } + } + } + if (!wrote_sig) msg += it2->signature; + + msg += "\n"; + } + msg += "\nInvoked with: "; + auto args_ = reinterpret_borrow(args_in); + bool some_args = false; + for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) { + if (!some_args) some_args = true; + else msg += ", "; + msg += pybind11::repr(args_[ti]); + } + if (kwargs_in) { + auto kwargs = reinterpret_borrow(kwargs_in); + if (kwargs.size() > 0) { + if (some_args) msg += "; "; + msg += "kwargs: "; + bool first = true; + for (auto kwarg : kwargs) { + if (first) first = false; + else msg += ", "; + msg += pybind11::str("{}={!r}").format(kwarg.first, kwarg.second); + } + } + } + + append_note_if_missing_header_is_suspected(msg); + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return nullptr; + } else if (!result) { + std::string msg = "Unable to convert function return value to a " + "Python type! The signature was\n\t"; + msg += it->signature; + append_note_if_missing_header_is_suspected(msg); + PyErr_SetString(PyExc_TypeError, msg.c_str()); + return nullptr; + } else { + if (overloads->is_constructor && !self_value_and_holder.holder_constructed()) { + auto *pi = reinterpret_cast(parent.ptr()); + self_value_and_holder.type->init_instance(pi, nullptr); + } + return result.ptr(); + } + } +}; + +/// Wrapper for Python extension modules +class module : public object { +public: + PYBIND11_OBJECT_DEFAULT(module, object, PyModule_Check) + + /// Create a new top-level Python module with the given name and docstring + explicit module(const char *name, const char *doc = nullptr) { + if (!options::show_user_defined_docstrings()) doc = nullptr; +#if PY_MAJOR_VERSION >= 3 + PyModuleDef *def = new PyModuleDef(); + std::memset(def, 0, sizeof(PyModuleDef)); + def->m_name = name; + def->m_doc = doc; + def->m_size = -1; + Py_INCREF(def); + m_ptr = PyModule_Create(def); +#else + m_ptr = Py_InitModule3(name, nullptr, doc); +#endif + if (m_ptr == nullptr) + pybind11_fail("Internal error in module::module()"); + inc_ref(); + } + + /** \rst + Create Python binding for a new function within the module scope. ``Func`` + can be a plain C++ function, a function pointer, or a lambda function. For + details on the ``Extra&& ... extra`` argument, see section :ref:`extras`. + \endrst */ + template + module &def(const char *name_, Func &&f, const Extra& ... extra) { + cpp_function func(std::forward(f), name(name_), scope(*this), + sibling(getattr(*this, name_, none())), extra...); + // NB: allow overwriting here because cpp_function sets up a chain with the intention of + // overwriting (and has already checked internally that it isn't overwriting non-functions). + add_object(name_, func, true /* overwrite */); + return *this; + } + + /** \rst + Create and return a new Python submodule with the given name and docstring. + This also works recursively, i.e. + + .. code-block:: cpp + + py::module m("example", "pybind11 example plugin"); + py::module m2 = m.def_submodule("sub", "A submodule of 'example'"); + py::module m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'"); + \endrst */ + module def_submodule(const char *name, const char *doc = nullptr) { + std::string full_name = std::string(PyModule_GetName(m_ptr)) + + std::string(".") + std::string(name); + auto result = reinterpret_borrow(PyImport_AddModule(full_name.c_str())); + if (doc && options::show_user_defined_docstrings()) + result.attr("__doc__") = pybind11::str(doc); + attr(name) = result; + return result; + } + + /// Import and return a module or throws `error_already_set`. + static module import(const char *name) { + PyObject *obj = PyImport_ImportModule(name); + if (!obj) + throw error_already_set(); + return reinterpret_steal(obj); + } + + /// Reload the module or throws `error_already_set`. + void reload() { + PyObject *obj = PyImport_ReloadModule(ptr()); + if (!obj) + throw error_already_set(); + *this = reinterpret_steal(obj); + } + + // Adds an object to the module using the given name. Throws if an object with the given name + // already exists. + // + // overwrite should almost always be false: attempting to overwrite objects that pybind11 has + // established will, in most cases, break things. + PYBIND11_NOINLINE void add_object(const char *name, handle obj, bool overwrite = false) { + if (!overwrite && hasattr(*this, name)) + pybind11_fail("Error during initialization: multiple incompatible definitions with name \"" + + std::string(name) + "\""); + + PyModule_AddObject(ptr(), name, obj.inc_ref().ptr() /* steals a reference */); + } +}; + +/// \ingroup python_builtins +/// Return a dictionary representing the global variables in the current execution frame, +/// or ``__main__.__dict__`` if there is no frame (usually when the interpreter is embedded). +inline dict globals() { + PyObject *p = PyEval_GetGlobals(); + return reinterpret_borrow(p ? p : module::import("__main__").attr("__dict__").ptr()); +} + +NAMESPACE_BEGIN(detail) +/// Generic support for creating new Python heap types +class generic_type : public object { + template friend class class_; +public: + PYBIND11_OBJECT_DEFAULT(generic_type, object, PyType_Check) +protected: + void initialize(const type_record &rec) { + if (rec.scope && hasattr(rec.scope, rec.name)) + pybind11_fail("generic_type: cannot initialize type \"" + std::string(rec.name) + + "\": an object with that name is already defined"); + + if (rec.module_local ? get_local_type_info(*rec.type) : get_global_type_info(*rec.type)) + pybind11_fail("generic_type: type \"" + std::string(rec.name) + + "\" is already registered!"); + + m_ptr = make_new_python_type(rec); + + /* Register supplemental type information in C++ dict */ + auto *tinfo = new detail::type_info(); + tinfo->type = (PyTypeObject *) m_ptr; + tinfo->cpptype = rec.type; + tinfo->type_size = rec.type_size; + tinfo->operator_new = rec.operator_new; + tinfo->holder_size_in_ptrs = size_in_ptrs(rec.holder_size); + tinfo->init_instance = rec.init_instance; + tinfo->dealloc = rec.dealloc; + tinfo->simple_type = true; + tinfo->simple_ancestors = true; + tinfo->default_holder = rec.default_holder; + tinfo->module_local = rec.module_local; + + auto &internals = get_internals(); + auto tindex = std::type_index(*rec.type); + tinfo->direct_conversions = &internals.direct_conversions[tindex]; + if (rec.module_local) + registered_local_types_cpp()[tindex] = tinfo; + else + internals.registered_types_cpp[tindex] = tinfo; + internals.registered_types_py[(PyTypeObject *) m_ptr] = { tinfo }; + + if (rec.bases.size() > 1 || rec.multiple_inheritance) { + mark_parents_nonsimple(tinfo->type); + tinfo->simple_ancestors = false; + } + else if (rec.bases.size() == 1) { + auto parent_tinfo = get_type_info((PyTypeObject *) rec.bases[0].ptr()); + tinfo->simple_ancestors = parent_tinfo->simple_ancestors; + } + + if (rec.module_local) { + // Stash the local typeinfo and loader so that external modules can access it. + tinfo->module_local_load = &type_caster_generic::local_load; + setattr(m_ptr, PYBIND11_MODULE_LOCAL_ID, capsule(tinfo)); + } + } + + /// Helper function which tags all parents of a type using mult. inheritance + void mark_parents_nonsimple(PyTypeObject *value) { + auto t = reinterpret_borrow(value->tp_bases); + for (handle h : t) { + auto tinfo2 = get_type_info((PyTypeObject *) h.ptr()); + if (tinfo2) + tinfo2->simple_type = false; + mark_parents_nonsimple((PyTypeObject *) h.ptr()); + } + } + + void install_buffer_funcs( + buffer_info *(*get_buffer)(PyObject *, void *), + void *get_buffer_data) { + PyHeapTypeObject *type = (PyHeapTypeObject*) m_ptr; + auto tinfo = detail::get_type_info(&type->ht_type); + + if (!type->ht_type.tp_as_buffer) + pybind11_fail( + "To be able to register buffer protocol support for the type '" + + std::string(tinfo->type->tp_name) + + "' the associated class<>(..) invocation must " + "include the pybind11::buffer_protocol() annotation!"); + + tinfo->get_buffer = get_buffer; + tinfo->get_buffer_data = get_buffer_data; + } + + void def_property_static_impl(const char *name, + handle fget, handle fset, + detail::function_record *rec_fget) { + const auto is_static = !(rec_fget->is_method && rec_fget->scope); + const auto has_doc = rec_fget->doc && pybind11::options::show_user_defined_docstrings(); + + auto property = handle((PyObject *) (is_static ? get_internals().static_property_type + : &PyProperty_Type)); + attr(name) = property(fget.ptr() ? fget : none(), + fset.ptr() ? fset : none(), + /*deleter*/none(), + pybind11::str(has_doc ? rec_fget->doc : "")); + } +}; + +/// Set the pointer to operator new if it exists. The cast is needed because it can be overloaded. +template (T::operator new))>> +void set_operator_new(type_record *r) { r->operator_new = &T::operator new; } + +template void set_operator_new(...) { } + +template struct has_operator_delete : std::false_type { }; +template struct has_operator_delete(T::operator delete))>> + : std::true_type { }; +template struct has_operator_delete_size : std::false_type { }; +template struct has_operator_delete_size(T::operator delete))>> + : std::true_type { }; +/// Call class-specific delete if it exists or global otherwise. Can also be an overload set. +template ::value, int> = 0> +void call_operator_delete(T *p, size_t) { T::operator delete(p); } +template ::value && has_operator_delete_size::value, int> = 0> +void call_operator_delete(T *p, size_t s) { T::operator delete(p, s); } + +inline void call_operator_delete(void *p, size_t) { ::operator delete(p); } + +NAMESPACE_END(detail) + +/// Given a pointer to a member function, cast it to its `Derived` version. +/// Forward everything else unchanged. +template +auto method_adaptor(F &&f) -> decltype(std::forward(f)) { return std::forward(f); } + +template +auto method_adaptor(Return (Class::*pmf)(Args...)) -> Return (Derived::*)(Args...) { return pmf; } + +template +auto method_adaptor(Return (Class::*pmf)(Args...) const) -> Return (Derived::*)(Args...) const { return pmf; } + +template +class class_ : public detail::generic_type { + template using is_holder = detail::is_holder_type; + template using is_subtype = detail::is_strict_base_of; + template using is_base = detail::is_strict_base_of; + // struct instead of using here to help MSVC: + template struct is_valid_class_option : + detail::any_of, is_subtype, is_base> {}; + +public: + using type = type_; + using type_alias = detail::exactly_one_t; + constexpr static bool has_alias = !std::is_void::value; + using holder_type = detail::exactly_one_t, options...>; + + static_assert(detail::all_of...>::value, + "Unknown/invalid class_ template parameters provided"); + + static_assert(!has_alias || std::is_polymorphic::value, + "Cannot use an alias class with a non-polymorphic type"); + + PYBIND11_OBJECT(class_, generic_type, PyType_Check) + + template + class_(handle scope, const char *name, const Extra &... extra) { + using namespace detail; + + // MI can only be specified via class_ template options, not constructor parameters + static_assert( + none_of...>::value || // no base class arguments, or: + ( constexpr_sum(is_pyobject::value...) == 1 && // Exactly one base + constexpr_sum(is_base::value...) == 0 && // no template option bases + none_of...>::value), // no multiple_inheritance attr + "Error: multiple inheritance bases must be specified via class_ template options"); + + type_record record; + record.scope = scope; + record.name = name; + record.type = &typeid(type); + record.type_size = sizeof(conditional_t); + record.holder_size = sizeof(holder_type); + record.init_instance = init_instance; + record.dealloc = dealloc; + record.default_holder = std::is_same>::value; + + set_operator_new(&record); + + /* Register base classes specified via template arguments to class_, if any */ + PYBIND11_EXPAND_SIDE_EFFECTS(add_base(record)); + + /* Process optional arguments, if any */ + process_attributes::init(extra..., &record); + + generic_type::initialize(record); + + if (has_alias) { + auto &instances = record.module_local ? registered_local_types_cpp() : get_internals().registered_types_cpp; + instances[std::type_index(typeid(type_alias))] = instances[std::type_index(typeid(type))]; + } + } + + template ::value, int> = 0> + static void add_base(detail::type_record &rec) { + rec.add_base(typeid(Base), [](void *src) -> void * { + return static_cast(reinterpret_cast(src)); + }); + } + + template ::value, int> = 0> + static void add_base(detail::type_record &) { } + + template + class_ &def(const char *name_, Func&& f, const Extra&... extra) { + cpp_function cf(method_adaptor(std::forward(f)), name(name_), is_method(*this), + sibling(getattr(*this, name_, none())), extra...); + attr(cf.name()) = cf; + return *this; + } + + template class_ & + def_static(const char *name_, Func &&f, const Extra&... extra) { + static_assert(!std::is_member_function_pointer::value, + "def_static(...) called with a non-static member function pointer"); + cpp_function cf(std::forward(f), name(name_), scope(*this), + sibling(getattr(*this, name_, none())), extra...); + attr(cf.name()) = cf; + return *this; + } + + template + class_ &def(const detail::op_ &op, const Extra&... extra) { + op.execute(*this, extra...); + return *this; + } + + template + class_ & def_cast(const detail::op_ &op, const Extra&... extra) { + op.execute_cast(*this, extra...); + return *this; + } + + template + class_ &def(const detail::initimpl::constructor &init, const Extra&... extra) { + init.execute(*this, extra...); + return *this; + } + + template + class_ &def(const detail::initimpl::alias_constructor &init, const Extra&... extra) { + init.execute(*this, extra...); + return *this; + } + + template + class_ &def(detail::initimpl::factory &&init, const Extra&... extra) { + std::move(init).execute(*this, extra...); + return *this; + } + + template + class_ &def(detail::initimpl::pickle_factory &&pf, const Extra &...extra) { + std::move(pf).execute(*this, extra...); + return *this; + } + + template class_& def_buffer(Func &&func) { + struct capture { Func func; }; + capture *ptr = new capture { std::forward(func) }; + install_buffer_funcs([](PyObject *obj, void *ptr) -> buffer_info* { + detail::make_caster caster; + if (!caster.load(obj, false)) + return nullptr; + return new buffer_info(((capture *) ptr)->func(caster)); + }, ptr); + return *this; + } + + template + class_ &def_buffer(Return (Class::*func)(Args...)) { + return def_buffer([func] (type &obj) { return (obj.*func)(); }); + } + + template + class_ &def_buffer(Return (Class::*func)(Args...) const) { + return def_buffer([func] (const type &obj) { return (obj.*func)(); }); + } + + template + class_ &def_readwrite(const char *name, D C::*pm, const Extra&... extra) { + static_assert(std::is_base_of::value, "def_readwrite() requires a class member (or base class member)"); + cpp_function fget([pm](const type &c) -> const D &{ return c.*pm; }, is_method(*this)), + fset([pm](type &c, const D &value) { c.*pm = value; }, is_method(*this)); + def_property(name, fget, fset, return_value_policy::reference_internal, extra...); + return *this; + } + + template + class_ &def_readonly(const char *name, const D C::*pm, const Extra& ...extra) { + static_assert(std::is_base_of::value, "def_readonly() requires a class member (or base class member)"); + cpp_function fget([pm](const type &c) -> const D &{ return c.*pm; }, is_method(*this)); + def_property_readonly(name, fget, return_value_policy::reference_internal, extra...); + return *this; + } + + template + class_ &def_readwrite_static(const char *name, D *pm, const Extra& ...extra) { + cpp_function fget([pm](object) -> const D &{ return *pm; }, scope(*this)), + fset([pm](object, const D &value) { *pm = value; }, scope(*this)); + def_property_static(name, fget, fset, return_value_policy::reference, extra...); + return *this; + } + + template + class_ &def_readonly_static(const char *name, const D *pm, const Extra& ...extra) { + cpp_function fget([pm](object) -> const D &{ return *pm; }, scope(*this)); + def_property_readonly_static(name, fget, return_value_policy::reference, extra...); + return *this; + } + + /// Uses return_value_policy::reference_internal by default + template + class_ &def_property_readonly(const char *name, const Getter &fget, const Extra& ...extra) { + return def_property_readonly(name, cpp_function(method_adaptor(fget)), + return_value_policy::reference_internal, extra...); + } + + /// Uses cpp_function's return_value_policy by default + template + class_ &def_property_readonly(const char *name, const cpp_function &fget, const Extra& ...extra) { + return def_property(name, fget, cpp_function(), extra...); + } + + /// Uses return_value_policy::reference by default + template + class_ &def_property_readonly_static(const char *name, const Getter &fget, const Extra& ...extra) { + return def_property_readonly_static(name, cpp_function(fget), return_value_policy::reference, extra...); + } + + /// Uses cpp_function's return_value_policy by default + template + class_ &def_property_readonly_static(const char *name, const cpp_function &fget, const Extra& ...extra) { + return def_property_static(name, fget, cpp_function(), extra...); + } + + /// Uses return_value_policy::reference_internal by default + template + class_ &def_property(const char *name, const Getter &fget, const Setter &fset, const Extra& ...extra) { + return def_property(name, fget, cpp_function(method_adaptor(fset)), extra...); + } + template + class_ &def_property(const char *name, const Getter &fget, const cpp_function &fset, const Extra& ...extra) { + return def_property(name, cpp_function(method_adaptor(fget)), fset, + return_value_policy::reference_internal, extra...); + } + + /// Uses cpp_function's return_value_policy by default + template + class_ &def_property(const char *name, const cpp_function &fget, const cpp_function &fset, const Extra& ...extra) { + return def_property_static(name, fget, fset, is_method(*this), extra...); + } + + /// Uses return_value_policy::reference by default + template + class_ &def_property_static(const char *name, const Getter &fget, const cpp_function &fset, const Extra& ...extra) { + return def_property_static(name, cpp_function(fget), fset, return_value_policy::reference, extra...); + } + + /// Uses cpp_function's return_value_policy by default + template + class_ &def_property_static(const char *name, const cpp_function &fget, const cpp_function &fset, const Extra& ...extra) { + auto rec_fget = get_function_record(fget), rec_fset = get_function_record(fset); + char *doc_prev = rec_fget->doc; /* 'extra' field may include a property-specific documentation string */ + detail::process_attributes::init(extra..., rec_fget); + if (rec_fget->doc && rec_fget->doc != doc_prev) { + free(doc_prev); + rec_fget->doc = strdup(rec_fget->doc); + } + if (rec_fset) { + doc_prev = rec_fset->doc; + detail::process_attributes::init(extra..., rec_fset); + if (rec_fset->doc && rec_fset->doc != doc_prev) { + free(doc_prev); + rec_fset->doc = strdup(rec_fset->doc); + } + } + def_property_static_impl(name, fget, fset, rec_fget); + return *this; + } + +private: + /// Initialize holder object, variant 1: object derives from enable_shared_from_this + template + static void init_holder(detail::instance *inst, detail::value_and_holder &v_h, + const holder_type * /* unused */, const std::enable_shared_from_this * /* dummy */) { + try { + auto sh = std::dynamic_pointer_cast( + v_h.value_ptr()->shared_from_this()); + if (sh) { + new (&v_h.holder()) holder_type(std::move(sh)); + v_h.set_holder_constructed(); + } + } catch (const std::bad_weak_ptr &) {} + + if (!v_h.holder_constructed() && inst->owned) { + new (&v_h.holder()) holder_type(v_h.value_ptr()); + v_h.set_holder_constructed(); + } + } + + static void init_holder_from_existing(const detail::value_and_holder &v_h, + const holder_type *holder_ptr, std::true_type /*is_copy_constructible*/) { + new (&v_h.holder()) holder_type(*reinterpret_cast(holder_ptr)); + } + + static void init_holder_from_existing(const detail::value_and_holder &v_h, + const holder_type *holder_ptr, std::false_type /*is_copy_constructible*/) { + new (&v_h.holder()) holder_type(std::move(*const_cast(holder_ptr))); + } + + /// Initialize holder object, variant 2: try to construct from existing holder object, if possible + static void init_holder(detail::instance *inst, detail::value_and_holder &v_h, + const holder_type *holder_ptr, const void * /* dummy -- not enable_shared_from_this) */) { + if (holder_ptr) { + init_holder_from_existing(v_h, holder_ptr, std::is_copy_constructible()); + v_h.set_holder_constructed(); + } else if (inst->owned || detail::always_construct_holder::value) { + new (&v_h.holder()) holder_type(v_h.value_ptr()); + v_h.set_holder_constructed(); + } + } + + /// Performs instance initialization including constructing a holder and registering the known + /// instance. Should be called as soon as the `type` value_ptr is set for an instance. Takes an + /// optional pointer to an existing holder to use; if not specified and the instance is + /// `.owned`, a new holder will be constructed to manage the value pointer. + static void init_instance(detail::instance *inst, const void *holder_ptr) { + auto v_h = inst->get_value_and_holder(detail::get_type_info(typeid(type))); + if (!v_h.instance_registered()) { + register_instance(inst, v_h.value_ptr(), v_h.type); + v_h.set_instance_registered(); + } + init_holder(inst, v_h, (const holder_type *) holder_ptr, v_h.value_ptr()); + } + + /// Deallocates an instance; via holder, if constructed; otherwise via operator delete. + static void dealloc(detail::value_and_holder &v_h) { + if (v_h.holder_constructed()) { + v_h.holder().~holder_type(); + v_h.set_holder_constructed(false); + } + else { + detail::call_operator_delete(v_h.value_ptr(), v_h.type->type_size); + } + v_h.value_ptr() = nullptr; + } + + static detail::function_record *get_function_record(handle h) { + h = detail::get_function(h); + return h ? (detail::function_record *) reinterpret_borrow(PyCFunction_GET_SELF(h.ptr())) + : nullptr; + } +}; + +/// Binds an existing constructor taking arguments Args... +template detail::initimpl::constructor init() { return {}; } +/// Like `init()`, but the instance is always constructed through the alias class (even +/// when not inheriting on the Python side). +template detail::initimpl::alias_constructor init_alias() { return {}; } + +/// Binds a factory function as a constructor +template > +Ret init(Func &&f) { return {std::forward(f)}; } + +/// Dual-argument factory function: the first function is called when no alias is needed, the second +/// when an alias is needed (i.e. due to python-side inheritance). Arguments must be identical. +template > +Ret init(CFunc &&c, AFunc &&a) { + return {std::forward(c), std::forward(a)}; +} + +/// Binds pickling functions `__getstate__` and `__setstate__` and ensures that the type +/// returned by `__getstate__` is the same as the argument accepted by `__setstate__`. +template +detail::initimpl::pickle_factory pickle(GetState &&g, SetState &&s) { + return {std::forward(g), std::forward(s)}; +} + +/// Binds C++ enumerations and enumeration classes to Python +template class enum_ : public class_ { +public: + using class_::def; + using class_::def_property_readonly_static; + using Scalar = typename std::underlying_type::type; + + template + enum_(const handle &scope, const char *name, const Extra&... extra) + : class_(scope, name, extra...), m_entries(), m_parent(scope) { + + constexpr bool is_arithmetic = detail::any_of...>::value; + + auto m_entries_ptr = m_entries.inc_ref().ptr(); + def("__repr__", [name, m_entries_ptr](Type value) -> pybind11::str { + for (const auto &kv : reinterpret_borrow(m_entries_ptr)) { + if (pybind11::cast(kv.second) == value) + return pybind11::str("{}.{}").format(name, kv.first); + } + return pybind11::str("{}.???").format(name); + }); + def_property_readonly_static("__members__", [m_entries_ptr](object /* self */) { + dict m; + for (const auto &kv : reinterpret_borrow(m_entries_ptr)) + m[kv.first] = kv.second; + return m; + }, return_value_policy::copy); + def(init([](Scalar i) { return static_cast(i); })); + def("__int__", [](Type value) { return (Scalar) value; }); + #if PY_MAJOR_VERSION < 3 + def("__long__", [](Type value) { return (Scalar) value; }); + #endif + def("__eq__", [](const Type &value, Type *value2) { return value2 && value == *value2; }); + def("__ne__", [](const Type &value, Type *value2) { return !value2 || value != *value2; }); + if (is_arithmetic) { + def("__lt__", [](const Type &value, Type *value2) { return value2 && value < *value2; }); + def("__gt__", [](const Type &value, Type *value2) { return value2 && value > *value2; }); + def("__le__", [](const Type &value, Type *value2) { return value2 && value <= *value2; }); + def("__ge__", [](const Type &value, Type *value2) { return value2 && value >= *value2; }); + } + if (std::is_convertible::value) { + // Don't provide comparison with the underlying type if the enum isn't convertible, + // i.e. if Type is a scoped enum, mirroring the C++ behaviour. (NB: we explicitly + // convert Type to Scalar below anyway because this needs to compile). + def("__eq__", [](const Type &value, Scalar value2) { return (Scalar) value == value2; }); + def("__ne__", [](const Type &value, Scalar value2) { return (Scalar) value != value2; }); + if (is_arithmetic) { + def("__lt__", [](const Type &value, Scalar value2) { return (Scalar) value < value2; }); + def("__gt__", [](const Type &value, Scalar value2) { return (Scalar) value > value2; }); + def("__le__", [](const Type &value, Scalar value2) { return (Scalar) value <= value2; }); + def("__ge__", [](const Type &value, Scalar value2) { return (Scalar) value >= value2; }); + def("__invert__", [](const Type &value) { return ~((Scalar) value); }); + def("__and__", [](const Type &value, Scalar value2) { return (Scalar) value & value2; }); + def("__or__", [](const Type &value, Scalar value2) { return (Scalar) value | value2; }); + def("__xor__", [](const Type &value, Scalar value2) { return (Scalar) value ^ value2; }); + def("__rand__", [](const Type &value, Scalar value2) { return (Scalar) value & value2; }); + def("__ror__", [](const Type &value, Scalar value2) { return (Scalar) value | value2; }); + def("__rxor__", [](const Type &value, Scalar value2) { return (Scalar) value ^ value2; }); + def("__and__", [](const Type &value, const Type &value2) { return (Scalar) value & (Scalar) value2; }); + def("__or__", [](const Type &value, const Type &value2) { return (Scalar) value | (Scalar) value2; }); + def("__xor__", [](const Type &value, const Type &value2) { return (Scalar) value ^ (Scalar) value2; }); + } + } + def("__hash__", [](const Type &value) { return (Scalar) value; }); + // Pickling and unpickling -- needed for use with the 'multiprocessing' module + def(pickle([](const Type &value) { return pybind11::make_tuple((Scalar) value); }, + [](tuple t) { return static_cast(t[0].cast()); })); + } + + /// Export enumeration entries into the parent scope + enum_& export_values() { + for (const auto &kv : m_entries) + m_parent.attr(kv.first) = kv.second; + return *this; + } + + /// Add an enumeration entry + enum_& value(char const* name, Type value) { + auto v = pybind11::cast(value, return_value_policy::copy); + this->attr(name) = v; + m_entries[pybind11::str(name)] = v; + return *this; + } + +private: + dict m_entries; + handle m_parent; +}; + +NAMESPACE_BEGIN(detail) + + +inline void keep_alive_impl(handle nurse, handle patient) { + if (!nurse || !patient) + pybind11_fail("Could not activate keep_alive!"); + + if (patient.is_none() || nurse.is_none()) + return; /* Nothing to keep alive or nothing to be kept alive by */ + + auto tinfo = all_type_info(Py_TYPE(nurse.ptr())); + if (!tinfo.empty()) { + /* It's a pybind-registered type, so we can store the patient in the + * internal list. */ + add_patient(nurse.ptr(), patient.ptr()); + } + else { + /* Fall back to clever approach based on weak references taken from + * Boost.Python. This is not used for pybind-registered types because + * the objects can be destroyed out-of-order in a GC pass. */ + cpp_function disable_lifesupport( + [patient](handle weakref) { patient.dec_ref(); weakref.dec_ref(); }); + + weakref wr(nurse, disable_lifesupport); + + patient.inc_ref(); /* reference patient and leak the weak reference */ + (void) wr.release(); + } +} + +PYBIND11_NOINLINE inline void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret) { + auto get_arg = [&](size_t n) { + if (n == 0) + return ret; + else if (n == 1 && call.init_self) + return call.init_self; + else if (n <= call.args.size()) + return call.args[n - 1]; + return handle(); + }; + + keep_alive_impl(get_arg(Nurse), get_arg(Patient)); +} + +inline std::pair all_type_info_get_cache(PyTypeObject *type) { + auto res = get_internals().registered_types_py +#ifdef __cpp_lib_unordered_map_try_emplace + .try_emplace(type); +#else + .emplace(type, std::vector()); +#endif + if (res.second) { + // New cache entry created; set up a weak reference to automatically remove it if the type + // gets destroyed: + weakref((PyObject *) type, cpp_function([type](handle wr) { + get_internals().registered_types_py.erase(type); + wr.dec_ref(); + })).release(); + } + + return res; +} + +template +struct iterator_state { + Iterator it; + Sentinel end; + bool first_or_done; +}; + +NAMESPACE_END(detail) + +/// Makes a python iterator from a first and past-the-end C++ InputIterator. +template ()), + typename... Extra> +iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) { + typedef detail::iterator_state state; + + if (!detail::get_type_info(typeid(state), false)) { + class_(handle(), "iterator", pybind11::module_local()) + .def("__iter__", [](state &s) -> state& { return s; }) + .def("__next__", [](state &s) -> ValueType { + if (!s.first_or_done) + ++s.it; + else + s.first_or_done = false; + if (s.it == s.end) { + s.first_or_done = true; + throw stop_iteration(); + } + return *s.it; + }, std::forward(extra)..., Policy); + } + + return cast(state{first, last, true}); +} + +/// Makes an python iterator over the keys (`.first`) of a iterator over pairs from a +/// first and past-the-end InputIterator. +template ()).first), + typename... Extra> +iterator make_key_iterator(Iterator first, Sentinel last, Extra &&... extra) { + typedef detail::iterator_state state; + + if (!detail::get_type_info(typeid(state), false)) { + class_(handle(), "iterator", pybind11::module_local()) + .def("__iter__", [](state &s) -> state& { return s; }) + .def("__next__", [](state &s) -> KeyType { + if (!s.first_or_done) + ++s.it; + else + s.first_or_done = false; + if (s.it == s.end) { + s.first_or_done = true; + throw stop_iteration(); + } + return (*s.it).first; + }, std::forward(extra)..., Policy); + } + + return cast(state{first, last, true}); +} + +/// Makes an iterator over values of an stl container or other container supporting +/// `std::begin()`/`std::end()` +template iterator make_iterator(Type &value, Extra&&... extra) { + return make_iterator(std::begin(value), std::end(value), extra...); +} + +/// Makes an iterator over the keys (`.first`) of a stl map-like container supporting +/// `std::begin()`/`std::end()` +template iterator make_key_iterator(Type &value, Extra&&... extra) { + return make_key_iterator(std::begin(value), std::end(value), extra...); +} + +template void implicitly_convertible() { + struct set_flag { + bool &flag; + set_flag(bool &flag) : flag(flag) { flag = true; } + ~set_flag() { flag = false; } + }; + auto implicit_caster = [](PyObject *obj, PyTypeObject *type) -> PyObject * { + static bool currently_used = false; + if (currently_used) // implicit conversions are non-reentrant + return nullptr; + set_flag flag_helper(currently_used); + if (!detail::make_caster().load(obj, false)) + return nullptr; + tuple args(1); + args[0] = obj; + PyObject *result = PyObject_Call((PyObject *) type, args.ptr(), nullptr); + if (result == nullptr) + PyErr_Clear(); + return result; + }; + + if (auto tinfo = detail::get_type_info(typeid(OutputType))) + tinfo->implicit_conversions.push_back(implicit_caster); + else + pybind11_fail("implicitly_convertible: Unable to find type " + type_id()); +} + +template +void register_exception_translator(ExceptionTranslator&& translator) { + detail::get_internals().registered_exception_translators.push_front( + std::forward(translator)); +} + +/** + * Wrapper to generate a new Python exception type. + * + * This should only be used with PyErr_SetString for now. + * It is not (yet) possible to use as a py::base. + * Template type argument is reserved for future use. + */ +template +class exception : public object { +public: + exception(handle scope, const char *name, PyObject *base = PyExc_Exception) { + std::string full_name = scope.attr("__name__").cast() + + std::string(".") + name; + m_ptr = PyErr_NewException(const_cast(full_name.c_str()), base, NULL); + if (hasattr(scope, name)) + pybind11_fail("Error during initialization: multiple incompatible " + "definitions with name \"" + std::string(name) + "\""); + scope.attr(name) = *this; + } + + // Sets the current python exception to this exception object with the given message + void operator()(const char *message) { + PyErr_SetString(m_ptr, message); + } +}; + +/** + * Registers a Python exception in `m` of the given `name` and installs an exception translator to + * translate the C++ exception to the created Python exception using the exceptions what() method. + * This is intended for simple exception translations; for more complex translation, register the + * exception object and translator directly. + */ +template +exception ®ister_exception(handle scope, + const char *name, + PyObject *base = PyExc_Exception) { + static exception ex(scope, name, base); + register_exception_translator([](std::exception_ptr p) { + if (!p) return; + try { + std::rethrow_exception(p); + } catch (const CppException &e) { + ex(e.what()); + } + }); + return ex; +} + +NAMESPACE_BEGIN(detail) +PYBIND11_NOINLINE inline void print(tuple args, dict kwargs) { + auto strings = tuple(args.size()); + for (size_t i = 0; i < args.size(); ++i) { + strings[i] = str(args[i]); + } + auto sep = kwargs.contains("sep") ? kwargs["sep"] : cast(" "); + auto line = sep.attr("join")(strings); + + object file; + if (kwargs.contains("file")) { + file = kwargs["file"].cast(); + } else { + try { + file = module::import("sys").attr("stdout"); + } catch (const error_already_set &) { + /* If print() is called from code that is executed as + part of garbage collection during interpreter shutdown, + importing 'sys' can fail. Give up rather than crashing the + interpreter in this case. */ + return; + } + } + + auto write = file.attr("write"); + write(line); + write(kwargs.contains("end") ? kwargs["end"] : cast("\n")); + + if (kwargs.contains("flush") && kwargs["flush"].cast()) + file.attr("flush")(); +} +NAMESPACE_END(detail) + +template +void print(Args &&...args) { + auto c = detail::collect_arguments(std::forward(args)...); + detail::print(c.args(), c.kwargs()); +} + +#if defined(WITH_THREAD) && !defined(PYPY_VERSION) + +/* The functions below essentially reproduce the PyGILState_* API using a RAII + * pattern, but there are a few important differences: + * + * 1. When acquiring the GIL from an non-main thread during the finalization + * phase, the GILState API blindly terminates the calling thread, which + * is often not what is wanted. This API does not do this. + * + * 2. The gil_scoped_release function can optionally cut the relationship + * of a PyThreadState and its associated thread, which allows moving it to + * another thread (this is a fairly rare/advanced use case). + * + * 3. The reference count of an acquired thread state can be controlled. This + * can be handy to prevent cases where callbacks issued from an external + * thread would otherwise constantly construct and destroy thread state data + * structures. + * + * See the Python bindings of NanoGUI (http://github.com/wjakob/nanogui) for an + * example which uses features 2 and 3 to migrate the Python thread of + * execution to another thread (to run the event loop on the original thread, + * in this case). + */ + +class gil_scoped_acquire { +public: + PYBIND11_NOINLINE gil_scoped_acquire() { + auto const &internals = detail::get_internals(); + tstate = (PyThreadState *) PyThread_get_key_value(internals.tstate); + + if (!tstate) { + tstate = PyThreadState_New(internals.istate); + #if !defined(NDEBUG) + if (!tstate) + pybind11_fail("scoped_acquire: could not create thread state!"); + #endif + tstate->gilstate_counter = 0; + #if PY_MAJOR_VERSION < 3 + PyThread_delete_key_value(internals.tstate); + #endif + PyThread_set_key_value(internals.tstate, tstate); + } else { + release = detail::get_thread_state_unchecked() != tstate; + } + + if (release) { + /* Work around an annoying assertion in PyThreadState_Swap */ + #if defined(Py_DEBUG) + PyInterpreterState *interp = tstate->interp; + tstate->interp = nullptr; + #endif + PyEval_AcquireThread(tstate); + #if defined(Py_DEBUG) + tstate->interp = interp; + #endif + } + + inc_ref(); + } + + void inc_ref() { + ++tstate->gilstate_counter; + } + + PYBIND11_NOINLINE void dec_ref() { + --tstate->gilstate_counter; + #if !defined(NDEBUG) + if (detail::get_thread_state_unchecked() != tstate) + pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!"); + if (tstate->gilstate_counter < 0) + pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!"); + #endif + if (tstate->gilstate_counter == 0) { + #if !defined(NDEBUG) + if (!release) + pybind11_fail("scoped_acquire::dec_ref(): internal error!"); + #endif + PyThreadState_Clear(tstate); + PyThreadState_DeleteCurrent(); + PyThread_delete_key_value(detail::get_internals().tstate); + release = false; + } + } + + PYBIND11_NOINLINE ~gil_scoped_acquire() { + dec_ref(); + if (release) + PyEval_SaveThread(); + } +private: + PyThreadState *tstate = nullptr; + bool release = true; +}; + +class gil_scoped_release { +public: + explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) { + // `get_internals()` must be called here unconditionally in order to initialize + // `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an + // initialization race could occur as multiple threads try `gil_scoped_acquire`. + const auto &internals = detail::get_internals(); + tstate = PyEval_SaveThread(); + if (disassoc) { + auto key = internals.tstate; + #if PY_MAJOR_VERSION < 3 + PyThread_delete_key_value(key); + #else + PyThread_set_key_value(key, nullptr); + #endif + } + } + ~gil_scoped_release() { + if (!tstate) + return; + PyEval_RestoreThread(tstate); + if (disassoc) { + auto key = detail::get_internals().tstate; + #if PY_MAJOR_VERSION < 3 + PyThread_delete_key_value(key); + #endif + PyThread_set_key_value(key, tstate); + } + } +private: + PyThreadState *tstate; + bool disassoc; +}; +#elif defined(PYPY_VERSION) +class gil_scoped_acquire { + PyGILState_STATE state; +public: + gil_scoped_acquire() { state = PyGILState_Ensure(); } + ~gil_scoped_acquire() { PyGILState_Release(state); } +}; + +class gil_scoped_release { + PyThreadState *state; +public: + gil_scoped_release() { state = PyEval_SaveThread(); } + ~gil_scoped_release() { PyEval_RestoreThread(state); } +}; +#else +class gil_scoped_acquire { }; +class gil_scoped_release { }; +#endif + +error_already_set::~error_already_set() { + if (type) { + gil_scoped_acquire gil; + type.release().dec_ref(); + value.release().dec_ref(); + trace.release().dec_ref(); + } +} + +inline function get_type_overload(const void *this_ptr, const detail::type_info *this_type, const char *name) { + handle self = detail::get_object_handle(this_ptr, this_type); + if (!self) + return function(); + handle type = self.get_type(); + auto key = std::make_pair(type.ptr(), name); + + /* Cache functions that aren't overloaded in Python to avoid + many costly Python dictionary lookups below */ + auto &cache = detail::get_internals().inactive_overload_cache; + if (cache.find(key) != cache.end()) + return function(); + + function overload = getattr(self, name, function()); + if (overload.is_cpp_function()) { + cache.insert(key); + return function(); + } + + /* Don't call dispatch code if invoked from overridden function. + Unfortunately this doesn't work on PyPy. */ +#if !defined(PYPY_VERSION) + PyFrameObject *frame = PyThreadState_Get()->frame; + if (frame && (std::string) str(frame->f_code->co_name) == name && + frame->f_code->co_argcount > 0) { + PyFrame_FastToLocals(frame); + PyObject *self_caller = PyDict_GetItem( + frame->f_locals, PyTuple_GET_ITEM(frame->f_code->co_varnames, 0)); + if (self_caller == self.ptr()) + return function(); + } +#else + /* PyPy currently doesn't provide a detailed cpyext emulation of + frame objects, so we have to emulate this using Python. This + is going to be slow..*/ + dict d; d["self"] = self; d["name"] = pybind11::str(name); + PyObject *result = PyRun_String( + "import inspect\n" + "frame = inspect.currentframe()\n" + "if frame is not None:\n" + " frame = frame.f_back\n" + " if frame is not None and str(frame.f_code.co_name) == name and " + "frame.f_code.co_argcount > 0:\n" + " self_caller = frame.f_locals[frame.f_code.co_varnames[0]]\n" + " if self_caller == self:\n" + " self = None\n", + Py_file_input, d.ptr(), d.ptr()); + if (result == nullptr) + throw error_already_set(); + if (d["self"].is_none()) + return function(); + Py_DECREF(result); +#endif + + return overload; +} + +template function get_overload(const T *this_ptr, const char *name) { + auto tinfo = detail::get_type_info(typeid(T)); + return tinfo ? get_type_overload(this_ptr, tinfo, name) : function(); +} + +#define PYBIND11_OVERLOAD_INT(ret_type, cname, name, ...) { \ + pybind11::gil_scoped_acquire gil; \ + pybind11::function overload = pybind11::get_overload(static_cast(this), name); \ + if (overload) { \ + auto o = overload(__VA_ARGS__); \ + if (pybind11::detail::cast_is_temporary_value_reference::value) { \ + static pybind11::detail::overload_caster_t caster; \ + return pybind11::detail::cast_ref(std::move(o), caster); \ + } \ + else return pybind11::detail::cast_safe(std::move(o)); \ + } \ + } + +#define PYBIND11_OVERLOAD_NAME(ret_type, cname, name, fn, ...) \ + PYBIND11_OVERLOAD_INT(ret_type, cname, name, __VA_ARGS__) \ + return cname::fn(__VA_ARGS__) + +#define PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, name, fn, ...) \ + PYBIND11_OVERLOAD_INT(ret_type, cname, name, __VA_ARGS__) \ + pybind11::pybind11_fail("Tried to call pure virtual function \"" #cname "::" name "\""); + +#define PYBIND11_OVERLOAD(ret_type, cname, fn, ...) \ + PYBIND11_OVERLOAD_NAME(ret_type, cname, #fn, fn, __VA_ARGS__) + +#define PYBIND11_OVERLOAD_PURE(ret_type, cname, fn, ...) \ + PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, #fn, fn, __VA_ARGS__) + +NAMESPACE_END(PYBIND11_NAMESPACE) + +#if defined(_MSC_VER) +# pragma warning(pop) +#elif defined(__INTEL_COMPILER) +/* Leave ignored warnings on */ +#elif defined(__GNUG__) && !defined(__clang__) +# pragma GCC diagnostic pop +#endif diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/pytypes.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/pytypes.h new file mode 100644 index 00000000..d7fa1777 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/pytypes.h @@ -0,0 +1,1332 @@ +/* + pybind11/pytypes.h: Convenience wrapper classes for basic Python types + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "detail/common.h" +#include "buffer_info.h" +#include +#include + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +/* A few forward declarations */ +class handle; class object; +class str; class iterator; +struct arg; struct arg_v; + +NAMESPACE_BEGIN(detail) +class args_proxy; +inline bool isinstance_generic(handle obj, const std::type_info &tp); + +// Accessor forward declarations +template class accessor; +namespace accessor_policies { + struct obj_attr; + struct str_attr; + struct generic_item; + struct sequence_item; + struct list_item; + struct tuple_item; +} +using obj_attr_accessor = accessor; +using str_attr_accessor = accessor; +using item_accessor = accessor; +using sequence_accessor = accessor; +using list_accessor = accessor; +using tuple_accessor = accessor; + +/// Tag and check to identify a class which implements the Python object API +class pyobject_tag { }; +template using is_pyobject = std::is_base_of>; + +/** \rst + A mixin class which adds common functions to `handle`, `object` and various accessors. + The only requirement for `Derived` is to implement ``PyObject *Derived::ptr() const``. +\endrst */ +template +class object_api : public pyobject_tag { + const Derived &derived() const { return static_cast(*this); } + +public: + /** \rst + Return an iterator equivalent to calling ``iter()`` in Python. The object + must be a collection which supports the iteration protocol. + \endrst */ + iterator begin() const; + /// Return a sentinel which ends iteration. + iterator end() const; + + /** \rst + Return an internal functor to invoke the object's sequence protocol. Casting + the returned ``detail::item_accessor`` instance to a `handle` or `object` + subclass causes a corresponding call to ``__getitem__``. Assigning a `handle` + or `object` subclass causes a call to ``__setitem__``. + \endrst */ + item_accessor operator[](handle key) const; + /// See above (the only difference is that they key is provided as a string literal) + item_accessor operator[](const char *key) const; + + /** \rst + Return an internal functor to access the object's attributes. Casting the + returned ``detail::obj_attr_accessor`` instance to a `handle` or `object` + subclass causes a corresponding call to ``getattr``. Assigning a `handle` + or `object` subclass causes a call to ``setattr``. + \endrst */ + obj_attr_accessor attr(handle key) const; + /// See above (the only difference is that they key is provided as a string literal) + str_attr_accessor attr(const char *key) const; + + /** \rst + Matches * unpacking in Python, e.g. to unpack arguments out of a ``tuple`` + or ``list`` for a function call. Applying another * to the result yields + ** unpacking, e.g. to unpack a dict as function keyword arguments. + See :ref:`calling_python_functions`. + \endrst */ + args_proxy operator*() const; + + /// Check if the given item is contained within this object, i.e. ``item in obj``. + template bool contains(T &&item) const; + + /** \rst + Assuming the Python object is a function or implements the ``__call__`` + protocol, ``operator()`` invokes the underlying function, passing an + arbitrary set of parameters. The result is returned as a `object` and + may need to be converted back into a Python object using `handle::cast()`. + + When some of the arguments cannot be converted to Python objects, the + function will throw a `cast_error` exception. When the Python function + call fails, a `error_already_set` exception is thrown. + \endrst */ + template + object operator()(Args &&...args) const; + template + PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)") + object call(Args&&... args) const; + + /// Equivalent to ``obj is other`` in Python. + bool is(object_api const& other) const { return derived().ptr() == other.derived().ptr(); } + /// Equivalent to ``obj is None`` in Python. + bool is_none() const { return derived().ptr() == Py_None; } + PYBIND11_DEPRECATED("Use py::str(obj) instead") + pybind11::str str() const; + + /// Get or set the object's docstring, i.e. ``obj.__doc__``. + str_attr_accessor doc() const; + + /// Return the object's current reference count + int ref_count() const { return static_cast(Py_REFCNT(derived().ptr())); } + /// Return a handle to the Python type object underlying the instance + handle get_type() const; +}; + +NAMESPACE_END(detail) + +/** \rst + Holds a reference to a Python object (no reference counting) + + The `handle` class is a thin wrapper around an arbitrary Python object (i.e. a + ``PyObject *`` in Python's C API). It does not perform any automatic reference + counting and merely provides a basic C++ interface to various Python API functions. + + .. seealso:: + The `object` class inherits from `handle` and adds automatic reference + counting features. +\endrst */ +class handle : public detail::object_api { +public: + /// The default constructor creates a handle with a ``nullptr``-valued pointer + handle() = default; + /// Creates a ``handle`` from the given raw Python object pointer + handle(PyObject *ptr) : m_ptr(ptr) { } // Allow implicit conversion from PyObject* + + /// Return the underlying ``PyObject *`` pointer + PyObject *ptr() const { return m_ptr; } + PyObject *&ptr() { return m_ptr; } + + /** \rst + Manually increase the reference count of the Python object. Usually, it is + preferable to use the `object` class which derives from `handle` and calls + this function automatically. Returns a reference to itself. + \endrst */ + const handle& inc_ref() const & { Py_XINCREF(m_ptr); return *this; } + + /** \rst + Manually decrease the reference count of the Python object. Usually, it is + preferable to use the `object` class which derives from `handle` and calls + this function automatically. Returns a reference to itself. + \endrst */ + const handle& dec_ref() const & { Py_XDECREF(m_ptr); return *this; } + + /** \rst + Attempt to cast the Python object into the given C++ type. A `cast_error` + will be throw upon failure. + \endrst */ + template T cast() const; + /// Return ``true`` when the `handle` wraps a valid Python object + explicit operator bool() const { return m_ptr != nullptr; } + /** \rst + Deprecated: Check that the underlying pointers are the same. + Equivalent to ``obj1 is obj2`` in Python. + \endrst */ + PYBIND11_DEPRECATED("Use obj1.is(obj2) instead") + bool operator==(const handle &h) const { return m_ptr == h.m_ptr; } + PYBIND11_DEPRECATED("Use !obj1.is(obj2) instead") + bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; } + PYBIND11_DEPRECATED("Use handle::operator bool() instead") + bool check() const { return m_ptr != nullptr; } +protected: + PyObject *m_ptr = nullptr; +}; + +/** \rst + Holds a reference to a Python object (with reference counting) + + Like `handle`, the `object` class is a thin wrapper around an arbitrary Python + object (i.e. a ``PyObject *`` in Python's C API). In contrast to `handle`, it + optionally increases the object's reference count upon construction, and it + *always* decreases the reference count when the `object` instance goes out of + scope and is destructed. When using `object` instances consistently, it is much + easier to get reference counting right at the first attempt. +\endrst */ +class object : public handle { +public: + object() = default; + PYBIND11_DEPRECATED("Use reinterpret_borrow() or reinterpret_steal()") + object(handle h, bool is_borrowed) : handle(h) { if (is_borrowed) inc_ref(); } + /// Copy constructor; always increases the reference count + object(const object &o) : handle(o) { inc_ref(); } + /// Move constructor; steals the object from ``other`` and preserves its reference count + object(object &&other) noexcept { m_ptr = other.m_ptr; other.m_ptr = nullptr; } + /// Destructor; automatically calls `handle::dec_ref()` + ~object() { dec_ref(); } + + /** \rst + Resets the internal pointer to ``nullptr`` without without decreasing the + object's reference count. The function returns a raw handle to the original + Python object. + \endrst */ + handle release() { + PyObject *tmp = m_ptr; + m_ptr = nullptr; + return handle(tmp); + } + + object& operator=(const object &other) { + other.inc_ref(); + dec_ref(); + m_ptr = other.m_ptr; + return *this; + } + + object& operator=(object &&other) noexcept { + if (this != &other) { + handle temp(m_ptr); + m_ptr = other.m_ptr; + other.m_ptr = nullptr; + temp.dec_ref(); + } + return *this; + } + + // Calling cast() on an object lvalue just copies (via handle::cast) + template T cast() const &; + // Calling on an object rvalue does a move, if needed and/or possible + template T cast() &&; + +protected: + // Tags for choosing constructors from raw PyObject * + struct borrowed_t { }; + struct stolen_t { }; + + template friend T reinterpret_borrow(handle); + template friend T reinterpret_steal(handle); + +public: + // Only accessible from derived classes and the reinterpret_* functions + object(handle h, borrowed_t) : handle(h) { inc_ref(); } + object(handle h, stolen_t) : handle(h) { } +}; + +/** \rst + Declare that a `handle` or ``PyObject *`` is a certain type and borrow the reference. + The target type ``T`` must be `object` or one of its derived classes. The function + doesn't do any conversions or checks. It's up to the user to make sure that the + target type is correct. + + .. code-block:: cpp + + PyObject *p = PyList_GetItem(obj, index); + py::object o = reinterpret_borrow(p); + // or + py::tuple t = reinterpret_borrow(p); // <-- `p` must be already be a `tuple` +\endrst */ +template T reinterpret_borrow(handle h) { return {h, object::borrowed_t{}}; } + +/** \rst + Like `reinterpret_borrow`, but steals the reference. + + .. code-block:: cpp + + PyObject *p = PyObject_Str(obj); + py::str s = reinterpret_steal(p); // <-- `p` must be already be a `str` +\endrst */ +template T reinterpret_steal(handle h) { return {h, object::stolen_t{}}; } + +NAMESPACE_BEGIN(detail) +inline std::string error_string(); +NAMESPACE_END(detail) + +/// Fetch and hold an error which was already set in Python. An instance of this is typically +/// thrown to propagate python-side errors back through C++ which can either be caught manually or +/// else falls back to the function dispatcher (which then raises the captured error back to +/// python). +class error_already_set : public std::runtime_error { +public: + /// Constructs a new exception from the current Python error indicator, if any. The current + /// Python error indicator will be cleared. + error_already_set() : std::runtime_error(detail::error_string()) { + PyErr_Fetch(&type.ptr(), &value.ptr(), &trace.ptr()); + } + + inline ~error_already_set(); + + /// Give the currently-held error back to Python, if any. If there is currently a Python error + /// already set it is cleared first. After this call, the current object no longer stores the + /// error variables (but the `.what()` string is still available). + void restore() { PyErr_Restore(type.release().ptr(), value.release().ptr(), trace.release().ptr()); } + + // Does nothing; provided for backwards compatibility. + PYBIND11_DEPRECATED("Use of error_already_set.clear() is deprecated") + void clear() {} + + /// Check if the currently trapped error type matches the given Python exception class (or a + /// subclass thereof). May also be passed a tuple to search for any exception class matches in + /// the given tuple. + bool matches(handle ex) const { return PyErr_GivenExceptionMatches(ex.ptr(), type.ptr()); } + +private: + object type, value, trace; +}; + +/** \defgroup python_builtins _ + Unless stated otherwise, the following C++ functions behave the same + as their Python counterparts. + */ + +/** \ingroup python_builtins + \rst + Return true if ``obj`` is an instance of ``T``. Type ``T`` must be a subclass of + `object` or a class which was exposed to Python as ``py::class_``. +\endrst */ +template ::value, int> = 0> +bool isinstance(handle obj) { return T::check_(obj); } + +template ::value, int> = 0> +bool isinstance(handle obj) { return detail::isinstance_generic(obj, typeid(T)); } + +template <> inline bool isinstance(handle obj) = delete; +template <> inline bool isinstance(handle obj) { return obj.ptr() != nullptr; } + +/// \ingroup python_builtins +/// Return true if ``obj`` is an instance of the ``type``. +inline bool isinstance(handle obj, handle type) { + const auto result = PyObject_IsInstance(obj.ptr(), type.ptr()); + if (result == -1) + throw error_already_set(); + return result != 0; +} + +/// \addtogroup python_builtins +/// @{ +inline bool hasattr(handle obj, handle name) { + return PyObject_HasAttr(obj.ptr(), name.ptr()) == 1; +} + +inline bool hasattr(handle obj, const char *name) { + return PyObject_HasAttrString(obj.ptr(), name) == 1; +} + +inline object getattr(handle obj, handle name) { + PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr()); + if (!result) { throw error_already_set(); } + return reinterpret_steal(result); +} + +inline object getattr(handle obj, const char *name) { + PyObject *result = PyObject_GetAttrString(obj.ptr(), name); + if (!result) { throw error_already_set(); } + return reinterpret_steal(result); +} + +inline object getattr(handle obj, handle name, handle default_) { + if (PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr())) { + return reinterpret_steal(result); + } else { + PyErr_Clear(); + return reinterpret_borrow(default_); + } +} + +inline object getattr(handle obj, const char *name, handle default_) { + if (PyObject *result = PyObject_GetAttrString(obj.ptr(), name)) { + return reinterpret_steal(result); + } else { + PyErr_Clear(); + return reinterpret_borrow(default_); + } +} + +inline void setattr(handle obj, handle name, handle value) { + if (PyObject_SetAttr(obj.ptr(), name.ptr(), value.ptr()) != 0) { throw error_already_set(); } +} + +inline void setattr(handle obj, const char *name, handle value) { + if (PyObject_SetAttrString(obj.ptr(), name, value.ptr()) != 0) { throw error_already_set(); } +} + +inline ssize_t hash(handle obj) { + auto h = PyObject_Hash(obj.ptr()); + if (h == -1) { throw error_already_set(); } + return h; +} + +/// @} python_builtins + +NAMESPACE_BEGIN(detail) +inline handle get_function(handle value) { + if (value) { +#if PY_MAJOR_VERSION >= 3 + if (PyInstanceMethod_Check(value.ptr())) + value = PyInstanceMethod_GET_FUNCTION(value.ptr()); + else +#endif + if (PyMethod_Check(value.ptr())) + value = PyMethod_GET_FUNCTION(value.ptr()); + } + return value; +} + +// Helper aliases/functions to support implicit casting of values given to python accessors/methods. +// When given a pyobject, this simply returns the pyobject as-is; for other C++ type, the value goes +// through pybind11::cast(obj) to convert it to an `object`. +template ::value, int> = 0> +auto object_or_cast(T &&o) -> decltype(std::forward(o)) { return std::forward(o); } +// The following casting version is implemented in cast.h: +template ::value, int> = 0> +object object_or_cast(T &&o); +// Match a PyObject*, which we want to convert directly to handle via its converting constructor +inline handle object_or_cast(PyObject *ptr) { return ptr; } + + +template +class accessor : public object_api> { + using key_type = typename Policy::key_type; + +public: + accessor(handle obj, key_type key) : obj(obj), key(std::move(key)) { } + accessor(const accessor &) = default; + accessor(accessor &&) = default; + + // accessor overload required to override default assignment operator (templates are not allowed + // to replace default compiler-generated assignments). + void operator=(const accessor &a) && { std::move(*this).operator=(handle(a)); } + void operator=(const accessor &a) & { operator=(handle(a)); } + + template void operator=(T &&value) && { + Policy::set(obj, key, object_or_cast(std::forward(value))); + } + template void operator=(T &&value) & { + get_cache() = reinterpret_borrow(object_or_cast(std::forward(value))); + } + + template + PYBIND11_DEPRECATED("Use of obj.attr(...) as bool is deprecated in favor of pybind11::hasattr(obj, ...)") + explicit operator enable_if_t::value || + std::is_same::value, bool>() const { + return hasattr(obj, key); + } + template + PYBIND11_DEPRECATED("Use of obj[key] as bool is deprecated in favor of obj.contains(key)") + explicit operator enable_if_t::value, bool>() const { + return obj.contains(key); + } + + operator object() const { return get_cache(); } + PyObject *ptr() const { return get_cache().ptr(); } + template T cast() const { return get_cache().template cast(); } + +private: + object &get_cache() const { + if (!cache) { cache = Policy::get(obj, key); } + return cache; + } + +private: + handle obj; + key_type key; + mutable object cache; +}; + +NAMESPACE_BEGIN(accessor_policies) +struct obj_attr { + using key_type = object; + static object get(handle obj, handle key) { return getattr(obj, key); } + static void set(handle obj, handle key, handle val) { setattr(obj, key, val); } +}; + +struct str_attr { + using key_type = const char *; + static object get(handle obj, const char *key) { return getattr(obj, key); } + static void set(handle obj, const char *key, handle val) { setattr(obj, key, val); } +}; + +struct generic_item { + using key_type = object; + + static object get(handle obj, handle key) { + PyObject *result = PyObject_GetItem(obj.ptr(), key.ptr()); + if (!result) { throw error_already_set(); } + return reinterpret_steal(result); + } + + static void set(handle obj, handle key, handle val) { + if (PyObject_SetItem(obj.ptr(), key.ptr(), val.ptr()) != 0) { throw error_already_set(); } + } +}; + +struct sequence_item { + using key_type = size_t; + + static object get(handle obj, size_t index) { + PyObject *result = PySequence_GetItem(obj.ptr(), static_cast(index)); + if (!result) { throw error_already_set(); } + return reinterpret_steal(result); + } + + static void set(handle obj, size_t index, handle val) { + // PySequence_SetItem does not steal a reference to 'val' + if (PySequence_SetItem(obj.ptr(), static_cast(index), val.ptr()) != 0) { + throw error_already_set(); + } + } +}; + +struct list_item { + using key_type = size_t; + + static object get(handle obj, size_t index) { + PyObject *result = PyList_GetItem(obj.ptr(), static_cast(index)); + if (!result) { throw error_already_set(); } + return reinterpret_borrow(result); + } + + static void set(handle obj, size_t index, handle val) { + // PyList_SetItem steals a reference to 'val' + if (PyList_SetItem(obj.ptr(), static_cast(index), val.inc_ref().ptr()) != 0) { + throw error_already_set(); + } + } +}; + +struct tuple_item { + using key_type = size_t; + + static object get(handle obj, size_t index) { + PyObject *result = PyTuple_GetItem(obj.ptr(), static_cast(index)); + if (!result) { throw error_already_set(); } + return reinterpret_borrow(result); + } + + static void set(handle obj, size_t index, handle val) { + // PyTuple_SetItem steals a reference to 'val' + if (PyTuple_SetItem(obj.ptr(), static_cast(index), val.inc_ref().ptr()) != 0) { + throw error_already_set(); + } + } +}; +NAMESPACE_END(accessor_policies) + +/// STL iterator template used for tuple, list, sequence and dict +template +class generic_iterator : public Policy { + using It = generic_iterator; + +public: + using difference_type = ssize_t; + using iterator_category = typename Policy::iterator_category; + using value_type = typename Policy::value_type; + using reference = typename Policy::reference; + using pointer = typename Policy::pointer; + + generic_iterator() = default; + generic_iterator(handle seq, ssize_t index) : Policy(seq, index) { } + + reference operator*() const { return Policy::dereference(); } + reference operator[](difference_type n) const { return *(*this + n); } + pointer operator->() const { return **this; } + + It &operator++() { Policy::increment(); return *this; } + It operator++(int) { auto copy = *this; Policy::increment(); return copy; } + It &operator--() { Policy::decrement(); return *this; } + It operator--(int) { auto copy = *this; Policy::decrement(); return copy; } + It &operator+=(difference_type n) { Policy::advance(n); return *this; } + It &operator-=(difference_type n) { Policy::advance(-n); return *this; } + + friend It operator+(const It &a, difference_type n) { auto copy = a; return copy += n; } + friend It operator+(difference_type n, const It &b) { return b + n; } + friend It operator-(const It &a, difference_type n) { auto copy = a; return copy -= n; } + friend difference_type operator-(const It &a, const It &b) { return a.distance_to(b); } + + friend bool operator==(const It &a, const It &b) { return a.equal(b); } + friend bool operator!=(const It &a, const It &b) { return !(a == b); } + friend bool operator< (const It &a, const It &b) { return b - a > 0; } + friend bool operator> (const It &a, const It &b) { return b < a; } + friend bool operator>=(const It &a, const It &b) { return !(a < b); } + friend bool operator<=(const It &a, const It &b) { return !(a > b); } +}; + +NAMESPACE_BEGIN(iterator_policies) +/// Quick proxy class needed to implement ``operator->`` for iterators which can't return pointers +template +struct arrow_proxy { + T value; + + arrow_proxy(T &&value) : value(std::move(value)) { } + T *operator->() const { return &value; } +}; + +/// Lightweight iterator policy using just a simple pointer: see ``PySequence_Fast_ITEMS`` +class sequence_fast_readonly { +protected: + using iterator_category = std::random_access_iterator_tag; + using value_type = handle; + using reference = const handle; + using pointer = arrow_proxy; + + sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) { } + + reference dereference() const { return *ptr; } + void increment() { ++ptr; } + void decrement() { --ptr; } + void advance(ssize_t n) { ptr += n; } + bool equal(const sequence_fast_readonly &b) const { return ptr == b.ptr; } + ssize_t distance_to(const sequence_fast_readonly &b) const { return ptr - b.ptr; } + +private: + PyObject **ptr; +}; + +/// Full read and write access using the sequence protocol: see ``detail::sequence_accessor`` +class sequence_slow_readwrite { +protected: + using iterator_category = std::random_access_iterator_tag; + using value_type = object; + using reference = sequence_accessor; + using pointer = arrow_proxy; + + sequence_slow_readwrite(handle obj, ssize_t index) : obj(obj), index(index) { } + + reference dereference() const { return {obj, static_cast(index)}; } + void increment() { ++index; } + void decrement() { --index; } + void advance(ssize_t n) { index += n; } + bool equal(const sequence_slow_readwrite &b) const { return index == b.index; } + ssize_t distance_to(const sequence_slow_readwrite &b) const { return index - b.index; } + +private: + handle obj; + ssize_t index; +}; + +/// Python's dictionary protocol permits this to be a forward iterator +class dict_readonly { +protected: + using iterator_category = std::forward_iterator_tag; + using value_type = std::pair; + using reference = const value_type; + using pointer = arrow_proxy; + + dict_readonly() = default; + dict_readonly(handle obj, ssize_t pos) : obj(obj), pos(pos) { increment(); } + + reference dereference() const { return {key, value}; } + void increment() { if (!PyDict_Next(obj.ptr(), &pos, &key, &value)) { pos = -1; } } + bool equal(const dict_readonly &b) const { return pos == b.pos; } + +private: + handle obj; + PyObject *key, *value; + ssize_t pos = -1; +}; +NAMESPACE_END(iterator_policies) + +#if !defined(PYPY_VERSION) +using tuple_iterator = generic_iterator; +using list_iterator = generic_iterator; +#else +using tuple_iterator = generic_iterator; +using list_iterator = generic_iterator; +#endif + +using sequence_iterator = generic_iterator; +using dict_iterator = generic_iterator; + +inline bool PyIterable_Check(PyObject *obj) { + PyObject *iter = PyObject_GetIter(obj); + if (iter) { + Py_DECREF(iter); + return true; + } else { + PyErr_Clear(); + return false; + } +} + +inline bool PyNone_Check(PyObject *o) { return o == Py_None; } + +inline bool PyUnicode_Check_Permissive(PyObject *o) { return PyUnicode_Check(o) || PYBIND11_BYTES_CHECK(o); } + +class kwargs_proxy : public handle { +public: + explicit kwargs_proxy(handle h) : handle(h) { } +}; + +class args_proxy : public handle { +public: + explicit args_proxy(handle h) : handle(h) { } + kwargs_proxy operator*() const { return kwargs_proxy(*this); } +}; + +/// Python argument categories (using PEP 448 terms) +template using is_keyword = std::is_base_of; +template using is_s_unpacking = std::is_same; // * unpacking +template using is_ds_unpacking = std::is_same; // ** unpacking +template using is_positional = satisfies_none_of; +template using is_keyword_or_ds = satisfies_any_of; + +// Call argument collector forward declarations +template +class simple_collector; +template +class unpacking_collector; + +NAMESPACE_END(detail) + +// TODO: After the deprecated constructors are removed, this macro can be simplified by +// inheriting ctors: `using Parent::Parent`. It's not an option right now because +// the `using` statement triggers the parent deprecation warning even if the ctor +// isn't even used. +#define PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \ + public: \ + PYBIND11_DEPRECATED("Use reinterpret_borrow<"#Name">() or reinterpret_steal<"#Name">()") \ + Name(handle h, bool is_borrowed) : Parent(is_borrowed ? Parent(h, borrowed_t{}) : Parent(h, stolen_t{})) { } \ + Name(handle h, borrowed_t) : Parent(h, borrowed_t{}) { } \ + Name(handle h, stolen_t) : Parent(h, stolen_t{}) { } \ + PYBIND11_DEPRECATED("Use py::isinstance(obj) instead") \ + bool check() const { return m_ptr != nullptr && (bool) CheckFun(m_ptr); } \ + static bool check_(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); } + +#define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun) \ + PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \ + /* This is deliberately not 'explicit' to allow implicit conversion from object: */ \ + Name(const object &o) \ + : Parent(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) \ + { if (!m_ptr) throw error_already_set(); } \ + Name(object &&o) \ + : Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) \ + { if (!m_ptr) throw error_already_set(); } \ + template \ + Name(const ::pybind11::detail::accessor &a) : Name(object(a)) { } + +#define PYBIND11_OBJECT(Name, Parent, CheckFun) \ + PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun) \ + /* This is deliberately not 'explicit' to allow implicit conversion from object: */ \ + Name(const object &o) : Parent(o) { } \ + Name(object &&o) : Parent(std::move(o)) { } + +#define PYBIND11_OBJECT_DEFAULT(Name, Parent, CheckFun) \ + PYBIND11_OBJECT(Name, Parent, CheckFun) \ + Name() : Parent() { } + +/// \addtogroup pytypes +/// @{ + +/** \rst + Wraps a Python iterator so that it can also be used as a C++ input iterator + + Caveat: copying an iterator does not (and cannot) clone the internal + state of the Python iterable. This also applies to the post-increment + operator. This iterator should only be used to retrieve the current + value using ``operator*()``. +\endrst */ +class iterator : public object { +public: + using iterator_category = std::input_iterator_tag; + using difference_type = ssize_t; + using value_type = handle; + using reference = const handle; + using pointer = const handle *; + + PYBIND11_OBJECT_DEFAULT(iterator, object, PyIter_Check) + + iterator& operator++() { + advance(); + return *this; + } + + iterator operator++(int) { + auto rv = *this; + advance(); + return rv; + } + + reference operator*() const { + if (m_ptr && !value.ptr()) { + auto& self = const_cast(*this); + self.advance(); + } + return value; + } + + pointer operator->() const { operator*(); return &value; } + + /** \rst + The value which marks the end of the iteration. ``it == iterator::sentinel()`` + is equivalent to catching ``StopIteration`` in Python. + + .. code-block:: cpp + + void foo(py::iterator it) { + while (it != py::iterator::sentinel()) { + // use `*it` + ++it; + } + } + \endrst */ + static iterator sentinel() { return {}; } + + friend bool operator==(const iterator &a, const iterator &b) { return a->ptr() == b->ptr(); } + friend bool operator!=(const iterator &a, const iterator &b) { return a->ptr() != b->ptr(); } + +private: + void advance() { + value = reinterpret_steal(PyIter_Next(m_ptr)); + if (PyErr_Occurred()) { throw error_already_set(); } + } + +private: + object value = {}; +}; + +class iterable : public object { +public: + PYBIND11_OBJECT_DEFAULT(iterable, object, detail::PyIterable_Check) +}; + +class bytes; + +class str : public object { +public: + PYBIND11_OBJECT_CVT(str, object, detail::PyUnicode_Check_Permissive, raw_str) + + str(const char *c, size_t n) + : object(PyUnicode_FromStringAndSize(c, (ssize_t) n), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate string object!"); + } + + // 'explicit' is explicitly omitted from the following constructors to allow implicit conversion to py::str from C++ string-like objects + str(const char *c = "") + : object(PyUnicode_FromString(c), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate string object!"); + } + + str(const std::string &s) : str(s.data(), s.size()) { } + + explicit str(const bytes &b); + + /** \rst + Return a string representation of the object. This is analogous to + the ``str()`` function in Python. + \endrst */ + explicit str(handle h) : object(raw_str(h.ptr()), stolen_t{}) { } + + operator std::string() const { + object temp = *this; + if (PyUnicode_Check(m_ptr)) { + temp = reinterpret_steal(PyUnicode_AsUTF8String(m_ptr)); + if (!temp) + pybind11_fail("Unable to extract string contents! (encoding issue)"); + } + char *buffer; + ssize_t length; + if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) + pybind11_fail("Unable to extract string contents! (invalid type)"); + return std::string(buffer, (size_t) length); + } + + template + str format(Args &&...args) const { + return attr("format")(std::forward(args)...); + } + +private: + /// Return string representation -- always returns a new reference, even if already a str + static PyObject *raw_str(PyObject *op) { + PyObject *str_value = PyObject_Str(op); +#if PY_MAJOR_VERSION < 3 + if (!str_value) throw error_already_set(); + PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr); + Py_XDECREF(str_value); str_value = unicode; +#endif + return str_value; + } +}; +/// @} pytypes + +inline namespace literals { +/** \rst + String literal version of `str` + \endrst */ +inline str operator"" _s(const char *s, size_t size) { return {s, size}; } +} + +/// \addtogroup pytypes +/// @{ +class bytes : public object { +public: + PYBIND11_OBJECT(bytes, object, PYBIND11_BYTES_CHECK) + + // Allow implicit conversion: + bytes(const char *c = "") + : object(PYBIND11_BYTES_FROM_STRING(c), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate bytes object!"); + } + + bytes(const char *c, size_t n) + : object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(c, (ssize_t) n), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate bytes object!"); + } + + // Allow implicit conversion: + bytes(const std::string &s) : bytes(s.data(), s.size()) { } + + explicit bytes(const pybind11::str &s); + + operator std::string() const { + char *buffer; + ssize_t length; + if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) + pybind11_fail("Unable to extract bytes contents!"); + return std::string(buffer, (size_t) length); + } +}; + +inline bytes::bytes(const pybind11::str &s) { + object temp = s; + if (PyUnicode_Check(s.ptr())) { + temp = reinterpret_steal(PyUnicode_AsUTF8String(s.ptr())); + if (!temp) + pybind11_fail("Unable to extract string contents! (encoding issue)"); + } + char *buffer; + ssize_t length; + if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) + pybind11_fail("Unable to extract string contents! (invalid type)"); + auto obj = reinterpret_steal(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length)); + if (!obj) + pybind11_fail("Could not allocate bytes object!"); + m_ptr = obj.release().ptr(); +} + +inline str::str(const bytes& b) { + char *buffer; + ssize_t length; + if (PYBIND11_BYTES_AS_STRING_AND_SIZE(b.ptr(), &buffer, &length)) + pybind11_fail("Unable to extract bytes contents!"); + auto obj = reinterpret_steal(PyUnicode_FromStringAndSize(buffer, (ssize_t) length)); + if (!obj) + pybind11_fail("Could not allocate string object!"); + m_ptr = obj.release().ptr(); +} + +class none : public object { +public: + PYBIND11_OBJECT(none, object, detail::PyNone_Check) + none() : object(Py_None, borrowed_t{}) { } +}; + +class bool_ : public object { +public: + PYBIND11_OBJECT_CVT(bool_, object, PyBool_Check, raw_bool) + bool_() : object(Py_False, borrowed_t{}) { } + // Allow implicit conversion from and to `bool`: + bool_(bool value) : object(value ? Py_True : Py_False, borrowed_t{}) { } + operator bool() const { return m_ptr && PyLong_AsLong(m_ptr) != 0; } + +private: + /// Return the truth value of an object -- always returns a new reference + static PyObject *raw_bool(PyObject *op) { + const auto value = PyObject_IsTrue(op); + if (value == -1) return nullptr; + return handle(value ? Py_True : Py_False).inc_ref().ptr(); + } +}; + +NAMESPACE_BEGIN(detail) +// Converts a value to the given unsigned type. If an error occurs, you get back (Unsigned) -1; +// otherwise you get back the unsigned long or unsigned long long value cast to (Unsigned). +// (The distinction is critically important when casting a returned -1 error value to some other +// unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes). +template +Unsigned as_unsigned(PyObject *o) { + if (sizeof(Unsigned) <= sizeof(unsigned long) +#if PY_VERSION_HEX < 0x03000000 + || PyInt_Check(o) +#endif + ) { + unsigned long v = PyLong_AsUnsignedLong(o); + return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v; + } + else { + unsigned long long v = PyLong_AsUnsignedLongLong(o); + return v == (unsigned long long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v; + } +} +NAMESPACE_END(detail) + +class int_ : public object { +public: + PYBIND11_OBJECT_CVT(int_, object, PYBIND11_LONG_CHECK, PyNumber_Long) + int_() : object(PyLong_FromLong(0), stolen_t{}) { } + // Allow implicit conversion from C++ integral types: + template ::value, int> = 0> + int_(T value) { + if (sizeof(T) <= sizeof(long)) { + if (std::is_signed::value) + m_ptr = PyLong_FromLong((long) value); + else + m_ptr = PyLong_FromUnsignedLong((unsigned long) value); + } else { + if (std::is_signed::value) + m_ptr = PyLong_FromLongLong((long long) value); + else + m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value); + } + if (!m_ptr) pybind11_fail("Could not allocate int object!"); + } + + template ::value, int> = 0> + operator T() const { + return std::is_unsigned::value + ? detail::as_unsigned(m_ptr) + : sizeof(T) <= sizeof(long) + ? (T) PyLong_AsLong(m_ptr) + : (T) PYBIND11_LONG_AS_LONGLONG(m_ptr); + } +}; + +class float_ : public object { +public: + PYBIND11_OBJECT_CVT(float_, object, PyFloat_Check, PyNumber_Float) + // Allow implicit conversion from float/double: + float_(float value) : object(PyFloat_FromDouble((double) value), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate float object!"); + } + float_(double value = .0) : object(PyFloat_FromDouble((double) value), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate float object!"); + } + operator float() const { return (float) PyFloat_AsDouble(m_ptr); } + operator double() const { return (double) PyFloat_AsDouble(m_ptr); } +}; + +class weakref : public object { +public: + PYBIND11_OBJECT_DEFAULT(weakref, object, PyWeakref_Check) + explicit weakref(handle obj, handle callback = {}) + : object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate weak reference!"); + } +}; + +class slice : public object { +public: + PYBIND11_OBJECT_DEFAULT(slice, object, PySlice_Check) + slice(ssize_t start_, ssize_t stop_, ssize_t step_) { + int_ start(start_), stop(stop_), step(step_); + m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr()); + if (!m_ptr) pybind11_fail("Could not allocate slice object!"); + } + bool compute(size_t length, size_t *start, size_t *stop, size_t *step, + size_t *slicelength) const { + return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr, + (ssize_t) length, (ssize_t *) start, + (ssize_t *) stop, (ssize_t *) step, + (ssize_t *) slicelength) == 0; + } +}; + +class capsule : public object { +public: + PYBIND11_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact) + PYBIND11_DEPRECATED("Use reinterpret_borrow() or reinterpret_steal()") + capsule(PyObject *ptr, bool is_borrowed) : object(is_borrowed ? object(ptr, borrowed_t{}) : object(ptr, stolen_t{})) { } + + explicit capsule(const void *value, const char *name = nullptr, void (*destructor)(PyObject *) = nullptr) + : object(PyCapsule_New(const_cast(value), name, destructor), stolen_t{}) { + if (!m_ptr) + pybind11_fail("Could not allocate capsule object!"); + } + + PYBIND11_DEPRECATED("Please pass a destructor that takes a void pointer as input") + capsule(const void *value, void (*destruct)(PyObject *)) + : object(PyCapsule_New(const_cast(value), nullptr, destruct), stolen_t{}) { + if (!m_ptr) + pybind11_fail("Could not allocate capsule object!"); + } + + capsule(const void *value, void (*destructor)(void *)) { + m_ptr = PyCapsule_New(const_cast(value), nullptr, [](PyObject *o) { + auto destructor = reinterpret_cast(PyCapsule_GetContext(o)); + void *ptr = PyCapsule_GetPointer(o, nullptr); + destructor(ptr); + }); + + if (!m_ptr) + pybind11_fail("Could not allocate capsule object!"); + + if (PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) + pybind11_fail("Could not set capsule context!"); + } + + capsule(void (*destructor)()) { + m_ptr = PyCapsule_New(reinterpret_cast(destructor), nullptr, [](PyObject *o) { + auto destructor = reinterpret_cast(PyCapsule_GetPointer(o, nullptr)); + destructor(); + }); + + if (!m_ptr) + pybind11_fail("Could not allocate capsule object!"); + } + + template operator T *() const { + auto name = this->name(); + T * result = static_cast(PyCapsule_GetPointer(m_ptr, name)); + if (!result) pybind11_fail("Unable to extract capsule contents!"); + return result; + } + + const char *name() const { return PyCapsule_GetName(m_ptr); } +}; + +class tuple : public object { +public: + PYBIND11_OBJECT_CVT(tuple, object, PyTuple_Check, PySequence_Tuple) + explicit tuple(size_t size = 0) : object(PyTuple_New((ssize_t) size), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate tuple object!"); + } + size_t size() const { return (size_t) PyTuple_Size(m_ptr); } + detail::tuple_accessor operator[](size_t index) const { return {*this, index}; } + detail::tuple_iterator begin() const { return {*this, 0}; } + detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; } +}; + +class dict : public object { +public: + PYBIND11_OBJECT_CVT(dict, object, PyDict_Check, raw_dict) + dict() : object(PyDict_New(), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate dict object!"); + } + template ...>::value>, + // MSVC workaround: it can't compile an out-of-line definition, so defer the collector + typename collector = detail::deferred_t, Args...>> + explicit dict(Args &&...args) : dict(collector(std::forward(args)...).kwargs()) { } + + size_t size() const { return (size_t) PyDict_Size(m_ptr); } + detail::dict_iterator begin() const { return {*this, 0}; } + detail::dict_iterator end() const { return {}; } + void clear() const { PyDict_Clear(ptr()); } + bool contains(handle key) const { return PyDict_Contains(ptr(), key.ptr()) == 1; } + bool contains(const char *key) const { return PyDict_Contains(ptr(), pybind11::str(key).ptr()) == 1; } + +private: + /// Call the `dict` Python type -- always returns a new reference + static PyObject *raw_dict(PyObject *op) { + if (PyDict_Check(op)) + return handle(op).inc_ref().ptr(); + return PyObject_CallFunctionObjArgs((PyObject *) &PyDict_Type, op, nullptr); + } +}; + +class sequence : public object { +public: + PYBIND11_OBJECT_DEFAULT(sequence, object, PySequence_Check) + size_t size() const { return (size_t) PySequence_Size(m_ptr); } + detail::sequence_accessor operator[](size_t index) const { return {*this, index}; } + detail::sequence_iterator begin() const { return {*this, 0}; } + detail::sequence_iterator end() const { return {*this, PySequence_Size(m_ptr)}; } +}; + +class list : public object { +public: + PYBIND11_OBJECT_CVT(list, object, PyList_Check, PySequence_List) + explicit list(size_t size = 0) : object(PyList_New((ssize_t) size), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate list object!"); + } + size_t size() const { return (size_t) PyList_Size(m_ptr); } + detail::list_accessor operator[](size_t index) const { return {*this, index}; } + detail::list_iterator begin() const { return {*this, 0}; } + detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; } + template void append(T &&val) const { + PyList_Append(m_ptr, detail::object_or_cast(std::forward(val)).ptr()); + } +}; + +class args : public tuple { PYBIND11_OBJECT_DEFAULT(args, tuple, PyTuple_Check) }; +class kwargs : public dict { PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check) }; + +class set : public object { +public: + PYBIND11_OBJECT_CVT(set, object, PySet_Check, PySet_New) + set() : object(PySet_New(nullptr), stolen_t{}) { + if (!m_ptr) pybind11_fail("Could not allocate set object!"); + } + size_t size() const { return (size_t) PySet_Size(m_ptr); } + template bool add(T &&val) const { + return PySet_Add(m_ptr, detail::object_or_cast(std::forward(val)).ptr()) == 0; + } + void clear() const { PySet_Clear(m_ptr); } +}; + +class function : public object { +public: + PYBIND11_OBJECT_DEFAULT(function, object, PyCallable_Check) + handle cpp_function() const { + handle fun = detail::get_function(m_ptr); + if (fun && PyCFunction_Check(fun.ptr())) + return fun; + return handle(); + } + bool is_cpp_function() const { return (bool) cpp_function(); } +}; + +class buffer : public object { +public: + PYBIND11_OBJECT_DEFAULT(buffer, object, PyObject_CheckBuffer) + + buffer_info request(bool writable = false) { + int flags = PyBUF_STRIDES | PyBUF_FORMAT; + if (writable) flags |= PyBUF_WRITABLE; + Py_buffer *view = new Py_buffer(); + if (PyObject_GetBuffer(m_ptr, view, flags) != 0) { + delete view; + throw error_already_set(); + } + return buffer_info(view); + } +}; + +class memoryview : public object { +public: + explicit memoryview(const buffer_info& info) { + static Py_buffer buf { }; + // Py_buffer uses signed sizes, strides and shape!.. + static std::vector py_strides { }; + static std::vector py_shape { }; + buf.buf = info.ptr; + buf.itemsize = info.itemsize; + buf.format = const_cast(info.format.c_str()); + buf.ndim = (int) info.ndim; + buf.len = info.size; + py_strides.clear(); + py_shape.clear(); + for (size_t i = 0; i < (size_t) info.ndim; ++i) { + py_strides.push_back(info.strides[i]); + py_shape.push_back(info.shape[i]); + } + buf.strides = py_strides.data(); + buf.shape = py_shape.data(); + buf.suboffsets = nullptr; + buf.readonly = false; + buf.internal = nullptr; + + m_ptr = PyMemoryView_FromBuffer(&buf); + if (!m_ptr) + pybind11_fail("Unable to create memoryview from buffer descriptor"); + } + + PYBIND11_OBJECT_CVT(memoryview, object, PyMemoryView_Check, PyMemoryView_FromObject) +}; +/// @} pytypes + +/// \addtogroup python_builtins +/// @{ +inline size_t len(handle h) { + ssize_t result = PyObject_Length(h.ptr()); + if (result < 0) + pybind11_fail("Unable to compute length of object"); + return (size_t) result; +} + +inline str repr(handle h) { + PyObject *str_value = PyObject_Repr(h.ptr()); + if (!str_value) throw error_already_set(); +#if PY_MAJOR_VERSION < 3 + PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr); + Py_XDECREF(str_value); str_value = unicode; + if (!str_value) throw error_already_set(); +#endif + return reinterpret_steal(str_value); +} + +inline iterator iter(handle obj) { + PyObject *result = PyObject_GetIter(obj.ptr()); + if (!result) { throw error_already_set(); } + return reinterpret_steal(result); +} +/// @} python_builtins + +NAMESPACE_BEGIN(detail) +template iterator object_api::begin() const { return iter(derived()); } +template iterator object_api::end() const { return iterator::sentinel(); } +template item_accessor object_api::operator[](handle key) const { + return {derived(), reinterpret_borrow(key)}; +} +template item_accessor object_api::operator[](const char *key) const { + return {derived(), pybind11::str(key)}; +} +template obj_attr_accessor object_api::attr(handle key) const { + return {derived(), reinterpret_borrow(key)}; +} +template str_attr_accessor object_api::attr(const char *key) const { + return {derived(), key}; +} +template args_proxy object_api::operator*() const { + return args_proxy(derived().ptr()); +} +template template bool object_api::contains(T &&item) const { + return attr("__contains__")(std::forward(item)).template cast(); +} + +template +pybind11::str object_api::str() const { return pybind11::str(derived()); } + +template +str_attr_accessor object_api::doc() const { return attr("__doc__"); } + +template +handle object_api::get_type() const { return (PyObject *) Py_TYPE(derived().ptr()); } + +NAMESPACE_END(detail) +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/stl.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/stl.h new file mode 100644 index 00000000..90eb7ea2 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/stl.h @@ -0,0 +1,370 @@ +/* + pybind11/stl.h: Transparent conversion for STL data types + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "pybind11.h" +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant +#endif + +#ifdef __has_include +// std::optional (but including it in c++14 mode isn't allowed) +# if defined(PYBIND11_CPP17) && __has_include() +# include +# define PYBIND11_HAS_OPTIONAL 1 +# endif +// std::experimental::optional (but not allowed in c++11 mode) +# if defined(PYBIND11_CPP14) && (__has_include() && \ + !__has_include()) +# include +# define PYBIND11_HAS_EXP_OPTIONAL 1 +# endif +// std::variant +# if defined(PYBIND11_CPP17) && __has_include() +# include +# define PYBIND11_HAS_VARIANT 1 +# endif +#elif defined(_MSC_VER) && defined(PYBIND11_CPP17) +# include +# include +# define PYBIND11_HAS_OPTIONAL 1 +# define PYBIND11_HAS_VARIANT 1 +#endif + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +/// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for +/// forwarding a container element). Typically used indirect via forwarded_type(), below. +template +using forwarded_type = conditional_t< + std::is_lvalue_reference::value, remove_reference_t &, remove_reference_t &&>; + +/// Forwards a value U as rvalue or lvalue according to whether T is rvalue or lvalue; typically +/// used for forwarding a container's elements. +template +forwarded_type forward_like(U &&u) { + return std::forward>(std::forward(u)); +} + +template struct set_caster { + using type = Type; + using key_conv = make_caster; + + bool load(handle src, bool convert) { + if (!isinstance(src)) + return false; + auto s = reinterpret_borrow(src); + value.clear(); + for (auto entry : s) { + key_conv conv; + if (!conv.load(entry, convert)) + return false; + value.insert(cast_op(std::move(conv))); + } + return true; + } + + template + static handle cast(T &&src, return_value_policy policy, handle parent) { + pybind11::set s; + for (auto &&value : src) { + auto value_ = reinterpret_steal(key_conv::cast(forward_like(value), policy, parent)); + if (!value_ || !s.add(value_)) + return handle(); + } + return s.release(); + } + + PYBIND11_TYPE_CASTER(type, _("Set[") + key_conv::name() + _("]")); +}; + +template struct map_caster { + using key_conv = make_caster; + using value_conv = make_caster; + + bool load(handle src, bool convert) { + if (!isinstance(src)) + return false; + auto d = reinterpret_borrow(src); + value.clear(); + for (auto it : d) { + key_conv kconv; + value_conv vconv; + if (!kconv.load(it.first.ptr(), convert) || + !vconv.load(it.second.ptr(), convert)) + return false; + value.emplace(cast_op(std::move(kconv)), cast_op(std::move(vconv))); + } + return true; + } + + template + static handle cast(T &&src, return_value_policy policy, handle parent) { + dict d; + for (auto &&kv : src) { + auto key = reinterpret_steal(key_conv::cast(forward_like(kv.first), policy, parent)); + auto value = reinterpret_steal(value_conv::cast(forward_like(kv.second), policy, parent)); + if (!key || !value) + return handle(); + d[key] = value; + } + return d.release(); + } + + PYBIND11_TYPE_CASTER(Type, _("Dict[") + key_conv::name() + _(", ") + value_conv::name() + _("]")); +}; + +template struct list_caster { + using value_conv = make_caster; + + bool load(handle src, bool convert) { + if (!isinstance(src)) + return false; + auto s = reinterpret_borrow(src); + value.clear(); + reserve_maybe(s, &value); + for (auto it : s) { + value_conv conv; + if (!conv.load(it, convert)) + return false; + value.push_back(cast_op(std::move(conv))); + } + return true; + } + +private: + template ().reserve(0)), void>::value, int> = 0> + void reserve_maybe(sequence s, Type *) { value.reserve(s.size()); } + void reserve_maybe(sequence, void *) { } + +public: + template + static handle cast(T &&src, return_value_policy policy, handle parent) { + list l(src.size()); + size_t index = 0; + for (auto &&value : src) { + auto value_ = reinterpret_steal(value_conv::cast(forward_like(value), policy, parent)); + if (!value_) + return handle(); + PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference + } + return l.release(); + } + + PYBIND11_TYPE_CASTER(Type, _("List[") + value_conv::name() + _("]")); +}; + +template struct type_caster> + : list_caster, Type> { }; + +template struct type_caster> + : list_caster, Type> { }; + +template struct array_caster { + using value_conv = make_caster; + +private: + template + bool require_size(enable_if_t size) { + if (value.size() != size) + value.resize(size); + return true; + } + template + bool require_size(enable_if_t size) { + return size == Size; + } + +public: + bool load(handle src, bool convert) { + if (!isinstance(src)) + return false; + auto l = reinterpret_borrow(src); + if (!require_size(l.size())) + return false; + size_t ctr = 0; + for (auto it : l) { + value_conv conv; + if (!conv.load(it, convert)) + return false; + value[ctr++] = cast_op(std::move(conv)); + } + return true; + } + + template + static handle cast(T &&src, return_value_policy policy, handle parent) { + list l(src.size()); + size_t index = 0; + for (auto &&value : src) { + auto value_ = reinterpret_steal(value_conv::cast(forward_like(value), policy, parent)); + if (!value_) + return handle(); + PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference + } + return l.release(); + } + + PYBIND11_TYPE_CASTER(ArrayType, _("List[") + value_conv::name() + _(_(""), _("[") + _() + _("]")) + _("]")); +}; + +template struct type_caster> + : array_caster, Type, false, Size> { }; + +template struct type_caster> + : array_caster, Type, true> { }; + +template struct type_caster> + : set_caster, Key> { }; + +template struct type_caster> + : set_caster, Key> { }; + +template struct type_caster> + : map_caster, Key, Value> { }; + +template struct type_caster> + : map_caster, Key, Value> { }; + +// This type caster is intended to be used for std::optional and std::experimental::optional +template struct optional_caster { + using value_conv = make_caster; + + template + static handle cast(T_ &&src, return_value_policy policy, handle parent) { + if (!src) + return none().inc_ref(); + return value_conv::cast(*std::forward(src), policy, parent); + } + + bool load(handle src, bool convert) { + if (!src) { + return false; + } else if (src.is_none()) { + return true; // default-constructed value is already empty + } + value_conv inner_caster; + if (!inner_caster.load(src, convert)) + return false; + + value.emplace(cast_op(std::move(inner_caster))); + return true; + } + + PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name() + _("]")); +}; + +#if PYBIND11_HAS_OPTIONAL +template struct type_caster> + : public optional_caster> {}; + +template<> struct type_caster + : public void_caster {}; +#endif + +#if PYBIND11_HAS_EXP_OPTIONAL +template struct type_caster> + : public optional_caster> {}; + +template<> struct type_caster + : public void_caster {}; +#endif + +/// Visit a variant and cast any found type to Python +struct variant_caster_visitor { + return_value_policy policy; + handle parent; + + using result_type = handle; // required by boost::variant in C++11 + + template + result_type operator()(T &&src) const { + return make_caster::cast(std::forward(src), policy, parent); + } +}; + +/// Helper class which abstracts away variant's `visit` function. `std::variant` and similar +/// `namespace::variant` types which provide a `namespace::visit()` function are handled here +/// automatically using argument-dependent lookup. Users can provide specializations for other +/// variant-like classes, e.g. `boost::variant` and `boost::apply_visitor`. +template class Variant> +struct visit_helper { + template + static auto call(Args &&...args) -> decltype(visit(std::forward(args)...)) { + return visit(std::forward(args)...); + } +}; + +/// Generic variant caster +template struct variant_caster; + +template class V, typename... Ts> +struct variant_caster> { + static_assert(sizeof...(Ts) > 0, "Variant must consist of at least one alternative."); + + template + bool load_alternative(handle src, bool convert, type_list) { + auto caster = make_caster(); + if (caster.load(src, convert)) { + value = cast_op(caster); + return true; + } + return load_alternative(src, convert, type_list{}); + } + + bool load_alternative(handle, bool, type_list<>) { return false; } + + bool load(handle src, bool convert) { + // Do a first pass without conversions to improve constructor resolution. + // E.g. `py::int_(1).cast>()` needs to fill the `int` + // slot of the variant. Without two-pass loading `double` would be filled + // because it appears first and a conversion is possible. + if (convert && load_alternative(src, false, type_list{})) + return true; + return load_alternative(src, convert, type_list{}); + } + + template + static handle cast(Variant &&src, return_value_policy policy, handle parent) { + return visit_helper::call(variant_caster_visitor{policy, parent}, + std::forward(src)); + } + + using Type = V; + PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster::name()...) + _("]")); +}; + +#if PYBIND11_HAS_VARIANT +template +struct type_caster> : variant_caster> { }; +#endif +NAMESPACE_END(detail) + +inline std::ostream &operator<<(std::ostream &os, const handle &obj) { + os << (std::string) str(obj); + return os; +} + +NAMESPACE_END(PYBIND11_NAMESPACE) + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/stl_bind.h b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/stl_bind.h new file mode 100644 index 00000000..38dd68f6 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/include/pybind11/stl_bind.h @@ -0,0 +1,599 @@ +/* + pybind11/std_bind.h: Binding generators for STL data types + + Copyright (c) 2016 Sergey Lyskov and Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "detail/common.h" +#include "operators.h" + +#include +#include + +NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +NAMESPACE_BEGIN(detail) + +/* SFINAE helper class used by 'is_comparable */ +template struct container_traits { + template static std::true_type test_comparable(decltype(std::declval() == std::declval())*); + template static std::false_type test_comparable(...); + template static std::true_type test_value(typename T2::value_type *); + template static std::false_type test_value(...); + template static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *); + template static std::false_type test_pair(...); + + static constexpr const bool is_comparable = std::is_same(nullptr))>::value; + static constexpr const bool is_pair = std::is_same(nullptr, nullptr))>::value; + static constexpr const bool is_vector = std::is_same(nullptr))>::value; + static constexpr const bool is_element = !is_pair && !is_vector; +}; + +/* Default: is_comparable -> std::false_type */ +template +struct is_comparable : std::false_type { }; + +/* For non-map data structures, check whether operator== can be instantiated */ +template +struct is_comparable< + T, enable_if_t::is_element && + container_traits::is_comparable>> + : std::true_type { }; + +/* For a vector/map data structure, recursively check the value type (which is std::pair for maps) */ +template +struct is_comparable::is_vector>> { + static constexpr const bool value = + is_comparable::value; +}; + +/* For pairs, recursively check the two data types */ +template +struct is_comparable::is_pair>> { + static constexpr const bool value = + is_comparable::value && + is_comparable::value; +}; + +/* Fallback functions */ +template void vector_if_copy_constructible(const Args &...) { } +template void vector_if_equal_operator(const Args &...) { } +template void vector_if_insertion_operator(const Args &...) { } +template void vector_modifiers(const Args &...) { } + +template +void vector_if_copy_constructible(enable_if_t::value, Class_> &cl) { + cl.def(init(), "Copy constructor"); +} + +template +void vector_if_equal_operator(enable_if_t::value, Class_> &cl) { + using T = typename Vector::value_type; + + cl.def(self == self); + cl.def(self != self); + + cl.def("count", + [](const Vector &v, const T &x) { + return std::count(v.begin(), v.end(), x); + }, + arg("x"), + "Return the number of times ``x`` appears in the list" + ); + + cl.def("remove", [](Vector &v, const T &x) { + auto p = std::find(v.begin(), v.end(), x); + if (p != v.end()) + v.erase(p); + else + throw value_error(); + }, + arg("x"), + "Remove the first item from the list whose value is x. " + "It is an error if there is no such item." + ); + + cl.def("__contains__", + [](const Vector &v, const T &x) { + return std::find(v.begin(), v.end(), x) != v.end(); + }, + arg("x"), + "Return true the container contains ``x``" + ); +} + +// Vector modifiers -- requires a copyable vector_type: +// (Technically, some of these (pop and __delitem__) don't actually require copyability, but it seems +// silly to allow deletion but not insertion, so include them here too.) +template +void vector_modifiers(enable_if_t::value, Class_> &cl) { + using T = typename Vector::value_type; + using SizeType = typename Vector::size_type; + using DiffType = typename Vector::difference_type; + + cl.def("append", + [](Vector &v, const T &value) { v.push_back(value); }, + arg("x"), + "Add an item to the end of the list"); + + cl.def(init([](iterable it) { + auto v = std::unique_ptr(new Vector()); + v->reserve(len(it)); + for (handle h : it) + v->push_back(h.cast()); + return v.release(); + })); + + cl.def("extend", + [](Vector &v, const Vector &src) { + v.insert(v.end(), src.begin(), src.end()); + }, + arg("L"), + "Extend the list by appending all the items in the given list" + ); + + cl.def("insert", + [](Vector &v, SizeType i, const T &x) { + if (i > v.size()) + throw index_error(); + v.insert(v.begin() + (DiffType) i, x); + }, + arg("i") , arg("x"), + "Insert an item at a given position." + ); + + cl.def("pop", + [](Vector &v) { + if (v.empty()) + throw index_error(); + T t = v.back(); + v.pop_back(); + return t; + }, + "Remove and return the last item" + ); + + cl.def("pop", + [](Vector &v, SizeType i) { + if (i >= v.size()) + throw index_error(); + T t = v[i]; + v.erase(v.begin() + (DiffType) i); + return t; + }, + arg("i"), + "Remove and return the item at index ``i``" + ); + + cl.def("__setitem__", + [](Vector &v, SizeType i, const T &t) { + if (i >= v.size()) + throw index_error(); + v[i] = t; + } + ); + + /// Slicing protocol + cl.def("__getitem__", + [](const Vector &v, slice slice) -> Vector * { + size_t start, stop, step, slicelength; + + if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) + throw error_already_set(); + + Vector *seq = new Vector(); + seq->reserve((size_t) slicelength); + + for (size_t i=0; ipush_back(v[start]); + start += step; + } + return seq; + }, + arg("s"), + "Retrieve list elements using a slice object" + ); + + cl.def("__setitem__", + [](Vector &v, slice slice, const Vector &value) { + size_t start, stop, step, slicelength; + if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) + throw error_already_set(); + + if (slicelength != value.size()) + throw std::runtime_error("Left and right hand size of slice assignment have different sizes!"); + + for (size_t i=0; i= v.size()) + throw index_error(); + v.erase(v.begin() + DiffType(i)); + }, + "Delete the list elements at index ``i``" + ); + + cl.def("__delitem__", + [](Vector &v, slice slice) { + size_t start, stop, step, slicelength; + + if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) + throw error_already_set(); + + if (step == 1 && false) { + v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength)); + } else { + for (size_t i = 0; i < slicelength; ++i) { + v.erase(v.begin() + DiffType(start)); + start += step - 1; + } + } + }, + "Delete list elements using a slice object" + ); + +} + +// If the type has an operator[] that doesn't return a reference (most notably std::vector), +// we have to access by copying; otherwise we return by reference. +template using vector_needs_copy = negation< + std::is_same()[typename Vector::size_type()]), typename Vector::value_type &>>; + +// The usual case: access and iterate by reference +template +void vector_accessor(enable_if_t::value, Class_> &cl) { + using T = typename Vector::value_type; + using SizeType = typename Vector::size_type; + using ItType = typename Vector::iterator; + + cl.def("__getitem__", + [](Vector &v, SizeType i) -> T & { + if (i >= v.size()) + throw index_error(); + return v[i]; + }, + return_value_policy::reference_internal // ref + keepalive + ); + + cl.def("__iter__", + [](Vector &v) { + return make_iterator< + return_value_policy::reference_internal, ItType, ItType, T&>( + v.begin(), v.end()); + }, + keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ + ); +} + +// The case for special objects, like std::vector, that have to be returned-by-copy: +template +void vector_accessor(enable_if_t::value, Class_> &cl) { + using T = typename Vector::value_type; + using SizeType = typename Vector::size_type; + using ItType = typename Vector::iterator; + cl.def("__getitem__", + [](const Vector &v, SizeType i) -> T { + if (i >= v.size()) + throw index_error(); + return v[i]; + } + ); + + cl.def("__iter__", + [](Vector &v) { + return make_iterator< + return_value_policy::copy, ItType, ItType, T>( + v.begin(), v.end()); + }, + keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ + ); +} + +template auto vector_if_insertion_operator(Class_ &cl, std::string const &name) + -> decltype(std::declval() << std::declval(), void()) { + using size_type = typename Vector::size_type; + + cl.def("__repr__", + [name](Vector &v) { + std::ostringstream s; + s << name << '['; + for (size_type i=0; i < v.size(); ++i) { + s << v[i]; + if (i != v.size() - 1) + s << ", "; + } + s << ']'; + return s.str(); + }, + "Return the canonical string representation of this list." + ); +} + +// Provide the buffer interface for vectors if we have data() and we have a format for it +// GCC seems to have "void std::vector::data()" - doing SFINAE on the existence of data() is insufficient, we need to check it returns an appropriate pointer +template +struct vector_has_data_and_format : std::false_type {}; +template +struct vector_has_data_and_format::format(), std::declval().data()), typename Vector::value_type*>::value>> : std::true_type {}; + +// Add the buffer interface to a vector +template +enable_if_t...>::value> +vector_buffer(Class_& cl) { + using T = typename Vector::value_type; + + static_assert(vector_has_data_and_format::value, "There is not an appropriate format descriptor for this vector"); + + // numpy.h declares this for arbitrary types, but it may raise an exception and crash hard at runtime if PYBIND11_NUMPY_DTYPE hasn't been called, so check here + format_descriptor::format(); + + cl.def_buffer([](Vector& v) -> buffer_info { + return buffer_info(v.data(), static_cast(sizeof(T)), format_descriptor::format(), 1, {v.size()}, {sizeof(T)}); + }); + + cl.def(init([](buffer buf) { + auto info = buf.request(); + if (info.ndim != 1 || info.strides[0] % static_cast(sizeof(T))) + throw type_error("Only valid 1D buffers can be copied to a vector"); + if (!detail::compare_buffer_info::compare(info) || (ssize_t) sizeof(T) != info.itemsize) + throw type_error("Format mismatch (Python: " + info.format + " C++: " + format_descriptor::format() + ")"); + + auto vec = std::unique_ptr(new Vector()); + vec->reserve((size_t) info.shape[0]); + T *p = static_cast(info.ptr); + ssize_t step = info.strides[0] / static_cast(sizeof(T)); + T *end = p + info.shape[0] * step; + for (; p != end; p += step) + vec->push_back(*p); + return vec.release(); + })); + + return; +} + +template +enable_if_t...>::value> vector_buffer(Class_&) {} + +NAMESPACE_END(detail) + +// +// std::vector +// +template , typename... Args> +class_ bind_vector(handle scope, std::string const &name, Args&&... args) { + using Class_ = class_; + + // If the value_type is unregistered (e.g. a converting type) or is itself registered + // module-local then make the vector binding module-local as well: + using vtype = typename Vector::value_type; + auto vtype_info = detail::get_type_info(typeid(vtype)); + bool local = !vtype_info || vtype_info->module_local; + + Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward(args)...); + + // Declare the buffer interface if a buffer_protocol() is passed in + detail::vector_buffer(cl); + + cl.def(init<>()); + + // Register copy constructor (if possible) + detail::vector_if_copy_constructible(cl); + + // Register comparison-related operators and functions (if possible) + detail::vector_if_equal_operator(cl); + + // Register stream insertion operator (if possible) + detail::vector_if_insertion_operator(cl, name); + + // Modifiers require copyable vector value type + detail::vector_modifiers(cl); + + // Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive + detail::vector_accessor(cl); + + cl.def("__bool__", + [](const Vector &v) -> bool { + return !v.empty(); + }, + "Check whether the list is nonempty" + ); + + cl.def("__len__", &Vector::size); + + + + +#if 0 + // C++ style functions deprecated, leaving it here as an example + cl.def(init()); + + cl.def("resize", + (void (Vector::*) (size_type count)) & Vector::resize, + "changes the number of elements stored"); + + cl.def("erase", + [](Vector &v, SizeType i) { + if (i >= v.size()) + throw index_error(); + v.erase(v.begin() + i); + }, "erases element at index ``i``"); + + cl.def("empty", &Vector::empty, "checks whether the container is empty"); + cl.def("size", &Vector::size, "returns the number of elements"); + cl.def("push_back", (void (Vector::*)(const T&)) &Vector::push_back, "adds an element to the end"); + cl.def("pop_back", &Vector::pop_back, "removes the last element"); + + cl.def("max_size", &Vector::max_size, "returns the maximum possible number of elements"); + cl.def("reserve", &Vector::reserve, "reserves storage"); + cl.def("capacity", &Vector::capacity, "returns the number of elements that can be held in currently allocated storage"); + cl.def("shrink_to_fit", &Vector::shrink_to_fit, "reduces memory usage by freeing unused memory"); + + cl.def("clear", &Vector::clear, "clears the contents"); + cl.def("swap", &Vector::swap, "swaps the contents"); + + cl.def("front", [](Vector &v) { + if (v.size()) return v.front(); + else throw index_error(); + }, "access the first element"); + + cl.def("back", [](Vector &v) { + if (v.size()) return v.back(); + else throw index_error(); + }, "access the last element "); + +#endif + + return cl; +} + + + +// +// std::map, std::unordered_map +// + +NAMESPACE_BEGIN(detail) + +/* Fallback functions */ +template void map_if_insertion_operator(const Args &...) { } +template void map_assignment(const Args &...) { } + +// Map assignment when copy-assignable: just copy the value +template +void map_assignment(enable_if_t::value, Class_> &cl) { + using KeyType = typename Map::key_type; + using MappedType = typename Map::mapped_type; + + cl.def("__setitem__", + [](Map &m, const KeyType &k, const MappedType &v) { + auto it = m.find(k); + if (it != m.end()) it->second = v; + else m.emplace(k, v); + } + ); +} + +// Not copy-assignable, but still copy-constructible: we can update the value by erasing and reinserting +template +void map_assignment(enable_if_t< + !std::is_copy_assignable::value && + is_copy_constructible::value, + Class_> &cl) { + using KeyType = typename Map::key_type; + using MappedType = typename Map::mapped_type; + + cl.def("__setitem__", + [](Map &m, const KeyType &k, const MappedType &v) { + // We can't use m[k] = v; because value type might not be default constructable + auto r = m.emplace(k, v); + if (!r.second) { + // value type is not copy assignable so the only way to insert it is to erase it first... + m.erase(r.first); + m.emplace(k, v); + } + } + ); +} + + +template auto map_if_insertion_operator(Class_ &cl, std::string const &name) +-> decltype(std::declval() << std::declval() << std::declval(), void()) { + + cl.def("__repr__", + [name](Map &m) { + std::ostringstream s; + s << name << '{'; + bool f = false; + for (auto const &kv : m) { + if (f) + s << ", "; + s << kv.first << ": " << kv.second; + f = true; + } + s << '}'; + return s.str(); + }, + "Return the canonical string representation of this map." + ); +} + + +NAMESPACE_END(detail) + +template , typename... Args> +class_ bind_map(handle scope, const std::string &name, Args&&... args) { + using KeyType = typename Map::key_type; + using MappedType = typename Map::mapped_type; + using Class_ = class_; + + // If either type is a non-module-local bound type then make the map binding non-local as well; + // otherwise (e.g. both types are either module-local or converting) the map will be + // module-local. + auto tinfo = detail::get_type_info(typeid(MappedType)); + bool local = !tinfo || tinfo->module_local; + if (local) { + tinfo = detail::get_type_info(typeid(KeyType)); + local = !tinfo || tinfo->module_local; + } + + Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward(args)...); + + cl.def(init<>()); + + // Register stream insertion operator (if possible) + detail::map_if_insertion_operator(cl, name); + + cl.def("__bool__", + [](const Map &m) -> bool { return !m.empty(); }, + "Check whether the map is nonempty" + ); + + cl.def("__iter__", + [](Map &m) { return make_key_iterator(m.begin(), m.end()); }, + keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ + ); + + cl.def("items", + [](Map &m) { return make_iterator(m.begin(), m.end()); }, + keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ + ); + + cl.def("__getitem__", + [](Map &m, const KeyType &k) -> MappedType & { + auto it = m.find(k); + if (it == m.end()) + throw key_error(); + return it->second; + }, + return_value_policy::reference_internal // ref + keepalive + ); + + // Assignment provided only if the type is copyable + detail::map_assignment(cl); + + cl.def("__delitem__", + [](Map &m, const KeyType &k) { + auto it = m.find(k); + if (it == m.end()) + throw key_error(); + m.erase(it); + } + ); + + cl.def("__len__", &Map::size); + + return cl; +} + +NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/tools/FindCatch.cmake b/lib/3rdParty/dlib/include/dlib/external/pybind11/tools/FindCatch.cmake new file mode 100644 index 00000000..9d490c5a --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/tools/FindCatch.cmake @@ -0,0 +1,57 @@ +# - Find the Catch test framework or download it (single header) +# +# This is a quick module for internal use. It assumes that Catch is +# REQUIRED and that a minimum version is provided (not EXACT). If +# a suitable version isn't found locally, the single header file +# will be downloaded and placed in the build dir: PROJECT_BINARY_DIR. +# +# This code sets the following variables: +# CATCH_INCLUDE_DIR - path to catch.hpp +# CATCH_VERSION - version number + +if(NOT Catch_FIND_VERSION) + message(FATAL_ERROR "A version number must be specified.") +elseif(Catch_FIND_REQUIRED) + message(FATAL_ERROR "This module assumes Catch is not required.") +elseif(Catch_FIND_VERSION_EXACT) + message(FATAL_ERROR "Exact version numbers are not supported, only minimum.") +endif() + +# Extract the version number from catch.hpp +function(_get_catch_version) + file(STRINGS "${CATCH_INCLUDE_DIR}/catch.hpp" version_line REGEX "Catch v.*" LIMIT_COUNT 1) + if(version_line MATCHES "Catch v([0-9]+)\\.([0-9]+)\\.([0-9]+)") + set(CATCH_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}" PARENT_SCOPE) + endif() +endfunction() + +# Download the single-header version of Catch +function(_download_catch version destination_dir) + message(STATUS "Downloading catch v${version}...") + set(url https://github.com/philsquared/Catch/releases/download/v${version}/catch.hpp) + file(DOWNLOAD ${url} "${destination_dir}/catch.hpp" STATUS status) + list(GET status 0 error) + if(error) + message(FATAL_ERROR "Could not download ${url}") + endif() + set(CATCH_INCLUDE_DIR "${destination_dir}" CACHE INTERNAL "") +endfunction() + +# Look for catch locally +find_path(CATCH_INCLUDE_DIR NAMES catch.hpp PATH_SUFFIXES catch) +if(CATCH_INCLUDE_DIR) + _get_catch_version() +endif() + +# Download the header if it wasn't found or if it's outdated +if(NOT CATCH_VERSION OR CATCH_VERSION VERSION_LESS ${Catch_FIND_VERSION}) + if(DOWNLOAD_CATCH) + _download_catch(${Catch_FIND_VERSION} "${PROJECT_BINARY_DIR}/catch/") + _get_catch_version() + else() + set(CATCH_FOUND FALSE) + return() + endif() +endif() + +set(CATCH_FOUND TRUE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/tools/FindEigen3.cmake b/lib/3rdParty/dlib/include/dlib/external/pybind11/tools/FindEigen3.cmake new file mode 100644 index 00000000..9c546a05 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/tools/FindEigen3.cmake @@ -0,0 +1,81 @@ +# - Try to find Eigen3 lib +# +# This module supports requiring a minimum version, e.g. you can do +# find_package(Eigen3 3.1.2) +# to require version 3.1.2 or newer of Eigen3. +# +# Once done this will define +# +# EIGEN3_FOUND - system has eigen lib with correct version +# EIGEN3_INCLUDE_DIR - the eigen include directory +# EIGEN3_VERSION - eigen version + +# Copyright (c) 2006, 2007 Montel Laurent, +# Copyright (c) 2008, 2009 Gael Guennebaud, +# Copyright (c) 2009 Benoit Jacob +# Redistribution and use is allowed according to the terms of the 2-clause BSD license. + +if(NOT Eigen3_FIND_VERSION) + if(NOT Eigen3_FIND_VERSION_MAJOR) + set(Eigen3_FIND_VERSION_MAJOR 2) + endif(NOT Eigen3_FIND_VERSION_MAJOR) + if(NOT Eigen3_FIND_VERSION_MINOR) + set(Eigen3_FIND_VERSION_MINOR 91) + endif(NOT Eigen3_FIND_VERSION_MINOR) + if(NOT Eigen3_FIND_VERSION_PATCH) + set(Eigen3_FIND_VERSION_PATCH 0) + endif(NOT Eigen3_FIND_VERSION_PATCH) + + set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}") +endif(NOT Eigen3_FIND_VERSION) + +macro(_eigen3_check_version) + file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header) + + string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}") + set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}") + string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}") + set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}") + string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}") + set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}") + + set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION}) + if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + set(EIGEN3_VERSION_OK FALSE) + else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + set(EIGEN3_VERSION_OK TRUE) + endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) + + if(NOT EIGEN3_VERSION_OK) + + message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, " + "but at least version ${Eigen3_FIND_VERSION} is required") + endif(NOT EIGEN3_VERSION_OK) +endmacro(_eigen3_check_version) + +if (EIGEN3_INCLUDE_DIR) + + # in cache already + _eigen3_check_version() + set(EIGEN3_FOUND ${EIGEN3_VERSION_OK}) + +else (EIGEN3_INCLUDE_DIR) + + find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library + PATHS + ${CMAKE_INSTALL_PREFIX}/include + ${KDE4_INCLUDE_DIR} + PATH_SUFFIXES eigen3 eigen + ) + + if(EIGEN3_INCLUDE_DIR) + _eigen3_check_version() + endif(EIGEN3_INCLUDE_DIR) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK) + + mark_as_advanced(EIGEN3_INCLUDE_DIR) + +endif(EIGEN3_INCLUDE_DIR) + diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/tools/FindPythonLibsNew.cmake b/lib/3rdParty/dlib/include/dlib/external/pybind11/tools/FindPythonLibsNew.cmake new file mode 100644 index 00000000..b29b287d --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/tools/FindPythonLibsNew.cmake @@ -0,0 +1,195 @@ +# - Find python libraries +# This module finds the libraries corresponding to the Python interpreter +# FindPythonInterp provides. +# This code sets the following variables: +# +# PYTHONLIBS_FOUND - have the Python libs been found +# PYTHON_PREFIX - path to the Python installation +# PYTHON_LIBRARIES - path to the python library +# PYTHON_INCLUDE_DIRS - path to where Python.h is found +# PYTHON_MODULE_EXTENSION - lib extension, e.g. '.so' or '.pyd' +# PYTHON_MODULE_PREFIX - lib name prefix: usually an empty string +# PYTHON_SITE_PACKAGES - path to installation site-packages +# PYTHON_IS_DEBUG - whether the Python interpreter is a debug build +# +# Thanks to talljimbo for the patch adding the 'LDVERSION' config +# variable usage. + +#============================================================================= +# Copyright 2001-2009 Kitware, Inc. +# Copyright 2012 Continuum Analytics, Inc. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the names of Kitware, Inc., the Insight Software Consortium, +# nor the names of their contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#============================================================================= + +# Checking for the extension makes sure that `LibsNew` was found and not just `Libs`. +if(PYTHONLIBS_FOUND AND PYTHON_MODULE_EXTENSION) + return() +endif() + +# Use the Python interpreter to find the libs. +if(PythonLibsNew_FIND_REQUIRED) + find_package(PythonInterp ${PythonLibsNew_FIND_VERSION} REQUIRED) +else() + find_package(PythonInterp ${PythonLibsNew_FIND_VERSION}) +endif() + +if(NOT PYTHONINTERP_FOUND) + set(PYTHONLIBS_FOUND FALSE) + return() +endif() + +# According to http://stackoverflow.com/questions/646518/python-how-to-detect-debug-interpreter +# testing whether sys has the gettotalrefcount function is a reliable, cross-platform +# way to detect a CPython debug interpreter. +# +# The library suffix is from the config var LDVERSION sometimes, otherwise +# VERSION. VERSION will typically be like "2.7" on unix, and "27" on windows. +execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" + "from distutils import sysconfig as s;import sys;import struct; +print('.'.join(str(v) for v in sys.version_info)); +print(sys.prefix); +print(s.get_python_inc(plat_specific=True)); +print(s.get_python_lib(plat_specific=True)); +print(s.get_config_var('SO')); +print(hasattr(sys, 'gettotalrefcount')+0); +print(struct.calcsize('@P')); +print(s.get_config_var('LDVERSION') or s.get_config_var('VERSION')); +print(s.get_config_var('LIBDIR') or ''); +print(s.get_config_var('MULTIARCH') or ''); +" + RESULT_VARIABLE _PYTHON_SUCCESS + OUTPUT_VARIABLE _PYTHON_VALUES + ERROR_VARIABLE _PYTHON_ERROR_VALUE) + +if(NOT _PYTHON_SUCCESS MATCHES 0) + if(PythonLibsNew_FIND_REQUIRED) + message(FATAL_ERROR + "Python config failure:\n${_PYTHON_ERROR_VALUE}") + endif() + set(PYTHONLIBS_FOUND FALSE) + return() +endif() + +# Convert the process output into a list +string(REGEX REPLACE ";" "\\\\;" _PYTHON_VALUES ${_PYTHON_VALUES}) +string(REGEX REPLACE "\n" ";" _PYTHON_VALUES ${_PYTHON_VALUES}) +list(GET _PYTHON_VALUES 0 _PYTHON_VERSION_LIST) +list(GET _PYTHON_VALUES 1 PYTHON_PREFIX) +list(GET _PYTHON_VALUES 2 PYTHON_INCLUDE_DIR) +list(GET _PYTHON_VALUES 3 PYTHON_SITE_PACKAGES) +list(GET _PYTHON_VALUES 4 PYTHON_MODULE_EXTENSION) +list(GET _PYTHON_VALUES 5 PYTHON_IS_DEBUG) +list(GET _PYTHON_VALUES 6 PYTHON_SIZEOF_VOID_P) +list(GET _PYTHON_VALUES 7 PYTHON_LIBRARY_SUFFIX) +list(GET _PYTHON_VALUES 8 PYTHON_LIBDIR) +list(GET _PYTHON_VALUES 9 PYTHON_MULTIARCH) + +# Make sure the Python has the same pointer-size as the chosen compiler +# Skip if CMAKE_SIZEOF_VOID_P is not defined +if(CMAKE_SIZEOF_VOID_P AND (NOT "${PYTHON_SIZEOF_VOID_P}" STREQUAL "${CMAKE_SIZEOF_VOID_P}")) + if(PythonLibsNew_FIND_REQUIRED) + math(EXPR _PYTHON_BITS "${PYTHON_SIZEOF_VOID_P} * 8") + math(EXPR _CMAKE_BITS "${CMAKE_SIZEOF_VOID_P} * 8") + message(FATAL_ERROR + "Python config failure: Python is ${_PYTHON_BITS}-bit, " + "chosen compiler is ${_CMAKE_BITS}-bit") + endif() + set(PYTHONLIBS_FOUND FALSE) + return() +endif() + +# The built-in FindPython didn't always give the version numbers +string(REGEX REPLACE "\\." ";" _PYTHON_VERSION_LIST ${_PYTHON_VERSION_LIST}) +list(GET _PYTHON_VERSION_LIST 0 PYTHON_VERSION_MAJOR) +list(GET _PYTHON_VERSION_LIST 1 PYTHON_VERSION_MINOR) +list(GET _PYTHON_VERSION_LIST 2 PYTHON_VERSION_PATCH) + +# Make sure all directory separators are '/' +string(REGEX REPLACE "\\\\" "/" PYTHON_PREFIX ${PYTHON_PREFIX}) +string(REGEX REPLACE "\\\\" "/" PYTHON_INCLUDE_DIR ${PYTHON_INCLUDE_DIR}) +string(REGEX REPLACE "\\\\" "/" PYTHON_SITE_PACKAGES ${PYTHON_SITE_PACKAGES}) + +if(CMAKE_HOST_WIN32) + set(PYTHON_LIBRARY + "${PYTHON_PREFIX}/libs/Python${PYTHON_LIBRARY_SUFFIX}.lib") + + # when run in a venv, PYTHON_PREFIX points to it. But the libraries remain in the + # original python installation. They may be found relative to PYTHON_INCLUDE_DIR. + if(NOT EXISTS "${PYTHON_LIBRARY}") + get_filename_component(_PYTHON_ROOT ${PYTHON_INCLUDE_DIR} DIRECTORY) + set(PYTHON_LIBRARY + "${_PYTHON_ROOT}/libs/Python${PYTHON_LIBRARY_SUFFIX}.lib") + endif() + + # raise an error if the python libs are still not found. + if(NOT EXISTS "${PYTHON_LIBRARY}") + message(FATAL_ERROR "Python libraries not found") + endif() + +else() + if(PYTHON_MULTIARCH) + set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}/${PYTHON_MULTIARCH}" "${PYTHON_LIBDIR}") + else() + set(_PYTHON_LIBS_SEARCH "${PYTHON_LIBDIR}") + endif() + #message(STATUS "Searching for Python libs in ${_PYTHON_LIBS_SEARCH}") + # Probably this needs to be more involved. It would be nice if the config + # information the python interpreter itself gave us were more complete. + find_library(PYTHON_LIBRARY + NAMES "python${PYTHON_LIBRARY_SUFFIX}" + PATHS ${_PYTHON_LIBS_SEARCH} + NO_DEFAULT_PATH) + + # If all else fails, just set the name/version and let the linker figure out the path. + if(NOT PYTHON_LIBRARY) + set(PYTHON_LIBRARY python${PYTHON_LIBRARY_SUFFIX}) + endif() +endif() + +MARK_AS_ADVANCED( + PYTHON_LIBRARY + PYTHON_INCLUDE_DIR +) + +# We use PYTHON_INCLUDE_DIR, PYTHON_LIBRARY and PYTHON_DEBUG_LIBRARY for the +# cache entries because they are meant to specify the location of a single +# library. We now set the variables listed by the documentation for this +# module. +SET(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}") +SET(PYTHON_LIBRARIES "${PYTHON_LIBRARY}") +SET(PYTHON_DEBUG_LIBRARIES "${PYTHON_DEBUG_LIBRARY}") + +find_package_message(PYTHON + "Found PythonLibs: ${PYTHON_LIBRARY}" + "${PYTHON_EXECUTABLE}${PYTHON_VERSION}") + +set(PYTHONLIBS_FOUND TRUE) diff --git a/lib/3rdParty/dlib/include/dlib/external/pybind11/tools/pybind11Tools.cmake b/lib/3rdParty/dlib/include/dlib/external/pybind11/tools/pybind11Tools.cmake new file mode 100644 index 00000000..a7c471a0 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/pybind11/tools/pybind11Tools.cmake @@ -0,0 +1,202 @@ +# tools/pybind11Tools.cmake -- Build system for the pybind11 modules +# +# Copyright (c) 2015 Wenzel Jakob +# +# All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +cmake_minimum_required(VERSION 2.8.12) + +# Add a CMake parameter for choosing a desired Python version +if(NOT PYBIND11_PYTHON_VERSION) + set(PYBIND11_PYTHON_VERSION "" CACHE STRING "Python version to use for compiling modules") +endif() + +set(Python_ADDITIONAL_VERSIONS 3.7 3.6 3.5 3.4) +find_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} REQUIRED) + +include(CheckCXXCompilerFlag) +include(CMakeParseArguments) + +if(NOT PYBIND11_CPP_STANDARD AND NOT CMAKE_CXX_STANDARD) + if(NOT MSVC) + check_cxx_compiler_flag("-std=c++14" HAS_CPP14_FLAG) + + if (HAS_CPP14_FLAG) + set(PYBIND11_CPP_STANDARD -std=c++14) + else() + check_cxx_compiler_flag("-std=c++11" HAS_CPP11_FLAG) + if (HAS_CPP11_FLAG) + set(PYBIND11_CPP_STANDARD -std=c++11) + else() + message(FATAL_ERROR "Unsupported compiler -- pybind11 requires C++11 support!") + endif() + endif() + elseif(MSVC) + set(PYBIND11_CPP_STANDARD /std:c++14) + endif() + + set(PYBIND11_CPP_STANDARD ${PYBIND11_CPP_STANDARD} CACHE STRING + "C++ standard flag, e.g. -std=c++11, -std=c++14, /std:c++14. Defaults to C++14 mode." FORCE) +endif() + +# Checks whether the given CXX/linker flags can compile and link a cxx file. cxxflags and +# linkerflags are lists of flags to use. The result variable is a unique variable name for each set +# of flags: the compilation result will be cached base on the result variable. If the flags work, +# sets them in cxxflags_out/linkerflags_out internal cache variables (in addition to ${result}). +function(_pybind11_return_if_cxx_and_linker_flags_work result cxxflags linkerflags cxxflags_out linkerflags_out) + set(CMAKE_REQUIRED_LIBRARIES ${linkerflags}) + check_cxx_compiler_flag("${cxxflags}" ${result}) + if (${result}) + set(${cxxflags_out} "${cxxflags}" CACHE INTERNAL "" FORCE) + set(${linkerflags_out} "${linkerflags}" CACHE INTERNAL "" FORCE) + endif() +endfunction() + +# Internal: find the appropriate link time optimization flags for this compiler +function(_pybind11_add_lto_flags target_name prefer_thin_lto) + if (NOT DEFINED PYBIND11_LTO_CXX_FLAGS) + set(PYBIND11_LTO_CXX_FLAGS "" CACHE INTERNAL "") + set(PYBIND11_LTO_LINKER_FLAGS "" CACHE INTERNAL "") + + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + set(cxx_append "") + set(linker_append "") + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT APPLE) + # Clang Gold plugin does not support -Os; append -O3 to MinSizeRel builds to override it + set(linker_append ";$<$:-O3>") + elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + set(cxx_append ";-fno-fat-lto-objects") + endif() + + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND prefer_thin_lto) + _pybind11_return_if_cxx_and_linker_flags_work(HAS_FLTO_THIN + "-flto=thin${cxx_append}" "-flto=thin${linker_append}" + PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) + endif() + + if (NOT HAS_FLTO_THIN) + _pybind11_return_if_cxx_and_linker_flags_work(HAS_FLTO + "-flto${cxx_append}" "-flto${linker_append}" + PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) + endif() + elseif (CMAKE_CXX_COMPILER_ID MATCHES "Intel") + # Intel equivalent to LTO is called IPO + _pybind11_return_if_cxx_and_linker_flags_work(HAS_INTEL_IPO + "-ipo" "-ipo" PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) + elseif(MSVC) + # cmake only interprets libraries as linker flags when they start with a - (otherwise it + # converts /LTCG to \LTCG as if it was a Windows path). Luckily MSVC supports passing flags + # with - instead of /, even if it is a bit non-standard: + _pybind11_return_if_cxx_and_linker_flags_work(HAS_MSVC_GL_LTCG + "/GL" "-LTCG" PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS) + endif() + + if (PYBIND11_LTO_CXX_FLAGS) + message(STATUS "LTO enabled") + else() + message(STATUS "LTO disabled (not supported by the compiler and/or linker)") + endif() + endif() + + # Enable LTO flags if found, except for Debug builds + if (PYBIND11_LTO_CXX_FLAGS) + target_compile_options(${target_name} PRIVATE "$<$>:${PYBIND11_LTO_CXX_FLAGS}>") + endif() + if (PYBIND11_LTO_LINKER_FLAGS) + target_link_libraries(${target_name} PRIVATE "$<$>:${PYBIND11_LTO_LINKER_FLAGS}>") + endif() +endfunction() + +# Build a Python extension module: +# pybind11_add_module( [MODULE | SHARED] [EXCLUDE_FROM_ALL] +# [NO_EXTRAS] [THIN_LTO] source1 [source2 ...]) +# +function(pybind11_add_module target_name) + set(options MODULE SHARED EXCLUDE_FROM_ALL NO_EXTRAS THIN_LTO) + cmake_parse_arguments(ARG "${options}" "" "" ${ARGN}) + + if(ARG_MODULE AND ARG_SHARED) + message(FATAL_ERROR "Can't be both MODULE and SHARED") + elseif(ARG_SHARED) + set(lib_type SHARED) + else() + set(lib_type MODULE) + endif() + + if(ARG_EXCLUDE_FROM_ALL) + set(exclude_from_all EXCLUDE_FROM_ALL) + endif() + + add_library(${target_name} ${lib_type} ${exclude_from_all} ${ARG_UNPARSED_ARGUMENTS}) + + target_include_directories(${target_name} + PRIVATE ${PYBIND11_INCLUDE_DIR} # from project CMakeLists.txt + PRIVATE ${pybind11_INCLUDE_DIR} # from pybind11Config + PRIVATE ${PYTHON_INCLUDE_DIRS}) + + # The prefix and extension are provided by FindPythonLibsNew.cmake + set_target_properties(${target_name} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}") + set_target_properties(${target_name} PROPERTIES SUFFIX "${PYTHON_MODULE_EXTENSION}") + + # -fvisibility=hidden is required to allow multiple modules compiled against + # different pybind versions to work properly, and for some features (e.g. + # py::module_local). We force it on everything inside the `pybind11` + # namespace; also turning it on for a pybind module compilation here avoids + # potential warnings or issues from having mixed hidden/non-hidden types. + set_target_properties(${target_name} PROPERTIES CXX_VISIBILITY_PRESET "hidden") + + if(WIN32 OR CYGWIN) + # Link against the Python shared library on Windows + target_link_libraries(${target_name} PRIVATE ${PYTHON_LIBRARIES}) + elseif(APPLE) + # It's quite common to have multiple copies of the same Python version + # installed on one's system. E.g.: one copy from the OS and another copy + # that's statically linked into an application like Blender or Maya. + # If we link our plugin library against the OS Python here and import it + # into Blender or Maya later on, this will cause segfaults when multiple + # conflicting Python instances are active at the same time (even when they + # are of the same version). + + # Windows is not affected by this issue since it handles DLL imports + # differently. The solution for Linux and Mac OS is simple: we just don't + # link against the Python library. The resulting shared library will have + # missing symbols, but that's perfectly fine -- they will be resolved at + # import time. + + target_link_libraries(${target_name} PRIVATE "-undefined dynamic_lookup") + + if(ARG_SHARED) + # Suppress CMake >= 3.0 warning for shared libraries + set_target_properties(${target_name} PROPERTIES MACOSX_RPATH ON) + endif() + endif() + + # Make sure C++11/14 are enabled + target_compile_options(${target_name} PUBLIC ${PYBIND11_CPP_STANDARD}) + + if(ARG_NO_EXTRAS) + return() + endif() + + _pybind11_add_lto_flags(${target_name} ${ARG_THIN_LTO}) + + if (NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug) + # Strip unnecessary sections of the binary on Linux/Mac OS + if(CMAKE_STRIP) + if(APPLE) + add_custom_command(TARGET ${target_name} POST_BUILD + COMMAND ${CMAKE_STRIP} -x $) + else() + add_custom_command(TARGET ${target_name} POST_BUILD + COMMAND ${CMAKE_STRIP} $) + endif() + endif() + endif() + + if(MSVC) + # /MP enables multithreaded builds (relevant when there are many files), /bigobj is + # needed for bigger binding projects due to the limit to 64k addressable sections + target_compile_options(${target_name} PRIVATE /MP /bigobj) + endif() +endfunction() diff --git a/lib/3rdParty/dlib/include/dlib/external/zlib/crc32.h b/lib/3rdParty/dlib/include/dlib/external/zlib/crc32.h new file mode 100644 index 00000000..9e0c7781 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const z_crc_t FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/lib/3rdParty/dlib/include/dlib/external/zlib/deflate.h b/lib/3rdParty/dlib/include/dlib/external/zlib/deflate.h new file mode 100644 index 00000000..ce0299ed --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/zlib/deflate.h @@ -0,0 +1,346 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2012 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define Buf_size 16 +/* size of bit buffer in bi_buf */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* can only be DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to suppress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + uInt insert; /* bytes at end of window left to insert */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + ulg high_water; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + +#define WIN_INIT MAX_MATCH +/* Number of bytes after end of data in window to initialize in order to avoid + memory checker errors from longest match routines */ + + /* in trees.c */ +void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); +int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); +void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); +void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); +void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch ZLIB_INTERNAL _length_code[]; + extern uch ZLIB_INTERNAL _dist_code[]; +#else + extern const uch ZLIB_INTERNAL _length_code[]; + extern const uch ZLIB_INTERNAL _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/lib/3rdParty/dlib/include/dlib/external/zlib/gzguts.h b/lib/3rdParty/dlib/include/dlib/external/zlib/gzguts.h new file mode 100644 index 00000000..2bb0b049 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/zlib/gzguts.h @@ -0,0 +1,219 @@ +/* gzguts.h -- zlib internal header definitions for gz* operations + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef _MSC_VER +// Disable the following warnings for Visual Studio +// This is a warning you get from visual studio 2005 about things in the standard C++ +// library being "deprecated." I checked the C++ standard and it doesn't say jack +// about any of them (I checked the searchable PDF). So this warning is total Bunk. +#pragma warning(disable : 4996) +#endif + +#ifdef _LARGEFILE64_SOURCE +# ifndef _LARGEFILE_SOURCE +# define _LARGEFILE_SOURCE 1 +# endif +# ifdef _FILE_OFFSET_BITS +# undef _FILE_OFFSET_BITS +# endif +#endif + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include +#include "zlib.h" +#ifdef STDC +# include +# include +# include +#endif +#include + +#ifdef _WIN32 +# include +#endif + +#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) +# include +#else +# include +#endif + +#ifdef WINAPI_FAMILY +# define open _open +# define read _read +# define write _write +# define close _close +#endif + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS +/* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 +/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) +# define vsnprintf _vsnprintf +# endif +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +# ifdef VMS +# define NO_vsnprintf +# endif +# ifdef __OS400__ +# define NO_vsnprintf +# endif +# ifdef __MVS__ +# define NO_vsnprintf +# endif +#endif + +/* unlike snprintf (which is required in C99, yet still not supported by + Microsoft more than a decade later!), _snprintf does not guarantee null + termination of the result -- however this is only used in gzlib.c where + the result is assured to fit in the space provided */ +#ifdef _MSC_VER +# define snprintf _snprintf +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +/* gz* functions always use library allocation functions */ +#ifndef STDC + extern voidp malloc OF((uInt size)); + extern void free OF((voidpf ptr)); +#endif + +/* get errno and strerror definition */ +#if defined UNDER_CE +# include +# define zstrerror() gz_strwinerror((DWORD)GetLastError()) +#else +# ifndef NO_STRERROR +# include +# define zstrerror() strerror(errno) +# else +# define zstrerror() "stdio error (consult errno)" +# endif +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); +#endif + +/* default memLevel */ +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif + +/* default i/o buffer size -- double this for output when reading (this and + twice this must be able to fit in an unsigned type) */ +#define GZBUFSIZE 8192 + +/* gzip modes, also provide a little integrity check on the passed structure */ +#define GZ_NONE 0 +#define GZ_READ 7247 +#define GZ_WRITE 31153 +#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ + +/* values for gz_state how */ +#define LOOK 0 /* look for a gzip header */ +#define COPY 1 /* copy input directly */ +#define GZIP 2 /* decompress a gzip stream */ + +/* internal gzip file state data structure */ +typedef struct { + /* exposed contents for gzgetc() macro */ + struct gzFile_s x; /* "x" for exposed */ + /* x.have: number of bytes available at x.next */ + /* x.next: next output data to deliver or write */ + /* x.pos: current position in uncompressed data */ + /* used for both reading and writing */ + int mode; /* see gzip modes above */ + int fd; /* file descriptor */ + char *path; /* path or fd for error messages */ + unsigned size; /* buffer size, zero if not allocated yet */ + unsigned want; /* requested buffer size, default is GZBUFSIZE */ + unsigned char *in; /* input buffer */ + unsigned char *out; /* output buffer (double-sized when reading) */ + int direct; /* 0 if processing gzip, 1 if transparent */ + /* just for reading */ + int how; /* 0: get header, 1: copy, 2: decompress */ + z_off64_t start; /* where the gzip data started, for rewinding */ + int eof; /* true if end of input file reached */ + int past; /* true if read requested past end */ + /* just for writing */ + int level; /* compression level */ + int strategy; /* compression strategy */ + /* seek request */ + z_off64_t skip; /* amount to skip (already rewound if backwards) */ + int seek; /* true if seek request pending */ + /* error information */ + int err; /* error code */ + char *msg; /* error message */ + /* zlib inflate or deflate stream */ + z_stream strm; /* stream structure in-place (not a pointer) */ +} gz_state; +typedef gz_state FAR *gz_statep; + +/* shared functions */ +void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); +#if defined UNDER_CE +char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); +#endif + +/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t + value -- needed when comparing unsigned to z_off64_t, which is signed + (possible z_off64_t types off_t, off64_t, and long are all signed) */ +#ifdef INT_MAX +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) +#else +unsigned ZLIB_INTERNAL gz_intmax OF((void)); +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) +#endif diff --git a/lib/3rdParty/dlib/include/dlib/external/zlib/inffast.h b/lib/3rdParty/dlib/include/dlib/external/zlib/inffast.h new file mode 100644 index 00000000..e5c1aa4c --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/lib/3rdParty/dlib/include/dlib/external/zlib/inffixed.h b/lib/3rdParty/dlib/include/dlib/external/zlib/inffixed.h new file mode 100644 index 00000000..d6283277 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. + It is part of the implementation of this library and is + subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/lib/3rdParty/dlib/include/dlib/external/zlib/inflate.h b/lib/3rdParty/dlib/include/dlib/external/zlib/inflate.h new file mode 100644 index 00000000..95f4986d --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/zlib/inflate.h @@ -0,0 +1,122 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2009 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY_, /* i/o: same as COPY below, but only first time in */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN_, /* i: same as LEN below, but only first time in */ + LEN, /* i: waiting for length/lit/eob code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to BAD or MEM on error -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) or (raw) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> + HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + (raw) -> TYPEDO + Read deflate blocks: + TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK + STORED -> COPY_ -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN_ + LEN_ -> LEN + Read deflate codes in fixed or dynamic block: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 10K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ + int sane; /* if false, allow invalid distance too far */ + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ +}; diff --git a/lib/3rdParty/dlib/include/dlib/external/zlib/inftrees.h b/lib/3rdParty/dlib/include/dlib/external/zlib/inftrees.h new file mode 100644 index 00000000..baa53a0b --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/zlib/inftrees.h @@ -0,0 +1,62 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1444, which is the sum of 852 for literal/length codes and 592 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribtution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns returns 852, and "enough 30 6 15" for distance codes returns 592. + The initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in inflate.c and infback.c. If the root table size is + changed, then these maximum sizes would be need to be recalculated and + updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 592 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/lib/3rdParty/dlib/include/dlib/external/zlib/trees.h b/lib/3rdParty/dlib/include/dlib/external/zlib/trees.h new file mode 100644 index 00000000..d35639d8 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/lib/3rdParty/dlib/include/dlib/external/zlib/zconf.h b/lib/3rdParty/dlib/include/dlib/external/zlib/zconf.h new file mode 100644 index 00000000..9987a775 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/zlib/zconf.h @@ -0,0 +1,511 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2013 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzvprintf z_gzvprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateGetDictionary z_inflateGetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateResetKeep z_inflateResetKeep +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) +# define Z_HAVE_UNISTD_H +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/lib/3rdParty/dlib/include/dlib/external/zlib/zlib.h b/lib/3rdParty/dlib/include/dlib/external/zlib/zlib.h new file mode 100644 index 00000000..3e0c7672 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/zlib/zlib.h @@ -0,0 +1,1768 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.8, April 28th, 2013 + + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.8" +#define ZLIB_VERNUM 0x1280 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 8 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + z_const Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total number of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total number of bytes output so far */ + + z_const char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use in the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). Some + output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed code + block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the stream + are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least the + value returned by deflateBound (see below). Then deflate is guaranteed to + return Z_STREAM_END. If not enough output space is provided, deflate will + not return Z_STREAM_END, and it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect the + compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the + exact value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit() does not process any header information -- that is deferred + until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing will + resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained, so applications that need that information should + instead use raw inflate, see inflateInit2() below, or inflateBack() and + perform their own processing of the gzip header and trailer. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + producted so far. The CRC-32 is checked against the gzip trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by the + caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. The + stream will keep the same compression level and any other attributes that + may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression level is changed, the input available so far is + compressed with the old level (and may be flushed); the new level will take + effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to be + compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if + strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. +*/ + +ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, + unsigned *pending, + int *bits)); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similary, if dictLength is Z_NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current current value of + total_in which indicates where valid compressed data was found. In the + error case, the application may repeatedly call inflateSync, providing more + input each time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + int windowBits)); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above or -1 << 16 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the parameters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, + z_const unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the normal + behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + +#ifndef Z_SOLO + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed buffer. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. +*/ + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); + + Opens a gzip (.gz) file for reading or writing. The mode parameter is as + in fopen ("rb" or "wb") but can also include a compression level ("wb9") or + a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only + compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' + for fixed code compression as in "wb9F". (See the description of + deflateInit2 for more information about the strategy parameter.) 'T' will + request transparent writing or appending with no compression and not using + the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen associates a gzFile with the file descriptor fd. File descriptors + are obtained from calls like open, dup, creat, pipe or fileno (if the file + has been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +/* + Set the internal buffer size used by this library's functions. The + default buffer size is 8192 bytes. This function must be called after + gzopen() or gzdopen(), and before any other calls that read or write the + file. The buffer memory allocation is always deferred to the first read or + write. Two buffers are allocated, either both of the specified size when + writing, or one of the specified size and the other twice that size when + reading. A larger buffer size of, for example, 64K or 128K bytes will + noticeably increase the speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. If + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. +*/ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes written or 0 in case of + error. +*/ + +ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the arguments to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or 0 in case of error. The number of + uncompressed bytes written is limited to 8191, or one less than the buffer + size given to gzbuffer(). The caller should assure that this limit is not + exceeded. If it is exceeded, then gzprintf() will return an error (0) with + nothing written. In this case, there may also be a buffer overflow with + unpredictable consequences, which is possible only if zlib was compiled with + the insecure functions sprintf() or vsprintf() because the secure snprintf() + or vsnprintf() functions were not available. This can be determined using + zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or a + newline character is read and transferred to buf, or an end-of-file + condition is encountered. If any characters are read or if len == 1, the + string is terminated with a null character. If no characters are read due + to an end-of-file or len < 1, then the buffer is left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte or -1 + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read as the first character + on the next read. At least one character of push-back is allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter flush + is as in the deflate() function. The return value is the zlib error number + (see function gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatented gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); + + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); + + Returns the starting position for the next gzread or gzwrite on the given + compressed file. This position represents a number of bytes in the + uncompressed data stream, and is zero when starting, even if appending or + reading a gzip stream from the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); + + Returns the current offset in the file being read or written. This offset + includes the count of bytes that precede the gzip stream, for example when + appending or when using gzdopen() for reading. When reading, the offset + does not include as yet unused buffered input. This information can be used + for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns true (1) if the end-of-file indicator has been set while reading, + false (0) otherwise. Note that the end-of-file indicator is set only if the + read tried to go past the end of the input, but came up short. Therefore, + just like feof(), gzeof() may return false even if there is no more data to + read, in the event that the last read request was for the exact number of + bytes remaining in the input file. This will happen if the input file size + is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file and + deallocates the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the given + compressed file. errnum is set to zlib error number. If an error occurred + in the file system and not in the compression library, errnum is set to + Z_ERRNO and the application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + +#endif /* !Z_SOLO */ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is Z_NULL, this function returns the + required initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is Z_NULL, this function returns the required + initial value for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +# define z_gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) +#else +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) +#endif + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#ifdef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); +#endif + +#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# endif +# ifndef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); +#endif + +#else /* Z_SOLO */ + + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + +#endif /* !Z_SOLO */ + +/* hack for buggy compilers */ +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; +#endif + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); +ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); +ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); +ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); +#if defined(_WIN32) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, + const char *mode)); +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, + const char *format, + va_list va)); +# endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/lib/3rdParty/dlib/include/dlib/external/zlib/zutil.h b/lib/3rdParty/dlib/include/dlib/external/zlib/zutil.h new file mode 100644 index 00000000..24ab06b1 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/external/zlib/zutil.h @@ -0,0 +1,253 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2013 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include "zlib.h" + +#if defined(STDC) && !defined(Z_SOLO) +# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) +# include +# endif +# include +# include +#endif + +#ifdef Z_SOLO + typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# ifndef Z_SOLO +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# if defined(M_I86) && !defined(Z_SOLO) +# include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# ifndef Z_SOLO +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + +#if defined(__BORLANDC__) && !defined(MSDOS) + #pragma warn -8004 + #pragma warn -8008 + #pragma warn -8066 +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_WIN32) && \ + (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(pyr) || defined(Z_SOLO) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int ZLIB_INTERNAL z_verbose; + extern void ZLIB_INTERNAL z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +#ifndef Z_SOLO + voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, + unsigned size)); + void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); +#endif + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +/* Reverse the bytes in a 32-bit value */ +#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +#endif /* ZUTIL_H */ diff --git a/lib/3rdParty/dlib/include/dlib/filtering/kalman_filter.h b/lib/3rdParty/dlib/include/dlib/filtering/kalman_filter.h index dc114594..30289fa4 100644 --- a/lib/3rdParty/dlib/include/dlib/filtering/kalman_filter.h +++ b/lib/3rdParty/dlib/include/dlib/filtering/kalman_filter.h @@ -5,6 +5,7 @@ #include "kalman_filter_abstract.h" #include "../matrix.h" +#include "../geometry.h" namespace dlib { @@ -36,6 +37,15 @@ namespace dlib void set_process_noise ( const matrix& Q_) { Q = Q_; } void set_measurement_noise ( const matrix& R_) { R = R_; } void set_estimation_error_covariance( const matrix& P_) { P = P_; } + void set_state ( const matrix& xb_) + { + xb = xb_; + if (!got_first_meas) + { + x = xb_; + got_first_meas = true; + } + } const matrix& get_observation_model ( ) const { return H; } @@ -152,6 +162,218 @@ namespace dlib }; +// ---------------------------------------------------------------------------------------- + + class momentum_filter + { + public: + + momentum_filter( + double meas_noise, + double acc, + double max_meas_dev + ) : + measurement_noise(meas_noise), + typical_acceleration(acc), + max_measurement_deviation(max_meas_dev) + { + DLIB_CASSERT(meas_noise >= 0); + DLIB_CASSERT(acc >= 0); + DLIB_CASSERT(max_meas_dev >= 0); + + kal.set_observation_model({1, 0}); + kal.set_transition_model( {1, 1, + 0, 1}); + kal.set_process_noise({0, 0, + 0, typical_acceleration*typical_acceleration}); + + kal.set_measurement_noise({measurement_noise*measurement_noise}); + } + + momentum_filter() = default; + + double get_measurement_noise ( + ) const { return measurement_noise; } + + double get_typical_acceleration ( + ) const { return typical_acceleration; } + + double get_max_measurement_deviation ( + ) const { return max_measurement_deviation; } + + void reset() + { + *this = momentum_filter(measurement_noise, typical_acceleration, max_measurement_deviation); + } + + double get_predicted_next_position( + ) const + { + return kal.get_predicted_next_state()(0); + } + + double operator()( + const double measured_position + ) + { + auto x = kal.get_predicted_next_state(); + const auto max_deviation = max_measurement_deviation*measurement_noise; + // Check if measured_position has suddenly jumped in value by a whole lot. This + // could happen if the velocity term experiences a much larger than normal + // acceleration, e.g. because the underlying object is doing a maneuver. If + // this happens then we clamp the state so that the predicted next value is no + // more than max_deviation away from measured_position at all times. + if (x(0) > measured_position + max_deviation) + { + x(0) = measured_position + max_deviation; + kal.set_state(x); + } + else if (x(0) < measured_position - max_deviation) + { + x(0) = measured_position - max_deviation; + kal.set_state(x); + } + + kal.update({measured_position}); + + return kal.get_current_state()(0); + } + + friend std::ostream& operator << (std::ostream& out, const momentum_filter& item) + { + out << "measurement_noise: " << item.measurement_noise << "\n"; + out << "typical_acceleration: " << item.typical_acceleration << "\n"; + out << "max_measurement_deviation: " << item.max_measurement_deviation; + return out; + } + + friend void serialize(const momentum_filter& item, std::ostream& out) + { + int version = 15; + serialize(version, out); + serialize(item.measurement_noise, out); + serialize(item.typical_acceleration, out); + serialize(item.max_measurement_deviation, out); + serialize(item.kal, out); + } + + friend void deserialize(momentum_filter& item, std::istream& in) + { + int version = 0; + deserialize(version, in); + if (version != 15) + throw serialization_error("Unexpected version found while deserializing momentum_filter."); + deserialize(item.measurement_noise, in); + deserialize(item.typical_acceleration, in); + deserialize(item.max_measurement_deviation, in); + deserialize(item.kal, in); + } + + private: + + double measurement_noise = 2; + double typical_acceleration = 0.1; + double max_measurement_deviation = 3; // nominally number of standard deviations + + kalman_filter<2,1> kal; + }; + +// ---------------------------------------------------------------------------------------- + + momentum_filter find_optimal_momentum_filter ( + const std::vector>& sequences, + const double smoothness = 1 + ); + +// ---------------------------------------------------------------------------------------- + + momentum_filter find_optimal_momentum_filter ( + const std::vector& sequence, + const double smoothness = 1 + ); + +// ---------------------------------------------------------------------------------------- + + class rect_filter + { + public: + rect_filter() = default; + + rect_filter( + double meas_noise, + double acc, + double max_meas_dev + ) : rect_filter(momentum_filter(meas_noise, acc, max_meas_dev)) {} + + rect_filter( + const momentum_filter& filt + ) : + left(filt), + top(filt), + right(filt), + bottom(filt) + { + } + + drectangle operator()(const drectangle& r) + { + return drectangle(left(r.left()), + top(r.top()), + right(r.right()), + bottom(r.bottom())); + } + + drectangle operator()(const rectangle& r) + { + return drectangle(left(r.left()), + top(r.top()), + right(r.right()), + bottom(r.bottom())); + } + + const momentum_filter& get_left () const { return left; } + momentum_filter& get_left () { return left; } + const momentum_filter& get_top () const { return top; } + momentum_filter& get_top () { return top; } + const momentum_filter& get_right () const { return right; } + momentum_filter& get_right () { return right; } + const momentum_filter& get_bottom () const { return bottom; } + momentum_filter& get_bottom () { return bottom; } + + friend void serialize(const rect_filter& item, std::ostream& out) + { + int version = 123; + serialize(version, out); + serialize(item.left, out); + serialize(item.top, out); + serialize(item.right, out); + serialize(item.bottom, out); + } + + friend void deserialize(rect_filter& item, std::istream& in) + { + int version = 0; + deserialize(version, in); + if (version != 123) + throw dlib::serialization_error("Unknown version number found while deserializing rect_filter object."); + deserialize(item.left, in); + deserialize(item.top, in); + deserialize(item.right, in); + deserialize(item.bottom, in); + } + + private: + + momentum_filter left, top, right, bottom; + }; + +// ---------------------------------------------------------------------------------------- + + rect_filter find_optimal_rect_filter ( + const std::vector& rects, + const double smoothness = 1 + ); + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/filtering/kalman_filter_abstract.h b/lib/3rdParty/dlib/include/dlib/filtering/kalman_filter_abstract.h index d5eb3fe9..cdac2c56 100644 --- a/lib/3rdParty/dlib/include/dlib/filtering/kalman_filter_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/filtering/kalman_filter_abstract.h @@ -93,6 +93,18 @@ namespace dlib understand what you are doing.) !*/ + void set_state ( + const matrix& xb + ); + /*! + ensures + - This function can be used when the initial state is known, or if the + state needs to be corrected before the next update(). + - #get_predicted_next_state() == xb + - If (update() hasn't been called yet) then + - #get_current_state() == xb + !*/ + const matrix& get_observation_model ( ) const; /*! @@ -199,6 +211,278 @@ namespace dlib provides deserialization support !*/ +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class momentum_filter + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a simple tool for filtering a single scalar value that + measures the location of a moving object that has some non-trivial + momentum. Importantly, the measurements are noisy and the object can + experience sudden unpredictable accelerations. To accomplish this + filtering we use a simple Kalman filter with a state transition model of: + + position_{i+1} = position_{i} + velocity_{i} + velocity_{i+1} = velocity_{i} + some_unpredictable_acceleration + + and a measurement model of: + + measured_position_{i} = position_{i} + measurement_noise + + Where some_unpredictable_acceleration and measurement_noise are 0 mean Gaussian + noise sources with standard deviations of get_typical_acceleration() and + get_measurement_noise() respectively. + + To allow for really sudden and large but infrequent accelerations, at each + step we check if the current measured position deviates from the predicted + filtered position by more than get_max_measurement_deviation()*get_measurement_noise() + and if so we adjust the filter's state to keep it within these bounds. + This allows the moving object to undergo large unmodeled accelerations, far + in excess of what would be suggested by get_typical_acceleration(), without + then experiencing a long lag time where the Kalman filter has to "catch + up" to the new position. + !*/ + + public: + + momentum_filter( + ) = default; + /*! + ensures + - #get_measurement_noise() == 2 + - #get_typical_acceleration() == 0.1 + - #get_max_measurement_deviation() == 3 + !*/ + + momentum_filter( + double meas_noise, + double acc, + double max_meas_dev + ); + /*! + requires + - meas_noise >= 0 + - acc >= 0 + - max_meas_dev >= 0 + ensures + - #get_measurement_noise() == meas_noise + - #get_typical_acceleration() == acc + - #get_max_measurement_deviation() == max_meas_dev + !*/ + + + double get_measurement_noise ( + ) const; + /*! + ensures + - Returns the standard deviation of the 0 mean Gaussian noise that corrupts + measurements of the moving object. + !*/ + + double get_typical_acceleration ( + ) const; + /*! + ensures + - We assume that the moving object experiences random accelerations that + are distributed by 0 mean Gaussian noise with get_typical_acceleration() + standard deviation. + !*/ + + double get_max_measurement_deviation ( + ) const; + /*! + ensures + - This object will never let the filtered location of the object deviate + from the measured location by much more than + get_max_measurement_deviation()*get_measurement_noise(). + !*/ + + void reset( + ); + /*! + ensures + - Returns this object to the state immediately after construction. To be precise, we do: + *this = momentum_filter(get_measurement_noise(), get_typical_acceleration(), get_max_measurement_deviation()); + !*/ + + double operator()( + const double measured_position + ); + /*! + ensures + - Updates the Kalman filter with the new measured position of the object + and returns the new filtered estimate of the object's position, now that + we have seen the latest measured position. + - #get_predicted_next_position() == the prediction for the *next* place we + will see the object. That is, where we think it will be in the future + rather than where it is now. + !*/ + + double get_predicted_next_position ( + ) const; + /*! + ensures + - Returns the Kalman filter's estimate of the next position we will see the object. + !*/ + }; + + std::ostream& operator << (std::ostream& out, const momentum_filter& item); + void serialize(const momentum_filter& item, std::ostream& out); + void deserialize(momentum_filter& item, std::istream& in); + /*! + Provide printing and serialization support. + !*/ + +// ---------------------------------------------------------------------------------------- + + momentum_filter find_optimal_momentum_filter ( + const std::vector>& sequences, + const double smoothness = 1 + ); + /*! + requires + - sequences.size() != 0 + - for all valid i: sequences[i].size() > 4 + - smoothness >= 0 + ensures + - This function finds the "optimal" settings of a momentum_filter based on + recorded measurement data stored in sequences. Here we assume that each + vector in sequences is a complete track history of some object's measured + positions. What we do is find the momentum_filter that minimizes the + following objective function: + sum of abs(predicted_location[i] - measured_location[i]) + smoothness*abs(filtered_location[i]-filtered_location[i-1]) + Where i is a time index. + The sum runs over all the data in sequences. So what we do is find the + filter settings that produce smooth filtered trajectories but also produce + filtered outputs that are as close to the measured positions as possible. + The larger the value of smoothness the less jittery the filter outputs will + be, but they might become biased or laggy if smoothness is set really high. + !*/ + +// ---------------------------------------------------------------------------------------- + + momentum_filter find_optimal_momentum_filter ( + const std::vector& sequence, + const double smoothness = 1 + ); + /*! + requires + - sequence.size() > 4 + - smoothness >= 0 + ensures + - performs: find_optimal_momentum_filter({1,sequence}, smoothness); + !*/ + +// ---------------------------------------------------------------------------------------- + + class rect_filter + { + /*! + WHAT THIS OBJECT REPRESENTS + This object simply contains four momentum_filters and applies them to the + 4 components of a dlib::rectangle's position. It therefore allows you to + easily filter a sequence of rectangles. For instance, it can be used to + smooth the output of an object detector running on a video. + !*/ + + public: + rect_filter( + ) = default; + /*! + ensures + - The four momentum_filters in this object are default initialized. + !*/ + + rect_filter( + const momentum_filter& filt + ); + /*! + ensures + - #get_left() == filt + - #get_top() == filt + - #get_right() == filt + - #get_bottom() == filt + !*/ + + rect_filter( + double meas_noise, + double acc, + double max_meas_dev + ) : rect_filter(momentum_filter(meas_noise, acc, max_meas_dev)) {} + /*! + requires + - meas_noise >= 0 + - acc >= 0 + - max_meas_dev >= 0 + ensures + - Initializes this object with momentum_filter(meas_noise, acc, max_meas_dev) + !*/ + + drectangle operator()( + const drectangle& r + ); + /*! + ensures + - Runs the given rectangle through the momentum_filters and returns the + filtered rectangle location. That is, performs: + return drectangle(get_left()(r.left()), + get_top()(r.top()), + get_right()(r.right()), + get_bottom()(r.bottom())); + !*/ + + drectangle operator()( + const rectangle& r + ); + /*! + ensures + - Runs the given rectangle through the momentum_filters and returns the + filtered rectangle location. That is, performs: + return drectangle(get_left()(r.left()), + get_top()(r.top()), + get_right()(r.right()), + get_bottom()(r.bottom())); + !*/ + + const momentum_filter& get_left() const; + momentum_filter& get_left(); + const momentum_filter& get_top() const; + momentum_filter& get_top(); + const momentum_filter& get_right() const; + momentum_filter& get_right(); + const momentum_filter& get_bottom() const; + momentum_filter& get_bottom(); + /*! + Provides access to the 4 momentum_filters used to filter the 4 coordinates that define a rectangle. + !*/ + }; + + void serialize(const rect_filter& item, std::ostream& out); + void deserialize(rect_filter& item, std::istream& in); + /*! + Provide serialization support. + !*/ + +// ---------------------------------------------------------------------------------------- + + rect_filter find_optimal_rect_filter ( + const std::vector& rects, + const double smoothness = 1 + ); + /*! + requires + - rects.size() > 4 + - smoothness >= 0 + ensures + - This routine simply invokes find_optimal_momentum_filter() to find the + momentum_filter that works best on the provided sequence of rectangles. It + then constructs a rect_filter using that momentum_filter and returns it. + Therefore, this routine finds the rect_filter that is "optimal" for filtering + the given sequence of rectangles. + !*/ + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/filtering/rls_filter.h b/lib/3rdParty/dlib/include/dlib/filtering/rls_filter.h index 148d693e..4481ab3f 100644 --- a/lib/3rdParty/dlib/include/dlib/filtering/rls_filter.h +++ b/lib/3rdParty/dlib/include/dlib/filtering/rls_filter.h @@ -151,7 +151,7 @@ namespace dlib } const matrix& get_predicted_next_state( - ) + ) const { return next; } diff --git a/lib/3rdParty/dlib/include/dlib/filtering/rls_filter_abstract.h b/lib/3rdParty/dlib/include/dlib/filtering/rls_filter_abstract.h index fd4f61b7..0a932cb8 100644 --- a/lib/3rdParty/dlib/include/dlib/filtering/rls_filter_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/filtering/rls_filter_abstract.h @@ -134,7 +134,7 @@ namespace dlib !*/ const matrix& get_predicted_next_state( - ); + ) const; /*! ensures - returns the estimate of the next point we will observe in the diff --git a/lib/3rdParty/dlib/include/dlib/float_details.h b/lib/3rdParty/dlib/include/dlib/float_details.h index ab859e0b..3dc7eae4 100644 --- a/lib/3rdParty/dlib/include/dlib/float_details.h +++ b/lib/3rdParty/dlib/include/dlib/float_details.h @@ -3,7 +3,7 @@ #ifndef DLIB_FLOAT_DEtAILS_Hh_ #define DLIB_FLOAT_DEtAILS_Hh_ -#include +#include #include "algs.h" #include @@ -100,24 +100,6 @@ namespace dlib // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- - - - - double _frexp(double v, int* e) const { return frexp(v,e); } - float _frexp(float v, int* e) const { return frexpf(v,e); } - - double _ldexp(double v, int e) const { return ldexp(v,e); } - float _ldexp(float v, int e) const { return ldexpf(v,e); } - -#ifdef __CYGWIN__ - // frexpl and ldexpl aren't available on cygwin so just use the double version. - long double _frexp(long double v, int* e) const { return _frexp((double)v,e); } - long double _ldexp(long double v, int e) const { return _ldexp((double)v,e); } -#else - long double _frexp(long double v, int* e) const { return frexpl(v,e); } - long double _ldexp(long double v, int e) const { return ldexpl(v,e); } -#endif - template void convert_from_T ( const T& val @@ -138,7 +120,7 @@ namespace dlib else if (val < std::numeric_limits::infinity()) { int exp; - mantissa = static_cast(_frexp(val, &exp)*(((uint64)1)<(std::frexp(val, &exp)*(((uint64)1)<::infinity(); else if (exponent == is_ninf) diff --git a/lib/3rdParty/dlib/include/dlib/fstream b/lib/3rdParty/dlib/include/dlib/fstream deleted file mode 100644 index eb0e59e4..00000000 --- a/lib/3rdParty/dlib/include/dlib/fstream +++ /dev/null @@ -1 +0,0 @@ -#include "dlib_include_path_tutorial.txt" diff --git a/lib/3rdParty/dlib/include/dlib/general_hash/count_bits.h b/lib/3rdParty/dlib/include/dlib/general_hash/count_bits.h index 9b052950..01acad2a 100644 --- a/lib/3rdParty/dlib/include/dlib/general_hash/count_bits.h +++ b/lib/3rdParty/dlib/include/dlib/general_hash/count_bits.h @@ -54,6 +54,26 @@ namespace dlib return count_bits(a^b); } +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + T hamming_distance ( + const std::pair& a, + const std::pair& b + ) + /*! + requires + - T is an unsigned integral type or a std::pair that, recursively, eventually + contains unsigned integral types. + ensures + - returns the number of bits which differ between a and b. + !*/ + { + return hamming_distance(a.first,b.first) + hamming_distance(a.second, b.second); + } + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/general_hash/murmur_hash3.h b/lib/3rdParty/dlib/include/dlib/general_hash/murmur_hash3.h index 40182338..b8e37260 100644 --- a/lib/3rdParty/dlib/include/dlib/general_hash/murmur_hash3.h +++ b/lib/3rdParty/dlib/include/dlib/general_hash/murmur_hash3.h @@ -214,7 +214,9 @@ namespace dlib switch(len & 3) { case 3: k1 ^= tail[2] << 16; + // fall through case 2: k1 ^= tail[1] << 8; + // fall through case 1: k1 ^= tail[0]; k1 *= c1; k1 = DLIB_ROTL32(k1,15); k1 *= c2; h1 ^= k1; }; @@ -384,24 +386,24 @@ namespace dlib switch(len & 15) { - case 15: k2 ^= uint64(tail[14]) << 48; - case 14: k2 ^= uint64(tail[13]) << 40; - case 13: k2 ^= uint64(tail[12]) << 32; - case 12: k2 ^= uint64(tail[11]) << 24; - case 11: k2 ^= uint64(tail[10]) << 16; - case 10: k2 ^= uint64(tail[ 9]) << 8; + case 15: k2 ^= uint64(tail[14]) << 48; // fall through + case 14: k2 ^= uint64(tail[13]) << 40; // fall through + case 13: k2 ^= uint64(tail[12]) << 32; // fall through + case 12: k2 ^= uint64(tail[11]) << 24; // fall through + case 11: k2 ^= uint64(tail[10]) << 16; // fall through + case 10: k2 ^= uint64(tail[ 9]) << 8; // fall through case 9: k2 ^= uint64(tail[ 8]) << 0; - k2 *= c2; k2 = DLIB_ROTL64(k2,33); k2 *= c1; h2 ^= k2; + k2 *= c2; k2 = DLIB_ROTL64(k2,33); k2 *= c1; h2 ^= k2; // fall through - case 8: k1 ^= uint64(tail[ 7]) << 56; - case 7: k1 ^= uint64(tail[ 6]) << 48; - case 6: k1 ^= uint64(tail[ 5]) << 40; - case 5: k1 ^= uint64(tail[ 4]) << 32; - case 4: k1 ^= uint64(tail[ 3]) << 24; - case 3: k1 ^= uint64(tail[ 2]) << 16; - case 2: k1 ^= uint64(tail[ 1]) << 8; + case 8: k1 ^= uint64(tail[ 7]) << 56; // fall through + case 7: k1 ^= uint64(tail[ 6]) << 48; // fall through + case 6: k1 ^= uint64(tail[ 5]) << 40; // fall through + case 5: k1 ^= uint64(tail[ 4]) << 32; // fall through + case 4: k1 ^= uint64(tail[ 3]) << 24; // fall through + case 3: k1 ^= uint64(tail[ 2]) << 16; // fall through + case 2: k1 ^= uint64(tail[ 1]) << 8; // fall through case 1: k1 ^= uint64(tail[ 0]) << 0; - k1 *= c1; k1 = DLIB_ROTL64(k1,31); k1 *= c2; h1 ^= k1; + k1 *= c1; k1 = DLIB_ROTL64(k1,31); k1 *= c2; h1 ^= k1; // fall through }; //---------- diff --git a/lib/3rdParty/dlib/include/dlib/general_hash/random_hashing.h b/lib/3rdParty/dlib/include/dlib/general_hash/random_hashing.h index 0a9e26ba..7a06a687 100644 --- a/lib/3rdParty/dlib/include/dlib/general_hash/random_hashing.h +++ b/lib/3rdParty/dlib/include/dlib/general_hash/random_hashing.h @@ -35,834 +35,834 @@ namespace dlib const static unsigned int max = 4096; - const static float logvals[max] = { - 4.079f, 3.905f, 3.8f, 3.723f, 3.663f, 3.613f, 3.57f, 3.532f, 3.499f, 3.468f, - 3.441f, 3.416f, 3.392f, 3.37f, 3.35f, 3.33f, 3.312f, 3.295f, 3.278f, 3.263f, - 3.248f, 3.233f, 3.219f, 3.206f, 3.193f, 3.181f, 3.169f, 3.158f, 3.147f, 3.136f, - 3.125f, 3.115f, 3.105f, 3.096f, 3.086f, 3.077f, 3.068f, 3.059f, 3.051f, 3.043f, - 3.035f, 3.027f, 3.019f, 3.011f, 3.004f, 2.996f, 2.989f, 2.982f, 2.975f, 2.968f, - 2.962f, 2.955f, 2.949f, 2.942f, 2.936f, 2.93f, 2.924f, 2.918f, 2.912f, 2.906f, - 2.901f, 2.895f, 2.89f, 2.884f, 2.879f, 2.873f, 2.868f, 2.863f, 2.858f, 2.853f, - 2.848f, 2.843f, 2.838f, 2.833f, 2.829f, 2.824f, 2.819f, 2.815f, 2.81f, 2.806f, - 2.801f, 2.797f, 2.792f, 2.788f, 2.784f, 2.78f, 2.776f, 2.771f, 2.767f, 2.763f, - 2.759f, 2.755f, 2.751f, 2.748f, 2.744f, 2.74f, 2.736f, 2.732f, 2.729f, 2.725f, - 2.721f, 2.718f, 2.714f, 2.71f, 2.707f, 2.703f, 2.7f, 2.697f, 2.693f, 2.69f, - 2.686f, 2.683f, 2.68f, 2.676f, 2.673f, 2.67f, 2.667f, 2.663f, 2.66f, 2.657f, - 2.654f, 2.651f, 2.648f, 2.645f, 2.642f, 2.639f, 2.636f, 2.633f, 2.63f, 2.627f, - 2.624f, 2.621f, 2.618f, 2.615f, 2.612f, 2.61f, 2.607f, 2.604f, 2.601f, 2.599f, - 2.596f, 2.593f, 2.59f, 2.588f, 2.585f, 2.582f, 2.58f, 2.577f, 2.574f, 2.572f, - 2.569f, 2.567f, 2.564f, 2.562f, 2.559f, 2.557f, 2.554f, 2.552f, 2.549f, 2.547f, - 2.544f, 2.542f, 2.539f, 2.537f, 2.534f, 2.532f, 2.53f, 2.527f, 2.525f, 2.523f, - 2.52f, 2.518f, 2.516f, 2.513f, 2.511f, 2.509f, 2.507f, 2.504f, 2.502f, 2.5f, - 2.498f, 2.495f, 2.493f, 2.491f, 2.489f, 2.487f, 2.485f, 2.482f, 2.48f, 2.478f, - 2.476f, 2.474f, 2.472f, 2.47f, 2.468f, 2.466f, 2.464f, 2.462f, 2.459f, 2.457f, - 2.455f, 2.453f, 2.451f, 2.449f, 2.447f, 2.445f, 2.443f, 2.441f, 2.439f, 2.437f, - 2.436f, 2.434f, 2.432f, 2.43f, 2.428f, 2.426f, 2.424f, 2.422f, 2.42f, 2.418f, - 2.416f, 2.415f, 2.413f, 2.411f, 2.409f, 2.407f, 2.405f, 2.404f, 2.402f, 2.4f, - 2.398f, 2.396f, 2.394f, 2.393f, 2.391f, 2.389f, 2.387f, 2.386f, 2.384f, 2.382f, - 2.38f, 2.379f, 2.377f, 2.375f, 2.373f, 2.372f, 2.37f, 2.368f, 2.367f, 2.365f, - 2.363f, 2.361f, 2.36f, 2.358f, 2.356f, 2.355f, 2.353f, 2.352f, 2.35f, 2.348f, - 2.347f, 2.345f, 2.343f, 2.342f, 2.34f, 2.338f, 2.337f, 2.335f, 2.334f, 2.332f, - 2.331f, 2.329f, 2.327f, 2.326f, 2.324f, 2.323f, 2.321f, 2.32f, 2.318f, 2.316f, - 2.315f, 2.313f, 2.312f, 2.31f, 2.309f, 2.307f, 2.306f, 2.304f, 2.303f, 2.301f, - 2.3f, 2.298f, 2.297f, 2.295f, 2.294f, 2.292f, 2.291f, 2.289f, 2.288f, 2.286f, - 2.285f, 2.284f, 2.282f, 2.281f, 2.279f, 2.278f, 2.276f, 2.275f, 2.274f, 2.272f, - 2.271f, 2.269f, 2.268f, 2.266f, 2.265f, 2.264f, 2.262f, 2.261f, 2.259f, 2.258f, - 2.257f, 2.255f, 2.254f, 2.253f, 2.251f, 2.25f, 2.248f, 2.247f, 2.246f, 2.244f, - 2.243f, 2.242f, 2.24f, 2.239f, 2.238f, 2.236f, 2.235f, 2.234f, 2.232f, 2.231f, - 2.23f, 2.228f, 2.227f, 2.226f, 2.225f, 2.223f, 2.222f, 2.221f, 2.219f, 2.218f, - 2.217f, 2.215f, 2.214f, 2.213f, 2.212f, 2.21f, 2.209f, 2.208f, 2.207f, 2.205f, - 2.204f, 2.203f, 2.202f, 2.2f, 2.199f, 2.198f, 2.197f, 2.195f, 2.194f, 2.193f, - 2.192f, 2.19f, 2.189f, 2.188f, 2.187f, 2.185f, 2.184f, 2.183f, 2.182f, 2.181f, - 2.179f, 2.178f, 2.177f, 2.176f, 2.175f, 2.173f, 2.172f, 2.171f, 2.17f, 2.169f, - 2.168f, 2.166f, 2.165f, 2.164f, 2.163f, 2.162f, 2.16f, 2.159f, 2.158f, 2.157f, - 2.156f, 2.155f, 2.154f, 2.152f, 2.151f, 2.15f, 2.149f, 2.148f, 2.147f, 2.146f, - 2.144f, 2.143f, 2.142f, 2.141f, 2.14f, 2.139f, 2.138f, 2.136f, 2.135f, 2.134f, - 2.133f, 2.132f, 2.131f, 2.13f, 2.129f, 2.128f, 2.126f, 2.125f, 2.124f, 2.123f, - 2.122f, 2.121f, 2.12f, 2.119f, 2.118f, 2.117f, 2.116f, 2.114f, 2.113f, 2.112f, - 2.111f, 2.11f, 2.109f, 2.108f, 2.107f, 2.106f, 2.105f, 2.104f, 2.103f, 2.102f, - 2.101f, 2.1f, 2.099f, 2.097f, 2.096f, 2.095f, 2.094f, 2.093f, 2.092f, 2.091f, - 2.09f, 2.089f, 2.088f, 2.087f, 2.086f, 2.085f, 2.084f, 2.083f, 2.082f, 2.081f, - 2.08f, 2.079f, 2.078f, 2.077f, 2.076f, 2.075f, 2.074f, 2.073f, 2.072f, 2.071f, - 2.07f, 2.069f, 2.068f, 2.067f, 2.066f, 2.065f, 2.064f, 2.063f, 2.062f, 2.061f, - 2.06f, 2.059f, 2.058f, 2.057f, 2.056f, 2.055f, 2.054f, 2.053f, 2.052f, 2.051f, - 2.05f, 2.049f, 2.048f, 2.047f, 2.046f, 2.045f, 2.044f, 2.043f, 2.042f, 2.041f, - 2.04f, 2.039f, 2.038f, 2.037f, 2.036f, 2.036f, 2.035f, 2.034f, 2.033f, 2.032f, - 2.031f, 2.03f, 2.029f, 2.028f, 2.027f, 2.026f, 2.025f, 2.024f, 2.023f, 2.022f, - 2.021f, 2.02f, 2.02f, 2.019f, 2.018f, 2.017f, 2.016f, 2.015f, 2.014f, 2.013f, - 2.012f, 2.011f, 2.01f, 2.009f, 2.008f, 2.008f, 2.007f, 2.006f, 2.005f, 2.004f, - 2.003f, 2.002f, 2.001f, 2.0f, 1.999f, 1.998f, 1.998f, 1.997f, 1.996f, 1.995f, - 1.994f, 1.993f, 1.992f, 1.991f, 1.99f, 1.99f, 1.989f, 1.988f, 1.987f, 1.986f, - 1.985f, 1.984f, 1.983f, 1.982f, 1.982f, 1.981f, 1.98f, 1.979f, 1.978f, 1.977f, - 1.976f, 1.975f, 1.975f, 1.974f, 1.973f, 1.972f, 1.971f, 1.97f, 1.969f, 1.969f, - 1.968f, 1.967f, 1.966f, 1.965f, 1.964f, 1.963f, 1.963f, 1.962f, 1.961f, 1.96f, - 1.959f, 1.958f, 1.957f, 1.957f, 1.956f, 1.955f, 1.954f, 1.953f, 1.952f, 1.952f, - 1.951f, 1.95f, 1.949f, 1.948f, 1.947f, 1.947f, 1.946f, 1.945f, 1.944f, 1.943f, - 1.942f, 1.942f, 1.941f, 1.94f, 1.939f, 1.938f, 1.937f, 1.937f, 1.936f, 1.935f, - 1.934f, 1.933f, 1.933f, 1.932f, 1.931f, 1.93f, 1.929f, 1.928f, 1.928f, 1.927f, - 1.926f, 1.925f, 1.924f, 1.924f, 1.923f, 1.922f, 1.921f, 1.92f, 1.92f, 1.919f, - 1.918f, 1.917f, 1.916f, 1.916f, 1.915f, 1.914f, 1.913f, 1.912f, 1.912f, 1.911f, - 1.91f, 1.909f, 1.908f, 1.908f, 1.907f, 1.906f, 1.905f, 1.904f, 1.904f, 1.903f, - 1.902f, 1.901f, 1.901f, 1.9f, 1.899f, 1.898f, 1.897f, 1.897f, 1.896f, 1.895f, - 1.894f, 1.894f, 1.893f, 1.892f, 1.891f, 1.89f, 1.89f, 1.889f, 1.888f, 1.887f, - 1.887f, 1.886f, 1.885f, 1.884f, 1.884f, 1.883f, 1.882f, 1.881f, 1.88f, 1.88f, - 1.879f, 1.878f, 1.877f, 1.877f, 1.876f, 1.875f, 1.874f, 1.874f, 1.873f, 1.872f, - 1.871f, 1.871f, 1.87f, 1.869f, 1.868f, 1.868f, 1.867f, 1.866f, 1.865f, 1.865f, - 1.864f, 1.863f, 1.862f, 1.862f, 1.861f, 1.86f, 1.859f, 1.859f, 1.858f, 1.857f, - 1.857f, 1.856f, 1.855f, 1.854f, 1.854f, 1.853f, 1.852f, 1.851f, 1.851f, 1.85f, - 1.849f, 1.848f, 1.848f, 1.847f, 1.846f, 1.846f, 1.845f, 1.844f, 1.843f, 1.843f, - 1.842f, 1.841f, 1.84f, 1.84f, 1.839f, 1.838f, 1.838f, 1.837f, 1.836f, 1.835f, - 1.835f, 1.834f, 1.833f, 1.833f, 1.832f, 1.831f, 1.83f, 1.83f, 1.829f, 1.828f, - 1.828f, 1.827f, 1.826f, 1.825f, 1.825f, 1.824f, 1.823f, 1.823f, 1.822f, 1.821f, - 1.821f, 1.82f, 1.819f, 1.818f, 1.818f, 1.817f, 1.816f, 1.816f, 1.815f, 1.814f, - 1.814f, 1.813f, 1.812f, 1.811f, 1.811f, 1.81f, 1.809f, 1.809f, 1.808f, 1.807f, - 1.807f, 1.806f, 1.805f, 1.805f, 1.804f, 1.803f, 1.802f, 1.802f, 1.801f, 1.8f, - 1.8f, 1.799f, 1.798f, 1.798f, 1.797f, 1.796f, 1.796f, 1.795f, 1.794f, 1.794f, - 1.793f, 1.792f, 1.792f, 1.791f, 1.79f, 1.79f, 1.789f, 1.788f, 1.787f, 1.787f, - 1.786f, 1.785f, 1.785f, 1.784f, 1.783f, 1.783f, 1.782f, 1.781f, 1.781f, 1.78f, - 1.779f, 1.779f, 1.778f, 1.777f, 1.777f, 1.776f, 1.775f, 1.775f, 1.774f, 1.773f, - 1.773f, 1.772f, 1.771f, 1.771f, 1.77f, 1.769f, 1.769f, 1.768f, 1.767f, 1.767f, - 1.766f, 1.766f, 1.765f, 1.764f, 1.764f, 1.763f, 1.762f, 1.762f, 1.761f, 1.76f, - 1.76f, 1.759f, 1.758f, 1.758f, 1.757f, 1.756f, 1.756f, 1.755f, 1.754f, 1.754f, - 1.753f, 1.752f, 1.752f, 1.751f, 1.751f, 1.75f, 1.749f, 1.749f, 1.748f, 1.747f, - 1.747f, 1.746f, 1.745f, 1.745f, 1.744f, 1.743f, 1.743f, 1.742f, 1.742f, 1.741f, - 1.74f, 1.74f, 1.739f, 1.738f, 1.738f, 1.737f, 1.736f, 1.736f, 1.735f, 1.735f, - 1.734f, 1.733f, 1.733f, 1.732f, 1.731f, 1.731f, 1.73f, 1.729f, 1.729f, 1.728f, - 1.728f, 1.727f, 1.726f, 1.726f, 1.725f, 1.724f, 1.724f, 1.723f, 1.723f, 1.722f, - 1.721f, 1.721f, 1.72f, 1.719f, 1.719f, 1.718f, 1.718f, 1.717f, 1.716f, 1.716f, - 1.715f, 1.715f, 1.714f, 1.713f, 1.713f, 1.712f, 1.711f, 1.711f, 1.71f, 1.71f, - 1.709f, 1.708f, 1.708f, 1.707f, 1.706f, 1.706f, 1.705f, 1.705f, 1.704f, 1.703f, - 1.703f, 1.702f, 1.702f, 1.701f, 1.7f, 1.7f, 1.699f, 1.699f, 1.698f, 1.697f, - 1.697f, 1.696f, 1.696f, 1.695f, 1.694f, 1.694f, 1.693f, 1.692f, 1.692f, 1.691f, - 1.691f, 1.69f, 1.689f, 1.689f, 1.688f, 1.688f, 1.687f, 1.686f, 1.686f, 1.685f, - 1.685f, 1.684f, 1.683f, 1.683f, 1.682f, 1.682f, 1.681f, 1.68f, 1.68f, 1.679f, - 1.679f, 1.678f, 1.678f, 1.677f, 1.676f, 1.676f, 1.675f, 1.675f, 1.674f, 1.673f, - 1.673f, 1.672f, 1.672f, 1.671f, 1.67f, 1.67f, 1.669f, 1.669f, 1.668f, 1.667f, - 1.667f, 1.666f, 1.666f, 1.665f, 1.665f, 1.664f, 1.663f, 1.663f, 1.662f, 1.662f, - 1.661f, 1.66f, 1.66f, 1.659f, 1.659f, 1.658f, 1.658f, 1.657f, 1.656f, 1.656f, - 1.655f, 1.655f, 1.654f, 1.653f, 1.653f, 1.652f, 1.652f, 1.651f, 1.651f, 1.65f, - 1.649f, 1.649f, 1.648f, 1.648f, 1.647f, 1.647f, 1.646f, 1.645f, 1.645f, 1.644f, - 1.644f, 1.643f, 1.643f, 1.642f, 1.641f, 1.641f, 1.64f, 1.64f, 1.639f, 1.639f, - 1.638f, 1.637f, 1.637f, 1.636f, 1.636f, 1.635f, 1.635f, 1.634f, 1.633f, 1.633f, - 1.632f, 1.632f, 1.631f, 1.631f, 1.63f, 1.629f, 1.629f, 1.628f, 1.628f, 1.627f, - 1.627f, 1.626f, 1.625f, 1.625f, 1.624f, 1.624f, 1.623f, 1.623f, 1.622f, 1.622f, - 1.621f, 1.62f, 1.62f, 1.619f, 1.619f, 1.618f, 1.618f, 1.617f, 1.617f, 1.616f, - 1.615f, 1.615f, 1.614f, 1.614f, 1.613f, 1.613f, 1.612f, 1.612f, 1.611f, 1.61f, - 1.61f, 1.609f, 1.609f, 1.608f, 1.608f, 1.607f, 1.607f, 1.606f, 1.605f, 1.605f, - 1.604f, 1.604f, 1.603f, 1.603f, 1.602f, 1.602f, 1.601f, 1.6f, 1.6f, 1.599f, - 1.599f, 1.598f, 1.598f, 1.597f, 1.597f, 1.596f, 1.596f, 1.595f, 1.594f, 1.594f, - 1.593f, 1.593f, 1.592f, 1.592f, 1.591f, 1.591f, 1.59f, 1.59f, 1.589f, 1.588f, - 1.588f, 1.587f, 1.587f, 1.586f, 1.586f, 1.585f, 1.585f, 1.584f, 1.584f, 1.583f, - 1.582f, 1.582f, 1.581f, 1.581f, 1.58f, 1.58f, 1.579f, 1.579f, 1.578f, 1.578f, - 1.577f, 1.577f, 1.576f, 1.576f, 1.575f, 1.574f, 1.574f, 1.573f, 1.573f, 1.572f, - 1.572f, 1.571f, 1.571f, 1.57f, 1.57f, 1.569f, 1.569f, 1.568f, 1.567f, 1.567f, - 1.566f, 1.566f, 1.565f, 1.565f, 1.564f, 1.564f, 1.563f, 1.563f, 1.562f, 1.562f, - 1.561f, 1.561f, 1.56f, 1.56f, 1.559f, 1.558f, 1.558f, 1.557f, 1.557f, 1.556f, - 1.556f, 1.555f, 1.555f, 1.554f, 1.554f, 1.553f, 1.553f, 1.552f, 1.552f, 1.551f, - 1.551f, 1.55f, 1.55f, 1.549f, 1.549f, 1.548f, 1.547f, 1.547f, 1.546f, 1.546f, - 1.545f, 1.545f, 1.544f, 1.544f, 1.543f, 1.543f, 1.542f, 1.542f, 1.541f, 1.541f, - 1.54f, 1.54f, 1.539f, 1.539f, 1.538f, 1.538f, 1.537f, 1.537f, 1.536f, 1.536f, - 1.535f, 1.534f, 1.534f, 1.533f, 1.533f, 1.532f, 1.532f, 1.531f, 1.531f, 1.53f, - 1.53f, 1.529f, 1.529f, 1.528f, 1.528f, 1.527f, 1.527f, 1.526f, 1.526f, 1.525f, - 1.525f, 1.524f, 1.524f, 1.523f, 1.523f, 1.522f, 1.522f, 1.521f, 1.521f, 1.52f, - 1.52f, 1.519f, 1.519f, 1.518f, 1.518f, 1.517f, 1.517f, 1.516f, 1.516f, 1.515f, - 1.515f, 1.514f, 1.514f, 1.513f, 1.512f, 1.512f, 1.511f, 1.511f, 1.51f, 1.51f, - 1.509f, 1.509f, 1.508f, 1.508f, 1.507f, 1.507f, 1.506f, 1.506f, 1.505f, 1.505f, - 1.504f, 1.504f, 1.503f, 1.503f, 1.502f, 1.502f, 1.501f, 1.501f, 1.5f, 1.5f, - 1.499f, 1.499f, 1.498f, 1.498f, 1.497f, 1.497f, 1.496f, 1.496f, 1.495f, 1.495f, - 1.494f, 1.494f, 1.493f, 1.493f, 1.492f, 1.492f, 1.491f, 1.491f, 1.49f, 1.49f, - 1.489f, 1.489f, 1.488f, 1.488f, 1.487f, 1.487f, 1.486f, 1.486f, 1.485f, 1.485f, - 1.484f, 1.484f, 1.483f, 1.483f, 1.482f, 1.482f, 1.481f, 1.481f, 1.48f, 1.48f, - 1.48f, 1.479f, 1.479f, 1.478f, 1.478f, 1.477f, 1.477f, 1.476f, 1.476f, 1.475f, - 1.475f, 1.474f, 1.474f, 1.473f, 1.473f, 1.472f, 1.472f, 1.471f, 1.471f, 1.47f, - 1.47f, 1.469f, 1.469f, 1.468f, 1.468f, 1.467f, 1.467f, 1.466f, 1.466f, 1.465f, - 1.465f, 1.464f, 1.464f, 1.463f, 1.463f, 1.462f, 1.462f, 1.461f, 1.461f, 1.46f, - 1.46f, 1.459f, 1.459f, 1.458f, 1.458f, 1.458f, 1.457f, 1.457f, 1.456f, 1.456f, - 1.455f, 1.455f, 1.454f, 1.454f, 1.453f, 1.453f, 1.452f, 1.452f, 1.451f, 1.451f, - 1.45f, 1.45f, 1.449f, 1.449f, 1.448f, 1.448f, 1.447f, 1.447f, 1.446f, 1.446f, - 1.445f, 1.445f, 1.444f, 1.444f, 1.444f, 1.443f, 1.443f, 1.442f, 1.442f, 1.441f, - 1.441f, 1.44f, 1.44f, 1.439f, 1.439f, 1.438f, 1.438f, 1.437f, 1.437f, 1.436f, - 1.436f, 1.435f, 1.435f, 1.434f, 1.434f, 1.434f, 1.433f, 1.433f, 1.432f, 1.432f, - 1.431f, 1.431f, 1.43f, 1.43f, 1.429f, 1.429f, 1.428f, 1.428f, 1.427f, 1.427f, - 1.426f, 1.426f, 1.425f, 1.425f, 1.424f, 1.424f, 1.424f, 1.423f, 1.423f, 1.422f, - 1.422f, 1.421f, 1.421f, 1.42f, 1.42f, 1.419f, 1.419f, 1.418f, 1.418f, 1.417f, - 1.417f, 1.416f, 1.416f, 1.416f, 1.415f, 1.415f, 1.414f, 1.414f, 1.413f, 1.413f, - 1.412f, 1.412f, 1.411f, 1.411f, 1.41f, 1.41f, 1.409f, 1.409f, 1.409f, 1.408f, - 1.408f, 1.407f, 1.407f, 1.406f, 1.406f, 1.405f, 1.405f, 1.404f, 1.404f, 1.403f, - 1.403f, 1.402f, 1.402f, 1.402f, 1.401f, 1.401f, 1.4f, 1.4f, 1.399f, 1.399f, - 1.398f, 1.398f, 1.397f, 1.397f, 1.396f, 1.396f, 1.395f, 1.395f, 1.395f, 1.394f, - 1.394f, 1.393f, 1.393f, 1.392f, 1.392f, 1.391f, 1.391f, 1.39f, 1.39f, 1.389f, - 1.389f, 1.389f, 1.388f, 1.388f, 1.387f, 1.387f, 1.386f, 1.386f, 1.385f, 1.385f, - 1.384f, 1.384f, 1.383f, 1.383f, 1.383f, 1.382f, 1.382f, 1.381f, 1.381f, 1.38f, - 1.38f, 1.379f, 1.379f, 1.378f, 1.378f, 1.378f, 1.377f, 1.377f, 1.376f, 1.376f, - 1.375f, 1.375f, 1.374f, 1.374f, 1.373f, 1.373f, 1.373f, 1.372f, 1.372f, 1.371f, - 1.371f, 1.37f, 1.37f, 1.369f, 1.369f, 1.368f, 1.368f, 1.367f, 1.367f, 1.367f, - 1.366f, 1.366f, 1.365f, 1.365f, 1.364f, 1.364f, 1.363f, 1.363f, 1.362f, 1.362f, - 1.362f, 1.361f, 1.361f, 1.36f, 1.36f, 1.359f, 1.359f, 1.358f, 1.358f, 1.358f, - 1.357f, 1.357f, 1.356f, 1.356f, 1.355f, 1.355f, 1.354f, 1.354f, 1.353f, 1.353f, - 1.353f, 1.352f, 1.352f, 1.351f, 1.351f, 1.35f, 1.35f, 1.349f, 1.349f, 1.349f, - 1.348f, 1.348f, 1.347f, 1.347f, 1.346f, 1.346f, 1.345f, 1.345f, 1.344f, 1.344f, - 1.344f, 1.343f, 1.343f, 1.342f, 1.342f, 1.341f, 1.341f, 1.34f, 1.34f, 1.34f, - 1.339f, 1.339f, 1.338f, 1.338f, 1.337f, 1.337f, 1.336f, 1.336f, 1.336f, 1.335f, - 1.335f, 1.334f, 1.334f, 1.333f, 1.333f, 1.332f, 1.332f, 1.332f, 1.331f, 1.331f, - 1.33f, 1.33f, 1.329f, 1.329f, 1.328f, 1.328f, 1.328f, 1.327f, 1.327f, 1.326f, - 1.326f, 1.325f, 1.325f, 1.324f, 1.324f, 1.324f, 1.323f, 1.323f, 1.322f, 1.322f, - 1.321f, 1.321f, 1.32f, 1.32f, 1.32f, 1.319f, 1.319f, 1.318f, 1.318f, 1.317f, - 1.317f, 1.316f, 1.316f, 1.316f, 1.315f, 1.315f, 1.314f, 1.314f, 1.313f, 1.313f, - 1.312f, 1.312f, 1.312f, 1.311f, 1.311f, 1.31f, 1.31f, 1.309f, 1.309f, 1.309f, - 1.308f, 1.308f, 1.307f, 1.307f, 1.306f, 1.306f, 1.305f, 1.305f, 1.305f, 1.304f, - 1.304f, 1.303f, 1.303f, 1.302f, 1.302f, 1.302f, 1.301f, 1.301f, 1.3f, 1.3f, - 1.299f, 1.299f, 1.298f, 1.298f, 1.298f, 1.297f, 1.297f, 1.296f, 1.296f, 1.295f, - 1.295f, 1.295f, 1.294f, 1.294f, 1.293f, 1.293f, 1.292f, 1.292f, 1.291f, 1.291f, - 1.291f, 1.29f, 1.29f, 1.289f, 1.289f, 1.288f, 1.288f, 1.288f, 1.287f, 1.287f, - 1.286f, 1.286f, 1.285f, 1.285f, 1.285f, 1.284f, 1.284f, 1.283f, 1.283f, 1.282f, - 1.282f, 1.281f, 1.281f, 1.281f, 1.28f, 1.28f, 1.279f, 1.279f, 1.278f, 1.278f, - 1.278f, 1.277f, 1.277f, 1.276f, 1.276f, 1.275f, 1.275f, 1.275f, 1.274f, 1.274f, - 1.273f, 1.273f, 1.272f, 1.272f, 1.272f, 1.271f, 1.271f, 1.27f, 1.27f, 1.269f, - 1.269f, 1.269f, 1.268f, 1.268f, 1.267f, 1.267f, 1.266f, 1.266f, 1.266f, 1.265f, - 1.265f, 1.264f, 1.264f, 1.263f, 1.263f, 1.263f, 1.262f, 1.262f, 1.261f, 1.261f, - 1.26f, 1.26f, 1.26f, 1.259f, 1.259f, 1.258f, 1.258f, 1.257f, 1.257f, 1.257f, - 1.256f, 1.256f, 1.255f, 1.255f, 1.254f, 1.254f, 1.254f, 1.253f, 1.253f, 1.252f, - 1.252f, 1.251f, 1.251f, 1.251f, 1.25f, 1.25f, 1.249f, 1.249f, 1.248f, 1.248f, - 1.248f, 1.247f, 1.247f, 1.246f, 1.246f, 1.245f, 1.245f, 1.245f, 1.244f, 1.244f, - 1.243f, 1.243f, 1.242f, 1.242f, 1.242f, 1.241f, 1.241f, 1.24f, 1.24f, 1.239f, - 1.239f, 1.239f, 1.238f, 1.238f, 1.237f, 1.237f, 1.237f, 1.236f, 1.236f, 1.235f, - 1.235f, 1.234f, 1.234f, 1.234f, 1.233f, 1.233f, 1.232f, 1.232f, 1.231f, 1.231f, - 1.231f, 1.23f, 1.23f, 1.229f, 1.229f, 1.228f, 1.228f, 1.228f, 1.227f, 1.227f, - 1.226f, 1.226f, 1.226f, 1.225f, 1.225f, 1.224f, 1.224f, 1.223f, 1.223f, 1.223f, - 1.222f, 1.222f, 1.221f, 1.221f, 1.22f, 1.22f, 1.22f, 1.219f, 1.219f, 1.218f, - 1.218f, 1.218f, 1.217f, 1.217f, 1.216f, 1.216f, 1.215f, 1.215f, 1.215f, 1.214f, - 1.214f, 1.213f, 1.213f, 1.212f, 1.212f, 1.212f, 1.211f, 1.211f, 1.21f, 1.21f, - 1.21f, 1.209f, 1.209f, 1.208f, 1.208f, 1.207f, 1.207f, 1.207f, 1.206f, 1.206f, - 1.205f, 1.205f, 1.204f, 1.204f, 1.204f, 1.203f, 1.203f, 1.202f, 1.202f, 1.202f, - 1.201f, 1.201f, 1.2f, 1.2f, 1.199f, 1.199f, 1.199f, 1.198f, 1.198f, 1.197f, - 1.197f, 1.197f, 1.196f, 1.196f, 1.195f, 1.195f, 1.194f, 1.194f, 1.194f, 1.193f, - 1.193f, 1.192f, 1.192f, 1.192f, 1.191f, 1.191f, 1.19f, 1.19f, 1.189f, 1.189f, - 1.189f, 1.188f, 1.188f, 1.187f, 1.187f, 1.187f, 1.186f, 1.186f, 1.185f, 1.185f, - 1.184f, 1.184f, 1.184f, 1.183f, 1.183f, 1.182f, 1.182f, 1.182f, 1.181f, 1.181f, - 1.18f, 1.18f, 1.179f, 1.179f, 1.179f, 1.178f, 1.178f, 1.177f, 1.177f, 1.177f, - 1.176f, 1.176f, 1.175f, 1.175f, 1.175f, 1.174f, 1.174f, 1.173f, 1.173f, 1.172f, - 1.172f, 1.172f, 1.171f, 1.171f, 1.17f, 1.17f, 1.17f, 1.169f, 1.169f, 1.168f, - 1.168f, 1.167f, 1.167f, 1.167f, 1.166f, 1.166f, 1.165f, 1.165f, 1.165f, 1.164f, - 1.164f, 1.163f, 1.163f, 1.163f, 1.162f, 1.162f, 1.161f, 1.161f, 1.16f, 1.16f, - 1.16f, 1.159f, 1.159f, 1.158f, 1.158f, 1.158f, 1.157f, 1.157f, 1.156f, 1.156f, - 1.156f, 1.155f, 1.155f, 1.154f, 1.154f, 1.153f, 1.153f, 1.153f, 1.152f, 1.152f, - 1.151f, 1.151f, 1.151f, 1.15f, 1.15f, 1.149f, 1.149f, 1.149f, 1.148f, 1.148f, - 1.147f, 1.147f, 1.146f, 1.146f, 1.146f, 1.145f, 1.145f, 1.144f, 1.144f, 1.144f, - 1.143f, 1.143f, 1.142f, 1.142f, 1.142f, 1.141f, 1.141f, 1.14f, 1.14f, 1.139f, - 1.139f, 1.139f, 1.138f, 1.138f, 1.137f, 1.137f, 1.137f, 1.136f, 1.136f, 1.135f, - 1.135f, 1.135f, 1.134f, 1.134f, 1.133f, 1.133f, 1.133f, 1.132f, 1.132f, 1.131f, - 1.131f, 1.13f, 1.13f, 1.13f, 1.129f, 1.129f, 1.128f, 1.128f, 1.128f, 1.127f, - 1.127f, 1.126f, 1.126f, 1.126f, 1.125f, 1.125f, 1.124f, 1.124f, 1.124f, 1.123f, - 1.123f, 1.122f, 1.122f, 1.121f, 1.121f, 1.121f, 1.12f, 1.12f, 1.119f, 1.119f, - 1.119f, 1.118f, 1.118f, 1.117f, 1.117f, 1.117f, 1.116f, 1.116f, 1.115f, 1.115f, - 1.115f, 1.114f, 1.114f, 1.113f, 1.113f, 1.113f, 1.112f, 1.112f, 1.111f, 1.111f, - 1.11f, 1.11f, 1.11f, 1.109f, 1.109f, 1.108f, 1.108f, 1.108f, 1.107f, 1.107f, - 1.106f, 1.106f, 1.106f, 1.105f, 1.105f, 1.104f, 1.104f, 1.104f, 1.103f, 1.103f, - 1.102f, 1.102f, 1.102f, 1.101f, 1.101f, 1.1f, 1.1f, 1.099f, 1.099f, 1.099f, - 1.098f, 1.098f, 1.097f, 1.097f, 1.097f, 1.096f, 1.096f, 1.095f, 1.095f, 1.095f, - 1.094f, 1.094f, 1.093f, 1.093f, 1.093f, 1.092f, 1.092f, 1.091f, 1.091f, 1.091f, - 1.09f, 1.09f, 1.089f, 1.089f, 1.089f, 1.088f, 1.088f, 1.087f, 1.087f, 1.086f, - 1.086f, 1.086f, 1.085f, 1.085f, 1.084f, 1.084f, 1.084f, 1.083f, 1.083f, 1.082f, - 1.082f, 1.082f, 1.081f, 1.081f, 1.08f, 1.08f, 1.08f, 1.079f, 1.079f, 1.078f, - 1.078f, 1.078f, 1.077f, 1.077f, 1.076f, 1.076f, 1.076f, 1.075f, 1.075f, 1.074f, - 1.074f, 1.074f, 1.073f, 1.073f, 1.072f, 1.072f, 1.072f, 1.071f, 1.071f, 1.07f, - 1.07f, 1.069f, 1.069f, 1.069f, 1.068f, 1.068f, 1.067f, 1.067f, 1.067f, 1.066f, - 1.066f, 1.065f, 1.065f, 1.065f, 1.064f, 1.064f, 1.063f, 1.063f, 1.063f, 1.062f, - 1.062f, 1.061f, 1.061f, 1.061f, 1.06f, 1.06f, 1.059f, 1.059f, 1.059f, 1.058f, - 1.058f, 1.057f, 1.057f, 1.057f, 1.056f, 1.056f, 1.055f, 1.055f, 1.055f, 1.054f, - 1.054f, 1.053f, 1.053f, 1.053f, 1.052f, 1.052f, 1.051f, 1.051f, 1.05f, 1.05f, - 1.05f, 1.049f, 1.049f, 1.048f, 1.048f, 1.048f, 1.047f, 1.047f, 1.046f, 1.046f, - 1.046f, 1.045f, 1.045f, 1.044f, 1.044f, 1.044f, 1.043f, 1.043f, 1.042f, 1.042f, - 1.042f, 1.041f, 1.041f, 1.04f, 1.04f, 1.04f, 1.039f, 1.039f, 1.038f, 1.038f, - 1.038f, 1.037f, 1.037f, 1.036f, 1.036f, 1.036f, 1.035f, 1.035f, 1.034f, 1.034f, - 1.034f, 1.033f, 1.033f, 1.032f, 1.032f, 1.032f, 1.031f, 1.031f, 1.03f, 1.03f, - 1.03f, 1.029f, 1.029f, 1.028f, 1.028f, 1.028f, 1.027f, 1.027f, 1.026f, 1.026f, - 1.026f, 1.025f, 1.025f, 1.024f, 1.024f, 1.023f, 1.023f, 1.023f, 1.022f, 1.022f, - 1.021f, 1.021f, 1.021f, 1.02f, 1.02f, 1.019f, 1.019f, 1.019f, 1.018f, 1.018f, - 1.017f, 1.017f, 1.017f, 1.016f, 1.016f, 1.015f, 1.015f, 1.015f, 1.014f, 1.014f, - 1.013f, 1.013f, 1.013f, 1.012f, 1.012f, 1.011f, 1.011f, 1.011f, 1.01f, 1.01f, - 1.009f, 1.009f, 1.009f, 1.008f, 1.008f, 1.007f, 1.007f, 1.007f, 1.006f, 1.006f, - 1.005f, 1.005f, 1.005f, 1.004f, 1.004f, 1.003f, 1.003f, 1.003f, 1.002f, 1.002f, - 1.001f, 1.001f, 1.001f, 1.0f, 0.9997f, 0.9993f, 0.9989f, 0.9985f, 0.9981f, 0.9977f, - 0.9973f, 0.9969f, 0.9965f, 0.9961f, 0.9957f, 0.9953f, 0.9949f, 0.9945f, 0.9941f, 0.9937f, - 0.9933f, 0.9929f, 0.9925f, 0.9921f, 0.9917f, 0.9913f, 0.9909f, 0.9905f, 0.9901f, 0.9897f, - 0.9893f, 0.9889f, 0.9885f, 0.9881f, 0.9877f, 0.9873f, 0.9869f, 0.9865f, 0.9861f, 0.9856f, - 0.9852f, 0.9848f, 0.9844f, 0.984f, 0.9836f, 0.9832f, 0.9828f, 0.9824f, 0.982f, 0.9816f, - 0.9812f, 0.9808f, 0.9804f, 0.98f, 0.9796f, 0.9792f, 0.9788f, 0.9784f, 0.978f, 0.9776f, - 0.9772f, 0.9768f, 0.9764f, 0.976f, 0.9756f, 0.9752f, 0.9748f, 0.9744f, 0.974f, 0.9736f, - 0.9732f, 0.9728f, 0.9724f, 0.972f, 0.9716f, 0.9712f, 0.9707f, 0.9703f, 0.9699f, 0.9695f, - 0.9691f, 0.9687f, 0.9683f, 0.9679f, 0.9675f, 0.9671f, 0.9667f, 0.9663f, 0.9659f, 0.9655f, - 0.9651f, 0.9647f, 0.9643f, 0.9639f, 0.9635f, 0.9631f, 0.9627f, 0.9623f, 0.9619f, 0.9615f, - 0.9611f, 0.9607f, 0.9603f, 0.9599f, 0.9595f, 0.9591f, 0.9587f, 0.9583f, 0.9579f, 0.9574f, - 0.957f, 0.9566f, 0.9562f, 0.9558f, 0.9554f, 0.955f, 0.9546f, 0.9542f, 0.9538f, 0.9534f, - 0.953f, 0.9526f, 0.9522f, 0.9518f, 0.9514f, 0.951f, 0.9506f, 0.9502f, 0.9498f, 0.9494f, - 0.949f, 0.9486f, 0.9482f, 0.9478f, 0.9474f, 0.947f, 0.9466f, 0.9462f, 0.9457f, 0.9453f, - 0.9449f, 0.9445f, 0.9441f, 0.9437f, 0.9433f, 0.9429f, 0.9425f, 0.9421f, 0.9417f, 0.9413f, - 0.9409f, 0.9405f, 0.9401f, 0.9397f, 0.9393f, 0.9389f, 0.9385f, 0.9381f, 0.9377f, 0.9373f, - 0.9369f, 0.9365f, 0.9361f, 0.9356f, 0.9352f, 0.9348f, 0.9344f, 0.934f, 0.9336f, 0.9332f, - 0.9328f, 0.9324f, 0.932f, 0.9316f, 0.9312f, 0.9308f, 0.9304f, 0.93f, 0.9296f, 0.9292f, - 0.9288f, 0.9284f, 0.928f, 0.9276f, 0.9272f, 0.9267f, 0.9263f, 0.9259f, 0.9255f, 0.9251f, - 0.9247f, 0.9243f, 0.9239f, 0.9235f, 0.9231f, 0.9227f, 0.9223f, 0.9219f, 0.9215f, 0.9211f, - 0.9207f, 0.9203f, 0.9199f, 0.9195f, 0.9191f, 0.9186f, 0.9182f, 0.9178f, 0.9174f, 0.917f, - 0.9166f, 0.9162f, 0.9158f, 0.9154f, 0.915f, 0.9146f, 0.9142f, 0.9138f, 0.9134f, 0.913f, - 0.9126f, 0.9122f, 0.9118f, 0.9113f, 0.9109f, 0.9105f, 0.9101f, 0.9097f, 0.9093f, 0.9089f, - 0.9085f, 0.9081f, 0.9077f, 0.9073f, 0.9069f, 0.9065f, 0.9061f, 0.9057f, 0.9053f, 0.9049f, - 0.9044f, 0.904f, 0.9036f, 0.9032f, 0.9028f, 0.9024f, 0.902f, 0.9016f, 0.9012f, 0.9008f, - 0.9004f, 0.9f, 0.8996f, 0.8992f, 0.8988f, 0.8983f, 0.8979f, 0.8975f, 0.8971f, 0.8967f, - 0.8963f, 0.8959f, 0.8955f, 0.8951f, 0.8947f, 0.8943f, 0.8939f, 0.8935f, 0.8931f, 0.8926f, - 0.8922f, 0.8918f, 0.8914f, 0.891f, 0.8906f, 0.8902f, 0.8898f, 0.8894f, 0.889f, 0.8886f, - 0.8882f, 0.8878f, 0.8873f, 0.8869f, 0.8865f, 0.8861f, 0.8857f, 0.8853f, 0.8849f, 0.8845f, - 0.8841f, 0.8837f, 0.8833f, 0.8829f, 0.8825f, 0.882f, 0.8816f, 0.8812f, 0.8808f, 0.8804f, - 0.88f, 0.8796f, 0.8792f, 0.8788f, 0.8784f, 0.878f, 0.8775f, 0.8771f, 0.8767f, 0.8763f, - 0.8759f, 0.8755f, 0.8751f, 0.8747f, 0.8743f, 0.8739f, 0.8735f, 0.873f, 0.8726f, 0.8722f, - 0.8718f, 0.8714f, 0.871f, 0.8706f, 0.8702f, 0.8698f, 0.8694f, 0.869f, 0.8685f, 0.8681f, - 0.8677f, 0.8673f, 0.8669f, 0.8665f, 0.8661f, 0.8657f, 0.8653f, 0.8649f, 0.8644f, 0.864f, - 0.8636f, 0.8632f, 0.8628f, 0.8624f, 0.862f, 0.8616f, 0.8612f, 0.8607f, 0.8603f, 0.8599f, - 0.8595f, 0.8591f, 0.8587f, 0.8583f, 0.8579f, 0.8575f, 0.857f, 0.8566f, 0.8562f, 0.8558f, - 0.8554f, 0.855f, 0.8546f, 0.8542f, 0.8538f, 0.8533f, 0.8529f, 0.8525f, 0.8521f, 0.8517f, - 0.8513f, 0.8509f, 0.8505f, 0.85f, 0.8496f, 0.8492f, 0.8488f, 0.8484f, 0.848f, 0.8476f, - 0.8472f, 0.8467f, 0.8463f, 0.8459f, 0.8455f, 0.8451f, 0.8447f, 0.8443f, 0.8439f, 0.8434f, - 0.843f, 0.8426f, 0.8422f, 0.8418f, 0.8414f, 0.841f, 0.8406f, 0.8401f, 0.8397f, 0.8393f, - 0.8389f, 0.8385f, 0.8381f, 0.8377f, 0.8372f, 0.8368f, 0.8364f, 0.836f, 0.8356f, 0.8352f, - 0.8348f, 0.8343f, 0.8339f, 0.8335f, 0.8331f, 0.8327f, 0.8323f, 0.8319f, 0.8314f, 0.831f, - 0.8306f, 0.8302f, 0.8298f, 0.8294f, 0.8289f, 0.8285f, 0.8281f, 0.8277f, 0.8273f, 0.8269f, - 0.8265f, 0.826f, 0.8256f, 0.8252f, 0.8248f, 0.8244f, 0.824f, 0.8235f, 0.8231f, 0.8227f, - 0.8223f, 0.8219f, 0.8215f, 0.821f, 0.8206f, 0.8202f, 0.8198f, 0.8194f, 0.819f, 0.8185f, - 0.8181f, 0.8177f, 0.8173f, 0.8169f, 0.8165f, 0.816f, 0.8156f, 0.8152f, 0.8148f, 0.8144f, - 0.814f, 0.8135f, 0.8131f, 0.8127f, 0.8123f, 0.8119f, 0.8114f, 0.811f, 0.8106f, 0.8102f, - 0.8098f, 0.8094f, 0.8089f, 0.8085f, 0.8081f, 0.8077f, 0.8073f, 0.8068f, 0.8064f, 0.806f, - 0.8056f, 0.8052f, 0.8047f, 0.8043f, 0.8039f, 0.8035f, 0.8031f, 0.8026f, 0.8022f, 0.8018f, - 0.8014f, 0.801f, 0.8005f, 0.8001f, 0.7997f, 0.7993f, 0.7989f, 0.7984f, 0.798f, 0.7976f, - 0.7972f, 0.7968f, 0.7963f, 0.7959f, 0.7955f, 0.7951f, 0.7947f, 0.7942f, 0.7938f, 0.7934f, - 0.793f, 0.7926f, 0.7921f, 0.7917f, 0.7913f, 0.7909f, 0.7904f, 0.79f, 0.7896f, 0.7892f, - 0.7888f, 0.7883f, 0.7879f, 0.7875f, 0.7871f, 0.7866f, 0.7862f, 0.7858f, 0.7854f, 0.7849f, - 0.7845f, 0.7841f, 0.7837f, 0.7833f, 0.7828f, 0.7824f, 0.782f, 0.7816f, 0.7811f, 0.7807f, - 0.7803f, 0.7799f, 0.7794f, 0.779f, 0.7786f, 0.7782f, 0.7777f, 0.7773f, 0.7769f, 0.7765f, - 0.776f, 0.7756f, 0.7752f, 0.7748f, 0.7743f, 0.7739f, 0.7735f, 0.7731f, 0.7726f, 0.7722f, - 0.7718f, 0.7714f, 0.7709f, 0.7705f, 0.7701f, 0.7697f, 0.7692f, 0.7688f, 0.7684f, 0.7679f, - 0.7675f, 0.7671f, 0.7667f, 0.7662f, 0.7658f, 0.7654f, 0.765f, 0.7645f, 0.7641f, 0.7637f, - 0.7632f, 0.7628f, 0.7624f, 0.762f, 0.7615f, 0.7611f, 0.7607f, 0.7602f, 0.7598f, 0.7594f, - 0.759f, 0.7585f, 0.7581f, 0.7577f, 0.7572f, 0.7568f, 0.7564f, 0.756f, 0.7555f, 0.7551f, - 0.7547f, 0.7542f, 0.7538f, 0.7534f, 0.7529f, 0.7525f, 0.7521f, 0.7516f, 0.7512f, 0.7508f, - 0.7504f, 0.7499f, 0.7495f, 0.7491f, 0.7486f, 0.7482f, 0.7478f, 0.7473f, 0.7469f, 0.7465f, - 0.746f, 0.7456f, 0.7452f, 0.7447f, 0.7443f, 0.7439f, 0.7434f, 0.743f, 0.7426f, 0.7421f, - 0.7417f, 0.7413f, 0.7408f, 0.7404f, 0.74f, 0.7395f, 0.7391f, 0.7387f, 0.7382f, 0.7378f, - 0.7374f, 0.7369f, 0.7365f, 0.7361f, 0.7356f, 0.7352f, 0.7348f, 0.7343f, 0.7339f, 0.7335f, - 0.733f, 0.7326f, 0.7321f, 0.7317f, 0.7313f, 0.7308f, 0.7304f, 0.73f, 0.7295f, 0.7291f, - 0.7287f, 0.7282f, 0.7278f, 0.7273f, 0.7269f, 0.7265f, 0.726f, 0.7256f, 0.7252f, 0.7247f, - 0.7243f, 0.7238f, 0.7234f, 0.723f, 0.7225f, 0.7221f, 0.7216f, 0.7212f, 0.7208f, 0.7203f, - 0.7199f, 0.7195f, 0.719f, 0.7186f, 0.7181f, 0.7177f, 0.7173f, 0.7168f, 0.7164f, 0.7159f, - 0.7155f, 0.7151f, 0.7146f, 0.7142f, 0.7137f, 0.7133f, 0.7128f, 0.7124f, 0.712f, 0.7115f, - 0.7111f, 0.7106f, 0.7102f, 0.7098f, 0.7093f, 0.7089f, 0.7084f, 0.708f, 0.7075f, 0.7071f, - 0.7066f, 0.7062f, 0.7058f, 0.7053f, 0.7049f, 0.7044f, 0.704f, 0.7035f, 0.7031f, 0.7027f, - 0.7022f, 0.7018f, 0.7013f, 0.7009f, 0.7004f, 0.7f, 0.6995f, 0.6991f, 0.6986f, 0.6982f, - 0.6978f, 0.6973f, 0.6969f, 0.6964f, 0.696f, 0.6955f, 0.6951f, 0.6946f, 0.6942f, 0.6937f, - 0.6933f, 0.6928f, 0.6924f, 0.6919f, 0.6915f, 0.691f, 0.6906f, 0.6901f, 0.6897f, 0.6892f, - 0.6888f, 0.6883f, 0.6879f, 0.6874f, 0.687f, 0.6865f, 0.6861f, 0.6856f, 0.6852f, 0.6847f, - 0.6843f, 0.6838f, 0.6834f, 0.6829f, 0.6825f, 0.682f, 0.6816f, 0.6811f, 0.6807f, 0.6802f, - 0.6798f, 0.6793f, 0.6789f, 0.6784f, 0.678f, 0.6775f, 0.6771f, 0.6766f, 0.6762f, 0.6757f, - 0.6752f, 0.6748f, 0.6743f, 0.6739f, 0.6734f, 0.673f, 0.6725f, 0.6721f, 0.6716f, 0.6711f, - 0.6707f, 0.6702f, 0.6698f, 0.6693f, 0.6689f, 0.6684f, 0.668f, 0.6675f, 0.667f, 0.6666f, - 0.6661f, 0.6657f, 0.6652f, 0.6648f, 0.6643f, 0.6638f, 0.6634f, 0.6629f, 0.6625f, 0.662f, - 0.6615f, 0.6611f, 0.6606f, 0.6602f, 0.6597f, 0.6592f, 0.6588f, 0.6583f, 0.6579f, 0.6574f, - 0.6569f, 0.6565f, 0.656f, 0.6556f, 0.6551f, 0.6546f, 0.6542f, 0.6537f, 0.6532f, 0.6528f, - 0.6523f, 0.6519f, 0.6514f, 0.6509f, 0.6505f, 0.65f, 0.6495f, 0.6491f, 0.6486f, 0.6481f, - 0.6477f, 0.6472f, 0.6468f, 0.6463f, 0.6458f, 0.6454f, 0.6449f, 0.6444f, 0.644f, 0.6435f, - 0.643f, 0.6426f, 0.6421f, 0.6416f, 0.6412f, 0.6407f, 0.6402f, 0.6397f, 0.6393f, 0.6388f, - 0.6383f, 0.6379f, 0.6374f, 0.6369f, 0.6365f, 0.636f, 0.6355f, 0.6351f, 0.6346f, 0.6341f, - 0.6336f, 0.6332f, 0.6327f, 0.6322f, 0.6318f, 0.6313f, 0.6308f, 0.6303f, 0.6299f, 0.6294f, - 0.6289f, 0.6285f, 0.628f, 0.6275f, 0.627f, 0.6266f, 0.6261f, 0.6256f, 0.6251f, 0.6247f, - 0.6242f, 0.6237f, 0.6232f, 0.6228f, 0.6223f, 0.6218f, 0.6213f, 0.6208f, 0.6204f, 0.6199f, - 0.6194f, 0.6189f, 0.6185f, 0.618f, 0.6175f, 0.617f, 0.6165f, 0.6161f, 0.6156f, 0.6151f, - 0.6146f, 0.6142f, 0.6137f, 0.6132f, 0.6127f, 0.6122f, 0.6117f, 0.6113f, 0.6108f, 0.6103f, - 0.6098f, 0.6093f, 0.6089f, 0.6084f, 0.6079f, 0.6074f, 0.6069f, 0.6064f, 0.606f, 0.6055f, - 0.605f, 0.6045f, 0.604f, 0.6035f, 0.603f, 0.6026f, 0.6021f, 0.6016f, 0.6011f, 0.6006f, - 0.6001f, 0.5996f, 0.5992f, 0.5987f, 0.5982f, 0.5977f, 0.5972f, 0.5967f, 0.5962f, 0.5957f, - 0.5952f, 0.5948f, 0.5943f, 0.5938f, 0.5933f, 0.5928f, 0.5923f, 0.5918f, 0.5913f, 0.5908f, - 0.5903f, 0.5898f, 0.5894f, 0.5889f, 0.5884f, 0.5879f, 0.5874f, 0.5869f, 0.5864f, 0.5859f, - 0.5854f, 0.5849f, 0.5844f, 0.5839f, 0.5834f, 0.5829f, 0.5824f, 0.5819f, 0.5814f, 0.5809f, - 0.5804f, 0.5799f, 0.5794f, 0.5789f, 0.5784f, 0.5779f, 0.5774f, 0.5769f, 0.5764f, 0.5759f, - 0.5754f, 0.5749f, 0.5744f, 0.5739f, 0.5734f, 0.5729f, 0.5724f, 0.5719f, 0.5714f, 0.5709f, - 0.5704f, 0.5699f, 0.5694f, 0.5689f, 0.5684f, 0.5679f, 0.5674f, 0.5669f, 0.5664f, 0.5659f, - 0.5654f, 0.5649f, 0.5644f, 0.5639f, 0.5633f, 0.5628f, 0.5623f, 0.5618f, 0.5613f, 0.5608f, - 0.5603f, 0.5598f, 0.5593f, 0.5588f, 0.5582f, 0.5577f, 0.5572f, 0.5567f, 0.5562f, 0.5557f, - 0.5552f, 0.5547f, 0.5541f, 0.5536f, 0.5531f, 0.5526f, 0.5521f, 0.5516f, 0.5511f, 0.5505f, - 0.55f, 0.5495f, 0.549f, 0.5485f, 0.548f, 0.5474f, 0.5469f, 0.5464f, 0.5459f, 0.5454f, - 0.5448f, 0.5443f, 0.5438f, 0.5433f, 0.5428f, 0.5422f, 0.5417f, 0.5412f, 0.5407f, 0.5402f, - 0.5396f, 0.5391f, 0.5386f, 0.5381f, 0.5375f, 0.537f, 0.5365f, 0.536f, 0.5354f, 0.5349f, - 0.5344f, 0.5339f, 0.5333f, 0.5328f, 0.5323f, 0.5317f, 0.5312f, 0.5307f, 0.5302f, 0.5296f, - 0.5291f, 0.5286f, 0.528f, 0.5275f, 0.527f, 0.5264f, 0.5259f, 0.5254f, 0.5248f, 0.5243f, - 0.5238f, 0.5232f, 0.5227f, 0.5222f, 0.5216f, 0.5211f, 0.5206f, 0.52f, 0.5195f, 0.5189f, - 0.5184f, 0.5179f, 0.5173f, 0.5168f, 0.5162f, 0.5157f, 0.5152f, 0.5146f, 0.5141f, 0.5135f, - 0.513f, 0.5124f, 0.5119f, 0.5114f, 0.5108f, 0.5103f, 0.5097f, 0.5092f, 0.5086f, 0.5081f, - 0.5075f, 0.507f, 0.5064f, 0.5059f, 0.5053f, 0.5048f, 0.5043f, 0.5037f, 0.5032f, 0.5026f, - 0.502f, 0.5015f, 0.5009f, 0.5004f, 0.4998f, 0.4993f, 0.4987f, 0.4982f, 0.4976f, 0.4971f, - 0.4965f, 0.496f, 0.4954f, 0.4948f, 0.4943f, 0.4937f, 0.4932f, 0.4926f, 0.492f, 0.4915f, - 0.4909f, 0.4904f, 0.4898f, 0.4892f, 0.4887f, 0.4881f, 0.4875f, 0.487f, 0.4864f, 0.4859f, - 0.4853f, 0.4847f, 0.4842f, 0.4836f, 0.483f, 0.4825f, 0.4819f, 0.4813f, 0.4807f, 0.4802f, - 0.4796f, 0.479f, 0.4785f, 0.4779f, 0.4773f, 0.4767f, 0.4762f, 0.4756f, 0.475f, 0.4744f, - 0.4739f, 0.4733f, 0.4727f, 0.4721f, 0.4716f, 0.471f, 0.4704f, 0.4698f, 0.4692f, 0.4687f, - 0.4681f, 0.4675f, 0.4669f, 0.4663f, 0.4657f, 0.4652f, 0.4646f, 0.464f, 0.4634f, 0.4628f, - 0.4622f, 0.4616f, 0.461f, 0.4605f, 0.4599f, 0.4593f, 0.4587f, 0.4581f, 0.4575f, 0.4569f, - 0.4563f, 0.4557f, 0.4551f, 0.4545f, 0.4539f, 0.4533f, 0.4527f, 0.4521f, 0.4515f, 0.451f, - 0.4504f, 0.4498f, 0.4491f, 0.4485f, 0.4479f, 0.4473f, 0.4467f, 0.4461f, 0.4455f, 0.4449f, - 0.4443f, 0.4437f, 0.4431f, 0.4425f, 0.4419f, 0.4413f, 0.4407f, 0.4401f, 0.4394f, 0.4388f, - 0.4382f, 0.4376f, 0.437f, 0.4364f, 0.4358f, 0.4351f, 0.4345f, 0.4339f, 0.4333f, 0.4327f, - 0.4321f, 0.4314f, 0.4308f, 0.4302f, 0.4296f, 0.4289f, 0.4283f, 0.4277f, 0.4271f, 0.4264f, - 0.4258f, 0.4252f, 0.4246f, 0.4239f, 0.4233f, 0.4227f, 0.422f, 0.4214f, 0.4208f, 0.4201f, - 0.4195f, 0.4189f, 0.4182f, 0.4176f, 0.4169f, 0.4163f, 0.4157f, 0.415f, 0.4144f, 0.4137f, - 0.4131f, 0.4125f, 0.4118f, 0.4112f, 0.4105f, 0.4099f, 0.4092f, 0.4086f, 0.4079f, 0.4073f, - 0.4066f, 0.406f, 0.4053f, 0.4047f, 0.404f, 0.4034f, 0.4027f, 0.402f, 0.4014f, 0.4007f, - 0.4001f, 0.3994f, 0.3987f, 0.3981f, 0.3974f, 0.3967f, 0.3961f, 0.3954f, 0.3947f, 0.3941f, - 0.3934f, 0.3927f, 0.3921f, 0.3914f, 0.3907f, 0.39f, 0.3894f, 0.3887f, 0.388f, 0.3873f, - 0.3866f, 0.386f, 0.3853f, 0.3846f, 0.3839f, 0.3832f, 0.3825f, 0.3819f, 0.3812f, 0.3805f, - 0.3798f, 0.3791f, 0.3784f, 0.3777f, 0.377f, 0.3763f, 0.3756f, 0.3749f, 0.3742f, 0.3735f, - 0.3728f, 0.3721f, 0.3714f, 0.3707f, 0.37f, 0.3693f, 0.3686f, 0.3679f, 0.3672f, 0.3665f, - 0.3657f, 0.365f, 0.3643f, 0.3636f, 0.3629f, 0.3622f, 0.3614f, 0.3607f, 0.36f, 0.3593f, - 0.3585f, 0.3578f, 0.3571f, 0.3564f, 0.3556f, 0.3549f, 0.3542f, 0.3534f, 0.3527f, 0.352f, - 0.3512f, 0.3505f, 0.3497f, 0.349f, 0.3483f, 0.3475f, 0.3468f, 0.346f, 0.3453f, 0.3445f, - 0.3438f, 0.343f, 0.3422f, 0.3415f, 0.3407f, 0.34f, 0.3392f, 0.3384f, 0.3377f, 0.3369f, - 0.3361f, 0.3354f, 0.3346f, 0.3338f, 0.3331f, 0.3323f, 0.3315f, 0.3307f, 0.3299f, 0.3292f, - 0.3284f, 0.3276f, 0.3268f, 0.326f, 0.3252f, 0.3244f, 0.3236f, 0.3228f, 0.3221f, 0.3213f, - 0.3205f, 0.3196f, 0.3188f, 0.318f, 0.3172f, 0.3164f, 0.3156f, 0.3148f, 0.314f, 0.3132f, - 0.3123f, 0.3115f, 0.3107f, 0.3099f, 0.309f, 0.3082f, 0.3074f, 0.3065f, 0.3057f, 0.3049f, - 0.304f, 0.3032f, 0.3023f, 0.3015f, 0.3007f, 0.2998f, 0.2989f, 0.2981f, 0.2972f, 0.2964f, - 0.2955f, 0.2946f, 0.2938f, 0.2929f, 0.292f, 0.2912f, 0.2903f, 0.2894f, 0.2885f, 0.2877f, - 0.2868f, 0.2859f, 0.285f, 0.2841f, 0.2832f, 0.2823f, 0.2814f, 0.2805f, 0.2796f, 0.2787f, - 0.2778f, 0.2768f, 0.2759f, 0.275f, 0.2741f, 0.2732f, 0.2722f, 0.2713f, 0.2704f, 0.2694f, - 0.2685f, 0.2675f, 0.2666f, 0.2656f, 0.2647f, 0.2637f, 0.2628f, 0.2618f, 0.2608f, 0.2599f, - 0.2589f, 0.2579f, 0.2569f, 0.256f, 0.255f, 0.254f, 0.253f, 0.252f, 0.251f, 0.25f, - 0.249f, 0.248f, 0.2469f, 0.2459f, 0.2449f, 0.2439f, 0.2428f, 0.2418f, 0.2408f, 0.2397f, - 0.2387f, 0.2376f, 0.2365f, 0.2355f, 0.2344f, 0.2333f, 0.2323f, 0.2312f, 0.2301f, 0.229f, - 0.2279f, 0.2268f, 0.2257f, 0.2246f, 0.2235f, 0.2223f, 0.2212f, 0.2201f, 0.2189f, 0.2178f, - 0.2166f, 0.2155f, 0.2143f, 0.2132f, 0.212f, 0.2108f, 0.2096f, 0.2084f, 0.2072f, 0.206f, - 0.2048f, 0.2036f, 0.2023f, 0.2011f, 0.1999f, 0.1986f, 0.1974f, 0.1961f, 0.1948f, 0.1935f, - 0.1923f, 0.191f, 0.1896f, 0.1883f, 0.187f, 0.1857f, 0.1843f, 0.183f, 0.1816f, 0.1802f, - 0.1789f, 0.1775f, 0.1761f, 0.1747f, 0.1732f, 0.1718f, 0.1703f, 0.1689f, 0.1674f, 0.1659f, - 0.1644f, 0.1629f, 0.1614f, 0.1599f, 0.1583f, 0.1567f, 0.1551f, 0.1535f, 0.1519f, 0.1503f, - 0.1486f, 0.147f, 0.1453f, 0.1436f, 0.1418f, 0.1401f, 0.1383f, 0.1365f, 0.1347f, 0.1329f, - 0.131f, 0.1291f, 0.1272f, 0.1252f, 0.1233f, 0.1213f, 0.1192f, 0.1171f, 0.115f, 0.1129f, - 0.1107f, 0.1084f, 0.1061f, 0.1038f, 0.1014f, 0.09894f, 0.09643f, 0.09385f, 0.0912f, 0.08847f, - 0.08566f, 0.08275f, 0.07974f, 0.0766f, 0.07334f, 0.06992f, 0.06633f, 0.06253f, 0.05849f, 0.05415f, - 0.04943f, 0.0442f, 0.03828f, 0.03125f, 0.0221f, -0.0f}; - - const static float cosvals[max] = { - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.9999f, 0.9999f, 0.9999f, 0.9999f, - 0.9999f, 0.9998f, 0.9998f, 0.9998f, 0.9997f, 0.9997f, 0.9997f, 0.9996f, 0.9996f, 0.9995f, - 0.9995f, 0.9994f, 0.9994f, 0.9993f, 0.9993f, 0.9992f, 0.9991f, 0.9991f, 0.999f, 0.9989f, - 0.9989f, 0.9988f, 0.9987f, 0.9986f, 0.9986f, 0.9985f, 0.9984f, 0.9983f, 0.9982f, 0.9981f, - 0.998f, 0.9979f, 0.9978f, 0.9977f, 0.9976f, 0.9975f, 0.9974f, 0.9973f, 0.9972f, 0.9971f, - 0.9969f, 0.9968f, 0.9967f, 0.9966f, 0.9964f, 0.9963f, 0.9962f, 0.996f, 0.9959f, 0.9958f, - 0.9956f, 0.9955f, 0.9953f, 0.9952f, 0.995f, 0.9949f, 0.9947f, 0.9946f, 0.9944f, 0.9942f, - 0.9941f, 0.9939f, 0.9937f, 0.9936f, 0.9934f, 0.9932f, 0.993f, 0.9929f, 0.9927f, 0.9925f, - 0.9923f, 0.9921f, 0.9919f, 0.9917f, 0.9915f, 0.9913f, 0.9911f, 0.9909f, 0.9907f, 0.9905f, - 0.9903f, 0.9901f, 0.9898f, 0.9896f, 0.9894f, 0.9892f, 0.989f, 0.9887f, 0.9885f, 0.9883f, - 0.988f, 0.9878f, 0.9875f, 0.9873f, 0.9871f, 0.9868f, 0.9866f, 0.9863f, 0.9861f, 0.9858f, - 0.9855f, 0.9853f, 0.985f, 0.9847f, 0.9845f, 0.9842f, 0.9839f, 0.9837f, 0.9834f, 0.9831f, - 0.9828f, 0.9825f, 0.9823f, 0.982f, 0.9817f, 0.9814f, 0.9811f, 0.9808f, 0.9805f, 0.9802f, - 0.9799f, 0.9796f, 0.9793f, 0.9789f, 0.9786f, 0.9783f, 0.978f, 0.9777f, 0.9774f, 0.977f, - 0.9767f, 0.9764f, 0.976f, 0.9757f, 0.9754f, 0.975f, 0.9747f, 0.9743f, 0.974f, 0.9736f, - 0.9733f, 0.9729f, 0.9726f, 0.9722f, 0.9719f, 0.9715f, 0.9711f, 0.9708f, 0.9704f, 0.97f, - 0.9697f, 0.9693f, 0.9689f, 0.9685f, 0.9681f, 0.9678f, 0.9674f, 0.967f, 0.9666f, 0.9662f, - 0.9658f, 0.9654f, 0.965f, 0.9646f, 0.9642f, 0.9638f, 0.9634f, 0.963f, 0.9625f, 0.9621f, - 0.9617f, 0.9613f, 0.9609f, 0.9604f, 0.96f, 0.9596f, 0.9591f, 0.9587f, 0.9583f, 0.9578f, - 0.9574f, 0.9569f, 0.9565f, 0.956f, 0.9556f, 0.9551f, 0.9547f, 0.9542f, 0.9538f, 0.9533f, - 0.9528f, 0.9524f, 0.9519f, 0.9514f, 0.951f, 0.9505f, 0.95f, 0.9495f, 0.949f, 0.9486f, - 0.9481f, 0.9476f, 0.9471f, 0.9466f, 0.9461f, 0.9456f, 0.9451f, 0.9446f, 0.9441f, 0.9436f, - 0.9431f, 0.9426f, 0.9421f, 0.9415f, 0.941f, 0.9405f, 0.94f, 0.9395f, 0.9389f, 0.9384f, - 0.9379f, 0.9373f, 0.9368f, 0.9363f, 0.9357f, 0.9352f, 0.9346f, 0.9341f, 0.9335f, 0.933f, - 0.9324f, 0.9319f, 0.9313f, 0.9308f, 0.9302f, 0.9296f, 0.9291f, 0.9285f, 0.9279f, 0.9274f, - 0.9268f, 0.9262f, 0.9256f, 0.925f, 0.9245f, 0.9239f, 0.9233f, 0.9227f, 0.9221f, 0.9215f, - 0.9209f, 0.9203f, 0.9197f, 0.9191f, 0.9185f, 0.9179f, 0.9173f, 0.9167f, 0.9161f, 0.9154f, - 0.9148f, 0.9142f, 0.9136f, 0.913f, 0.9123f, 0.9117f, 0.9111f, 0.9104f, 0.9098f, 0.9092f, - 0.9085f, 0.9079f, 0.9072f, 0.9066f, 0.9059f, 0.9053f, 0.9046f, 0.904f, 0.9033f, 0.9027f, - 0.902f, 0.9013f, 0.9007f, 0.9f, 0.8993f, 0.8987f, 0.898f, 0.8973f, 0.8966f, 0.896f, - 0.8953f, 0.8946f, 0.8939f, 0.8932f, 0.8925f, 0.8918f, 0.8911f, 0.8904f, 0.8897f, 0.889f, - 0.8883f, 0.8876f, 0.8869f, 0.8862f, 0.8855f, 0.8848f, 0.8841f, 0.8834f, 0.8826f, 0.8819f, - 0.8812f, 0.8805f, 0.8797f, 0.879f, 0.8783f, 0.8775f, 0.8768f, 0.8761f, 0.8753f, 0.8746f, - 0.8738f, 0.8731f, 0.8723f, 0.8716f, 0.8708f, 0.8701f, 0.8693f, 0.8686f, 0.8678f, 0.867f, - 0.8663f, 0.8655f, 0.8647f, 0.864f, 0.8632f, 0.8624f, 0.8616f, 0.8609f, 0.8601f, 0.8593f, - 0.8585f, 0.8577f, 0.8569f, 0.8561f, 0.8554f, 0.8546f, 0.8538f, 0.853f, 0.8522f, 0.8514f, - 0.8505f, 0.8497f, 0.8489f, 0.8481f, 0.8473f, 0.8465f, 0.8457f, 0.8449f, 0.844f, 0.8432f, - 0.8424f, 0.8416f, 0.8407f, 0.8399f, 0.8391f, 0.8382f, 0.8374f, 0.8365f, 0.8357f, 0.8349f, - 0.834f, 0.8332f, 0.8323f, 0.8315f, 0.8306f, 0.8298f, 0.8289f, 0.828f, 0.8272f, 0.8263f, - 0.8255f, 0.8246f, 0.8237f, 0.8228f, 0.822f, 0.8211f, 0.8202f, 0.8193f, 0.8185f, 0.8176f, - 0.8167f, 0.8158f, 0.8149f, 0.814f, 0.8131f, 0.8123f, 0.8114f, 0.8105f, 0.8096f, 0.8087f, - 0.8078f, 0.8068f, 0.8059f, 0.805f, 0.8041f, 0.8032f, 0.8023f, 0.8014f, 0.8005f, 0.7995f, - 0.7986f, 0.7977f, 0.7968f, 0.7958f, 0.7949f, 0.794f, 0.793f, 0.7921f, 0.7912f, 0.7902f, - 0.7893f, 0.7883f, 0.7874f, 0.7865f, 0.7855f, 0.7846f, 0.7836f, 0.7827f, 0.7817f, 0.7807f, - 0.7798f, 0.7788f, 0.7779f, 0.7769f, 0.7759f, 0.775f, 0.774f, 0.773f, 0.772f, 0.7711f, - 0.7701f, 0.7691f, 0.7681f, 0.7671f, 0.7662f, 0.7652f, 0.7642f, 0.7632f, 0.7622f, 0.7612f, - 0.7602f, 0.7592f, 0.7582f, 0.7572f, 0.7562f, 0.7552f, 0.7542f, 0.7532f, 0.7522f, 0.7512f, - 0.7502f, 0.7491f, 0.7481f, 0.7471f, 0.7461f, 0.7451f, 0.744f, 0.743f, 0.742f, 0.741f, - 0.7399f, 0.7389f, 0.7379f, 0.7368f, 0.7358f, 0.7347f, 0.7337f, 0.7327f, 0.7316f, 0.7306f, - 0.7295f, 0.7285f, 0.7274f, 0.7264f, 0.7253f, 0.7242f, 0.7232f, 0.7221f, 0.7211f, 0.72f, - 0.7189f, 0.7179f, 0.7168f, 0.7157f, 0.7147f, 0.7136f, 0.7125f, 0.7114f, 0.7104f, 0.7093f, - 0.7082f, 0.7071f, 0.706f, 0.7049f, 0.7038f, 0.7028f, 0.7017f, 0.7006f, 0.6995f, 0.6984f, - 0.6973f, 0.6962f, 0.6951f, 0.694f, 0.6929f, 0.6918f, 0.6907f, 0.6895f, 0.6884f, 0.6873f, - 0.6862f, 0.6851f, 0.684f, 0.6828f, 0.6817f, 0.6806f, 0.6795f, 0.6784f, 0.6772f, 0.6761f, - 0.675f, 0.6738f, 0.6727f, 0.6716f, 0.6704f, 0.6693f, 0.6681f, 0.667f, 0.6659f, 0.6647f, - 0.6636f, 0.6624f, 0.6613f, 0.6601f, 0.659f, 0.6578f, 0.6567f, 0.6555f, 0.6543f, 0.6532f, - 0.652f, 0.6508f, 0.6497f, 0.6485f, 0.6473f, 0.6462f, 0.645f, 0.6438f, 0.6427f, 0.6415f, - 0.6403f, 0.6391f, 0.6379f, 0.6368f, 0.6356f, 0.6344f, 0.6332f, 0.632f, 0.6308f, 0.6296f, - 0.6284f, 0.6273f, 0.6261f, 0.6249f, 0.6237f, 0.6225f, 0.6213f, 0.6201f, 0.6189f, 0.6176f, - 0.6164f, 0.6152f, 0.614f, 0.6128f, 0.6116f, 0.6104f, 0.6092f, 0.6079f, 0.6067f, 0.6055f, - 0.6043f, 0.6031f, 0.6018f, 0.6006f, 0.5994f, 0.5982f, 0.5969f, 0.5957f, 0.5945f, 0.5932f, - 0.592f, 0.5908f, 0.5895f, 0.5883f, 0.587f, 0.5858f, 0.5846f, 0.5833f, 0.5821f, 0.5808f, - 0.5796f, 0.5783f, 0.5771f, 0.5758f, 0.5746f, 0.5733f, 0.572f, 0.5708f, 0.5695f, 0.5683f, - 0.567f, 0.5657f, 0.5645f, 0.5632f, 0.5619f, 0.5607f, 0.5594f, 0.5581f, 0.5568f, 0.5556f, - 0.5543f, 0.553f, 0.5517f, 0.5505f, 0.5492f, 0.5479f, 0.5466f, 0.5453f, 0.544f, 0.5428f, - 0.5415f, 0.5402f, 0.5389f, 0.5376f, 0.5363f, 0.535f, 0.5337f, 0.5324f, 0.5311f, 0.5298f, - 0.5285f, 0.5272f, 0.5259f, 0.5246f, 0.5233f, 0.522f, 0.5207f, 0.5194f, 0.518f, 0.5167f, - 0.5154f, 0.5141f, 0.5128f, 0.5115f, 0.5102f, 0.5088f, 0.5075f, 0.5062f, 0.5049f, 0.5035f, - 0.5022f, 0.5009f, 0.4996f, 0.4982f, 0.4969f, 0.4956f, 0.4942f, 0.4929f, 0.4916f, 0.4902f, - 0.4889f, 0.4876f, 0.4862f, 0.4849f, 0.4835f, 0.4822f, 0.4808f, 0.4795f, 0.4781f, 0.4768f, - 0.4755f, 0.4741f, 0.4727f, 0.4714f, 0.47f, 0.4687f, 0.4673f, 0.466f, 0.4646f, 0.4633f, - 0.4619f, 0.4605f, 0.4592f, 0.4578f, 0.4564f, 0.4551f, 0.4537f, 0.4523f, 0.451f, 0.4496f, - 0.4482f, 0.4469f, 0.4455f, 0.4441f, 0.4427f, 0.4414f, 0.44f, 0.4386f, 0.4372f, 0.4359f, - 0.4345f, 0.4331f, 0.4317f, 0.4303f, 0.4289f, 0.4276f, 0.4262f, 0.4248f, 0.4234f, 0.422f, - 0.4206f, 0.4192f, 0.4178f, 0.4164f, 0.415f, 0.4136f, 0.4122f, 0.4108f, 0.4094f, 0.408f, - 0.4066f, 0.4052f, 0.4038f, 0.4024f, 0.401f, 0.3996f, 0.3982f, 0.3968f, 0.3954f, 0.394f, - 0.3926f, 0.3912f, 0.3898f, 0.3883f, 0.3869f, 0.3855f, 0.3841f, 0.3827f, 0.3813f, 0.3798f, - 0.3784f, 0.377f, 0.3756f, 0.3742f, 0.3727f, 0.3713f, 0.3699f, 0.3685f, 0.367f, 0.3656f, - 0.3642f, 0.3628f, 0.3613f, 0.3599f, 0.3585f, 0.357f, 0.3556f, 0.3542f, 0.3527f, 0.3513f, - 0.3499f, 0.3484f, 0.347f, 0.3455f, 0.3441f, 0.3427f, 0.3412f, 0.3398f, 0.3383f, 0.3369f, - 0.3354f, 0.334f, 0.3326f, 0.3311f, 0.3297f, 0.3282f, 0.3268f, 0.3253f, 0.3239f, 0.3224f, - 0.321f, 0.3195f, 0.318f, 0.3166f, 0.3151f, 0.3137f, 0.3122f, 0.3108f, 0.3093f, 0.3078f, - 0.3064f, 0.3049f, 0.3035f, 0.302f, 0.3005f, 0.2991f, 0.2976f, 0.2962f, 0.2947f, 0.2932f, - 0.2918f, 0.2903f, 0.2888f, 0.2873f, 0.2859f, 0.2844f, 0.2829f, 0.2815f, 0.28f, 0.2785f, - 0.277f, 0.2756f, 0.2741f, 0.2726f, 0.2711f, 0.2697f, 0.2682f, 0.2667f, 0.2652f, 0.2638f, - 0.2623f, 0.2608f, 0.2593f, 0.2578f, 0.2563f, 0.2549f, 0.2534f, 0.2519f, 0.2504f, 0.2489f, - 0.2474f, 0.246f, 0.2445f, 0.243f, 0.2415f, 0.24f, 0.2385f, 0.237f, 0.2355f, 0.234f, - 0.2326f, 0.2311f, 0.2296f, 0.2281f, 0.2266f, 0.2251f, 0.2236f, 0.2221f, 0.2206f, 0.2191f, - 0.2176f, 0.2161f, 0.2146f, 0.2131f, 0.2116f, 0.2101f, 0.2086f, 0.2071f, 0.2056f, 0.2041f, - 0.2026f, 0.2011f, 0.1996f, 0.1981f, 0.1966f, 0.1951f, 0.1936f, 0.1921f, 0.1906f, 0.1891f, - 0.1876f, 0.1861f, 0.1845f, 0.183f, 0.1815f, 0.18f, 0.1785f, 0.177f, 0.1755f, 0.174f, - 0.1725f, 0.171f, 0.1695f, 0.1679f, 0.1664f, 0.1649f, 0.1634f, 0.1619f, 0.1604f, 0.1589f, - 0.1573f, 0.1558f, 0.1543f, 0.1528f, 0.1513f, 0.1498f, 0.1482f, 0.1467f, 0.1452f, 0.1437f, - 0.1422f, 0.1407f, 0.1391f, 0.1376f, 0.1361f, 0.1346f, 0.1331f, 0.1315f, 0.13f, 0.1285f, - 0.127f, 0.1255f, 0.1239f, 0.1224f, 0.1209f, 0.1194f, 0.1178f, 0.1163f, 0.1148f, 0.1133f, - 0.1117f, 0.1102f, 0.1087f, 0.1072f, 0.1056f, 0.1041f, 0.1026f, 0.1011f, 0.09954f, 0.09802f, - 0.09649f, 0.09496f, 0.09344f, 0.09191f, 0.09038f, 0.08885f, 0.08733f, 0.0858f, 0.08427f, 0.08274f, - 0.08121f, 0.07968f, 0.07815f, 0.07662f, 0.07509f, 0.07356f, 0.07203f, 0.0705f, 0.06897f, 0.06744f, - 0.06591f, 0.06438f, 0.06285f, 0.06132f, 0.05979f, 0.05826f, 0.05673f, 0.0552f, 0.05366f, 0.05213f, - 0.0506f, 0.04907f, 0.04754f, 0.046f, 0.04447f, 0.04294f, 0.04141f, 0.03987f, 0.03834f, 0.03681f, - 0.03527f, 0.03374f, 0.03221f, 0.03067f, 0.02914f, 0.02761f, 0.02607f, 0.02454f, 0.02301f, 0.02147f, - 0.01994f, 0.01841f, 0.01687f, 0.01534f, 0.01381f, 0.01227f, 0.01074f, 0.009204f, 0.00767f, 0.006136f, - 0.004602f, 0.003068f, 0.001534f, 6.123e-17f, -0.001534f, -0.003068f, -0.004602f, -0.006136f, -0.00767f, -0.009204f, - -0.01074f, -0.01227f, -0.01381f, -0.01534f, -0.01687f, -0.01841f, -0.01994f, -0.02147f, -0.02301f, -0.02454f, - -0.02607f, -0.02761f, -0.02914f, -0.03067f, -0.03221f, -0.03374f, -0.03527f, -0.03681f, -0.03834f, -0.03987f, - -0.04141f, -0.04294f, -0.04447f, -0.046f, -0.04754f, -0.04907f, -0.0506f, -0.05213f, -0.05366f, -0.0552f, - -0.05673f, -0.05826f, -0.05979f, -0.06132f, -0.06285f, -0.06438f, -0.06591f, -0.06744f, -0.06897f, -0.0705f, - -0.07203f, -0.07356f, -0.07509f, -0.07662f, -0.07815f, -0.07968f, -0.08121f, -0.08274f, -0.08427f, -0.0858f, - -0.08733f, -0.08885f, -0.09038f, -0.09191f, -0.09344f, -0.09496f, -0.09649f, -0.09802f, -0.09954f, -0.1011f, - -0.1026f, -0.1041f, -0.1056f, -0.1072f, -0.1087f, -0.1102f, -0.1117f, -0.1133f, -0.1148f, -0.1163f, - -0.1178f, -0.1194f, -0.1209f, -0.1224f, -0.1239f, -0.1255f, -0.127f, -0.1285f, -0.13f, -0.1315f, - -0.1331f, -0.1346f, -0.1361f, -0.1376f, -0.1391f, -0.1407f, -0.1422f, -0.1437f, -0.1452f, -0.1467f, - -0.1482f, -0.1498f, -0.1513f, -0.1528f, -0.1543f, -0.1558f, -0.1573f, -0.1589f, -0.1604f, -0.1619f, - -0.1634f, -0.1649f, -0.1664f, -0.1679f, -0.1695f, -0.171f, -0.1725f, -0.174f, -0.1755f, -0.177f, - -0.1785f, -0.18f, -0.1815f, -0.183f, -0.1845f, -0.1861f, -0.1876f, -0.1891f, -0.1906f, -0.1921f, - -0.1936f, -0.1951f, -0.1966f, -0.1981f, -0.1996f, -0.2011f, -0.2026f, -0.2041f, -0.2056f, -0.2071f, - -0.2086f, -0.2101f, -0.2116f, -0.2131f, -0.2146f, -0.2161f, -0.2176f, -0.2191f, -0.2206f, -0.2221f, - -0.2236f, -0.2251f, -0.2266f, -0.2281f, -0.2296f, -0.2311f, -0.2326f, -0.234f, -0.2355f, -0.237f, - -0.2385f, -0.24f, -0.2415f, -0.243f, -0.2445f, -0.246f, -0.2474f, -0.2489f, -0.2504f, -0.2519f, - -0.2534f, -0.2549f, -0.2563f, -0.2578f, -0.2593f, -0.2608f, -0.2623f, -0.2638f, -0.2652f, -0.2667f, - -0.2682f, -0.2697f, -0.2711f, -0.2726f, -0.2741f, -0.2756f, -0.277f, -0.2785f, -0.28f, -0.2815f, - -0.2829f, -0.2844f, -0.2859f, -0.2873f, -0.2888f, -0.2903f, -0.2918f, -0.2932f, -0.2947f, -0.2962f, - -0.2976f, -0.2991f, -0.3005f, -0.302f, -0.3035f, -0.3049f, -0.3064f, -0.3078f, -0.3093f, -0.3108f, - -0.3122f, -0.3137f, -0.3151f, -0.3166f, -0.318f, -0.3195f, -0.321f, -0.3224f, -0.3239f, -0.3253f, - -0.3268f, -0.3282f, -0.3297f, -0.3311f, -0.3326f, -0.334f, -0.3354f, -0.3369f, -0.3383f, -0.3398f, - -0.3412f, -0.3427f, -0.3441f, -0.3455f, -0.347f, -0.3484f, -0.3499f, -0.3513f, -0.3527f, -0.3542f, - -0.3556f, -0.357f, -0.3585f, -0.3599f, -0.3613f, -0.3628f, -0.3642f, -0.3656f, -0.367f, -0.3685f, - -0.3699f, -0.3713f, -0.3727f, -0.3742f, -0.3756f, -0.377f, -0.3784f, -0.3798f, -0.3813f, -0.3827f, - -0.3841f, -0.3855f, -0.3869f, -0.3883f, -0.3898f, -0.3912f, -0.3926f, -0.394f, -0.3954f, -0.3968f, - -0.3982f, -0.3996f, -0.401f, -0.4024f, -0.4038f, -0.4052f, -0.4066f, -0.408f, -0.4094f, -0.4108f, - -0.4122f, -0.4136f, -0.415f, -0.4164f, -0.4178f, -0.4192f, -0.4206f, -0.422f, -0.4234f, -0.4248f, - -0.4262f, -0.4276f, -0.4289f, -0.4303f, -0.4317f, -0.4331f, -0.4345f, -0.4359f, -0.4372f, -0.4386f, - -0.44f, -0.4414f, -0.4427f, -0.4441f, -0.4455f, -0.4469f, -0.4482f, -0.4496f, -0.451f, -0.4523f, - -0.4537f, -0.4551f, -0.4564f, -0.4578f, -0.4592f, -0.4605f, -0.4619f, -0.4633f, -0.4646f, -0.466f, - -0.4673f, -0.4687f, -0.47f, -0.4714f, -0.4727f, -0.4741f, -0.4755f, -0.4768f, -0.4781f, -0.4795f, - -0.4808f, -0.4822f, -0.4835f, -0.4849f, -0.4862f, -0.4876f, -0.4889f, -0.4902f, -0.4916f, -0.4929f, - -0.4942f, -0.4956f, -0.4969f, -0.4982f, -0.4996f, -0.5009f, -0.5022f, -0.5035f, -0.5049f, -0.5062f, - -0.5075f, -0.5088f, -0.5102f, -0.5115f, -0.5128f, -0.5141f, -0.5154f, -0.5167f, -0.518f, -0.5194f, - -0.5207f, -0.522f, -0.5233f, -0.5246f, -0.5259f, -0.5272f, -0.5285f, -0.5298f, -0.5311f, -0.5324f, - -0.5337f, -0.535f, -0.5363f, -0.5376f, -0.5389f, -0.5402f, -0.5415f, -0.5428f, -0.544f, -0.5453f, - -0.5466f, -0.5479f, -0.5492f, -0.5505f, -0.5517f, -0.553f, -0.5543f, -0.5556f, -0.5568f, -0.5581f, - -0.5594f, -0.5607f, -0.5619f, -0.5632f, -0.5645f, -0.5657f, -0.567f, -0.5683f, -0.5695f, -0.5708f, - -0.572f, -0.5733f, -0.5746f, -0.5758f, -0.5771f, -0.5783f, -0.5796f, -0.5808f, -0.5821f, -0.5833f, - -0.5846f, -0.5858f, -0.587f, -0.5883f, -0.5895f, -0.5908f, -0.592f, -0.5932f, -0.5945f, -0.5957f, - -0.5969f, -0.5982f, -0.5994f, -0.6006f, -0.6018f, -0.6031f, -0.6043f, -0.6055f, -0.6067f, -0.6079f, - -0.6092f, -0.6104f, -0.6116f, -0.6128f, -0.614f, -0.6152f, -0.6164f, -0.6176f, -0.6189f, -0.6201f, - -0.6213f, -0.6225f, -0.6237f, -0.6249f, -0.6261f, -0.6273f, -0.6284f, -0.6296f, -0.6308f, -0.632f, - -0.6332f, -0.6344f, -0.6356f, -0.6368f, -0.6379f, -0.6391f, -0.6403f, -0.6415f, -0.6427f, -0.6438f, - -0.645f, -0.6462f, -0.6473f, -0.6485f, -0.6497f, -0.6508f, -0.652f, -0.6532f, -0.6543f, -0.6555f, - -0.6567f, -0.6578f, -0.659f, -0.6601f, -0.6613f, -0.6624f, -0.6636f, -0.6647f, -0.6659f, -0.667f, - -0.6681f, -0.6693f, -0.6704f, -0.6716f, -0.6727f, -0.6738f, -0.675f, -0.6761f, -0.6772f, -0.6784f, - -0.6795f, -0.6806f, -0.6817f, -0.6828f, -0.684f, -0.6851f, -0.6862f, -0.6873f, -0.6884f, -0.6895f, - -0.6907f, -0.6918f, -0.6929f, -0.694f, -0.6951f, -0.6962f, -0.6973f, -0.6984f, -0.6995f, -0.7006f, - -0.7017f, -0.7028f, -0.7038f, -0.7049f, -0.706f, -0.7071f, -0.7082f, -0.7093f, -0.7104f, -0.7114f, - -0.7125f, -0.7136f, -0.7147f, -0.7157f, -0.7168f, -0.7179f, -0.7189f, -0.72f, -0.7211f, -0.7221f, - -0.7232f, -0.7242f, -0.7253f, -0.7264f, -0.7274f, -0.7285f, -0.7295f, -0.7306f, -0.7316f, -0.7327f, - -0.7337f, -0.7347f, -0.7358f, -0.7368f, -0.7379f, -0.7389f, -0.7399f, -0.741f, -0.742f, -0.743f, - -0.744f, -0.7451f, -0.7461f, -0.7471f, -0.7481f, -0.7491f, -0.7502f, -0.7512f, -0.7522f, -0.7532f, - -0.7542f, -0.7552f, -0.7562f, -0.7572f, -0.7582f, -0.7592f, -0.7602f, -0.7612f, -0.7622f, -0.7632f, - -0.7642f, -0.7652f, -0.7662f, -0.7671f, -0.7681f, -0.7691f, -0.7701f, -0.7711f, -0.772f, -0.773f, - -0.774f, -0.775f, -0.7759f, -0.7769f, -0.7779f, -0.7788f, -0.7798f, -0.7807f, -0.7817f, -0.7827f, - -0.7836f, -0.7846f, -0.7855f, -0.7865f, -0.7874f, -0.7883f, -0.7893f, -0.7902f, -0.7912f, -0.7921f, - -0.793f, -0.794f, -0.7949f, -0.7958f, -0.7968f, -0.7977f, -0.7986f, -0.7995f, -0.8005f, -0.8014f, - -0.8023f, -0.8032f, -0.8041f, -0.805f, -0.8059f, -0.8068f, -0.8078f, -0.8087f, -0.8096f, -0.8105f, - -0.8114f, -0.8123f, -0.8131f, -0.814f, -0.8149f, -0.8158f, -0.8167f, -0.8176f, -0.8185f, -0.8193f, - -0.8202f, -0.8211f, -0.822f, -0.8228f, -0.8237f, -0.8246f, -0.8255f, -0.8263f, -0.8272f, -0.828f, - -0.8289f, -0.8298f, -0.8306f, -0.8315f, -0.8323f, -0.8332f, -0.834f, -0.8349f, -0.8357f, -0.8365f, - -0.8374f, -0.8382f, -0.8391f, -0.8399f, -0.8407f, -0.8416f, -0.8424f, -0.8432f, -0.844f, -0.8449f, - -0.8457f, -0.8465f, -0.8473f, -0.8481f, -0.8489f, -0.8497f, -0.8505f, -0.8514f, -0.8522f, -0.853f, - -0.8538f, -0.8546f, -0.8554f, -0.8561f, -0.8569f, -0.8577f, -0.8585f, -0.8593f, -0.8601f, -0.8609f, - -0.8616f, -0.8624f, -0.8632f, -0.864f, -0.8647f, -0.8655f, -0.8663f, -0.867f, -0.8678f, -0.8686f, - -0.8693f, -0.8701f, -0.8708f, -0.8716f, -0.8723f, -0.8731f, -0.8738f, -0.8746f, -0.8753f, -0.8761f, - -0.8768f, -0.8775f, -0.8783f, -0.879f, -0.8797f, -0.8805f, -0.8812f, -0.8819f, -0.8826f, -0.8834f, - -0.8841f, -0.8848f, -0.8855f, -0.8862f, -0.8869f, -0.8876f, -0.8883f, -0.889f, -0.8897f, -0.8904f, - -0.8911f, -0.8918f, -0.8925f, -0.8932f, -0.8939f, -0.8946f, -0.8953f, -0.896f, -0.8966f, -0.8973f, - -0.898f, -0.8987f, -0.8993f, -0.9f, -0.9007f, -0.9013f, -0.902f, -0.9027f, -0.9033f, -0.904f, - -0.9046f, -0.9053f, -0.9059f, -0.9066f, -0.9072f, -0.9079f, -0.9085f, -0.9092f, -0.9098f, -0.9104f, - -0.9111f, -0.9117f, -0.9123f, -0.913f, -0.9136f, -0.9142f, -0.9148f, -0.9154f, -0.9161f, -0.9167f, - -0.9173f, -0.9179f, -0.9185f, -0.9191f, -0.9197f, -0.9203f, -0.9209f, -0.9215f, -0.9221f, -0.9227f, - -0.9233f, -0.9239f, -0.9245f, -0.925f, -0.9256f, -0.9262f, -0.9268f, -0.9274f, -0.9279f, -0.9285f, - -0.9291f, -0.9296f, -0.9302f, -0.9308f, -0.9313f, -0.9319f, -0.9324f, -0.933f, -0.9335f, -0.9341f, - -0.9346f, -0.9352f, -0.9357f, -0.9363f, -0.9368f, -0.9373f, -0.9379f, -0.9384f, -0.9389f, -0.9395f, - -0.94f, -0.9405f, -0.941f, -0.9415f, -0.9421f, -0.9426f, -0.9431f, -0.9436f, -0.9441f, -0.9446f, - -0.9451f, -0.9456f, -0.9461f, -0.9466f, -0.9471f, -0.9476f, -0.9481f, -0.9486f, -0.949f, -0.9495f, - -0.95f, -0.9505f, -0.951f, -0.9514f, -0.9519f, -0.9524f, -0.9528f, -0.9533f, -0.9538f, -0.9542f, - -0.9547f, -0.9551f, -0.9556f, -0.956f, -0.9565f, -0.9569f, -0.9574f, -0.9578f, -0.9583f, -0.9587f, - -0.9591f, -0.9596f, -0.96f, -0.9604f, -0.9609f, -0.9613f, -0.9617f, -0.9621f, -0.9625f, -0.963f, - -0.9634f, -0.9638f, -0.9642f, -0.9646f, -0.965f, -0.9654f, -0.9658f, -0.9662f, -0.9666f, -0.967f, - -0.9674f, -0.9678f, -0.9681f, -0.9685f, -0.9689f, -0.9693f, -0.9697f, -0.97f, -0.9704f, -0.9708f, - -0.9711f, -0.9715f, -0.9719f, -0.9722f, -0.9726f, -0.9729f, -0.9733f, -0.9736f, -0.974f, -0.9743f, - -0.9747f, -0.975f, -0.9754f, -0.9757f, -0.976f, -0.9764f, -0.9767f, -0.977f, -0.9774f, -0.9777f, - -0.978f, -0.9783f, -0.9786f, -0.9789f, -0.9793f, -0.9796f, -0.9799f, -0.9802f, -0.9805f, -0.9808f, - -0.9811f, -0.9814f, -0.9817f, -0.982f, -0.9823f, -0.9825f, -0.9828f, -0.9831f, -0.9834f, -0.9837f, - -0.9839f, -0.9842f, -0.9845f, -0.9847f, -0.985f, -0.9853f, -0.9855f, -0.9858f, -0.9861f, -0.9863f, - -0.9866f, -0.9868f, -0.9871f, -0.9873f, -0.9875f, -0.9878f, -0.988f, -0.9883f, -0.9885f, -0.9887f, - -0.989f, -0.9892f, -0.9894f, -0.9896f, -0.9898f, -0.9901f, -0.9903f, -0.9905f, -0.9907f, -0.9909f, - -0.9911f, -0.9913f, -0.9915f, -0.9917f, -0.9919f, -0.9921f, -0.9923f, -0.9925f, -0.9927f, -0.9929f, - -0.993f, -0.9932f, -0.9934f, -0.9936f, -0.9937f, -0.9939f, -0.9941f, -0.9942f, -0.9944f, -0.9946f, - -0.9947f, -0.9949f, -0.995f, -0.9952f, -0.9953f, -0.9955f, -0.9956f, -0.9958f, -0.9959f, -0.996f, - -0.9962f, -0.9963f, -0.9964f, -0.9966f, -0.9967f, -0.9968f, -0.9969f, -0.9971f, -0.9972f, -0.9973f, - -0.9974f, -0.9975f, -0.9976f, -0.9977f, -0.9978f, -0.9979f, -0.998f, -0.9981f, -0.9982f, -0.9983f, - -0.9984f, -0.9985f, -0.9986f, -0.9986f, -0.9987f, -0.9988f, -0.9989f, -0.9989f, -0.999f, -0.9991f, - -0.9991f, -0.9992f, -0.9993f, -0.9993f, -0.9994f, -0.9994f, -0.9995f, -0.9995f, -0.9996f, -0.9996f, - -0.9997f, -0.9997f, -0.9997f, -0.9998f, -0.9998f, -0.9998f, -0.9999f, -0.9999f, -0.9999f, -0.9999f, - -0.9999f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, - -1.0f, -1.0f, -1.0f, -1.0f, -0.9999f, -0.9999f, -0.9999f, -0.9999f, -0.9999f, -0.9998f, - -0.9998f, -0.9998f, -0.9997f, -0.9997f, -0.9997f, -0.9996f, -0.9996f, -0.9995f, -0.9995f, -0.9994f, - -0.9994f, -0.9993f, -0.9993f, -0.9992f, -0.9991f, -0.9991f, -0.999f, -0.9989f, -0.9989f, -0.9988f, - -0.9987f, -0.9986f, -0.9986f, -0.9985f, -0.9984f, -0.9983f, -0.9982f, -0.9981f, -0.998f, -0.9979f, - -0.9978f, -0.9977f, -0.9976f, -0.9975f, -0.9974f, -0.9973f, -0.9972f, -0.9971f, -0.9969f, -0.9968f, - -0.9967f, -0.9966f, -0.9964f, -0.9963f, -0.9962f, -0.996f, -0.9959f, -0.9958f, -0.9956f, -0.9955f, - -0.9953f, -0.9952f, -0.995f, -0.9949f, -0.9947f, -0.9946f, -0.9944f, -0.9942f, -0.9941f, -0.9939f, - -0.9937f, -0.9936f, -0.9934f, -0.9932f, -0.993f, -0.9929f, -0.9927f, -0.9925f, -0.9923f, -0.9921f, - -0.9919f, -0.9917f, -0.9915f, -0.9913f, -0.9911f, -0.9909f, -0.9907f, -0.9905f, -0.9903f, -0.9901f, - -0.9898f, -0.9896f, -0.9894f, -0.9892f, -0.989f, -0.9887f, -0.9885f, -0.9883f, -0.988f, -0.9878f, - -0.9875f, -0.9873f, -0.9871f, -0.9868f, -0.9866f, -0.9863f, -0.9861f, -0.9858f, -0.9855f, -0.9853f, - -0.985f, -0.9847f, -0.9845f, -0.9842f, -0.9839f, -0.9837f, -0.9834f, -0.9831f, -0.9828f, -0.9825f, - -0.9823f, -0.982f, -0.9817f, -0.9814f, -0.9811f, -0.9808f, -0.9805f, -0.9802f, -0.9799f, -0.9796f, - -0.9793f, -0.9789f, -0.9786f, -0.9783f, -0.978f, -0.9777f, -0.9774f, -0.977f, -0.9767f, -0.9764f, - -0.976f, -0.9757f, -0.9754f, -0.975f, -0.9747f, -0.9743f, -0.974f, -0.9736f, -0.9733f, -0.9729f, - -0.9726f, -0.9722f, -0.9719f, -0.9715f, -0.9711f, -0.9708f, -0.9704f, -0.97f, -0.9697f, -0.9693f, - -0.9689f, -0.9685f, -0.9681f, -0.9678f, -0.9674f, -0.967f, -0.9666f, -0.9662f, -0.9658f, -0.9654f, - -0.965f, -0.9646f, -0.9642f, -0.9638f, -0.9634f, -0.963f, -0.9625f, -0.9621f, -0.9617f, -0.9613f, - -0.9609f, -0.9604f, -0.96f, -0.9596f, -0.9591f, -0.9587f, -0.9583f, -0.9578f, -0.9574f, -0.9569f, - -0.9565f, -0.956f, -0.9556f, -0.9551f, -0.9547f, -0.9542f, -0.9538f, -0.9533f, -0.9528f, -0.9524f, - -0.9519f, -0.9514f, -0.951f, -0.9505f, -0.95f, -0.9495f, -0.949f, -0.9486f, -0.9481f, -0.9476f, - -0.9471f, -0.9466f, -0.9461f, -0.9456f, -0.9451f, -0.9446f, -0.9441f, -0.9436f, -0.9431f, -0.9426f, - -0.9421f, -0.9415f, -0.941f, -0.9405f, -0.94f, -0.9395f, -0.9389f, -0.9384f, -0.9379f, -0.9373f, - -0.9368f, -0.9363f, -0.9357f, -0.9352f, -0.9346f, -0.9341f, -0.9335f, -0.933f, -0.9324f, -0.9319f, - -0.9313f, -0.9308f, -0.9302f, -0.9296f, -0.9291f, -0.9285f, -0.9279f, -0.9274f, -0.9268f, -0.9262f, - -0.9256f, -0.925f, -0.9245f, -0.9239f, -0.9233f, -0.9227f, -0.9221f, -0.9215f, -0.9209f, -0.9203f, - -0.9197f, -0.9191f, -0.9185f, -0.9179f, -0.9173f, -0.9167f, -0.9161f, -0.9154f, -0.9148f, -0.9142f, - -0.9136f, -0.913f, -0.9123f, -0.9117f, -0.9111f, -0.9104f, -0.9098f, -0.9092f, -0.9085f, -0.9079f, - -0.9072f, -0.9066f, -0.9059f, -0.9053f, -0.9046f, -0.904f, -0.9033f, -0.9027f, -0.902f, -0.9013f, - -0.9007f, -0.9f, -0.8993f, -0.8987f, -0.898f, -0.8973f, -0.8966f, -0.896f, -0.8953f, -0.8946f, - -0.8939f, -0.8932f, -0.8925f, -0.8918f, -0.8911f, -0.8904f, -0.8897f, -0.889f, -0.8883f, -0.8876f, - -0.8869f, -0.8862f, -0.8855f, -0.8848f, -0.8841f, -0.8834f, -0.8826f, -0.8819f, -0.8812f, -0.8805f, - -0.8797f, -0.879f, -0.8783f, -0.8775f, -0.8768f, -0.8761f, -0.8753f, -0.8746f, -0.8738f, -0.8731f, - -0.8723f, -0.8716f, -0.8708f, -0.8701f, -0.8693f, -0.8686f, -0.8678f, -0.867f, -0.8663f, -0.8655f, - -0.8647f, -0.864f, -0.8632f, -0.8624f, -0.8616f, -0.8609f, -0.8601f, -0.8593f, -0.8585f, -0.8577f, - -0.8569f, -0.8561f, -0.8554f, -0.8546f, -0.8538f, -0.853f, -0.8522f, -0.8514f, -0.8505f, -0.8497f, - -0.8489f, -0.8481f, -0.8473f, -0.8465f, -0.8457f, -0.8449f, -0.844f, -0.8432f, -0.8424f, -0.8416f, - -0.8407f, -0.8399f, -0.8391f, -0.8382f, -0.8374f, -0.8365f, -0.8357f, -0.8349f, -0.834f, -0.8332f, - -0.8323f, -0.8315f, -0.8306f, -0.8298f, -0.8289f, -0.828f, -0.8272f, -0.8263f, -0.8255f, -0.8246f, - -0.8237f, -0.8228f, -0.822f, -0.8211f, -0.8202f, -0.8193f, -0.8185f, -0.8176f, -0.8167f, -0.8158f, - -0.8149f, -0.814f, -0.8131f, -0.8123f, -0.8114f, -0.8105f, -0.8096f, -0.8087f, -0.8078f, -0.8068f, - -0.8059f, -0.805f, -0.8041f, -0.8032f, -0.8023f, -0.8014f, -0.8005f, -0.7995f, -0.7986f, -0.7977f, - -0.7968f, -0.7958f, -0.7949f, -0.794f, -0.793f, -0.7921f, -0.7912f, -0.7902f, -0.7893f, -0.7883f, - -0.7874f, -0.7865f, -0.7855f, -0.7846f, -0.7836f, -0.7827f, -0.7817f, -0.7807f, -0.7798f, -0.7788f, - -0.7779f, -0.7769f, -0.7759f, -0.775f, -0.774f, -0.773f, -0.772f, -0.7711f, -0.7701f, -0.7691f, - -0.7681f, -0.7671f, -0.7662f, -0.7652f, -0.7642f, -0.7632f, -0.7622f, -0.7612f, -0.7602f, -0.7592f, - -0.7582f, -0.7572f, -0.7562f, -0.7552f, -0.7542f, -0.7532f, -0.7522f, -0.7512f, -0.7502f, -0.7491f, - -0.7481f, -0.7471f, -0.7461f, -0.7451f, -0.744f, -0.743f, -0.742f, -0.741f, -0.7399f, -0.7389f, - -0.7379f, -0.7368f, -0.7358f, -0.7347f, -0.7337f, -0.7327f, -0.7316f, -0.7306f, -0.7295f, -0.7285f, - -0.7274f, -0.7264f, -0.7253f, -0.7242f, -0.7232f, -0.7221f, -0.7211f, -0.72f, -0.7189f, -0.7179f, - -0.7168f, -0.7157f, -0.7147f, -0.7136f, -0.7125f, -0.7114f, -0.7104f, -0.7093f, -0.7082f, -0.7071f, - -0.706f, -0.7049f, -0.7038f, -0.7028f, -0.7017f, -0.7006f, -0.6995f, -0.6984f, -0.6973f, -0.6962f, - -0.6951f, -0.694f, -0.6929f, -0.6918f, -0.6907f, -0.6895f, -0.6884f, -0.6873f, -0.6862f, -0.6851f, - -0.684f, -0.6828f, -0.6817f, -0.6806f, -0.6795f, -0.6784f, -0.6772f, -0.6761f, -0.675f, -0.6738f, - -0.6727f, -0.6716f, -0.6704f, -0.6693f, -0.6681f, -0.667f, -0.6659f, -0.6647f, -0.6636f, -0.6624f, - -0.6613f, -0.6601f, -0.659f, -0.6578f, -0.6567f, -0.6555f, -0.6543f, -0.6532f, -0.652f, -0.6508f, - -0.6497f, -0.6485f, -0.6473f, -0.6462f, -0.645f, -0.6438f, -0.6427f, -0.6415f, -0.6403f, -0.6391f, - -0.6379f, -0.6368f, -0.6356f, -0.6344f, -0.6332f, -0.632f, -0.6308f, -0.6296f, -0.6284f, -0.6273f, - -0.6261f, -0.6249f, -0.6237f, -0.6225f, -0.6213f, -0.6201f, -0.6189f, -0.6176f, -0.6164f, -0.6152f, - -0.614f, -0.6128f, -0.6116f, -0.6104f, -0.6092f, -0.6079f, -0.6067f, -0.6055f, -0.6043f, -0.6031f, - -0.6018f, -0.6006f, -0.5994f, -0.5982f, -0.5969f, -0.5957f, -0.5945f, -0.5932f, -0.592f, -0.5908f, - -0.5895f, -0.5883f, -0.587f, -0.5858f, -0.5846f, -0.5833f, -0.5821f, -0.5808f, -0.5796f, -0.5783f, - -0.5771f, -0.5758f, -0.5746f, -0.5733f, -0.572f, -0.5708f, -0.5695f, -0.5683f, -0.567f, -0.5657f, - -0.5645f, -0.5632f, -0.5619f, -0.5607f, -0.5594f, -0.5581f, -0.5568f, -0.5556f, -0.5543f, -0.553f, - -0.5517f, -0.5505f, -0.5492f, -0.5479f, -0.5466f, -0.5453f, -0.544f, -0.5428f, -0.5415f, -0.5402f, - -0.5389f, -0.5376f, -0.5363f, -0.535f, -0.5337f, -0.5324f, -0.5311f, -0.5298f, -0.5285f, -0.5272f, - -0.5259f, -0.5246f, -0.5233f, -0.522f, -0.5207f, -0.5194f, -0.518f, -0.5167f, -0.5154f, -0.5141f, - -0.5128f, -0.5115f, -0.5102f, -0.5088f, -0.5075f, -0.5062f, -0.5049f, -0.5035f, -0.5022f, -0.5009f, - -0.4996f, -0.4982f, -0.4969f, -0.4956f, -0.4942f, -0.4929f, -0.4916f, -0.4902f, -0.4889f, -0.4876f, - -0.4862f, -0.4849f, -0.4835f, -0.4822f, -0.4808f, -0.4795f, -0.4781f, -0.4768f, -0.4755f, -0.4741f, - -0.4727f, -0.4714f, -0.47f, -0.4687f, -0.4673f, -0.466f, -0.4646f, -0.4633f, -0.4619f, -0.4605f, - -0.4592f, -0.4578f, -0.4564f, -0.4551f, -0.4537f, -0.4523f, -0.451f, -0.4496f, -0.4482f, -0.4469f, - -0.4455f, -0.4441f, -0.4427f, -0.4414f, -0.44f, -0.4386f, -0.4372f, -0.4359f, -0.4345f, -0.4331f, - -0.4317f, -0.4303f, -0.4289f, -0.4276f, -0.4262f, -0.4248f, -0.4234f, -0.422f, -0.4206f, -0.4192f, - -0.4178f, -0.4164f, -0.415f, -0.4136f, -0.4122f, -0.4108f, -0.4094f, -0.408f, -0.4066f, -0.4052f, - -0.4038f, -0.4024f, -0.401f, -0.3996f, -0.3982f, -0.3968f, -0.3954f, -0.394f, -0.3926f, -0.3912f, - -0.3898f, -0.3883f, -0.3869f, -0.3855f, -0.3841f, -0.3827f, -0.3813f, -0.3798f, -0.3784f, -0.377f, - -0.3756f, -0.3742f, -0.3727f, -0.3713f, -0.3699f, -0.3685f, -0.367f, -0.3656f, -0.3642f, -0.3628f, - -0.3613f, -0.3599f, -0.3585f, -0.357f, -0.3556f, -0.3542f, -0.3527f, -0.3513f, -0.3499f, -0.3484f, - -0.347f, -0.3455f, -0.3441f, -0.3427f, -0.3412f, -0.3398f, -0.3383f, -0.3369f, -0.3354f, -0.334f, - -0.3326f, -0.3311f, -0.3297f, -0.3282f, -0.3268f, -0.3253f, -0.3239f, -0.3224f, -0.321f, -0.3195f, - -0.318f, -0.3166f, -0.3151f, -0.3137f, -0.3122f, -0.3108f, -0.3093f, -0.3078f, -0.3064f, -0.3049f, - -0.3035f, -0.302f, -0.3005f, -0.2991f, -0.2976f, -0.2962f, -0.2947f, -0.2932f, -0.2918f, -0.2903f, - -0.2888f, -0.2873f, -0.2859f, -0.2844f, -0.2829f, -0.2815f, -0.28f, -0.2785f, -0.277f, -0.2756f, - -0.2741f, -0.2726f, -0.2711f, -0.2697f, -0.2682f, -0.2667f, -0.2652f, -0.2638f, -0.2623f, -0.2608f, - -0.2593f, -0.2578f, -0.2563f, -0.2549f, -0.2534f, -0.2519f, -0.2504f, -0.2489f, -0.2474f, -0.246f, - -0.2445f, -0.243f, -0.2415f, -0.24f, -0.2385f, -0.237f, -0.2355f, -0.234f, -0.2326f, -0.2311f, - -0.2296f, -0.2281f, -0.2266f, -0.2251f, -0.2236f, -0.2221f, -0.2206f, -0.2191f, -0.2176f, -0.2161f, - -0.2146f, -0.2131f, -0.2116f, -0.2101f, -0.2086f, -0.2071f, -0.2056f, -0.2041f, -0.2026f, -0.2011f, - -0.1996f, -0.1981f, -0.1966f, -0.1951f, -0.1936f, -0.1921f, -0.1906f, -0.1891f, -0.1876f, -0.1861f, - -0.1845f, -0.183f, -0.1815f, -0.18f, -0.1785f, -0.177f, -0.1755f, -0.174f, -0.1725f, -0.171f, - -0.1695f, -0.1679f, -0.1664f, -0.1649f, -0.1634f, -0.1619f, -0.1604f, -0.1589f, -0.1573f, -0.1558f, - -0.1543f, -0.1528f, -0.1513f, -0.1498f, -0.1482f, -0.1467f, -0.1452f, -0.1437f, -0.1422f, -0.1407f, - -0.1391f, -0.1376f, -0.1361f, -0.1346f, -0.1331f, -0.1315f, -0.13f, -0.1285f, -0.127f, -0.1255f, - -0.1239f, -0.1224f, -0.1209f, -0.1194f, -0.1178f, -0.1163f, -0.1148f, -0.1133f, -0.1117f, -0.1102f, - -0.1087f, -0.1072f, -0.1056f, -0.1041f, -0.1026f, -0.1011f, -0.09954f, -0.09802f, -0.09649f, -0.09496f, - -0.09344f, -0.09191f, -0.09038f, -0.08885f, -0.08733f, -0.0858f, -0.08427f, -0.08274f, -0.08121f, -0.07968f, - -0.07815f, -0.07662f, -0.07509f, -0.07356f, -0.07203f, -0.0705f, -0.06897f, -0.06744f, -0.06591f, -0.06438f, - -0.06285f, -0.06132f, -0.05979f, -0.05826f, -0.05673f, -0.0552f, -0.05366f, -0.05213f, -0.0506f, -0.04907f, - -0.04754f, -0.046f, -0.04447f, -0.04294f, -0.04141f, -0.03987f, -0.03834f, -0.03681f, -0.03527f, -0.03374f, - -0.03221f, -0.03067f, -0.02914f, -0.02761f, -0.02607f, -0.02454f, -0.02301f, -0.02147f, -0.01994f, -0.01841f, - -0.01687f, -0.01534f, -0.01381f, -0.01227f, -0.01074f, -0.009204f, -0.00767f, -0.006136f, -0.004602f, -0.003068f, - -0.001534f, -1.837e-16f, 0.001534f, 0.003068f, 0.004602f, 0.006136f, 0.00767f, 0.009204f, 0.01074f, 0.01227f, - 0.01381f, 0.01534f, 0.01687f, 0.01841f, 0.01994f, 0.02147f, 0.02301f, 0.02454f, 0.02607f, 0.02761f, - 0.02914f, 0.03067f, 0.03221f, 0.03374f, 0.03527f, 0.03681f, 0.03834f, 0.03987f, 0.04141f, 0.04294f, - 0.04447f, 0.046f, 0.04754f, 0.04907f, 0.0506f, 0.05213f, 0.05366f, 0.0552f, 0.05673f, 0.05826f, - 0.05979f, 0.06132f, 0.06285f, 0.06438f, 0.06591f, 0.06744f, 0.06897f, 0.0705f, 0.07203f, 0.07356f, - 0.07509f, 0.07662f, 0.07815f, 0.07968f, 0.08121f, 0.08274f, 0.08427f, 0.0858f, 0.08733f, 0.08885f, - 0.09038f, 0.09191f, 0.09344f, 0.09496f, 0.09649f, 0.09802f, 0.09954f, 0.1011f, 0.1026f, 0.1041f, - 0.1056f, 0.1072f, 0.1087f, 0.1102f, 0.1117f, 0.1133f, 0.1148f, 0.1163f, 0.1178f, 0.1194f, - 0.1209f, 0.1224f, 0.1239f, 0.1255f, 0.127f, 0.1285f, 0.13f, 0.1315f, 0.1331f, 0.1346f, - 0.1361f, 0.1376f, 0.1391f, 0.1407f, 0.1422f, 0.1437f, 0.1452f, 0.1467f, 0.1482f, 0.1498f, - 0.1513f, 0.1528f, 0.1543f, 0.1558f, 0.1573f, 0.1589f, 0.1604f, 0.1619f, 0.1634f, 0.1649f, - 0.1664f, 0.1679f, 0.1695f, 0.171f, 0.1725f, 0.174f, 0.1755f, 0.177f, 0.1785f, 0.18f, - 0.1815f, 0.183f, 0.1845f, 0.1861f, 0.1876f, 0.1891f, 0.1906f, 0.1921f, 0.1936f, 0.1951f, - 0.1966f, 0.1981f, 0.1996f, 0.2011f, 0.2026f, 0.2041f, 0.2056f, 0.2071f, 0.2086f, 0.2101f, - 0.2116f, 0.2131f, 0.2146f, 0.2161f, 0.2176f, 0.2191f, 0.2206f, 0.2221f, 0.2236f, 0.2251f, - 0.2266f, 0.2281f, 0.2296f, 0.2311f, 0.2326f, 0.234f, 0.2355f, 0.237f, 0.2385f, 0.24f, - 0.2415f, 0.243f, 0.2445f, 0.246f, 0.2474f, 0.2489f, 0.2504f, 0.2519f, 0.2534f, 0.2549f, - 0.2563f, 0.2578f, 0.2593f, 0.2608f, 0.2623f, 0.2638f, 0.2652f, 0.2667f, 0.2682f, 0.2697f, - 0.2711f, 0.2726f, 0.2741f, 0.2756f, 0.277f, 0.2785f, 0.28f, 0.2815f, 0.2829f, 0.2844f, - 0.2859f, 0.2873f, 0.2888f, 0.2903f, 0.2918f, 0.2932f, 0.2947f, 0.2962f, 0.2976f, 0.2991f, - 0.3005f, 0.302f, 0.3035f, 0.3049f, 0.3064f, 0.3078f, 0.3093f, 0.3108f, 0.3122f, 0.3137f, - 0.3151f, 0.3166f, 0.318f, 0.3195f, 0.321f, 0.3224f, 0.3239f, 0.3253f, 0.3268f, 0.3282f, - 0.3297f, 0.3311f, 0.3326f, 0.334f, 0.3354f, 0.3369f, 0.3383f, 0.3398f, 0.3412f, 0.3427f, - 0.3441f, 0.3455f, 0.347f, 0.3484f, 0.3499f, 0.3513f, 0.3527f, 0.3542f, 0.3556f, 0.357f, - 0.3585f, 0.3599f, 0.3613f, 0.3628f, 0.3642f, 0.3656f, 0.367f, 0.3685f, 0.3699f, 0.3713f, - 0.3727f, 0.3742f, 0.3756f, 0.377f, 0.3784f, 0.3798f, 0.3813f, 0.3827f, 0.3841f, 0.3855f, - 0.3869f, 0.3883f, 0.3898f, 0.3912f, 0.3926f, 0.394f, 0.3954f, 0.3968f, 0.3982f, 0.3996f, - 0.401f, 0.4024f, 0.4038f, 0.4052f, 0.4066f, 0.408f, 0.4094f, 0.4108f, 0.4122f, 0.4136f, - 0.415f, 0.4164f, 0.4178f, 0.4192f, 0.4206f, 0.422f, 0.4234f, 0.4248f, 0.4262f, 0.4276f, - 0.4289f, 0.4303f, 0.4317f, 0.4331f, 0.4345f, 0.4359f, 0.4372f, 0.4386f, 0.44f, 0.4414f, - 0.4427f, 0.4441f, 0.4455f, 0.4469f, 0.4482f, 0.4496f, 0.451f, 0.4523f, 0.4537f, 0.4551f, - 0.4564f, 0.4578f, 0.4592f, 0.4605f, 0.4619f, 0.4633f, 0.4646f, 0.466f, 0.4673f, 0.4687f, - 0.47f, 0.4714f, 0.4727f, 0.4741f, 0.4755f, 0.4768f, 0.4781f, 0.4795f, 0.4808f, 0.4822f, - 0.4835f, 0.4849f, 0.4862f, 0.4876f, 0.4889f, 0.4902f, 0.4916f, 0.4929f, 0.4942f, 0.4956f, - 0.4969f, 0.4982f, 0.4996f, 0.5009f, 0.5022f, 0.5035f, 0.5049f, 0.5062f, 0.5075f, 0.5088f, - 0.5102f, 0.5115f, 0.5128f, 0.5141f, 0.5154f, 0.5167f, 0.518f, 0.5194f, 0.5207f, 0.522f, - 0.5233f, 0.5246f, 0.5259f, 0.5272f, 0.5285f, 0.5298f, 0.5311f, 0.5324f, 0.5337f, 0.535f, - 0.5363f, 0.5376f, 0.5389f, 0.5402f, 0.5415f, 0.5428f, 0.544f, 0.5453f, 0.5466f, 0.5479f, - 0.5492f, 0.5505f, 0.5517f, 0.553f, 0.5543f, 0.5556f, 0.5568f, 0.5581f, 0.5594f, 0.5607f, - 0.5619f, 0.5632f, 0.5645f, 0.5657f, 0.567f, 0.5683f, 0.5695f, 0.5708f, 0.572f, 0.5733f, - 0.5746f, 0.5758f, 0.5771f, 0.5783f, 0.5796f, 0.5808f, 0.5821f, 0.5833f, 0.5846f, 0.5858f, - 0.587f, 0.5883f, 0.5895f, 0.5908f, 0.592f, 0.5932f, 0.5945f, 0.5957f, 0.5969f, 0.5982f, - 0.5994f, 0.6006f, 0.6018f, 0.6031f, 0.6043f, 0.6055f, 0.6067f, 0.6079f, 0.6092f, 0.6104f, - 0.6116f, 0.6128f, 0.614f, 0.6152f, 0.6164f, 0.6176f, 0.6189f, 0.6201f, 0.6213f, 0.6225f, - 0.6237f, 0.6249f, 0.6261f, 0.6273f, 0.6284f, 0.6296f, 0.6308f, 0.632f, 0.6332f, 0.6344f, - 0.6356f, 0.6368f, 0.6379f, 0.6391f, 0.6403f, 0.6415f, 0.6427f, 0.6438f, 0.645f, 0.6462f, - 0.6473f, 0.6485f, 0.6497f, 0.6508f, 0.652f, 0.6532f, 0.6543f, 0.6555f, 0.6567f, 0.6578f, - 0.659f, 0.6601f, 0.6613f, 0.6624f, 0.6636f, 0.6647f, 0.6659f, 0.667f, 0.6681f, 0.6693f, - 0.6704f, 0.6716f, 0.6727f, 0.6738f, 0.675f, 0.6761f, 0.6772f, 0.6784f, 0.6795f, 0.6806f, - 0.6817f, 0.6828f, 0.684f, 0.6851f, 0.6862f, 0.6873f, 0.6884f, 0.6895f, 0.6907f, 0.6918f, - 0.6929f, 0.694f, 0.6951f, 0.6962f, 0.6973f, 0.6984f, 0.6995f, 0.7006f, 0.7017f, 0.7028f, - 0.7038f, 0.7049f, 0.706f, 0.7071f, 0.7082f, 0.7093f, 0.7104f, 0.7114f, 0.7125f, 0.7136f, - 0.7147f, 0.7157f, 0.7168f, 0.7179f, 0.7189f, 0.72f, 0.7211f, 0.7221f, 0.7232f, 0.7242f, - 0.7253f, 0.7264f, 0.7274f, 0.7285f, 0.7295f, 0.7306f, 0.7316f, 0.7327f, 0.7337f, 0.7347f, - 0.7358f, 0.7368f, 0.7379f, 0.7389f, 0.7399f, 0.741f, 0.742f, 0.743f, 0.744f, 0.7451f, - 0.7461f, 0.7471f, 0.7481f, 0.7491f, 0.7502f, 0.7512f, 0.7522f, 0.7532f, 0.7542f, 0.7552f, - 0.7562f, 0.7572f, 0.7582f, 0.7592f, 0.7602f, 0.7612f, 0.7622f, 0.7632f, 0.7642f, 0.7652f, - 0.7662f, 0.7671f, 0.7681f, 0.7691f, 0.7701f, 0.7711f, 0.772f, 0.773f, 0.774f, 0.775f, - 0.7759f, 0.7769f, 0.7779f, 0.7788f, 0.7798f, 0.7807f, 0.7817f, 0.7827f, 0.7836f, 0.7846f, - 0.7855f, 0.7865f, 0.7874f, 0.7883f, 0.7893f, 0.7902f, 0.7912f, 0.7921f, 0.793f, 0.794f, - 0.7949f, 0.7958f, 0.7968f, 0.7977f, 0.7986f, 0.7995f, 0.8005f, 0.8014f, 0.8023f, 0.8032f, - 0.8041f, 0.805f, 0.8059f, 0.8068f, 0.8078f, 0.8087f, 0.8096f, 0.8105f, 0.8114f, 0.8123f, - 0.8131f, 0.814f, 0.8149f, 0.8158f, 0.8167f, 0.8176f, 0.8185f, 0.8193f, 0.8202f, 0.8211f, - 0.822f, 0.8228f, 0.8237f, 0.8246f, 0.8255f, 0.8263f, 0.8272f, 0.828f, 0.8289f, 0.8298f, - 0.8306f, 0.8315f, 0.8323f, 0.8332f, 0.834f, 0.8349f, 0.8357f, 0.8365f, 0.8374f, 0.8382f, - 0.8391f, 0.8399f, 0.8407f, 0.8416f, 0.8424f, 0.8432f, 0.844f, 0.8449f, 0.8457f, 0.8465f, - 0.8473f, 0.8481f, 0.8489f, 0.8497f, 0.8505f, 0.8514f, 0.8522f, 0.853f, 0.8538f, 0.8546f, - 0.8554f, 0.8561f, 0.8569f, 0.8577f, 0.8585f, 0.8593f, 0.8601f, 0.8609f, 0.8616f, 0.8624f, - 0.8632f, 0.864f, 0.8647f, 0.8655f, 0.8663f, 0.867f, 0.8678f, 0.8686f, 0.8693f, 0.8701f, - 0.8708f, 0.8716f, 0.8723f, 0.8731f, 0.8738f, 0.8746f, 0.8753f, 0.8761f, 0.8768f, 0.8775f, - 0.8783f, 0.879f, 0.8797f, 0.8805f, 0.8812f, 0.8819f, 0.8826f, 0.8834f, 0.8841f, 0.8848f, - 0.8855f, 0.8862f, 0.8869f, 0.8876f, 0.8883f, 0.889f, 0.8897f, 0.8904f, 0.8911f, 0.8918f, - 0.8925f, 0.8932f, 0.8939f, 0.8946f, 0.8953f, 0.896f, 0.8966f, 0.8973f, 0.898f, 0.8987f, - 0.8993f, 0.9f, 0.9007f, 0.9013f, 0.902f, 0.9027f, 0.9033f, 0.904f, 0.9046f, 0.9053f, - 0.9059f, 0.9066f, 0.9072f, 0.9079f, 0.9085f, 0.9092f, 0.9098f, 0.9104f, 0.9111f, 0.9117f, - 0.9123f, 0.913f, 0.9136f, 0.9142f, 0.9148f, 0.9154f, 0.9161f, 0.9167f, 0.9173f, 0.9179f, - 0.9185f, 0.9191f, 0.9197f, 0.9203f, 0.9209f, 0.9215f, 0.9221f, 0.9227f, 0.9233f, 0.9239f, - 0.9245f, 0.925f, 0.9256f, 0.9262f, 0.9268f, 0.9274f, 0.9279f, 0.9285f, 0.9291f, 0.9296f, - 0.9302f, 0.9308f, 0.9313f, 0.9319f, 0.9324f, 0.933f, 0.9335f, 0.9341f, 0.9346f, 0.9352f, - 0.9357f, 0.9363f, 0.9368f, 0.9373f, 0.9379f, 0.9384f, 0.9389f, 0.9395f, 0.94f, 0.9405f, - 0.941f, 0.9415f, 0.9421f, 0.9426f, 0.9431f, 0.9436f, 0.9441f, 0.9446f, 0.9451f, 0.9456f, - 0.9461f, 0.9466f, 0.9471f, 0.9476f, 0.9481f, 0.9486f, 0.949f, 0.9495f, 0.95f, 0.9505f, - 0.951f, 0.9514f, 0.9519f, 0.9524f, 0.9528f, 0.9533f, 0.9538f, 0.9542f, 0.9547f, 0.9551f, - 0.9556f, 0.956f, 0.9565f, 0.9569f, 0.9574f, 0.9578f, 0.9583f, 0.9587f, 0.9591f, 0.9596f, - 0.96f, 0.9604f, 0.9609f, 0.9613f, 0.9617f, 0.9621f, 0.9625f, 0.963f, 0.9634f, 0.9638f, - 0.9642f, 0.9646f, 0.965f, 0.9654f, 0.9658f, 0.9662f, 0.9666f, 0.967f, 0.9674f, 0.9678f, - 0.9681f, 0.9685f, 0.9689f, 0.9693f, 0.9697f, 0.97f, 0.9704f, 0.9708f, 0.9711f, 0.9715f, - 0.9719f, 0.9722f, 0.9726f, 0.9729f, 0.9733f, 0.9736f, 0.974f, 0.9743f, 0.9747f, 0.975f, - 0.9754f, 0.9757f, 0.976f, 0.9764f, 0.9767f, 0.977f, 0.9774f, 0.9777f, 0.978f, 0.9783f, - 0.9786f, 0.9789f, 0.9793f, 0.9796f, 0.9799f, 0.9802f, 0.9805f, 0.9808f, 0.9811f, 0.9814f, - 0.9817f, 0.982f, 0.9823f, 0.9825f, 0.9828f, 0.9831f, 0.9834f, 0.9837f, 0.9839f, 0.9842f, - 0.9845f, 0.9847f, 0.985f, 0.9853f, 0.9855f, 0.9858f, 0.9861f, 0.9863f, 0.9866f, 0.9868f, - 0.9871f, 0.9873f, 0.9875f, 0.9878f, 0.988f, 0.9883f, 0.9885f, 0.9887f, 0.989f, 0.9892f, - 0.9894f, 0.9896f, 0.9898f, 0.9901f, 0.9903f, 0.9905f, 0.9907f, 0.9909f, 0.9911f, 0.9913f, - 0.9915f, 0.9917f, 0.9919f, 0.9921f, 0.9923f, 0.9925f, 0.9927f, 0.9929f, 0.993f, 0.9932f, - 0.9934f, 0.9936f, 0.9937f, 0.9939f, 0.9941f, 0.9942f, 0.9944f, 0.9946f, 0.9947f, 0.9949f, - 0.995f, 0.9952f, 0.9953f, 0.9955f, 0.9956f, 0.9958f, 0.9959f, 0.996f, 0.9962f, 0.9963f, - 0.9964f, 0.9966f, 0.9967f, 0.9968f, 0.9969f, 0.9971f, 0.9972f, 0.9973f, 0.9974f, 0.9975f, - 0.9976f, 0.9977f, 0.9978f, 0.9979f, 0.998f, 0.9981f, 0.9982f, 0.9983f, 0.9984f, 0.9985f, - 0.9986f, 0.9986f, 0.9987f, 0.9988f, 0.9989f, 0.9989f, 0.999f, 0.9991f, 0.9991f, 0.9992f, - 0.9993f, 0.9993f, 0.9994f, 0.9994f, 0.9995f, 0.9995f, 0.9996f, 0.9996f, 0.9997f, 0.9997f, - 0.9997f, 0.9998f, 0.9998f, 0.9998f, 0.9999f, 0.9999f, 0.9999f, 0.9999f, 0.9999f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}; + const static double logvals[max] = { + 4.079, 3.905, 3.8, 3.723, 3.663, 3.613, 3.57, 3.532, 3.499, 3.468, + 3.441, 3.416, 3.392, 3.37, 3.35, 3.33, 3.312, 3.295, 3.278, 3.263, + 3.248, 3.233, 3.219, 3.206, 3.193, 3.181, 3.169, 3.158, 3.147, 3.136, + 3.125, 3.115, 3.105, 3.096, 3.086, 3.077, 3.068, 3.059, 3.051, 3.043, + 3.035, 3.027, 3.019, 3.011, 3.004, 2.996, 2.989, 2.982, 2.975, 2.968, + 2.962, 2.955, 2.949, 2.942, 2.936, 2.93, 2.924, 2.918, 2.912, 2.906, + 2.901, 2.895, 2.89, 2.884, 2.879, 2.873, 2.868, 2.863, 2.858, 2.853, + 2.848, 2.843, 2.838, 2.833, 2.829, 2.824, 2.819, 2.815, 2.81, 2.806, + 2.801, 2.797, 2.792, 2.788, 2.784, 2.78, 2.776, 2.771, 2.767, 2.763, + 2.759, 2.755, 2.751, 2.748, 2.744, 2.74, 2.736, 2.732, 2.729, 2.725, + 2.721, 2.718, 2.714, 2.71, 2.707, 2.703, 2.7, 2.697, 2.693, 2.69, + 2.686, 2.683, 2.68, 2.676, 2.673, 2.67, 2.667, 2.663, 2.66, 2.657, + 2.654, 2.651, 2.648, 2.645, 2.642, 2.639, 2.636, 2.633, 2.63, 2.627, + 2.624, 2.621, 2.618, 2.615, 2.612, 2.61, 2.607, 2.604, 2.601, 2.599, + 2.596, 2.593, 2.59, 2.588, 2.585, 2.582, 2.58, 2.577, 2.574, 2.572, + 2.569, 2.567, 2.564, 2.562, 2.559, 2.557, 2.554, 2.552, 2.549, 2.547, + 2.544, 2.542, 2.539, 2.537, 2.534, 2.532, 2.53, 2.527, 2.525, 2.523, + 2.52, 2.518, 2.516, 2.513, 2.511, 2.509, 2.507, 2.504, 2.502, 2.5, + 2.498, 2.495, 2.493, 2.491, 2.489, 2.487, 2.485, 2.482, 2.48, 2.478, + 2.476, 2.474, 2.472, 2.47, 2.468, 2.466, 2.464, 2.462, 2.459, 2.457, + 2.455, 2.453, 2.451, 2.449, 2.447, 2.445, 2.443, 2.441, 2.439, 2.437, + 2.436, 2.434, 2.432, 2.43, 2.428, 2.426, 2.424, 2.422, 2.42, 2.418, + 2.416, 2.415, 2.413, 2.411, 2.409, 2.407, 2.405, 2.404, 2.402, 2.4, + 2.398, 2.396, 2.394, 2.393, 2.391, 2.389, 2.387, 2.386, 2.384, 2.382, + 2.38, 2.379, 2.377, 2.375, 2.373, 2.372, 2.37, 2.368, 2.367, 2.365, + 2.363, 2.361, 2.36, 2.358, 2.356, 2.355, 2.353, 2.352, 2.35, 2.348, + 2.347, 2.345, 2.343, 2.342, 2.34, 2.338, 2.337, 2.335, 2.334, 2.332, + 2.331, 2.329, 2.327, 2.326, 2.324, 2.323, 2.321, 2.32, 2.318, 2.316, + 2.315, 2.313, 2.312, 2.31, 2.309, 2.307, 2.306, 2.304, 2.303, 2.301, + 2.3, 2.298, 2.297, 2.295, 2.294, 2.292, 2.291, 2.289, 2.288, 2.286, + 2.285, 2.284, 2.282, 2.281, 2.279, 2.278, 2.276, 2.275, 2.274, 2.272, + 2.271, 2.269, 2.268, 2.266, 2.265, 2.264, 2.262, 2.261, 2.259, 2.258, + 2.257, 2.255, 2.254, 2.253, 2.251, 2.25, 2.248, 2.247, 2.246, 2.244, + 2.243, 2.242, 2.24, 2.239, 2.238, 2.236, 2.235, 2.234, 2.232, 2.231, + 2.23, 2.228, 2.227, 2.226, 2.225, 2.223, 2.222, 2.221, 2.219, 2.218, + 2.217, 2.215, 2.214, 2.213, 2.212, 2.21, 2.209, 2.208, 2.207, 2.205, + 2.204, 2.203, 2.202, 2.2, 2.199, 2.198, 2.197, 2.195, 2.194, 2.193, + 2.192, 2.19, 2.189, 2.188, 2.187, 2.185, 2.184, 2.183, 2.182, 2.181, + 2.179, 2.178, 2.177, 2.176, 2.175, 2.173, 2.172, 2.171, 2.17, 2.169, + 2.168, 2.166, 2.165, 2.164, 2.163, 2.162, 2.16, 2.159, 2.158, 2.157, + 2.156, 2.155, 2.154, 2.152, 2.151, 2.15, 2.149, 2.148, 2.147, 2.146, + 2.144, 2.143, 2.142, 2.141, 2.14, 2.139, 2.138, 2.136, 2.135, 2.134, + 2.133, 2.132, 2.131, 2.13, 2.129, 2.128, 2.126, 2.125, 2.124, 2.123, + 2.122, 2.121, 2.12, 2.119, 2.118, 2.117, 2.116, 2.114, 2.113, 2.112, + 2.111, 2.11, 2.109, 2.108, 2.107, 2.106, 2.105, 2.104, 2.103, 2.102, + 2.101, 2.1, 2.099, 2.097, 2.096, 2.095, 2.094, 2.093, 2.092, 2.091, + 2.09, 2.089, 2.088, 2.087, 2.086, 2.085, 2.084, 2.083, 2.082, 2.081, + 2.08, 2.079, 2.078, 2.077, 2.076, 2.075, 2.074, 2.073, 2.072, 2.071, + 2.07, 2.069, 2.068, 2.067, 2.066, 2.065, 2.064, 2.063, 2.062, 2.061, + 2.06, 2.059, 2.058, 2.057, 2.056, 2.055, 2.054, 2.053, 2.052, 2.051, + 2.05, 2.049, 2.048, 2.047, 2.046, 2.045, 2.044, 2.043, 2.042, 2.041, + 2.04, 2.039, 2.038, 2.037, 2.036, 2.036, 2.035, 2.034, 2.033, 2.032, + 2.031, 2.03, 2.029, 2.028, 2.027, 2.026, 2.025, 2.024, 2.023, 2.022, + 2.021, 2.02, 2.02, 2.019, 2.018, 2.017, 2.016, 2.015, 2.014, 2.013, + 2.012, 2.011, 2.01, 2.009, 2.008, 2.008, 2.007, 2.006, 2.005, 2.004, + 2.003, 2.002, 2.001, 2, 1.999, 1.998, 1.998, 1.997, 1.996, 1.995, + 1.994, 1.993, 1.992, 1.991, 1.99, 1.99, 1.989, 1.988, 1.987, 1.986, + 1.985, 1.984, 1.983, 1.982, 1.982, 1.981, 1.98, 1.979, 1.978, 1.977, + 1.976, 1.975, 1.975, 1.974, 1.973, 1.972, 1.971, 1.97, 1.969, 1.969, + 1.968, 1.967, 1.966, 1.965, 1.964, 1.963, 1.963, 1.962, 1.961, 1.96, + 1.959, 1.958, 1.957, 1.957, 1.956, 1.955, 1.954, 1.953, 1.952, 1.952, + 1.951, 1.95, 1.949, 1.948, 1.947, 1.947, 1.946, 1.945, 1.944, 1.943, + 1.942, 1.942, 1.941, 1.94, 1.939, 1.938, 1.937, 1.937, 1.936, 1.935, + 1.934, 1.933, 1.933, 1.932, 1.931, 1.93, 1.929, 1.928, 1.928, 1.927, + 1.926, 1.925, 1.924, 1.924, 1.923, 1.922, 1.921, 1.92, 1.92, 1.919, + 1.918, 1.917, 1.916, 1.916, 1.915, 1.914, 1.913, 1.912, 1.912, 1.911, + 1.91, 1.909, 1.908, 1.908, 1.907, 1.906, 1.905, 1.904, 1.904, 1.903, + 1.902, 1.901, 1.901, 1.9, 1.899, 1.898, 1.897, 1.897, 1.896, 1.895, + 1.894, 1.894, 1.893, 1.892, 1.891, 1.89, 1.89, 1.889, 1.888, 1.887, + 1.887, 1.886, 1.885, 1.884, 1.884, 1.883, 1.882, 1.881, 1.88, 1.88, + 1.879, 1.878, 1.877, 1.877, 1.876, 1.875, 1.874, 1.874, 1.873, 1.872, + 1.871, 1.871, 1.87, 1.869, 1.868, 1.868, 1.867, 1.866, 1.865, 1.865, + 1.864, 1.863, 1.862, 1.862, 1.861, 1.86, 1.859, 1.859, 1.858, 1.857, + 1.857, 1.856, 1.855, 1.854, 1.854, 1.853, 1.852, 1.851, 1.851, 1.85, + 1.849, 1.848, 1.848, 1.847, 1.846, 1.846, 1.845, 1.844, 1.843, 1.843, + 1.842, 1.841, 1.84, 1.84, 1.839, 1.838, 1.838, 1.837, 1.836, 1.835, + 1.835, 1.834, 1.833, 1.833, 1.832, 1.831, 1.83, 1.83, 1.829, 1.828, + 1.828, 1.827, 1.826, 1.825, 1.825, 1.824, 1.823, 1.823, 1.822, 1.821, + 1.821, 1.82, 1.819, 1.818, 1.818, 1.817, 1.816, 1.816, 1.815, 1.814, + 1.814, 1.813, 1.812, 1.811, 1.811, 1.81, 1.809, 1.809, 1.808, 1.807, + 1.807, 1.806, 1.805, 1.805, 1.804, 1.803, 1.802, 1.802, 1.801, 1.8, + 1.8, 1.799, 1.798, 1.798, 1.797, 1.796, 1.796, 1.795, 1.794, 1.794, + 1.793, 1.792, 1.792, 1.791, 1.79, 1.79, 1.789, 1.788, 1.787, 1.787, + 1.786, 1.785, 1.785, 1.784, 1.783, 1.783, 1.782, 1.781, 1.781, 1.78, + 1.779, 1.779, 1.778, 1.777, 1.777, 1.776, 1.775, 1.775, 1.774, 1.773, + 1.773, 1.772, 1.771, 1.771, 1.77, 1.769, 1.769, 1.768, 1.767, 1.767, + 1.766, 1.766, 1.765, 1.764, 1.764, 1.763, 1.762, 1.762, 1.761, 1.76, + 1.76, 1.759, 1.758, 1.758, 1.757, 1.756, 1.756, 1.755, 1.754, 1.754, + 1.753, 1.752, 1.752, 1.751, 1.751, 1.75, 1.749, 1.749, 1.748, 1.747, + 1.747, 1.746, 1.745, 1.745, 1.744, 1.743, 1.743, 1.742, 1.742, 1.741, + 1.74, 1.74, 1.739, 1.738, 1.738, 1.737, 1.736, 1.736, 1.735, 1.735, + 1.734, 1.733, 1.733, 1.732, 1.731, 1.731, 1.73, 1.729, 1.729, 1.728, + 1.728, 1.727, 1.726, 1.726, 1.725, 1.724, 1.724, 1.723, 1.723, 1.722, + 1.721, 1.721, 1.72, 1.719, 1.719, 1.718, 1.718, 1.717, 1.716, 1.716, + 1.715, 1.715, 1.714, 1.713, 1.713, 1.712, 1.711, 1.711, 1.71, 1.71, + 1.709, 1.708, 1.708, 1.707, 1.706, 1.706, 1.705, 1.705, 1.704, 1.703, + 1.703, 1.702, 1.702, 1.701, 1.7, 1.7, 1.699, 1.699, 1.698, 1.697, + 1.697, 1.696, 1.696, 1.695, 1.694, 1.694, 1.693, 1.692, 1.692, 1.691, + 1.691, 1.69, 1.689, 1.689, 1.688, 1.688, 1.687, 1.686, 1.686, 1.685, + 1.685, 1.684, 1.683, 1.683, 1.682, 1.682, 1.681, 1.68, 1.68, 1.679, + 1.679, 1.678, 1.678, 1.677, 1.676, 1.676, 1.675, 1.675, 1.674, 1.673, + 1.673, 1.672, 1.672, 1.671, 1.67, 1.67, 1.669, 1.669, 1.668, 1.667, + 1.667, 1.666, 1.666, 1.665, 1.665, 1.664, 1.663, 1.663, 1.662, 1.662, + 1.661, 1.66, 1.66, 1.659, 1.659, 1.658, 1.658, 1.657, 1.656, 1.656, + 1.655, 1.655, 1.654, 1.653, 1.653, 1.652, 1.652, 1.651, 1.651, 1.65, + 1.649, 1.649, 1.648, 1.648, 1.647, 1.647, 1.646, 1.645, 1.645, 1.644, + 1.644, 1.643, 1.643, 1.642, 1.641, 1.641, 1.64, 1.64, 1.639, 1.639, + 1.638, 1.637, 1.637, 1.636, 1.636, 1.635, 1.635, 1.634, 1.633, 1.633, + 1.632, 1.632, 1.631, 1.631, 1.63, 1.629, 1.629, 1.628, 1.628, 1.627, + 1.627, 1.626, 1.625, 1.625, 1.624, 1.624, 1.623, 1.623, 1.622, 1.622, + 1.621, 1.62, 1.62, 1.619, 1.619, 1.618, 1.618, 1.617, 1.617, 1.616, + 1.615, 1.615, 1.614, 1.614, 1.613, 1.613, 1.612, 1.612, 1.611, 1.61, + 1.61, 1.609, 1.609, 1.608, 1.608, 1.607, 1.607, 1.606, 1.605, 1.605, + 1.604, 1.604, 1.603, 1.603, 1.602, 1.602, 1.601, 1.6, 1.6, 1.599, + 1.599, 1.598, 1.598, 1.597, 1.597, 1.596, 1.596, 1.595, 1.594, 1.594, + 1.593, 1.593, 1.592, 1.592, 1.591, 1.591, 1.59, 1.59, 1.589, 1.588, + 1.588, 1.587, 1.587, 1.586, 1.586, 1.585, 1.585, 1.584, 1.584, 1.583, + 1.582, 1.582, 1.581, 1.581, 1.58, 1.58, 1.579, 1.579, 1.578, 1.578, + 1.577, 1.577, 1.576, 1.576, 1.575, 1.574, 1.574, 1.573, 1.573, 1.572, + 1.572, 1.571, 1.571, 1.57, 1.57, 1.569, 1.569, 1.568, 1.567, 1.567, + 1.566, 1.566, 1.565, 1.565, 1.564, 1.564, 1.563, 1.563, 1.562, 1.562, + 1.561, 1.561, 1.56, 1.56, 1.559, 1.558, 1.558, 1.557, 1.557, 1.556, + 1.556, 1.555, 1.555, 1.554, 1.554, 1.553, 1.553, 1.552, 1.552, 1.551, + 1.551, 1.55, 1.55, 1.549, 1.549, 1.548, 1.547, 1.547, 1.546, 1.546, + 1.545, 1.545, 1.544, 1.544, 1.543, 1.543, 1.542, 1.542, 1.541, 1.541, + 1.54, 1.54, 1.539, 1.539, 1.538, 1.538, 1.537, 1.537, 1.536, 1.536, + 1.535, 1.534, 1.534, 1.533, 1.533, 1.532, 1.532, 1.531, 1.531, 1.53, + 1.53, 1.529, 1.529, 1.528, 1.528, 1.527, 1.527, 1.526, 1.526, 1.525, + 1.525, 1.524, 1.524, 1.523, 1.523, 1.522, 1.522, 1.521, 1.521, 1.52, + 1.52, 1.519, 1.519, 1.518, 1.518, 1.517, 1.517, 1.516, 1.516, 1.515, + 1.515, 1.514, 1.514, 1.513, 1.512, 1.512, 1.511, 1.511, 1.51, 1.51, + 1.509, 1.509, 1.508, 1.508, 1.507, 1.507, 1.506, 1.506, 1.505, 1.505, + 1.504, 1.504, 1.503, 1.503, 1.502, 1.502, 1.501, 1.501, 1.5, 1.5, + 1.499, 1.499, 1.498, 1.498, 1.497, 1.497, 1.496, 1.496, 1.495, 1.495, + 1.494, 1.494, 1.493, 1.493, 1.492, 1.492, 1.491, 1.491, 1.49, 1.49, + 1.489, 1.489, 1.488, 1.488, 1.487, 1.487, 1.486, 1.486, 1.485, 1.485, + 1.484, 1.484, 1.483, 1.483, 1.482, 1.482, 1.481, 1.481, 1.48, 1.48, + 1.48, 1.479, 1.479, 1.478, 1.478, 1.477, 1.477, 1.476, 1.476, 1.475, + 1.475, 1.474, 1.474, 1.473, 1.473, 1.472, 1.472, 1.471, 1.471, 1.47, + 1.47, 1.469, 1.469, 1.468, 1.468, 1.467, 1.467, 1.466, 1.466, 1.465, + 1.465, 1.464, 1.464, 1.463, 1.463, 1.462, 1.462, 1.461, 1.461, 1.46, + 1.46, 1.459, 1.459, 1.458, 1.458, 1.458, 1.457, 1.457, 1.456, 1.456, + 1.455, 1.455, 1.454, 1.454, 1.453, 1.453, 1.452, 1.452, 1.451, 1.451, + 1.45, 1.45, 1.449, 1.449, 1.448, 1.448, 1.447, 1.447, 1.446, 1.446, + 1.445, 1.445, 1.444, 1.444, 1.444, 1.443, 1.443, 1.442, 1.442, 1.441, + 1.441, 1.44, 1.44, 1.439, 1.439, 1.438, 1.438, 1.437, 1.437, 1.436, + 1.436, 1.435, 1.435, 1.434, 1.434, 1.434, 1.433, 1.433, 1.432, 1.432, + 1.431, 1.431, 1.43, 1.43, 1.429, 1.429, 1.428, 1.428, 1.427, 1.427, + 1.426, 1.426, 1.425, 1.425, 1.424, 1.424, 1.424, 1.423, 1.423, 1.422, + 1.422, 1.421, 1.421, 1.42, 1.42, 1.419, 1.419, 1.418, 1.418, 1.417, + 1.417, 1.416, 1.416, 1.416, 1.415, 1.415, 1.414, 1.414, 1.413, 1.413, + 1.412, 1.412, 1.411, 1.411, 1.41, 1.41, 1.409, 1.409, 1.409, 1.408, + 1.408, 1.407, 1.407, 1.406, 1.406, 1.405, 1.405, 1.404, 1.404, 1.403, + 1.403, 1.402, 1.402, 1.402, 1.401, 1.401, 1.4, 1.4, 1.399, 1.399, + 1.398, 1.398, 1.397, 1.397, 1.396, 1.396, 1.395, 1.395, 1.395, 1.394, + 1.394, 1.393, 1.393, 1.392, 1.392, 1.391, 1.391, 1.39, 1.39, 1.389, + 1.389, 1.389, 1.388, 1.388, 1.387, 1.387, 1.386, 1.386, 1.385, 1.385, + 1.384, 1.384, 1.383, 1.383, 1.383, 1.382, 1.382, 1.381, 1.381, 1.38, + 1.38, 1.379, 1.379, 1.378, 1.378, 1.378, 1.377, 1.377, 1.376, 1.376, + 1.375, 1.375, 1.374, 1.374, 1.373, 1.373, 1.373, 1.372, 1.372, 1.371, + 1.371, 1.37, 1.37, 1.369, 1.369, 1.368, 1.368, 1.367, 1.367, 1.367, + 1.366, 1.366, 1.365, 1.365, 1.364, 1.364, 1.363, 1.363, 1.362, 1.362, + 1.362, 1.361, 1.361, 1.36, 1.36, 1.359, 1.359, 1.358, 1.358, 1.358, + 1.357, 1.357, 1.356, 1.356, 1.355, 1.355, 1.354, 1.354, 1.353, 1.353, + 1.353, 1.352, 1.352, 1.351, 1.351, 1.35, 1.35, 1.349, 1.349, 1.349, + 1.348, 1.348, 1.347, 1.347, 1.346, 1.346, 1.345, 1.345, 1.344, 1.344, + 1.344, 1.343, 1.343, 1.342, 1.342, 1.341, 1.341, 1.34, 1.34, 1.34, + 1.339, 1.339, 1.338, 1.338, 1.337, 1.337, 1.336, 1.336, 1.336, 1.335, + 1.335, 1.334, 1.334, 1.333, 1.333, 1.332, 1.332, 1.332, 1.331, 1.331, + 1.33, 1.33, 1.329, 1.329, 1.328, 1.328, 1.328, 1.327, 1.327, 1.326, + 1.326, 1.325, 1.325, 1.324, 1.324, 1.324, 1.323, 1.323, 1.322, 1.322, + 1.321, 1.321, 1.32, 1.32, 1.32, 1.319, 1.319, 1.318, 1.318, 1.317, + 1.317, 1.316, 1.316, 1.316, 1.315, 1.315, 1.314, 1.314, 1.313, 1.313, + 1.312, 1.312, 1.312, 1.311, 1.311, 1.31, 1.31, 1.309, 1.309, 1.309, + 1.308, 1.308, 1.307, 1.307, 1.306, 1.306, 1.305, 1.305, 1.305, 1.304, + 1.304, 1.303, 1.303, 1.302, 1.302, 1.302, 1.301, 1.301, 1.3, 1.3, + 1.299, 1.299, 1.298, 1.298, 1.298, 1.297, 1.297, 1.296, 1.296, 1.295, + 1.295, 1.295, 1.294, 1.294, 1.293, 1.293, 1.292, 1.292, 1.291, 1.291, + 1.291, 1.29, 1.29, 1.289, 1.289, 1.288, 1.288, 1.288, 1.287, 1.287, + 1.286, 1.286, 1.285, 1.285, 1.285, 1.284, 1.284, 1.283, 1.283, 1.282, + 1.282, 1.281, 1.281, 1.281, 1.28, 1.28, 1.279, 1.279, 1.278, 1.278, + 1.278, 1.277, 1.277, 1.276, 1.276, 1.275, 1.275, 1.275, 1.274, 1.274, + 1.273, 1.273, 1.272, 1.272, 1.272, 1.271, 1.271, 1.27, 1.27, 1.269, + 1.269, 1.269, 1.268, 1.268, 1.267, 1.267, 1.266, 1.266, 1.266, 1.265, + 1.265, 1.264, 1.264, 1.263, 1.263, 1.263, 1.262, 1.262, 1.261, 1.261, + 1.26, 1.26, 1.26, 1.259, 1.259, 1.258, 1.258, 1.257, 1.257, 1.257, + 1.256, 1.256, 1.255, 1.255, 1.254, 1.254, 1.254, 1.253, 1.253, 1.252, + 1.252, 1.251, 1.251, 1.251, 1.25, 1.25, 1.249, 1.249, 1.248, 1.248, + 1.248, 1.247, 1.247, 1.246, 1.246, 1.245, 1.245, 1.245, 1.244, 1.244, + 1.243, 1.243, 1.242, 1.242, 1.242, 1.241, 1.241, 1.24, 1.24, 1.239, + 1.239, 1.239, 1.238, 1.238, 1.237, 1.237, 1.237, 1.236, 1.236, 1.235, + 1.235, 1.234, 1.234, 1.234, 1.233, 1.233, 1.232, 1.232, 1.231, 1.231, + 1.231, 1.23, 1.23, 1.229, 1.229, 1.228, 1.228, 1.228, 1.227, 1.227, + 1.226, 1.226, 1.226, 1.225, 1.225, 1.224, 1.224, 1.223, 1.223, 1.223, + 1.222, 1.222, 1.221, 1.221, 1.22, 1.22, 1.22, 1.219, 1.219, 1.218, + 1.218, 1.218, 1.217, 1.217, 1.216, 1.216, 1.215, 1.215, 1.215, 1.214, + 1.214, 1.213, 1.213, 1.212, 1.212, 1.212, 1.211, 1.211, 1.21, 1.21, + 1.21, 1.209, 1.209, 1.208, 1.208, 1.207, 1.207, 1.207, 1.206, 1.206, + 1.205, 1.205, 1.204, 1.204, 1.204, 1.203, 1.203, 1.202, 1.202, 1.202, + 1.201, 1.201, 1.2, 1.2, 1.199, 1.199, 1.199, 1.198, 1.198, 1.197, + 1.197, 1.197, 1.196, 1.196, 1.195, 1.195, 1.194, 1.194, 1.194, 1.193, + 1.193, 1.192, 1.192, 1.192, 1.191, 1.191, 1.19, 1.19, 1.189, 1.189, + 1.189, 1.188, 1.188, 1.187, 1.187, 1.187, 1.186, 1.186, 1.185, 1.185, + 1.184, 1.184, 1.184, 1.183, 1.183, 1.182, 1.182, 1.182, 1.181, 1.181, + 1.18, 1.18, 1.179, 1.179, 1.179, 1.178, 1.178, 1.177, 1.177, 1.177, + 1.176, 1.176, 1.175, 1.175, 1.175, 1.174, 1.174, 1.173, 1.173, 1.172, + 1.172, 1.172, 1.171, 1.171, 1.17, 1.17, 1.17, 1.169, 1.169, 1.168, + 1.168, 1.167, 1.167, 1.167, 1.166, 1.166, 1.165, 1.165, 1.165, 1.164, + 1.164, 1.163, 1.163, 1.163, 1.162, 1.162, 1.161, 1.161, 1.16, 1.16, + 1.16, 1.159, 1.159, 1.158, 1.158, 1.158, 1.157, 1.157, 1.156, 1.156, + 1.156, 1.155, 1.155, 1.154, 1.154, 1.153, 1.153, 1.153, 1.152, 1.152, + 1.151, 1.151, 1.151, 1.15, 1.15, 1.149, 1.149, 1.149, 1.148, 1.148, + 1.147, 1.147, 1.146, 1.146, 1.146, 1.145, 1.145, 1.144, 1.144, 1.144, + 1.143, 1.143, 1.142, 1.142, 1.142, 1.141, 1.141, 1.14, 1.14, 1.139, + 1.139, 1.139, 1.138, 1.138, 1.137, 1.137, 1.137, 1.136, 1.136, 1.135, + 1.135, 1.135, 1.134, 1.134, 1.133, 1.133, 1.133, 1.132, 1.132, 1.131, + 1.131, 1.13, 1.13, 1.13, 1.129, 1.129, 1.128, 1.128, 1.128, 1.127, + 1.127, 1.126, 1.126, 1.126, 1.125, 1.125, 1.124, 1.124, 1.124, 1.123, + 1.123, 1.122, 1.122, 1.121, 1.121, 1.121, 1.12, 1.12, 1.119, 1.119, + 1.119, 1.118, 1.118, 1.117, 1.117, 1.117, 1.116, 1.116, 1.115, 1.115, + 1.115, 1.114, 1.114, 1.113, 1.113, 1.113, 1.112, 1.112, 1.111, 1.111, + 1.11, 1.11, 1.11, 1.109, 1.109, 1.108, 1.108, 1.108, 1.107, 1.107, + 1.106, 1.106, 1.106, 1.105, 1.105, 1.104, 1.104, 1.104, 1.103, 1.103, + 1.102, 1.102, 1.102, 1.101, 1.101, 1.1, 1.1, 1.099, 1.099, 1.099, + 1.098, 1.098, 1.097, 1.097, 1.097, 1.096, 1.096, 1.095, 1.095, 1.095, + 1.094, 1.094, 1.093, 1.093, 1.093, 1.092, 1.092, 1.091, 1.091, 1.091, + 1.09, 1.09, 1.089, 1.089, 1.089, 1.088, 1.088, 1.087, 1.087, 1.086, + 1.086, 1.086, 1.085, 1.085, 1.084, 1.084, 1.084, 1.083, 1.083, 1.082, + 1.082, 1.082, 1.081, 1.081, 1.08, 1.08, 1.08, 1.079, 1.079, 1.078, + 1.078, 1.078, 1.077, 1.077, 1.076, 1.076, 1.076, 1.075, 1.075, 1.074, + 1.074, 1.074, 1.073, 1.073, 1.072, 1.072, 1.072, 1.071, 1.071, 1.07, + 1.07, 1.069, 1.069, 1.069, 1.068, 1.068, 1.067, 1.067, 1.067, 1.066, + 1.066, 1.065, 1.065, 1.065, 1.064, 1.064, 1.063, 1.063, 1.063, 1.062, + 1.062, 1.061, 1.061, 1.061, 1.06, 1.06, 1.059, 1.059, 1.059, 1.058, + 1.058, 1.057, 1.057, 1.057, 1.056, 1.056, 1.055, 1.055, 1.055, 1.054, + 1.054, 1.053, 1.053, 1.053, 1.052, 1.052, 1.051, 1.051, 1.05, 1.05, + 1.05, 1.049, 1.049, 1.048, 1.048, 1.048, 1.047, 1.047, 1.046, 1.046, + 1.046, 1.045, 1.045, 1.044, 1.044, 1.044, 1.043, 1.043, 1.042, 1.042, + 1.042, 1.041, 1.041, 1.04, 1.04, 1.04, 1.039, 1.039, 1.038, 1.038, + 1.038, 1.037, 1.037, 1.036, 1.036, 1.036, 1.035, 1.035, 1.034, 1.034, + 1.034, 1.033, 1.033, 1.032, 1.032, 1.032, 1.031, 1.031, 1.03, 1.03, + 1.03, 1.029, 1.029, 1.028, 1.028, 1.028, 1.027, 1.027, 1.026, 1.026, + 1.026, 1.025, 1.025, 1.024, 1.024, 1.023, 1.023, 1.023, 1.022, 1.022, + 1.021, 1.021, 1.021, 1.02, 1.02, 1.019, 1.019, 1.019, 1.018, 1.018, + 1.017, 1.017, 1.017, 1.016, 1.016, 1.015, 1.015, 1.015, 1.014, 1.014, + 1.013, 1.013, 1.013, 1.012, 1.012, 1.011, 1.011, 1.011, 1.01, 1.01, + 1.009, 1.009, 1.009, 1.008, 1.008, 1.007, 1.007, 1.007, 1.006, 1.006, + 1.005, 1.005, 1.005, 1.004, 1.004, 1.003, 1.003, 1.003, 1.002, 1.002, + 1.001, 1.001, 1.001, 1, 0.9997, 0.9993, 0.9989, 0.9985, 0.9981, 0.9977, + 0.9973, 0.9969, 0.9965, 0.9961, 0.9957, 0.9953, 0.9949, 0.9945, 0.9941, 0.9937, + 0.9933, 0.9929, 0.9925, 0.9921, 0.9917, 0.9913, 0.9909, 0.9905, 0.9901, 0.9897, + 0.9893, 0.9889, 0.9885, 0.9881, 0.9877, 0.9873, 0.9869, 0.9865, 0.9861, 0.9856, + 0.9852, 0.9848, 0.9844, 0.984, 0.9836, 0.9832, 0.9828, 0.9824, 0.982, 0.9816, + 0.9812, 0.9808, 0.9804, 0.98, 0.9796, 0.9792, 0.9788, 0.9784, 0.978, 0.9776, + 0.9772, 0.9768, 0.9764, 0.976, 0.9756, 0.9752, 0.9748, 0.9744, 0.974, 0.9736, + 0.9732, 0.9728, 0.9724, 0.972, 0.9716, 0.9712, 0.9707, 0.9703, 0.9699, 0.9695, + 0.9691, 0.9687, 0.9683, 0.9679, 0.9675, 0.9671, 0.9667, 0.9663, 0.9659, 0.9655, + 0.9651, 0.9647, 0.9643, 0.9639, 0.9635, 0.9631, 0.9627, 0.9623, 0.9619, 0.9615, + 0.9611, 0.9607, 0.9603, 0.9599, 0.9595, 0.9591, 0.9587, 0.9583, 0.9579, 0.9574, + 0.957, 0.9566, 0.9562, 0.9558, 0.9554, 0.955, 0.9546, 0.9542, 0.9538, 0.9534, + 0.953, 0.9526, 0.9522, 0.9518, 0.9514, 0.951, 0.9506, 0.9502, 0.9498, 0.9494, + 0.949, 0.9486, 0.9482, 0.9478, 0.9474, 0.947, 0.9466, 0.9462, 0.9457, 0.9453, + 0.9449, 0.9445, 0.9441, 0.9437, 0.9433, 0.9429, 0.9425, 0.9421, 0.9417, 0.9413, + 0.9409, 0.9405, 0.9401, 0.9397, 0.9393, 0.9389, 0.9385, 0.9381, 0.9377, 0.9373, + 0.9369, 0.9365, 0.9361, 0.9356, 0.9352, 0.9348, 0.9344, 0.934, 0.9336, 0.9332, + 0.9328, 0.9324, 0.932, 0.9316, 0.9312, 0.9308, 0.9304, 0.93, 0.9296, 0.9292, + 0.9288, 0.9284, 0.928, 0.9276, 0.9272, 0.9267, 0.9263, 0.9259, 0.9255, 0.9251, + 0.9247, 0.9243, 0.9239, 0.9235, 0.9231, 0.9227, 0.9223, 0.9219, 0.9215, 0.9211, + 0.9207, 0.9203, 0.9199, 0.9195, 0.9191, 0.9186, 0.9182, 0.9178, 0.9174, 0.917, + 0.9166, 0.9162, 0.9158, 0.9154, 0.915, 0.9146, 0.9142, 0.9138, 0.9134, 0.913, + 0.9126, 0.9122, 0.9118, 0.9113, 0.9109, 0.9105, 0.9101, 0.9097, 0.9093, 0.9089, + 0.9085, 0.9081, 0.9077, 0.9073, 0.9069, 0.9065, 0.9061, 0.9057, 0.9053, 0.9049, + 0.9044, 0.904, 0.9036, 0.9032, 0.9028, 0.9024, 0.902, 0.9016, 0.9012, 0.9008, + 0.9004, 0.9, 0.8996, 0.8992, 0.8988, 0.8983, 0.8979, 0.8975, 0.8971, 0.8967, + 0.8963, 0.8959, 0.8955, 0.8951, 0.8947, 0.8943, 0.8939, 0.8935, 0.8931, 0.8926, + 0.8922, 0.8918, 0.8914, 0.891, 0.8906, 0.8902, 0.8898, 0.8894, 0.889, 0.8886, + 0.8882, 0.8878, 0.8873, 0.8869, 0.8865, 0.8861, 0.8857, 0.8853, 0.8849, 0.8845, + 0.8841, 0.8837, 0.8833, 0.8829, 0.8825, 0.882, 0.8816, 0.8812, 0.8808, 0.8804, + 0.88, 0.8796, 0.8792, 0.8788, 0.8784, 0.878, 0.8775, 0.8771, 0.8767, 0.8763, + 0.8759, 0.8755, 0.8751, 0.8747, 0.8743, 0.8739, 0.8735, 0.873, 0.8726, 0.8722, + 0.8718, 0.8714, 0.871, 0.8706, 0.8702, 0.8698, 0.8694, 0.869, 0.8685, 0.8681, + 0.8677, 0.8673, 0.8669, 0.8665, 0.8661, 0.8657, 0.8653, 0.8649, 0.8644, 0.864, + 0.8636, 0.8632, 0.8628, 0.8624, 0.862, 0.8616, 0.8612, 0.8607, 0.8603, 0.8599, + 0.8595, 0.8591, 0.8587, 0.8583, 0.8579, 0.8575, 0.857, 0.8566, 0.8562, 0.8558, + 0.8554, 0.855, 0.8546, 0.8542, 0.8538, 0.8533, 0.8529, 0.8525, 0.8521, 0.8517, + 0.8513, 0.8509, 0.8505, 0.85, 0.8496, 0.8492, 0.8488, 0.8484, 0.848, 0.8476, + 0.8472, 0.8467, 0.8463, 0.8459, 0.8455, 0.8451, 0.8447, 0.8443, 0.8439, 0.8434, + 0.843, 0.8426, 0.8422, 0.8418, 0.8414, 0.841, 0.8406, 0.8401, 0.8397, 0.8393, + 0.8389, 0.8385, 0.8381, 0.8377, 0.8372, 0.8368, 0.8364, 0.836, 0.8356, 0.8352, + 0.8348, 0.8343, 0.8339, 0.8335, 0.8331, 0.8327, 0.8323, 0.8319, 0.8314, 0.831, + 0.8306, 0.8302, 0.8298, 0.8294, 0.8289, 0.8285, 0.8281, 0.8277, 0.8273, 0.8269, + 0.8265, 0.826, 0.8256, 0.8252, 0.8248, 0.8244, 0.824, 0.8235, 0.8231, 0.8227, + 0.8223, 0.8219, 0.8215, 0.821, 0.8206, 0.8202, 0.8198, 0.8194, 0.819, 0.8185, + 0.8181, 0.8177, 0.8173, 0.8169, 0.8165, 0.816, 0.8156, 0.8152, 0.8148, 0.8144, + 0.814, 0.8135, 0.8131, 0.8127, 0.8123, 0.8119, 0.8114, 0.811, 0.8106, 0.8102, + 0.8098, 0.8094, 0.8089, 0.8085, 0.8081, 0.8077, 0.8073, 0.8068, 0.8064, 0.806, + 0.8056, 0.8052, 0.8047, 0.8043, 0.8039, 0.8035, 0.8031, 0.8026, 0.8022, 0.8018, + 0.8014, 0.801, 0.8005, 0.8001, 0.7997, 0.7993, 0.7989, 0.7984, 0.798, 0.7976, + 0.7972, 0.7968, 0.7963, 0.7959, 0.7955, 0.7951, 0.7947, 0.7942, 0.7938, 0.7934, + 0.793, 0.7926, 0.7921, 0.7917, 0.7913, 0.7909, 0.7904, 0.79, 0.7896, 0.7892, + 0.7888, 0.7883, 0.7879, 0.7875, 0.7871, 0.7866, 0.7862, 0.7858, 0.7854, 0.7849, + 0.7845, 0.7841, 0.7837, 0.7833, 0.7828, 0.7824, 0.782, 0.7816, 0.7811, 0.7807, + 0.7803, 0.7799, 0.7794, 0.779, 0.7786, 0.7782, 0.7777, 0.7773, 0.7769, 0.7765, + 0.776, 0.7756, 0.7752, 0.7748, 0.7743, 0.7739, 0.7735, 0.7731, 0.7726, 0.7722, + 0.7718, 0.7714, 0.7709, 0.7705, 0.7701, 0.7697, 0.7692, 0.7688, 0.7684, 0.7679, + 0.7675, 0.7671, 0.7667, 0.7662, 0.7658, 0.7654, 0.765, 0.7645, 0.7641, 0.7637, + 0.7632, 0.7628, 0.7624, 0.762, 0.7615, 0.7611, 0.7607, 0.7602, 0.7598, 0.7594, + 0.759, 0.7585, 0.7581, 0.7577, 0.7572, 0.7568, 0.7564, 0.756, 0.7555, 0.7551, + 0.7547, 0.7542, 0.7538, 0.7534, 0.7529, 0.7525, 0.7521, 0.7516, 0.7512, 0.7508, + 0.7504, 0.7499, 0.7495, 0.7491, 0.7486, 0.7482, 0.7478, 0.7473, 0.7469, 0.7465, + 0.746, 0.7456, 0.7452, 0.7447, 0.7443, 0.7439, 0.7434, 0.743, 0.7426, 0.7421, + 0.7417, 0.7413, 0.7408, 0.7404, 0.74, 0.7395, 0.7391, 0.7387, 0.7382, 0.7378, + 0.7374, 0.7369, 0.7365, 0.7361, 0.7356, 0.7352, 0.7348, 0.7343, 0.7339, 0.7335, + 0.733, 0.7326, 0.7321, 0.7317, 0.7313, 0.7308, 0.7304, 0.73, 0.7295, 0.7291, + 0.7287, 0.7282, 0.7278, 0.7273, 0.7269, 0.7265, 0.726, 0.7256, 0.7252, 0.7247, + 0.7243, 0.7238, 0.7234, 0.723, 0.7225, 0.7221, 0.7216, 0.7212, 0.7208, 0.7203, + 0.7199, 0.7195, 0.719, 0.7186, 0.7181, 0.7177, 0.7173, 0.7168, 0.7164, 0.7159, + 0.7155, 0.7151, 0.7146, 0.7142, 0.7137, 0.7133, 0.7128, 0.7124, 0.712, 0.7115, + 0.7111, 0.7106, 0.7102, 0.7098, 0.7093, 0.7089, 0.7084, 0.708, 0.7075, 0.7071, + 0.7066, 0.7062, 0.7058, 0.7053, 0.7049, 0.7044, 0.704, 0.7035, 0.7031, 0.7027, + 0.7022, 0.7018, 0.7013, 0.7009, 0.7004, 0.7, 0.6995, 0.6991, 0.6986, 0.6982, + 0.6978, 0.6973, 0.6969, 0.6964, 0.696, 0.6955, 0.6951, 0.6946, 0.6942, 0.6937, + 0.6933, 0.6928, 0.6924, 0.6919, 0.6915, 0.691, 0.6906, 0.6901, 0.6897, 0.6892, + 0.6888, 0.6883, 0.6879, 0.6874, 0.687, 0.6865, 0.6861, 0.6856, 0.6852, 0.6847, + 0.6843, 0.6838, 0.6834, 0.6829, 0.6825, 0.682, 0.6816, 0.6811, 0.6807, 0.6802, + 0.6798, 0.6793, 0.6789, 0.6784, 0.678, 0.6775, 0.6771, 0.6766, 0.6762, 0.6757, + 0.6752, 0.6748, 0.6743, 0.6739, 0.6734, 0.673, 0.6725, 0.6721, 0.6716, 0.6711, + 0.6707, 0.6702, 0.6698, 0.6693, 0.6689, 0.6684, 0.668, 0.6675, 0.667, 0.6666, + 0.6661, 0.6657, 0.6652, 0.6648, 0.6643, 0.6638, 0.6634, 0.6629, 0.6625, 0.662, + 0.6615, 0.6611, 0.6606, 0.6602, 0.6597, 0.6592, 0.6588, 0.6583, 0.6579, 0.6574, + 0.6569, 0.6565, 0.656, 0.6556, 0.6551, 0.6546, 0.6542, 0.6537, 0.6532, 0.6528, + 0.6523, 0.6519, 0.6514, 0.6509, 0.6505, 0.65, 0.6495, 0.6491, 0.6486, 0.6481, + 0.6477, 0.6472, 0.6468, 0.6463, 0.6458, 0.6454, 0.6449, 0.6444, 0.644, 0.6435, + 0.643, 0.6426, 0.6421, 0.6416, 0.6412, 0.6407, 0.6402, 0.6397, 0.6393, 0.6388, + 0.6383, 0.6379, 0.6374, 0.6369, 0.6365, 0.636, 0.6355, 0.6351, 0.6346, 0.6341, + 0.6336, 0.6332, 0.6327, 0.6322, 0.6318, 0.6313, 0.6308, 0.6303, 0.6299, 0.6294, + 0.6289, 0.6285, 0.628, 0.6275, 0.627, 0.6266, 0.6261, 0.6256, 0.6251, 0.6247, + 0.6242, 0.6237, 0.6232, 0.6228, 0.6223, 0.6218, 0.6213, 0.6208, 0.6204, 0.6199, + 0.6194, 0.6189, 0.6185, 0.618, 0.6175, 0.617, 0.6165, 0.6161, 0.6156, 0.6151, + 0.6146, 0.6142, 0.6137, 0.6132, 0.6127, 0.6122, 0.6117, 0.6113, 0.6108, 0.6103, + 0.6098, 0.6093, 0.6089, 0.6084, 0.6079, 0.6074, 0.6069, 0.6064, 0.606, 0.6055, + 0.605, 0.6045, 0.604, 0.6035, 0.603, 0.6026, 0.6021, 0.6016, 0.6011, 0.6006, + 0.6001, 0.5996, 0.5992, 0.5987, 0.5982, 0.5977, 0.5972, 0.5967, 0.5962, 0.5957, + 0.5952, 0.5948, 0.5943, 0.5938, 0.5933, 0.5928, 0.5923, 0.5918, 0.5913, 0.5908, + 0.5903, 0.5898, 0.5894, 0.5889, 0.5884, 0.5879, 0.5874, 0.5869, 0.5864, 0.5859, + 0.5854, 0.5849, 0.5844, 0.5839, 0.5834, 0.5829, 0.5824, 0.5819, 0.5814, 0.5809, + 0.5804, 0.5799, 0.5794, 0.5789, 0.5784, 0.5779, 0.5774, 0.5769, 0.5764, 0.5759, + 0.5754, 0.5749, 0.5744, 0.5739, 0.5734, 0.5729, 0.5724, 0.5719, 0.5714, 0.5709, + 0.5704, 0.5699, 0.5694, 0.5689, 0.5684, 0.5679, 0.5674, 0.5669, 0.5664, 0.5659, + 0.5654, 0.5649, 0.5644, 0.5639, 0.5633, 0.5628, 0.5623, 0.5618, 0.5613, 0.5608, + 0.5603, 0.5598, 0.5593, 0.5588, 0.5582, 0.5577, 0.5572, 0.5567, 0.5562, 0.5557, + 0.5552, 0.5547, 0.5541, 0.5536, 0.5531, 0.5526, 0.5521, 0.5516, 0.5511, 0.5505, + 0.55, 0.5495, 0.549, 0.5485, 0.548, 0.5474, 0.5469, 0.5464, 0.5459, 0.5454, + 0.5448, 0.5443, 0.5438, 0.5433, 0.5428, 0.5422, 0.5417, 0.5412, 0.5407, 0.5402, + 0.5396, 0.5391, 0.5386, 0.5381, 0.5375, 0.537, 0.5365, 0.536, 0.5354, 0.5349, + 0.5344, 0.5339, 0.5333, 0.5328, 0.5323, 0.5317, 0.5312, 0.5307, 0.5302, 0.5296, + 0.5291, 0.5286, 0.528, 0.5275, 0.527, 0.5264, 0.5259, 0.5254, 0.5248, 0.5243, + 0.5238, 0.5232, 0.5227, 0.5222, 0.5216, 0.5211, 0.5206, 0.52, 0.5195, 0.5189, + 0.5184, 0.5179, 0.5173, 0.5168, 0.5162, 0.5157, 0.5152, 0.5146, 0.5141, 0.5135, + 0.513, 0.5124, 0.5119, 0.5114, 0.5108, 0.5103, 0.5097, 0.5092, 0.5086, 0.5081, + 0.5075, 0.507, 0.5064, 0.5059, 0.5053, 0.5048, 0.5043, 0.5037, 0.5032, 0.5026, + 0.502, 0.5015, 0.5009, 0.5004, 0.4998, 0.4993, 0.4987, 0.4982, 0.4976, 0.4971, + 0.4965, 0.496, 0.4954, 0.4948, 0.4943, 0.4937, 0.4932, 0.4926, 0.492, 0.4915, + 0.4909, 0.4904, 0.4898, 0.4892, 0.4887, 0.4881, 0.4875, 0.487, 0.4864, 0.4859, + 0.4853, 0.4847, 0.4842, 0.4836, 0.483, 0.4825, 0.4819, 0.4813, 0.4807, 0.4802, + 0.4796, 0.479, 0.4785, 0.4779, 0.4773, 0.4767, 0.4762, 0.4756, 0.475, 0.4744, + 0.4739, 0.4733, 0.4727, 0.4721, 0.4716, 0.471, 0.4704, 0.4698, 0.4692, 0.4687, + 0.4681, 0.4675, 0.4669, 0.4663, 0.4657, 0.4652, 0.4646, 0.464, 0.4634, 0.4628, + 0.4622, 0.4616, 0.461, 0.4605, 0.4599, 0.4593, 0.4587, 0.4581, 0.4575, 0.4569, + 0.4563, 0.4557, 0.4551, 0.4545, 0.4539, 0.4533, 0.4527, 0.4521, 0.4515, 0.451, + 0.4504, 0.4498, 0.4491, 0.4485, 0.4479, 0.4473, 0.4467, 0.4461, 0.4455, 0.4449, + 0.4443, 0.4437, 0.4431, 0.4425, 0.4419, 0.4413, 0.4407, 0.4401, 0.4394, 0.4388, + 0.4382, 0.4376, 0.437, 0.4364, 0.4358, 0.4351, 0.4345, 0.4339, 0.4333, 0.4327, + 0.4321, 0.4314, 0.4308, 0.4302, 0.4296, 0.4289, 0.4283, 0.4277, 0.4271, 0.4264, + 0.4258, 0.4252, 0.4246, 0.4239, 0.4233, 0.4227, 0.422, 0.4214, 0.4208, 0.4201, + 0.4195, 0.4189, 0.4182, 0.4176, 0.4169, 0.4163, 0.4157, 0.415, 0.4144, 0.4137, + 0.4131, 0.4125, 0.4118, 0.4112, 0.4105, 0.4099, 0.4092, 0.4086, 0.4079, 0.4073, + 0.4066, 0.406, 0.4053, 0.4047, 0.404, 0.4034, 0.4027, 0.402, 0.4014, 0.4007, + 0.4001, 0.3994, 0.3987, 0.3981, 0.3974, 0.3967, 0.3961, 0.3954, 0.3947, 0.3941, + 0.3934, 0.3927, 0.3921, 0.3914, 0.3907, 0.39, 0.3894, 0.3887, 0.388, 0.3873, + 0.3866, 0.386, 0.3853, 0.3846, 0.3839, 0.3832, 0.3825, 0.3819, 0.3812, 0.3805, + 0.3798, 0.3791, 0.3784, 0.3777, 0.377, 0.3763, 0.3756, 0.3749, 0.3742, 0.3735, + 0.3728, 0.3721, 0.3714, 0.3707, 0.37, 0.3693, 0.3686, 0.3679, 0.3672, 0.3665, + 0.3657, 0.365, 0.3643, 0.3636, 0.3629, 0.3622, 0.3614, 0.3607, 0.36, 0.3593, + 0.3585, 0.3578, 0.3571, 0.3564, 0.3556, 0.3549, 0.3542, 0.3534, 0.3527, 0.352, + 0.3512, 0.3505, 0.3497, 0.349, 0.3483, 0.3475, 0.3468, 0.346, 0.3453, 0.3445, + 0.3438, 0.343, 0.3422, 0.3415, 0.3407, 0.34, 0.3392, 0.3384, 0.3377, 0.3369, + 0.3361, 0.3354, 0.3346, 0.3338, 0.3331, 0.3323, 0.3315, 0.3307, 0.3299, 0.3292, + 0.3284, 0.3276, 0.3268, 0.326, 0.3252, 0.3244, 0.3236, 0.3228, 0.3221, 0.3213, + 0.3205, 0.3196, 0.3188, 0.318, 0.3172, 0.3164, 0.3156, 0.3148, 0.314, 0.3132, + 0.3123, 0.3115, 0.3107, 0.3099, 0.309, 0.3082, 0.3074, 0.3065, 0.3057, 0.3049, + 0.304, 0.3032, 0.3023, 0.3015, 0.3007, 0.2998, 0.2989, 0.2981, 0.2972, 0.2964, + 0.2955, 0.2946, 0.2938, 0.2929, 0.292, 0.2912, 0.2903, 0.2894, 0.2885, 0.2877, + 0.2868, 0.2859, 0.285, 0.2841, 0.2832, 0.2823, 0.2814, 0.2805, 0.2796, 0.2787, + 0.2778, 0.2768, 0.2759, 0.275, 0.2741, 0.2732, 0.2722, 0.2713, 0.2704, 0.2694, + 0.2685, 0.2675, 0.2666, 0.2656, 0.2647, 0.2637, 0.2628, 0.2618, 0.2608, 0.2599, + 0.2589, 0.2579, 0.2569, 0.256, 0.255, 0.254, 0.253, 0.252, 0.251, 0.25, + 0.249, 0.248, 0.2469, 0.2459, 0.2449, 0.2439, 0.2428, 0.2418, 0.2408, 0.2397, + 0.2387, 0.2376, 0.2365, 0.2355, 0.2344, 0.2333, 0.2323, 0.2312, 0.2301, 0.229, + 0.2279, 0.2268, 0.2257, 0.2246, 0.2235, 0.2223, 0.2212, 0.2201, 0.2189, 0.2178, + 0.2166, 0.2155, 0.2143, 0.2132, 0.212, 0.2108, 0.2096, 0.2084, 0.2072, 0.206, + 0.2048, 0.2036, 0.2023, 0.2011, 0.1999, 0.1986, 0.1974, 0.1961, 0.1948, 0.1935, + 0.1923, 0.191, 0.1896, 0.1883, 0.187, 0.1857, 0.1843, 0.183, 0.1816, 0.1802, + 0.1789, 0.1775, 0.1761, 0.1747, 0.1732, 0.1718, 0.1703, 0.1689, 0.1674, 0.1659, + 0.1644, 0.1629, 0.1614, 0.1599, 0.1583, 0.1567, 0.1551, 0.1535, 0.1519, 0.1503, + 0.1486, 0.147, 0.1453, 0.1436, 0.1418, 0.1401, 0.1383, 0.1365, 0.1347, 0.1329, + 0.131, 0.1291, 0.1272, 0.1252, 0.1233, 0.1213, 0.1192, 0.1171, 0.115, 0.1129, + 0.1107, 0.1084, 0.1061, 0.1038, 0.1014, 0.09894, 0.09643, 0.09385, 0.0912, 0.08847, + 0.08566, 0.08275, 0.07974, 0.0766, 0.07334, 0.06992, 0.06633, 0.06253, 0.05849, 0.05415, + 0.04943, 0.0442, 0.03828, 0.03125, 0.0221, -0}; - const static uint64 mask = max-1; + const static double cosvals[max] = { + 1, 1, 1, 1, 1, 1, 0.9999, 0.9999, 0.9999, 0.9999, + 0.9999, 0.9998, 0.9998, 0.9998, 0.9997, 0.9997, 0.9997, 0.9996, 0.9996, 0.9995, + 0.9995, 0.9994, 0.9994, 0.9993, 0.9993, 0.9992, 0.9991, 0.9991, 0.999, 0.9989, + 0.9989, 0.9988, 0.9987, 0.9986, 0.9986, 0.9985, 0.9984, 0.9983, 0.9982, 0.9981, + 0.998, 0.9979, 0.9978, 0.9977, 0.9976, 0.9975, 0.9974, 0.9973, 0.9972, 0.9971, + 0.9969, 0.9968, 0.9967, 0.9966, 0.9964, 0.9963, 0.9962, 0.996, 0.9959, 0.9958, + 0.9956, 0.9955, 0.9953, 0.9952, 0.995, 0.9949, 0.9947, 0.9946, 0.9944, 0.9942, + 0.9941, 0.9939, 0.9937, 0.9936, 0.9934, 0.9932, 0.993, 0.9929, 0.9927, 0.9925, + 0.9923, 0.9921, 0.9919, 0.9917, 0.9915, 0.9913, 0.9911, 0.9909, 0.9907, 0.9905, + 0.9903, 0.9901, 0.9898, 0.9896, 0.9894, 0.9892, 0.989, 0.9887, 0.9885, 0.9883, + 0.988, 0.9878, 0.9875, 0.9873, 0.9871, 0.9868, 0.9866, 0.9863, 0.9861, 0.9858, + 0.9855, 0.9853, 0.985, 0.9847, 0.9845, 0.9842, 0.9839, 0.9837, 0.9834, 0.9831, + 0.9828, 0.9825, 0.9823, 0.982, 0.9817, 0.9814, 0.9811, 0.9808, 0.9805, 0.9802, + 0.9799, 0.9796, 0.9793, 0.9789, 0.9786, 0.9783, 0.978, 0.9777, 0.9774, 0.977, + 0.9767, 0.9764, 0.976, 0.9757, 0.9754, 0.975, 0.9747, 0.9743, 0.974, 0.9736, + 0.9733, 0.9729, 0.9726, 0.9722, 0.9719, 0.9715, 0.9711, 0.9708, 0.9704, 0.97, + 0.9697, 0.9693, 0.9689, 0.9685, 0.9681, 0.9678, 0.9674, 0.967, 0.9666, 0.9662, + 0.9658, 0.9654, 0.965, 0.9646, 0.9642, 0.9638, 0.9634, 0.963, 0.9625, 0.9621, + 0.9617, 0.9613, 0.9609, 0.9604, 0.96, 0.9596, 0.9591, 0.9587, 0.9583, 0.9578, + 0.9574, 0.9569, 0.9565, 0.956, 0.9556, 0.9551, 0.9547, 0.9542, 0.9538, 0.9533, + 0.9528, 0.9524, 0.9519, 0.9514, 0.951, 0.9505, 0.95, 0.9495, 0.949, 0.9486, + 0.9481, 0.9476, 0.9471, 0.9466, 0.9461, 0.9456, 0.9451, 0.9446, 0.9441, 0.9436, + 0.9431, 0.9426, 0.9421, 0.9415, 0.941, 0.9405, 0.94, 0.9395, 0.9389, 0.9384, + 0.9379, 0.9373, 0.9368, 0.9363, 0.9357, 0.9352, 0.9346, 0.9341, 0.9335, 0.933, + 0.9324, 0.9319, 0.9313, 0.9308, 0.9302, 0.9296, 0.9291, 0.9285, 0.9279, 0.9274, + 0.9268, 0.9262, 0.9256, 0.925, 0.9245, 0.9239, 0.9233, 0.9227, 0.9221, 0.9215, + 0.9209, 0.9203, 0.9197, 0.9191, 0.9185, 0.9179, 0.9173, 0.9167, 0.9161, 0.9154, + 0.9148, 0.9142, 0.9136, 0.913, 0.9123, 0.9117, 0.9111, 0.9104, 0.9098, 0.9092, + 0.9085, 0.9079, 0.9072, 0.9066, 0.9059, 0.9053, 0.9046, 0.904, 0.9033, 0.9027, + 0.902, 0.9013, 0.9007, 0.9, 0.8993, 0.8987, 0.898, 0.8973, 0.8966, 0.896, + 0.8953, 0.8946, 0.8939, 0.8932, 0.8925, 0.8918, 0.8911, 0.8904, 0.8897, 0.889, + 0.8883, 0.8876, 0.8869, 0.8862, 0.8855, 0.8848, 0.8841, 0.8834, 0.8826, 0.8819, + 0.8812, 0.8805, 0.8797, 0.879, 0.8783, 0.8775, 0.8768, 0.8761, 0.8753, 0.8746, + 0.8738, 0.8731, 0.8723, 0.8716, 0.8708, 0.8701, 0.8693, 0.8686, 0.8678, 0.867, + 0.8663, 0.8655, 0.8647, 0.864, 0.8632, 0.8624, 0.8616, 0.8609, 0.8601, 0.8593, + 0.8585, 0.8577, 0.8569, 0.8561, 0.8554, 0.8546, 0.8538, 0.853, 0.8522, 0.8514, + 0.8505, 0.8497, 0.8489, 0.8481, 0.8473, 0.8465, 0.8457, 0.8449, 0.844, 0.8432, + 0.8424, 0.8416, 0.8407, 0.8399, 0.8391, 0.8382, 0.8374, 0.8365, 0.8357, 0.8349, + 0.834, 0.8332, 0.8323, 0.8315, 0.8306, 0.8298, 0.8289, 0.828, 0.8272, 0.8263, + 0.8255, 0.8246, 0.8237, 0.8228, 0.822, 0.8211, 0.8202, 0.8193, 0.8185, 0.8176, + 0.8167, 0.8158, 0.8149, 0.814, 0.8131, 0.8123, 0.8114, 0.8105, 0.8096, 0.8087, + 0.8078, 0.8068, 0.8059, 0.805, 0.8041, 0.8032, 0.8023, 0.8014, 0.8005, 0.7995, + 0.7986, 0.7977, 0.7968, 0.7958, 0.7949, 0.794, 0.793, 0.7921, 0.7912, 0.7902, + 0.7893, 0.7883, 0.7874, 0.7865, 0.7855, 0.7846, 0.7836, 0.7827, 0.7817, 0.7807, + 0.7798, 0.7788, 0.7779, 0.7769, 0.7759, 0.775, 0.774, 0.773, 0.772, 0.7711, + 0.7701, 0.7691, 0.7681, 0.7671, 0.7662, 0.7652, 0.7642, 0.7632, 0.7622, 0.7612, + 0.7602, 0.7592, 0.7582, 0.7572, 0.7562, 0.7552, 0.7542, 0.7532, 0.7522, 0.7512, + 0.7502, 0.7491, 0.7481, 0.7471, 0.7461, 0.7451, 0.744, 0.743, 0.742, 0.741, + 0.7399, 0.7389, 0.7379, 0.7368, 0.7358, 0.7347, 0.7337, 0.7327, 0.7316, 0.7306, + 0.7295, 0.7285, 0.7274, 0.7264, 0.7253, 0.7242, 0.7232, 0.7221, 0.7211, 0.72, + 0.7189, 0.7179, 0.7168, 0.7157, 0.7147, 0.7136, 0.7125, 0.7114, 0.7104, 0.7093, + 0.7082, 0.7071, 0.706, 0.7049, 0.7038, 0.7028, 0.7017, 0.7006, 0.6995, 0.6984, + 0.6973, 0.6962, 0.6951, 0.694, 0.6929, 0.6918, 0.6907, 0.6895, 0.6884, 0.6873, + 0.6862, 0.6851, 0.684, 0.6828, 0.6817, 0.6806, 0.6795, 0.6784, 0.6772, 0.6761, + 0.675, 0.6738, 0.6727, 0.6716, 0.6704, 0.6693, 0.6681, 0.667, 0.6659, 0.6647, + 0.6636, 0.6624, 0.6613, 0.6601, 0.659, 0.6578, 0.6567, 0.6555, 0.6543, 0.6532, + 0.652, 0.6508, 0.6497, 0.6485, 0.6473, 0.6462, 0.645, 0.6438, 0.6427, 0.6415, + 0.6403, 0.6391, 0.6379, 0.6368, 0.6356, 0.6344, 0.6332, 0.632, 0.6308, 0.6296, + 0.6284, 0.6273, 0.6261, 0.6249, 0.6237, 0.6225, 0.6213, 0.6201, 0.6189, 0.6176, + 0.6164, 0.6152, 0.614, 0.6128, 0.6116, 0.6104, 0.6092, 0.6079, 0.6067, 0.6055, + 0.6043, 0.6031, 0.6018, 0.6006, 0.5994, 0.5982, 0.5969, 0.5957, 0.5945, 0.5932, + 0.592, 0.5908, 0.5895, 0.5883, 0.587, 0.5858, 0.5846, 0.5833, 0.5821, 0.5808, + 0.5796, 0.5783, 0.5771, 0.5758, 0.5746, 0.5733, 0.572, 0.5708, 0.5695, 0.5683, + 0.567, 0.5657, 0.5645, 0.5632, 0.5619, 0.5607, 0.5594, 0.5581, 0.5568, 0.5556, + 0.5543, 0.553, 0.5517, 0.5505, 0.5492, 0.5479, 0.5466, 0.5453, 0.544, 0.5428, + 0.5415, 0.5402, 0.5389, 0.5376, 0.5363, 0.535, 0.5337, 0.5324, 0.5311, 0.5298, + 0.5285, 0.5272, 0.5259, 0.5246, 0.5233, 0.522, 0.5207, 0.5194, 0.518, 0.5167, + 0.5154, 0.5141, 0.5128, 0.5115, 0.5102, 0.5088, 0.5075, 0.5062, 0.5049, 0.5035, + 0.5022, 0.5009, 0.4996, 0.4982, 0.4969, 0.4956, 0.4942, 0.4929, 0.4916, 0.4902, + 0.4889, 0.4876, 0.4862, 0.4849, 0.4835, 0.4822, 0.4808, 0.4795, 0.4781, 0.4768, + 0.4755, 0.4741, 0.4727, 0.4714, 0.47, 0.4687, 0.4673, 0.466, 0.4646, 0.4633, + 0.4619, 0.4605, 0.4592, 0.4578, 0.4564, 0.4551, 0.4537, 0.4523, 0.451, 0.4496, + 0.4482, 0.4469, 0.4455, 0.4441, 0.4427, 0.4414, 0.44, 0.4386, 0.4372, 0.4359, + 0.4345, 0.4331, 0.4317, 0.4303, 0.4289, 0.4276, 0.4262, 0.4248, 0.4234, 0.422, + 0.4206, 0.4192, 0.4178, 0.4164, 0.415, 0.4136, 0.4122, 0.4108, 0.4094, 0.408, + 0.4066, 0.4052, 0.4038, 0.4024, 0.401, 0.3996, 0.3982, 0.3968, 0.3954, 0.394, + 0.3926, 0.3912, 0.3898, 0.3883, 0.3869, 0.3855, 0.3841, 0.3827, 0.3813, 0.3798, + 0.3784, 0.377, 0.3756, 0.3742, 0.3727, 0.3713, 0.3699, 0.3685, 0.367, 0.3656, + 0.3642, 0.3628, 0.3613, 0.3599, 0.3585, 0.357, 0.3556, 0.3542, 0.3527, 0.3513, + 0.3499, 0.3484, 0.347, 0.3455, 0.3441, 0.3427, 0.3412, 0.3398, 0.3383, 0.3369, + 0.3354, 0.334, 0.3326, 0.3311, 0.3297, 0.3282, 0.3268, 0.3253, 0.3239, 0.3224, + 0.321, 0.3195, 0.318, 0.3166, 0.3151, 0.3137, 0.3122, 0.3108, 0.3093, 0.3078, + 0.3064, 0.3049, 0.3035, 0.302, 0.3005, 0.2991, 0.2976, 0.2962, 0.2947, 0.2932, + 0.2918, 0.2903, 0.2888, 0.2873, 0.2859, 0.2844, 0.2829, 0.2815, 0.28, 0.2785, + 0.277, 0.2756, 0.2741, 0.2726, 0.2711, 0.2697, 0.2682, 0.2667, 0.2652, 0.2638, + 0.2623, 0.2608, 0.2593, 0.2578, 0.2563, 0.2549, 0.2534, 0.2519, 0.2504, 0.2489, + 0.2474, 0.246, 0.2445, 0.243, 0.2415, 0.24, 0.2385, 0.237, 0.2355, 0.234, + 0.2326, 0.2311, 0.2296, 0.2281, 0.2266, 0.2251, 0.2236, 0.2221, 0.2206, 0.2191, + 0.2176, 0.2161, 0.2146, 0.2131, 0.2116, 0.2101, 0.2086, 0.2071, 0.2056, 0.2041, + 0.2026, 0.2011, 0.1996, 0.1981, 0.1966, 0.1951, 0.1936, 0.1921, 0.1906, 0.1891, + 0.1876, 0.1861, 0.1845, 0.183, 0.1815, 0.18, 0.1785, 0.177, 0.1755, 0.174, + 0.1725, 0.171, 0.1695, 0.1679, 0.1664, 0.1649, 0.1634, 0.1619, 0.1604, 0.1589, + 0.1573, 0.1558, 0.1543, 0.1528, 0.1513, 0.1498, 0.1482, 0.1467, 0.1452, 0.1437, + 0.1422, 0.1407, 0.1391, 0.1376, 0.1361, 0.1346, 0.1331, 0.1315, 0.13, 0.1285, + 0.127, 0.1255, 0.1239, 0.1224, 0.1209, 0.1194, 0.1178, 0.1163, 0.1148, 0.1133, + 0.1117, 0.1102, 0.1087, 0.1072, 0.1056, 0.1041, 0.1026, 0.1011, 0.09954, 0.09802, + 0.09649, 0.09496, 0.09344, 0.09191, 0.09038, 0.08885, 0.08733, 0.0858, 0.08427, 0.08274, + 0.08121, 0.07968, 0.07815, 0.07662, 0.07509, 0.07356, 0.07203, 0.0705, 0.06897, 0.06744, + 0.06591, 0.06438, 0.06285, 0.06132, 0.05979, 0.05826, 0.05673, 0.0552, 0.05366, 0.05213, + 0.0506, 0.04907, 0.04754, 0.046, 0.04447, 0.04294, 0.04141, 0.03987, 0.03834, 0.03681, + 0.03527, 0.03374, 0.03221, 0.03067, 0.02914, 0.02761, 0.02607, 0.02454, 0.02301, 0.02147, + 0.01994, 0.01841, 0.01687, 0.01534, 0.01381, 0.01227, 0.01074, 0.009204, 0.00767, 0.006136, + 0.004602, 0.003068, 0.001534, 6.123e-17, -0.001534, -0.003068, -0.004602, -0.006136, -0.00767, -0.009204, + -0.01074, -0.01227, -0.01381, -0.01534, -0.01687, -0.01841, -0.01994, -0.02147, -0.02301, -0.02454, + -0.02607, -0.02761, -0.02914, -0.03067, -0.03221, -0.03374, -0.03527, -0.03681, -0.03834, -0.03987, + -0.04141, -0.04294, -0.04447, -0.046, -0.04754, -0.04907, -0.0506, -0.05213, -0.05366, -0.0552, + -0.05673, -0.05826, -0.05979, -0.06132, -0.06285, -0.06438, -0.06591, -0.06744, -0.06897, -0.0705, + -0.07203, -0.07356, -0.07509, -0.07662, -0.07815, -0.07968, -0.08121, -0.08274, -0.08427, -0.0858, + -0.08733, -0.08885, -0.09038, -0.09191, -0.09344, -0.09496, -0.09649, -0.09802, -0.09954, -0.1011, + -0.1026, -0.1041, -0.1056, -0.1072, -0.1087, -0.1102, -0.1117, -0.1133, -0.1148, -0.1163, + -0.1178, -0.1194, -0.1209, -0.1224, -0.1239, -0.1255, -0.127, -0.1285, -0.13, -0.1315, + -0.1331, -0.1346, -0.1361, -0.1376, -0.1391, -0.1407, -0.1422, -0.1437, -0.1452, -0.1467, + -0.1482, -0.1498, -0.1513, -0.1528, -0.1543, -0.1558, -0.1573, -0.1589, -0.1604, -0.1619, + -0.1634, -0.1649, -0.1664, -0.1679, -0.1695, -0.171, -0.1725, -0.174, -0.1755, -0.177, + -0.1785, -0.18, -0.1815, -0.183, -0.1845, -0.1861, -0.1876, -0.1891, -0.1906, -0.1921, + -0.1936, -0.1951, -0.1966, -0.1981, -0.1996, -0.2011, -0.2026, -0.2041, -0.2056, -0.2071, + -0.2086, -0.2101, -0.2116, -0.2131, -0.2146, -0.2161, -0.2176, -0.2191, -0.2206, -0.2221, + -0.2236, -0.2251, -0.2266, -0.2281, -0.2296, -0.2311, -0.2326, -0.234, -0.2355, -0.237, + -0.2385, -0.24, -0.2415, -0.243, -0.2445, -0.246, -0.2474, -0.2489, -0.2504, -0.2519, + -0.2534, -0.2549, -0.2563, -0.2578, -0.2593, -0.2608, -0.2623, -0.2638, -0.2652, -0.2667, + -0.2682, -0.2697, -0.2711, -0.2726, -0.2741, -0.2756, -0.277, -0.2785, -0.28, -0.2815, + -0.2829, -0.2844, -0.2859, -0.2873, -0.2888, -0.2903, -0.2918, -0.2932, -0.2947, -0.2962, + -0.2976, -0.2991, -0.3005, -0.302, -0.3035, -0.3049, -0.3064, -0.3078, -0.3093, -0.3108, + -0.3122, -0.3137, -0.3151, -0.3166, -0.318, -0.3195, -0.321, -0.3224, -0.3239, -0.3253, + -0.3268, -0.3282, -0.3297, -0.3311, -0.3326, -0.334, -0.3354, -0.3369, -0.3383, -0.3398, + -0.3412, -0.3427, -0.3441, -0.3455, -0.347, -0.3484, -0.3499, -0.3513, -0.3527, -0.3542, + -0.3556, -0.357, -0.3585, -0.3599, -0.3613, -0.3628, -0.3642, -0.3656, -0.367, -0.3685, + -0.3699, -0.3713, -0.3727, -0.3742, -0.3756, -0.377, -0.3784, -0.3798, -0.3813, -0.3827, + -0.3841, -0.3855, -0.3869, -0.3883, -0.3898, -0.3912, -0.3926, -0.394, -0.3954, -0.3968, + -0.3982, -0.3996, -0.401, -0.4024, -0.4038, -0.4052, -0.4066, -0.408, -0.4094, -0.4108, + -0.4122, -0.4136, -0.415, -0.4164, -0.4178, -0.4192, -0.4206, -0.422, -0.4234, -0.4248, + -0.4262, -0.4276, -0.4289, -0.4303, -0.4317, -0.4331, -0.4345, -0.4359, -0.4372, -0.4386, + -0.44, -0.4414, -0.4427, -0.4441, -0.4455, -0.4469, -0.4482, -0.4496, -0.451, -0.4523, + -0.4537, -0.4551, -0.4564, -0.4578, -0.4592, -0.4605, -0.4619, -0.4633, -0.4646, -0.466, + -0.4673, -0.4687, -0.47, -0.4714, -0.4727, -0.4741, -0.4755, -0.4768, -0.4781, -0.4795, + -0.4808, -0.4822, -0.4835, -0.4849, -0.4862, -0.4876, -0.4889, -0.4902, -0.4916, -0.4929, + -0.4942, -0.4956, -0.4969, -0.4982, -0.4996, -0.5009, -0.5022, -0.5035, -0.5049, -0.5062, + -0.5075, -0.5088, -0.5102, -0.5115, -0.5128, -0.5141, -0.5154, -0.5167, -0.518, -0.5194, + -0.5207, -0.522, -0.5233, -0.5246, -0.5259, -0.5272, -0.5285, -0.5298, -0.5311, -0.5324, + -0.5337, -0.535, -0.5363, -0.5376, -0.5389, -0.5402, -0.5415, -0.5428, -0.544, -0.5453, + -0.5466, -0.5479, -0.5492, -0.5505, -0.5517, -0.553, -0.5543, -0.5556, -0.5568, -0.5581, + -0.5594, -0.5607, -0.5619, -0.5632, -0.5645, -0.5657, -0.567, -0.5683, -0.5695, -0.5708, + -0.572, -0.5733, -0.5746, -0.5758, -0.5771, -0.5783, -0.5796, -0.5808, -0.5821, -0.5833, + -0.5846, -0.5858, -0.587, -0.5883, -0.5895, -0.5908, -0.592, -0.5932, -0.5945, -0.5957, + -0.5969, -0.5982, -0.5994, -0.6006, -0.6018, -0.6031, -0.6043, -0.6055, -0.6067, -0.6079, + -0.6092, -0.6104, -0.6116, -0.6128, -0.614, -0.6152, -0.6164, -0.6176, -0.6189, -0.6201, + -0.6213, -0.6225, -0.6237, -0.6249, -0.6261, -0.6273, -0.6284, -0.6296, -0.6308, -0.632, + -0.6332, -0.6344, -0.6356, -0.6368, -0.6379, -0.6391, -0.6403, -0.6415, -0.6427, -0.6438, + -0.645, -0.6462, -0.6473, -0.6485, -0.6497, -0.6508, -0.652, -0.6532, -0.6543, -0.6555, + -0.6567, -0.6578, -0.659, -0.6601, -0.6613, -0.6624, -0.6636, -0.6647, -0.6659, -0.667, + -0.6681, -0.6693, -0.6704, -0.6716, -0.6727, -0.6738, -0.675, -0.6761, -0.6772, -0.6784, + -0.6795, -0.6806, -0.6817, -0.6828, -0.684, -0.6851, -0.6862, -0.6873, -0.6884, -0.6895, + -0.6907, -0.6918, -0.6929, -0.694, -0.6951, -0.6962, -0.6973, -0.6984, -0.6995, -0.7006, + -0.7017, -0.7028, -0.7038, -0.7049, -0.706, -0.7071, -0.7082, -0.7093, -0.7104, -0.7114, + -0.7125, -0.7136, -0.7147, -0.7157, -0.7168, -0.7179, -0.7189, -0.72, -0.7211, -0.7221, + -0.7232, -0.7242, -0.7253, -0.7264, -0.7274, -0.7285, -0.7295, -0.7306, -0.7316, -0.7327, + -0.7337, -0.7347, -0.7358, -0.7368, -0.7379, -0.7389, -0.7399, -0.741, -0.742, -0.743, + -0.744, -0.7451, -0.7461, -0.7471, -0.7481, -0.7491, -0.7502, -0.7512, -0.7522, -0.7532, + -0.7542, -0.7552, -0.7562, -0.7572, -0.7582, -0.7592, -0.7602, -0.7612, -0.7622, -0.7632, + -0.7642, -0.7652, -0.7662, -0.7671, -0.7681, -0.7691, -0.7701, -0.7711, -0.772, -0.773, + -0.774, -0.775, -0.7759, -0.7769, -0.7779, -0.7788, -0.7798, -0.7807, -0.7817, -0.7827, + -0.7836, -0.7846, -0.7855, -0.7865, -0.7874, -0.7883, -0.7893, -0.7902, -0.7912, -0.7921, + -0.793, -0.794, -0.7949, -0.7958, -0.7968, -0.7977, -0.7986, -0.7995, -0.8005, -0.8014, + -0.8023, -0.8032, -0.8041, -0.805, -0.8059, -0.8068, -0.8078, -0.8087, -0.8096, -0.8105, + -0.8114, -0.8123, -0.8131, -0.814, -0.8149, -0.8158, -0.8167, -0.8176, -0.8185, -0.8193, + -0.8202, -0.8211, -0.822, -0.8228, -0.8237, -0.8246, -0.8255, -0.8263, -0.8272, -0.828, + -0.8289, -0.8298, -0.8306, -0.8315, -0.8323, -0.8332, -0.834, -0.8349, -0.8357, -0.8365, + -0.8374, -0.8382, -0.8391, -0.8399, -0.8407, -0.8416, -0.8424, -0.8432, -0.844, -0.8449, + -0.8457, -0.8465, -0.8473, -0.8481, -0.8489, -0.8497, -0.8505, -0.8514, -0.8522, -0.853, + -0.8538, -0.8546, -0.8554, -0.8561, -0.8569, -0.8577, -0.8585, -0.8593, -0.8601, -0.8609, + -0.8616, -0.8624, -0.8632, -0.864, -0.8647, -0.8655, -0.8663, -0.867, -0.8678, -0.8686, + -0.8693, -0.8701, -0.8708, -0.8716, -0.8723, -0.8731, -0.8738, -0.8746, -0.8753, -0.8761, + -0.8768, -0.8775, -0.8783, -0.879, -0.8797, -0.8805, -0.8812, -0.8819, -0.8826, -0.8834, + -0.8841, -0.8848, -0.8855, -0.8862, -0.8869, -0.8876, -0.8883, -0.889, -0.8897, -0.8904, + -0.8911, -0.8918, -0.8925, -0.8932, -0.8939, -0.8946, -0.8953, -0.896, -0.8966, -0.8973, + -0.898, -0.8987, -0.8993, -0.9, -0.9007, -0.9013, -0.902, -0.9027, -0.9033, -0.904, + -0.9046, -0.9053, -0.9059, -0.9066, -0.9072, -0.9079, -0.9085, -0.9092, -0.9098, -0.9104, + -0.9111, -0.9117, -0.9123, -0.913, -0.9136, -0.9142, -0.9148, -0.9154, -0.9161, -0.9167, + -0.9173, -0.9179, -0.9185, -0.9191, -0.9197, -0.9203, -0.9209, -0.9215, -0.9221, -0.9227, + -0.9233, -0.9239, -0.9245, -0.925, -0.9256, -0.9262, -0.9268, -0.9274, -0.9279, -0.9285, + -0.9291, -0.9296, -0.9302, -0.9308, -0.9313, -0.9319, -0.9324, -0.933, -0.9335, -0.9341, + -0.9346, -0.9352, -0.9357, -0.9363, -0.9368, -0.9373, -0.9379, -0.9384, -0.9389, -0.9395, + -0.94, -0.9405, -0.941, -0.9415, -0.9421, -0.9426, -0.9431, -0.9436, -0.9441, -0.9446, + -0.9451, -0.9456, -0.9461, -0.9466, -0.9471, -0.9476, -0.9481, -0.9486, -0.949, -0.9495, + -0.95, -0.9505, -0.951, -0.9514, -0.9519, -0.9524, -0.9528, -0.9533, -0.9538, -0.9542, + -0.9547, -0.9551, -0.9556, -0.956, -0.9565, -0.9569, -0.9574, -0.9578, -0.9583, -0.9587, + -0.9591, -0.9596, -0.96, -0.9604, -0.9609, -0.9613, -0.9617, -0.9621, -0.9625, -0.963, + -0.9634, -0.9638, -0.9642, -0.9646, -0.965, -0.9654, -0.9658, -0.9662, -0.9666, -0.967, + -0.9674, -0.9678, -0.9681, -0.9685, -0.9689, -0.9693, -0.9697, -0.97, -0.9704, -0.9708, + -0.9711, -0.9715, -0.9719, -0.9722, -0.9726, -0.9729, -0.9733, -0.9736, -0.974, -0.9743, + -0.9747, -0.975, -0.9754, -0.9757, -0.976, -0.9764, -0.9767, -0.977, -0.9774, -0.9777, + -0.978, -0.9783, -0.9786, -0.9789, -0.9793, -0.9796, -0.9799, -0.9802, -0.9805, -0.9808, + -0.9811, -0.9814, -0.9817, -0.982, -0.9823, -0.9825, -0.9828, -0.9831, -0.9834, -0.9837, + -0.9839, -0.9842, -0.9845, -0.9847, -0.985, -0.9853, -0.9855, -0.9858, -0.9861, -0.9863, + -0.9866, -0.9868, -0.9871, -0.9873, -0.9875, -0.9878, -0.988, -0.9883, -0.9885, -0.9887, + -0.989, -0.9892, -0.9894, -0.9896, -0.9898, -0.9901, -0.9903, -0.9905, -0.9907, -0.9909, + -0.9911, -0.9913, -0.9915, -0.9917, -0.9919, -0.9921, -0.9923, -0.9925, -0.9927, -0.9929, + -0.993, -0.9932, -0.9934, -0.9936, -0.9937, -0.9939, -0.9941, -0.9942, -0.9944, -0.9946, + -0.9947, -0.9949, -0.995, -0.9952, -0.9953, -0.9955, -0.9956, -0.9958, -0.9959, -0.996, + -0.9962, -0.9963, -0.9964, -0.9966, -0.9967, -0.9968, -0.9969, -0.9971, -0.9972, -0.9973, + -0.9974, -0.9975, -0.9976, -0.9977, -0.9978, -0.9979, -0.998, -0.9981, -0.9982, -0.9983, + -0.9984, -0.9985, -0.9986, -0.9986, -0.9987, -0.9988, -0.9989, -0.9989, -0.999, -0.9991, + -0.9991, -0.9992, -0.9993, -0.9993, -0.9994, -0.9994, -0.9995, -0.9995, -0.9996, -0.9996, + -0.9997, -0.9997, -0.9997, -0.9998, -0.9998, -0.9998, -0.9999, -0.9999, -0.9999, -0.9999, + -0.9999, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -0.9999, -0.9999, -0.9999, -0.9999, -0.9999, -0.9998, + -0.9998, -0.9998, -0.9997, -0.9997, -0.9997, -0.9996, -0.9996, -0.9995, -0.9995, -0.9994, + -0.9994, -0.9993, -0.9993, -0.9992, -0.9991, -0.9991, -0.999, -0.9989, -0.9989, -0.9988, + -0.9987, -0.9986, -0.9986, -0.9985, -0.9984, -0.9983, -0.9982, -0.9981, -0.998, -0.9979, + -0.9978, -0.9977, -0.9976, -0.9975, -0.9974, -0.9973, -0.9972, -0.9971, -0.9969, -0.9968, + -0.9967, -0.9966, -0.9964, -0.9963, -0.9962, -0.996, -0.9959, -0.9958, -0.9956, -0.9955, + -0.9953, -0.9952, -0.995, -0.9949, -0.9947, -0.9946, -0.9944, -0.9942, -0.9941, -0.9939, + -0.9937, -0.9936, -0.9934, -0.9932, -0.993, -0.9929, -0.9927, -0.9925, -0.9923, -0.9921, + -0.9919, -0.9917, -0.9915, -0.9913, -0.9911, -0.9909, -0.9907, -0.9905, -0.9903, -0.9901, + -0.9898, -0.9896, -0.9894, -0.9892, -0.989, -0.9887, -0.9885, -0.9883, -0.988, -0.9878, + -0.9875, -0.9873, -0.9871, -0.9868, -0.9866, -0.9863, -0.9861, -0.9858, -0.9855, -0.9853, + -0.985, -0.9847, -0.9845, -0.9842, -0.9839, -0.9837, -0.9834, -0.9831, -0.9828, -0.9825, + -0.9823, -0.982, -0.9817, -0.9814, -0.9811, -0.9808, -0.9805, -0.9802, -0.9799, -0.9796, + -0.9793, -0.9789, -0.9786, -0.9783, -0.978, -0.9777, -0.9774, -0.977, -0.9767, -0.9764, + -0.976, -0.9757, -0.9754, -0.975, -0.9747, -0.9743, -0.974, -0.9736, -0.9733, -0.9729, + -0.9726, -0.9722, -0.9719, -0.9715, -0.9711, -0.9708, -0.9704, -0.97, -0.9697, -0.9693, + -0.9689, -0.9685, -0.9681, -0.9678, -0.9674, -0.967, -0.9666, -0.9662, -0.9658, -0.9654, + -0.965, -0.9646, -0.9642, -0.9638, -0.9634, -0.963, -0.9625, -0.9621, -0.9617, -0.9613, + -0.9609, -0.9604, -0.96, -0.9596, -0.9591, -0.9587, -0.9583, -0.9578, -0.9574, -0.9569, + -0.9565, -0.956, -0.9556, -0.9551, -0.9547, -0.9542, -0.9538, -0.9533, -0.9528, -0.9524, + -0.9519, -0.9514, -0.951, -0.9505, -0.95, -0.9495, -0.949, -0.9486, -0.9481, -0.9476, + -0.9471, -0.9466, -0.9461, -0.9456, -0.9451, -0.9446, -0.9441, -0.9436, -0.9431, -0.9426, + -0.9421, -0.9415, -0.941, -0.9405, -0.94, -0.9395, -0.9389, -0.9384, -0.9379, -0.9373, + -0.9368, -0.9363, -0.9357, -0.9352, -0.9346, -0.9341, -0.9335, -0.933, -0.9324, -0.9319, + -0.9313, -0.9308, -0.9302, -0.9296, -0.9291, -0.9285, -0.9279, -0.9274, -0.9268, -0.9262, + -0.9256, -0.925, -0.9245, -0.9239, -0.9233, -0.9227, -0.9221, -0.9215, -0.9209, -0.9203, + -0.9197, -0.9191, -0.9185, -0.9179, -0.9173, -0.9167, -0.9161, -0.9154, -0.9148, -0.9142, + -0.9136, -0.913, -0.9123, -0.9117, -0.9111, -0.9104, -0.9098, -0.9092, -0.9085, -0.9079, + -0.9072, -0.9066, -0.9059, -0.9053, -0.9046, -0.904, -0.9033, -0.9027, -0.902, -0.9013, + -0.9007, -0.9, -0.8993, -0.8987, -0.898, -0.8973, -0.8966, -0.896, -0.8953, -0.8946, + -0.8939, -0.8932, -0.8925, -0.8918, -0.8911, -0.8904, -0.8897, -0.889, -0.8883, -0.8876, + -0.8869, -0.8862, -0.8855, -0.8848, -0.8841, -0.8834, -0.8826, -0.8819, -0.8812, -0.8805, + -0.8797, -0.879, -0.8783, -0.8775, -0.8768, -0.8761, -0.8753, -0.8746, -0.8738, -0.8731, + -0.8723, -0.8716, -0.8708, -0.8701, -0.8693, -0.8686, -0.8678, -0.867, -0.8663, -0.8655, + -0.8647, -0.864, -0.8632, -0.8624, -0.8616, -0.8609, -0.8601, -0.8593, -0.8585, -0.8577, + -0.8569, -0.8561, -0.8554, -0.8546, -0.8538, -0.853, -0.8522, -0.8514, -0.8505, -0.8497, + -0.8489, -0.8481, -0.8473, -0.8465, -0.8457, -0.8449, -0.844, -0.8432, -0.8424, -0.8416, + -0.8407, -0.8399, -0.8391, -0.8382, -0.8374, -0.8365, -0.8357, -0.8349, -0.834, -0.8332, + -0.8323, -0.8315, -0.8306, -0.8298, -0.8289, -0.828, -0.8272, -0.8263, -0.8255, -0.8246, + -0.8237, -0.8228, -0.822, -0.8211, -0.8202, -0.8193, -0.8185, -0.8176, -0.8167, -0.8158, + -0.8149, -0.814, -0.8131, -0.8123, -0.8114, -0.8105, -0.8096, -0.8087, -0.8078, -0.8068, + -0.8059, -0.805, -0.8041, -0.8032, -0.8023, -0.8014, -0.8005, -0.7995, -0.7986, -0.7977, + -0.7968, -0.7958, -0.7949, -0.794, -0.793, -0.7921, -0.7912, -0.7902, -0.7893, -0.7883, + -0.7874, -0.7865, -0.7855, -0.7846, -0.7836, -0.7827, -0.7817, -0.7807, -0.7798, -0.7788, + -0.7779, -0.7769, -0.7759, -0.775, -0.774, -0.773, -0.772, -0.7711, -0.7701, -0.7691, + -0.7681, -0.7671, -0.7662, -0.7652, -0.7642, -0.7632, -0.7622, -0.7612, -0.7602, -0.7592, + -0.7582, -0.7572, -0.7562, -0.7552, -0.7542, -0.7532, -0.7522, -0.7512, -0.7502, -0.7491, + -0.7481, -0.7471, -0.7461, -0.7451, -0.744, -0.743, -0.742, -0.741, -0.7399, -0.7389, + -0.7379, -0.7368, -0.7358, -0.7347, -0.7337, -0.7327, -0.7316, -0.7306, -0.7295, -0.7285, + -0.7274, -0.7264, -0.7253, -0.7242, -0.7232, -0.7221, -0.7211, -0.72, -0.7189, -0.7179, + -0.7168, -0.7157, -0.7147, -0.7136, -0.7125, -0.7114, -0.7104, -0.7093, -0.7082, -0.7071, + -0.706, -0.7049, -0.7038, -0.7028, -0.7017, -0.7006, -0.6995, -0.6984, -0.6973, -0.6962, + -0.6951, -0.694, -0.6929, -0.6918, -0.6907, -0.6895, -0.6884, -0.6873, -0.6862, -0.6851, + -0.684, -0.6828, -0.6817, -0.6806, -0.6795, -0.6784, -0.6772, -0.6761, -0.675, -0.6738, + -0.6727, -0.6716, -0.6704, -0.6693, -0.6681, -0.667, -0.6659, -0.6647, -0.6636, -0.6624, + -0.6613, -0.6601, -0.659, -0.6578, -0.6567, -0.6555, -0.6543, -0.6532, -0.652, -0.6508, + -0.6497, -0.6485, -0.6473, -0.6462, -0.645, -0.6438, -0.6427, -0.6415, -0.6403, -0.6391, + -0.6379, -0.6368, -0.6356, -0.6344, -0.6332, -0.632, -0.6308, -0.6296, -0.6284, -0.6273, + -0.6261, -0.6249, -0.6237, -0.6225, -0.6213, -0.6201, -0.6189, -0.6176, -0.6164, -0.6152, + -0.614, -0.6128, -0.6116, -0.6104, -0.6092, -0.6079, -0.6067, -0.6055, -0.6043, -0.6031, + -0.6018, -0.6006, -0.5994, -0.5982, -0.5969, -0.5957, -0.5945, -0.5932, -0.592, -0.5908, + -0.5895, -0.5883, -0.587, -0.5858, -0.5846, -0.5833, -0.5821, -0.5808, -0.5796, -0.5783, + -0.5771, -0.5758, -0.5746, -0.5733, -0.572, -0.5708, -0.5695, -0.5683, -0.567, -0.5657, + -0.5645, -0.5632, -0.5619, -0.5607, -0.5594, -0.5581, -0.5568, -0.5556, -0.5543, -0.553, + -0.5517, -0.5505, -0.5492, -0.5479, -0.5466, -0.5453, -0.544, -0.5428, -0.5415, -0.5402, + -0.5389, -0.5376, -0.5363, -0.535, -0.5337, -0.5324, -0.5311, -0.5298, -0.5285, -0.5272, + -0.5259, -0.5246, -0.5233, -0.522, -0.5207, -0.5194, -0.518, -0.5167, -0.5154, -0.5141, + -0.5128, -0.5115, -0.5102, -0.5088, -0.5075, -0.5062, -0.5049, -0.5035, -0.5022, -0.5009, + -0.4996, -0.4982, -0.4969, -0.4956, -0.4942, -0.4929, -0.4916, -0.4902, -0.4889, -0.4876, + -0.4862, -0.4849, -0.4835, -0.4822, -0.4808, -0.4795, -0.4781, -0.4768, -0.4755, -0.4741, + -0.4727, -0.4714, -0.47, -0.4687, -0.4673, -0.466, -0.4646, -0.4633, -0.4619, -0.4605, + -0.4592, -0.4578, -0.4564, -0.4551, -0.4537, -0.4523, -0.451, -0.4496, -0.4482, -0.4469, + -0.4455, -0.4441, -0.4427, -0.4414, -0.44, -0.4386, -0.4372, -0.4359, -0.4345, -0.4331, + -0.4317, -0.4303, -0.4289, -0.4276, -0.4262, -0.4248, -0.4234, -0.422, -0.4206, -0.4192, + -0.4178, -0.4164, -0.415, -0.4136, -0.4122, -0.4108, -0.4094, -0.408, -0.4066, -0.4052, + -0.4038, -0.4024, -0.401, -0.3996, -0.3982, -0.3968, -0.3954, -0.394, -0.3926, -0.3912, + -0.3898, -0.3883, -0.3869, -0.3855, -0.3841, -0.3827, -0.3813, -0.3798, -0.3784, -0.377, + -0.3756, -0.3742, -0.3727, -0.3713, -0.3699, -0.3685, -0.367, -0.3656, -0.3642, -0.3628, + -0.3613, -0.3599, -0.3585, -0.357, -0.3556, -0.3542, -0.3527, -0.3513, -0.3499, -0.3484, + -0.347, -0.3455, -0.3441, -0.3427, -0.3412, -0.3398, -0.3383, -0.3369, -0.3354, -0.334, + -0.3326, -0.3311, -0.3297, -0.3282, -0.3268, -0.3253, -0.3239, -0.3224, -0.321, -0.3195, + -0.318, -0.3166, -0.3151, -0.3137, -0.3122, -0.3108, -0.3093, -0.3078, -0.3064, -0.3049, + -0.3035, -0.302, -0.3005, -0.2991, -0.2976, -0.2962, -0.2947, -0.2932, -0.2918, -0.2903, + -0.2888, -0.2873, -0.2859, -0.2844, -0.2829, -0.2815, -0.28, -0.2785, -0.277, -0.2756, + -0.2741, -0.2726, -0.2711, -0.2697, -0.2682, -0.2667, -0.2652, -0.2638, -0.2623, -0.2608, + -0.2593, -0.2578, -0.2563, -0.2549, -0.2534, -0.2519, -0.2504, -0.2489, -0.2474, -0.246, + -0.2445, -0.243, -0.2415, -0.24, -0.2385, -0.237, -0.2355, -0.234, -0.2326, -0.2311, + -0.2296, -0.2281, -0.2266, -0.2251, -0.2236, -0.2221, -0.2206, -0.2191, -0.2176, -0.2161, + -0.2146, -0.2131, -0.2116, -0.2101, -0.2086, -0.2071, -0.2056, -0.2041, -0.2026, -0.2011, + -0.1996, -0.1981, -0.1966, -0.1951, -0.1936, -0.1921, -0.1906, -0.1891, -0.1876, -0.1861, + -0.1845, -0.183, -0.1815, -0.18, -0.1785, -0.177, -0.1755, -0.174, -0.1725, -0.171, + -0.1695, -0.1679, -0.1664, -0.1649, -0.1634, -0.1619, -0.1604, -0.1589, -0.1573, -0.1558, + -0.1543, -0.1528, -0.1513, -0.1498, -0.1482, -0.1467, -0.1452, -0.1437, -0.1422, -0.1407, + -0.1391, -0.1376, -0.1361, -0.1346, -0.1331, -0.1315, -0.13, -0.1285, -0.127, -0.1255, + -0.1239, -0.1224, -0.1209, -0.1194, -0.1178, -0.1163, -0.1148, -0.1133, -0.1117, -0.1102, + -0.1087, -0.1072, -0.1056, -0.1041, -0.1026, -0.1011, -0.09954, -0.09802, -0.09649, -0.09496, + -0.09344, -0.09191, -0.09038, -0.08885, -0.08733, -0.0858, -0.08427, -0.08274, -0.08121, -0.07968, + -0.07815, -0.07662, -0.07509, -0.07356, -0.07203, -0.0705, -0.06897, -0.06744, -0.06591, -0.06438, + -0.06285, -0.06132, -0.05979, -0.05826, -0.05673, -0.0552, -0.05366, -0.05213, -0.0506, -0.04907, + -0.04754, -0.046, -0.04447, -0.04294, -0.04141, -0.03987, -0.03834, -0.03681, -0.03527, -0.03374, + -0.03221, -0.03067, -0.02914, -0.02761, -0.02607, -0.02454, -0.02301, -0.02147, -0.01994, -0.01841, + -0.01687, -0.01534, -0.01381, -0.01227, -0.01074, -0.009204, -0.00767, -0.006136, -0.004602, -0.003068, + -0.001534, -1.837e-16, 0.001534, 0.003068, 0.004602, 0.006136, 0.00767, 0.009204, 0.01074, 0.01227, + 0.01381, 0.01534, 0.01687, 0.01841, 0.01994, 0.02147, 0.02301, 0.02454, 0.02607, 0.02761, + 0.02914, 0.03067, 0.03221, 0.03374, 0.03527, 0.03681, 0.03834, 0.03987, 0.04141, 0.04294, + 0.04447, 0.046, 0.04754, 0.04907, 0.0506, 0.05213, 0.05366, 0.0552, 0.05673, 0.05826, + 0.05979, 0.06132, 0.06285, 0.06438, 0.06591, 0.06744, 0.06897, 0.0705, 0.07203, 0.07356, + 0.07509, 0.07662, 0.07815, 0.07968, 0.08121, 0.08274, 0.08427, 0.0858, 0.08733, 0.08885, + 0.09038, 0.09191, 0.09344, 0.09496, 0.09649, 0.09802, 0.09954, 0.1011, 0.1026, 0.1041, + 0.1056, 0.1072, 0.1087, 0.1102, 0.1117, 0.1133, 0.1148, 0.1163, 0.1178, 0.1194, + 0.1209, 0.1224, 0.1239, 0.1255, 0.127, 0.1285, 0.13, 0.1315, 0.1331, 0.1346, + 0.1361, 0.1376, 0.1391, 0.1407, 0.1422, 0.1437, 0.1452, 0.1467, 0.1482, 0.1498, + 0.1513, 0.1528, 0.1543, 0.1558, 0.1573, 0.1589, 0.1604, 0.1619, 0.1634, 0.1649, + 0.1664, 0.1679, 0.1695, 0.171, 0.1725, 0.174, 0.1755, 0.177, 0.1785, 0.18, + 0.1815, 0.183, 0.1845, 0.1861, 0.1876, 0.1891, 0.1906, 0.1921, 0.1936, 0.1951, + 0.1966, 0.1981, 0.1996, 0.2011, 0.2026, 0.2041, 0.2056, 0.2071, 0.2086, 0.2101, + 0.2116, 0.2131, 0.2146, 0.2161, 0.2176, 0.2191, 0.2206, 0.2221, 0.2236, 0.2251, + 0.2266, 0.2281, 0.2296, 0.2311, 0.2326, 0.234, 0.2355, 0.237, 0.2385, 0.24, + 0.2415, 0.243, 0.2445, 0.246, 0.2474, 0.2489, 0.2504, 0.2519, 0.2534, 0.2549, + 0.2563, 0.2578, 0.2593, 0.2608, 0.2623, 0.2638, 0.2652, 0.2667, 0.2682, 0.2697, + 0.2711, 0.2726, 0.2741, 0.2756, 0.277, 0.2785, 0.28, 0.2815, 0.2829, 0.2844, + 0.2859, 0.2873, 0.2888, 0.2903, 0.2918, 0.2932, 0.2947, 0.2962, 0.2976, 0.2991, + 0.3005, 0.302, 0.3035, 0.3049, 0.3064, 0.3078, 0.3093, 0.3108, 0.3122, 0.3137, + 0.3151, 0.3166, 0.318, 0.3195, 0.321, 0.3224, 0.3239, 0.3253, 0.3268, 0.3282, + 0.3297, 0.3311, 0.3326, 0.334, 0.3354, 0.3369, 0.3383, 0.3398, 0.3412, 0.3427, + 0.3441, 0.3455, 0.347, 0.3484, 0.3499, 0.3513, 0.3527, 0.3542, 0.3556, 0.357, + 0.3585, 0.3599, 0.3613, 0.3628, 0.3642, 0.3656, 0.367, 0.3685, 0.3699, 0.3713, + 0.3727, 0.3742, 0.3756, 0.377, 0.3784, 0.3798, 0.3813, 0.3827, 0.3841, 0.3855, + 0.3869, 0.3883, 0.3898, 0.3912, 0.3926, 0.394, 0.3954, 0.3968, 0.3982, 0.3996, + 0.401, 0.4024, 0.4038, 0.4052, 0.4066, 0.408, 0.4094, 0.4108, 0.4122, 0.4136, + 0.415, 0.4164, 0.4178, 0.4192, 0.4206, 0.422, 0.4234, 0.4248, 0.4262, 0.4276, + 0.4289, 0.4303, 0.4317, 0.4331, 0.4345, 0.4359, 0.4372, 0.4386, 0.44, 0.4414, + 0.4427, 0.4441, 0.4455, 0.4469, 0.4482, 0.4496, 0.451, 0.4523, 0.4537, 0.4551, + 0.4564, 0.4578, 0.4592, 0.4605, 0.4619, 0.4633, 0.4646, 0.466, 0.4673, 0.4687, + 0.47, 0.4714, 0.4727, 0.4741, 0.4755, 0.4768, 0.4781, 0.4795, 0.4808, 0.4822, + 0.4835, 0.4849, 0.4862, 0.4876, 0.4889, 0.4902, 0.4916, 0.4929, 0.4942, 0.4956, + 0.4969, 0.4982, 0.4996, 0.5009, 0.5022, 0.5035, 0.5049, 0.5062, 0.5075, 0.5088, + 0.5102, 0.5115, 0.5128, 0.5141, 0.5154, 0.5167, 0.518, 0.5194, 0.5207, 0.522, + 0.5233, 0.5246, 0.5259, 0.5272, 0.5285, 0.5298, 0.5311, 0.5324, 0.5337, 0.535, + 0.5363, 0.5376, 0.5389, 0.5402, 0.5415, 0.5428, 0.544, 0.5453, 0.5466, 0.5479, + 0.5492, 0.5505, 0.5517, 0.553, 0.5543, 0.5556, 0.5568, 0.5581, 0.5594, 0.5607, + 0.5619, 0.5632, 0.5645, 0.5657, 0.567, 0.5683, 0.5695, 0.5708, 0.572, 0.5733, + 0.5746, 0.5758, 0.5771, 0.5783, 0.5796, 0.5808, 0.5821, 0.5833, 0.5846, 0.5858, + 0.587, 0.5883, 0.5895, 0.5908, 0.592, 0.5932, 0.5945, 0.5957, 0.5969, 0.5982, + 0.5994, 0.6006, 0.6018, 0.6031, 0.6043, 0.6055, 0.6067, 0.6079, 0.6092, 0.6104, + 0.6116, 0.6128, 0.614, 0.6152, 0.6164, 0.6176, 0.6189, 0.6201, 0.6213, 0.6225, + 0.6237, 0.6249, 0.6261, 0.6273, 0.6284, 0.6296, 0.6308, 0.632, 0.6332, 0.6344, + 0.6356, 0.6368, 0.6379, 0.6391, 0.6403, 0.6415, 0.6427, 0.6438, 0.645, 0.6462, + 0.6473, 0.6485, 0.6497, 0.6508, 0.652, 0.6532, 0.6543, 0.6555, 0.6567, 0.6578, + 0.659, 0.6601, 0.6613, 0.6624, 0.6636, 0.6647, 0.6659, 0.667, 0.6681, 0.6693, + 0.6704, 0.6716, 0.6727, 0.6738, 0.675, 0.6761, 0.6772, 0.6784, 0.6795, 0.6806, + 0.6817, 0.6828, 0.684, 0.6851, 0.6862, 0.6873, 0.6884, 0.6895, 0.6907, 0.6918, + 0.6929, 0.694, 0.6951, 0.6962, 0.6973, 0.6984, 0.6995, 0.7006, 0.7017, 0.7028, + 0.7038, 0.7049, 0.706, 0.7071, 0.7082, 0.7093, 0.7104, 0.7114, 0.7125, 0.7136, + 0.7147, 0.7157, 0.7168, 0.7179, 0.7189, 0.72, 0.7211, 0.7221, 0.7232, 0.7242, + 0.7253, 0.7264, 0.7274, 0.7285, 0.7295, 0.7306, 0.7316, 0.7327, 0.7337, 0.7347, + 0.7358, 0.7368, 0.7379, 0.7389, 0.7399, 0.741, 0.742, 0.743, 0.744, 0.7451, + 0.7461, 0.7471, 0.7481, 0.7491, 0.7502, 0.7512, 0.7522, 0.7532, 0.7542, 0.7552, + 0.7562, 0.7572, 0.7582, 0.7592, 0.7602, 0.7612, 0.7622, 0.7632, 0.7642, 0.7652, + 0.7662, 0.7671, 0.7681, 0.7691, 0.7701, 0.7711, 0.772, 0.773, 0.774, 0.775, + 0.7759, 0.7769, 0.7779, 0.7788, 0.7798, 0.7807, 0.7817, 0.7827, 0.7836, 0.7846, + 0.7855, 0.7865, 0.7874, 0.7883, 0.7893, 0.7902, 0.7912, 0.7921, 0.793, 0.794, + 0.7949, 0.7958, 0.7968, 0.7977, 0.7986, 0.7995, 0.8005, 0.8014, 0.8023, 0.8032, + 0.8041, 0.805, 0.8059, 0.8068, 0.8078, 0.8087, 0.8096, 0.8105, 0.8114, 0.8123, + 0.8131, 0.814, 0.8149, 0.8158, 0.8167, 0.8176, 0.8185, 0.8193, 0.8202, 0.8211, + 0.822, 0.8228, 0.8237, 0.8246, 0.8255, 0.8263, 0.8272, 0.828, 0.8289, 0.8298, + 0.8306, 0.8315, 0.8323, 0.8332, 0.834, 0.8349, 0.8357, 0.8365, 0.8374, 0.8382, + 0.8391, 0.8399, 0.8407, 0.8416, 0.8424, 0.8432, 0.844, 0.8449, 0.8457, 0.8465, + 0.8473, 0.8481, 0.8489, 0.8497, 0.8505, 0.8514, 0.8522, 0.853, 0.8538, 0.8546, + 0.8554, 0.8561, 0.8569, 0.8577, 0.8585, 0.8593, 0.8601, 0.8609, 0.8616, 0.8624, + 0.8632, 0.864, 0.8647, 0.8655, 0.8663, 0.867, 0.8678, 0.8686, 0.8693, 0.8701, + 0.8708, 0.8716, 0.8723, 0.8731, 0.8738, 0.8746, 0.8753, 0.8761, 0.8768, 0.8775, + 0.8783, 0.879, 0.8797, 0.8805, 0.8812, 0.8819, 0.8826, 0.8834, 0.8841, 0.8848, + 0.8855, 0.8862, 0.8869, 0.8876, 0.8883, 0.889, 0.8897, 0.8904, 0.8911, 0.8918, + 0.8925, 0.8932, 0.8939, 0.8946, 0.8953, 0.896, 0.8966, 0.8973, 0.898, 0.8987, + 0.8993, 0.9, 0.9007, 0.9013, 0.902, 0.9027, 0.9033, 0.904, 0.9046, 0.9053, + 0.9059, 0.9066, 0.9072, 0.9079, 0.9085, 0.9092, 0.9098, 0.9104, 0.9111, 0.9117, + 0.9123, 0.913, 0.9136, 0.9142, 0.9148, 0.9154, 0.9161, 0.9167, 0.9173, 0.9179, + 0.9185, 0.9191, 0.9197, 0.9203, 0.9209, 0.9215, 0.9221, 0.9227, 0.9233, 0.9239, + 0.9245, 0.925, 0.9256, 0.9262, 0.9268, 0.9274, 0.9279, 0.9285, 0.9291, 0.9296, + 0.9302, 0.9308, 0.9313, 0.9319, 0.9324, 0.933, 0.9335, 0.9341, 0.9346, 0.9352, + 0.9357, 0.9363, 0.9368, 0.9373, 0.9379, 0.9384, 0.9389, 0.9395, 0.94, 0.9405, + 0.941, 0.9415, 0.9421, 0.9426, 0.9431, 0.9436, 0.9441, 0.9446, 0.9451, 0.9456, + 0.9461, 0.9466, 0.9471, 0.9476, 0.9481, 0.9486, 0.949, 0.9495, 0.95, 0.9505, + 0.951, 0.9514, 0.9519, 0.9524, 0.9528, 0.9533, 0.9538, 0.9542, 0.9547, 0.9551, + 0.9556, 0.956, 0.9565, 0.9569, 0.9574, 0.9578, 0.9583, 0.9587, 0.9591, 0.9596, + 0.96, 0.9604, 0.9609, 0.9613, 0.9617, 0.9621, 0.9625, 0.963, 0.9634, 0.9638, + 0.9642, 0.9646, 0.965, 0.9654, 0.9658, 0.9662, 0.9666, 0.967, 0.9674, 0.9678, + 0.9681, 0.9685, 0.9689, 0.9693, 0.9697, 0.97, 0.9704, 0.9708, 0.9711, 0.9715, + 0.9719, 0.9722, 0.9726, 0.9729, 0.9733, 0.9736, 0.974, 0.9743, 0.9747, 0.975, + 0.9754, 0.9757, 0.976, 0.9764, 0.9767, 0.977, 0.9774, 0.9777, 0.978, 0.9783, + 0.9786, 0.9789, 0.9793, 0.9796, 0.9799, 0.9802, 0.9805, 0.9808, 0.9811, 0.9814, + 0.9817, 0.982, 0.9823, 0.9825, 0.9828, 0.9831, 0.9834, 0.9837, 0.9839, 0.9842, + 0.9845, 0.9847, 0.985, 0.9853, 0.9855, 0.9858, 0.9861, 0.9863, 0.9866, 0.9868, + 0.9871, 0.9873, 0.9875, 0.9878, 0.988, 0.9883, 0.9885, 0.9887, 0.989, 0.9892, + 0.9894, 0.9896, 0.9898, 0.9901, 0.9903, 0.9905, 0.9907, 0.9909, 0.9911, 0.9913, + 0.9915, 0.9917, 0.9919, 0.9921, 0.9923, 0.9925, 0.9927, 0.9929, 0.993, 0.9932, + 0.9934, 0.9936, 0.9937, 0.9939, 0.9941, 0.9942, 0.9944, 0.9946, 0.9947, 0.9949, + 0.995, 0.9952, 0.9953, 0.9955, 0.9956, 0.9958, 0.9959, 0.996, 0.9962, 0.9963, + 0.9964, 0.9966, 0.9967, 0.9968, 0.9969, 0.9971, 0.9972, 0.9973, 0.9974, 0.9975, + 0.9976, 0.9977, 0.9978, 0.9979, 0.998, 0.9981, 0.9982, 0.9983, 0.9984, 0.9985, + 0.9986, 0.9986, 0.9987, 0.9988, 0.9989, 0.9989, 0.999, 0.9991, 0.9991, 0.9992, + 0.9993, 0.9993, 0.9994, 0.9994, 0.9995, 0.9995, 0.9996, 0.9996, 0.9997, 0.9997, + 0.9997, 0.9998, 0.9998, 0.9998, 0.9999, 0.9999, 0.9999, 0.9999, 0.9999, 1, + 1, 1, 1, 1, 1, 1}; + + const static uint64 mask = max-1; return logvals[h.first&mask]*cosvals[h.second&mask]; - // Note that we are just using the Box–Muller transform to compute the result. In + // Note that we are just using the Box-Muller transform to compute the result. In // particular, we are doing this (where u1 and u2 are uniform random variables in // the range [0,1]): // return sqrt(-2*log(u1)) * cos(2*PI*u2); diff --git a/lib/3rdParty/dlib/include/dlib/geometry.h b/lib/3rdParty/dlib/include/dlib/geometry.h index 4dd12389..0f18718c 100644 --- a/lib/3rdParty/dlib/include/dlib/geometry.h +++ b/lib/3rdParty/dlib/include/dlib/geometry.h @@ -4,9 +4,11 @@ #define DLIB_GEOMETRy_HEADER #include "geometry/rectangle.h" +#include "geometry/drectangle.h" #include "geometry/vector.h" #include "geometry/border_enumerator.h" #include "geometry/point_transforms.h" +#include "geometry/line.h" #endif // DLIB_GEOMETRy_HEADER diff --git a/lib/3rdParty/dlib/include/dlib/geometry/border_enumerator.h b/lib/3rdParty/dlib/include/dlib/geometry/border_enumerator.h index 25c56f94..0c69cc37 100644 --- a/lib/3rdParty/dlib/include/dlib/geometry/border_enumerator.h +++ b/lib/3rdParty/dlib/include/dlib/geometry/border_enumerator.h @@ -125,7 +125,7 @@ namespace dlib return false; } - unsigned long size ( + size_t size ( ) const { return rect.area() - inner_rect.area(); diff --git a/lib/3rdParty/dlib/include/dlib/geometry/border_enumerator_abstract.h b/lib/3rdParty/dlib/include/dlib/geometry/border_enumerator_abstract.h index e61568ce..11118d57 100644 --- a/lib/3rdParty/dlib/include/dlib/geometry/border_enumerator_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/geometry/border_enumerator_abstract.h @@ -99,7 +99,7 @@ namespace dlib - returns false if there are no more elements in the container !*/ - unsigned long size ( + size_t size ( ) const; /*! ensures diff --git a/lib/3rdParty/dlib/include/dlib/geometry/drectangle.h b/lib/3rdParty/dlib/include/dlib/geometry/drectangle.h new file mode 100644 index 00000000..9ccc5c0e --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/geometry/drectangle.h @@ -0,0 +1,488 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DRECTANGLe_ +#define DLIB_DRECTANGLe_ + +#include "drectangle_abstract.h" +#include "rectangle.h" + +namespace dlib +{ + class drectangle; + drectangle operator* ( + const drectangle& rect, + const double& scale + ); + +// ---------------------------------------------------------------------------------------- + + class drectangle + { + public: + + drectangle ( + ) : l(0), t(0), r(-1), b(-1) {} + + drectangle ( + double l_, + double t_, + double r_, + double b_ + ) : + l(l_), + t(t_), + r(r_), + b(b_) + {} + + drectangle ( + const dlib::vector& p + ) : + l(p.x()), + t(p.y()), + r(p.x()), + b(p.y()) + { + } + + template + drectangle ( + const vector& p1, + const vector& p2 + ) + { + *this = drectangle(p1) + drectangle(p2); + } + + drectangle ( + const rectangle& rect + ) : l(rect.left()), + t(rect.top()), + r(rect.right()), + b(rect.bottom()) {} + + operator rectangle ( + ) const + { + return rectangle((long)std::floor(l+0.5), + (long)std::floor(t+0.5), + (long)std::floor(r+0.5), + (long)std::floor(b+0.5)); + } + + double left() const { return l; } + double top() const { return t; } + double right() const { return r; } + double bottom() const { return b; } + + double& left() { return l; } + double& top() { return t; } + double& right() { return r; } + double& bottom() { return b; } + + const dlib::vector tl_corner ( + ) const { return dlib::vector(left(), top()); } + + const dlib::vector bl_corner ( + ) const { return dlib::vector(left(), bottom()); } + + const dlib::vector tr_corner ( + ) const { return dlib::vector(right(), top()); } + + const dlib::vector br_corner ( + ) const { return dlib::vector(right(), bottom()); } + + double width ( + ) const + { + if (is_empty()) + return 0; + else + return r - l + 1; + } + + double height ( + ) const + { + if (is_empty()) + return 0; + else + return b - t + 1; + } + + double area ( + ) const + { + return width()*height(); + } + + bool is_empty ( + ) const { return (t > b || l > r); } + + drectangle operator + ( + const drectangle& rhs + ) const + { + if (rhs.is_empty()) + return *this; + else if (is_empty()) + return rhs; + + return drectangle ( + std::min(l,rhs.l), + std::min(t,rhs.t), + std::max(r,rhs.r), + std::max(b,rhs.b) + ); + } + + drectangle intersect ( + const drectangle& rhs + ) const + { + return drectangle ( + std::max(l,rhs.l), + std::max(t,rhs.t), + std::min(r,rhs.r), + std::min(b,rhs.b) + ); + } + + bool contains ( + const dlib::vector& p + ) const + { + if (p.x() < l || p.x() > r || p.y() < t || p.y() > b) + return false; + return true; + } + + bool contains ( + const drectangle& rect + ) const + { + if (rect.is_empty()) + return true; + if (l <= rect.left() && + r >= rect.right() && + t <= rect.top() && + b >= rect.bottom()) + return true; + return false; + } + + drectangle& operator *= ( + const double& scale + ) + { + *this = *this*scale; + return *this; + } + + drectangle& operator /= ( + const double& scale + ) + { + *this = *this*(1.0/scale); + return *this; + } + + drectangle& operator += ( + const dlib::vector& p + ) + { + *this = *this + drectangle(p); + return *this; + } + + bool operator== ( + const drectangle& rect + ) const + { + return (l == rect.l) && (t == rect.t) && (r == rect.r) && (b == rect.b); + } + + bool operator!= ( + const drectangle& rect + ) const + { + return !(*this == rect); + } + + private: + double l; + double t; + double r; + double b; + }; + +// ---------------------------------------------------------------------------------------- + + inline void serialize ( + const drectangle& item, + std::ostream& out + ) + { + try + { + serialize(item.left(),out); + serialize(item.top(),out); + serialize(item.right(),out); + serialize(item.bottom(),out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing an object of type drectangle"); + } + } + + inline void deserialize ( + drectangle& item, + std::istream& in + ) + { + try + { + deserialize(item.left(),in); + deserialize(item.top(),in); + deserialize(item.right(),in); + deserialize(item.bottom(),in); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing an object of type drectangle"); + } + } + + inline std::ostream& operator<< ( + std::ostream& out, + const drectangle& item + ) + { + out << "[(" << item.left() << ", " << item.top() << ") (" << item.right() << ", " << item.bottom() << ")]"; + return out; + } + + inline std::istream& operator>>( + std::istream& in, + drectangle& item + ) + { + // ignore any whitespace + while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\r' || in.peek() == '\n') + in.get(); + // now eat the leading '[' character + if (in.get() != '[') + { + in.setstate(in.rdstate() | std::ios::failbit); + return in; + } + + dlib::vector p1, p2; + in >> p1; + in >> p2; + item = drectangle(p1) + drectangle(p2); + + // ignore any whitespace + while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\r' || in.peek() == '\n') + in.get(); + // now eat the trailing ']' character + if (in.get() != ']') + { + in.setstate(in.rdstate() | std::ios::failbit); + } + return in; + } + +// ---------------------------------------------------------------------------------------- + + inline dlib::vector center ( + const drectangle& rect + ) + { + dlib::vector temp(rect.left() + rect.right(), + rect.top() + rect.bottom()); + + return temp/2.0; + } + + inline dlib::vector dcenter ( + const drectangle& rect + ) + { + return center(rect); + } + + inline drectangle operator* ( + const drectangle& rect, + const double& scale + ) + { + if (!rect.is_empty()) + { + const double width = (rect.right()-rect.left())*scale; + const double height = (rect.bottom()-rect.top())*scale; + const dlib::vector p = center(rect); + return drectangle(p.x()-width/2, p.y()-height/2, p.x()+width/2, p.y()+height/2); + } + else + { + return rect; + } + } + + inline drectangle operator* ( + const double& scale, + const drectangle& rect + ) + { + return rect*scale; + } + + inline drectangle operator/ ( + const drectangle& rect, + const double& scale + ) + { + return rect*(1.0/scale); + } + + inline drectangle operator+ ( + const drectangle& r, + const dlib::vector& p + ) + { + return r + drectangle(p); + } + + inline drectangle operator+ ( + const dlib::vector& p, + const drectangle& r + ) + { + return r + drectangle(p); + } + + template + inline drectangle translate_rect ( + const drectangle& rect, + const dlib::vector& p + ) + { + drectangle result; + result.top () = rect.top() + p.y(); + result.bottom () = rect.bottom() + p.y(); + result.left () = rect.left() + p.x(); + result.right () = rect.right() + p.x(); + return result; + } + + inline drectangle intersect ( + const drectangle& a, + const drectangle& b + ) { return a.intersect(b); } + + inline double area ( + const drectangle& a + ) { return a.area(); } + + inline drectangle centered_drect ( + const dlib::vector& p, + double width, + double height + ) + { + width--; + height--; + + return drectangle(p.x()-width/2, p.y()-height/2, p.x()+width/2, p.y()+height/2); + } + + inline drectangle centered_drect ( + const drectangle& rect, + double width, + double height + ) + { + return centered_drect(dcenter(rect), width, height); + } + + inline const drectangle shrink_rect ( + const drectangle& rect, + double num + ) + { + return drectangle(rect.left()+num, rect.top()+num, rect.right()-num, rect.bottom()-num); + } + + inline const drectangle grow_rect ( + const drectangle& rect, + double num + ) + { + return shrink_rect(rect, -num); + } + + inline const drectangle shrink_rect ( + const drectangle& rect, + double width, + double height + ) + { + return drectangle(rect.left()+width, rect.top()+height, rect.right()-width, rect.bottom()-height); + } + + inline const drectangle grow_rect ( + const drectangle& rect, + double width, + double height + ) + { + return shrink_rect(rect, -width, -height); + } + + inline drectangle set_rect_area ( + const drectangle& rect, + double area + ) + { + DLIB_ASSERT(area >= 0, "drectangle can't have a negative area."); + + if (area == 0) + return drectangle(dcenter(rect)); + + if (rect.area() == 0) + { + // In this case we will make the output rectangle a square with the requested + // area. + double scale = std::sqrt(area); + return centered_drect(rect, scale, scale); + } + else + { + double scale = std::sqrt(area/rect.area()); + return centered_drect(rect, rect.width()*scale, rect.height()*scale); + } + } + + inline drectangle set_aspect_ratio ( + const drectangle& rect, + double ratio + ) + { + DLIB_ASSERT(ratio > 0, + "\t drectangle set_aspect_ratio()" + << "\n\t ratio: " << ratio + ); + + const double h = std::sqrt(rect.area()/ratio); + const double w = h*ratio; + return centered_drect(rect, w, h); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DRECTANGLe_ + diff --git a/lib/3rdParty/dlib/include/dlib/geometry/drectangle_abstract.h b/lib/3rdParty/dlib/include/dlib/geometry/drectangle_abstract.h new file mode 100644 index 00000000..0f222135 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/geometry/drectangle_abstract.h @@ -0,0 +1,628 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_DRECTANGLe_ABSTRACT_H_ +#ifdef DLIB_DRECTANGLe_ABSTRACT_H_ + +#include "rectangle_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class drectangle + { + /*! + INITIAL VALUE + The initial value of this object is defined by its constructor. + + WHAT THIS OBJECT REPRESENTS + This object is just like dlib::rectangle except that it stores the + coordinates of the rectangle using double rather than long variables. As + such, this object represents a rectangular region inside an image. The + region is the rectangle with its top left corner at position (left(),top()) + and its bottom right corner at (right(),bottom()). + + Note that the origin of the coordinate system, i.e. (0,0), is located at + the upper left corner. That is, points such as (1,1) or (3,5) represent + locations that are below and to the right of the origin. + + Also note that rectangles where top() > bottom() or left() > right() + represent empty rectangles. + !*/ + public: + + drectangle ( + ); + /*! + ensures + - #left() == 0 + - #top() == 0 + - #right() == -1 + - #bottom() == -1 + - #is_empty() == true + !*/ + + drectangle ( + double left_, + double top_, + double right_, + double bottom_ + ); + /*! + ensures + - #left() == left_ + - #top() == top_ + - #right() == right_ + - #bottom() == bottom_ + !*/ + + drectangle ( + const vector& p + ); + /*! + ensures + - #left() == p.x() + - #top() == p.y() + - #right() == p.x() + - #bottom() == p.y() + !*/ + + template + drectangle ( + const vector& p1, + const vector& p2 + ); + /*! + ensures + - #*this == drectangle(p1) + drectangle(p2) + !*/ + + drectangle ( + const drectangle& rect + ); + /*! + ensures + - #*this represents the same rectangle as rect + !*/ + + drectangle ( + const rectangle& rect + ); + /*! + ensures + - left() == rect.left() + - top() == rect.top() + - right() == rect.right() + - bottom() == rect.bottom() + - dcenter(*this) == dcenter(rect) + - width() == rect.width() + - height() == rect.height() + !*/ + + operator rectangle ( + ) const; + /*! + ensures + - returns a rectangle where left(), top(), right(), and bottom() have been + rounded to the nearest integer values. + !*/ + + double left ( + ) const; + /*! + ensures + - returns the x coordinate for the left side of this rectangle + !*/ + + double& left ( + ); + /*! + ensures + - returns a non-const reference to the x coordinate for the left side + of this rectangle + !*/ + + double top ( + ) const; + /*! + ensures + - returns the y coordinate for the top of this rectangle + !*/ + + double& top ( + ); + /*! + ensures + - returns a non-const reference to the y coordinate for the + top of this rectangle + !*/ + + double right ( + ) const; + /*! + ensures + - returns the x coordinate for the right side of this rectangle + !*/ + + double& right ( + ); + /*! + ensures + - returns a non-const reference to the x coordinate for the right + side of this rectangle + !*/ + + double bottom ( + ) const; + /*! + ensures + - returns the y coordinate for the bottom of this rectangle + !*/ + + double& bottom ( + ); + /*! + ensures + - returns a non-const reference to the y coordinate for the bottom + of this rectangle + !*/ + + const vector tl_corner ( + ) const; + /*! + ensures + - returns vector(left(), top()) + (i.e. returns the top left corner point for this rectangle) + !*/ + + const vector bl_corner ( + ) const; + /*! + ensures + - returns vector(left(), bottom()) + (i.e. returns the bottom left corner point for this rectangle) + !*/ + + const vector tr_corner ( + ) const; + /*! + ensures + - returns vector(right(), top()) + (i.e. returns the top right corner point for this rectangle) + !*/ + + const vector br_corner ( + ) const; + /*! + ensures + - returns vector(right(), bottom()) + (i.e. returns the bottom right corner point for this rectangle) + !*/ + + double width ( + ) const; + /*! + ensures + - if (is_empty()) then + - returns 0 + - else + - returns the width of this rectangle. + (i.e. right() - left() + 1) + !*/ + + double height ( + ) const; + /*! + ensures + - if (is_empty()) then + - returns 0 + - else + - returns the height of this rectangle. + (i.e. bottom() - top() + 1) + !*/ + + double area ( + ) const; + /*! + ensures + - returns width()*height() + !*/ + + bool is_empty ( + ) const; + /*! + ensures + - if (top() > bottom() || left() > right()) then + - returns true + - else + - returns false + !*/ + + drectangle operator + ( + const drectangle& rhs + ) const; + /*! + ensures + - if (rhs.is_empty() == false && this->is_empty() == false) then + - returns the smallest rectangle that contains both *this and + rhs. + - if (rhs.is_empty() == true && this->is_empty() == false) then + - returns *this + - if (rhs.is_empty() == false && this->is_empty() == true) then + - returns rhs + - if (rhs.is_empty() == true && this->is_empty() == true) then + - returns a rectangle that has is_empty() == true + !*/ + + drectangle intersect ( + const drectangle& rhs + ) const; + /*! + ensures + - if (there is a region of intersection between *this and rhs) then + - returns a rectangle that represents the intersection of *this + and rhs. + - else + - returns a rectangle where is_empty() == true + !*/ + + bool contains ( + const vector& p + ) const; + /*! + ensures + - if (the point (p.x(),p.y()) is contained in this rectangle) then + - returns true + - else + - returns false + !*/ + + bool contains ( + const drectangle& rect + ) const + /*! + ensures + - if (rect + *this == *this) then + - returns true + (i.e. returns true if *this contains the given rectangle) + - else + - returns false + !*/ + + drectangle& operator *= ( + const double& scale + ); + /*! + ensures + - performs: *this = *this*scale; + - returns #*this + !*/ + + drectangle& operator /= ( + const double& scale + ); + /*! + requires + - scale != 0 + ensures + - performs: *this = *this*(1.0/scale); + - returns #*this + !*/ + + drectangle& operator += ( + const dlib::vector& p + ); + /*! + ensures + - performs: *this = *this + drectangle(p) + - returns #*this + !*/ + + bool operator== ( + const drectangle& rect + ) const; + /*! + ensures + - if (top() == rect.top() && left() == rect.left() && + right() == rect.right() && bottom() == rect.bottom()) then + - returns true + - else + - returns false + !*/ + + bool operator!= ( + const drectangle& rect + ) const; + /*! + ensures + - returns !(*this == rect) + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + void serialize ( + const drectangle& item, + std::ostream& out + ); + /*! + provides serialization support + !*/ + + void deserialize ( + drectangle& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ + +// ---------------------------------------------------------------------------------------- + + std::ostream& operator<< ( + std::ostream& out, + const drectangle& item + ); + /*! + ensures + - writes item to out in the form "[(left, top) (right, bottom)]" + !*/ + +// ---------------------------------------------------------------------------------------- + + std::istream& operator>>( + std::istream& in, + drectangle& item + ); + /*! + ensures + - reads a drectangle from the input stream in and stores it in #item. The data + in the input stream should be of the form [(left, top) (right, bottom)] + !*/ + +// ---------------------------------------------------------------------------------------- + + vector center ( + const drectangle& rect + ); + /*! + ensures + - returns the center of the given rectangle + !*/ + +// ---------------------------------------------------------------------------------------- + + vector dcenter ( + const drectangle& rect + ); + /*! + ensures + - returns the center of the given rectangle. (Both center() and dcenter() are + identical when applied to drectangle objects) + !*/ + +// ---------------------------------------------------------------------------------------- + + drectangle operator* ( + const drectangle& rect, + const double& scale + ); + /*! + ensures + - This function returns a rectangle that has the same center as rect but with + dimensions that are scale times larger. That is, we return a new rectangle R + such that: + - center(R) == center(rect) + - R.right()-R.left() == (rect.right()-rect.left())*scale + - R.bottom()-R.top() == (rect.bottom()-rect.top())*scale + !*/ + +// ---------------------------------------------------------------------------------------- + + drectangle operator* ( + const double& scale, + const drectangle& rect + ); + /*! + ensures + - returns rect*scale + !*/ + +// ---------------------------------------------------------------------------------------- + + drectangle operator/ ( + const drectangle& rect, + const double& scale + ); + /*! + ensures + - returns rect*(1.0/scale) + !*/ + +// ---------------------------------------------------------------------------------------- + + drectangle operator+ ( + const drectangle& r, + const vector& p + ); + /*! + ensures + - returns r + drectangle(p) + (i.e. returns the rectangle that contains both r and p) + !*/ + +// ---------------------------------------------------------------------------------------- + + drectangle operator+ ( + const vector& p, + const drectangle& r + ); + /*! + ensures + - returns r + drectangle(p) + (i.e. returns the rectangle that contains both r and p) + !*/ + +// ---------------------------------------------------------------------------------------- + + template + drectangle translate_rect ( + const drectangle& rect, + const vector& p + ); + /*! + ensures + - returns a rectangle R such that: + - R.left() == rect.left() + p.x() + - R.right() == rect.right() + p.x() + - R.top() == rect.top() + p.y() + - R.bottom() == rect.bottom() + p.y() + !*/ + +// ---------------------------------------------------------------------------------------- + + drectangle intersect ( + const drectangle& a, + const drectangle& b + ); + /*! + ensures + - returns a.intersect(b) + (i.e. returns a rectangle representing the intersection of a and b) + !*/ + +// ---------------------------------------------------------------------------------------- + + double area ( + const drectangle& a + ); + /*! + ensures + - returns a.area() + !*/ + +// ---------------------------------------------------------------------------------------- + + drectangle centered_drect ( + const vector& p, + double width, + double height + ); + /*! + ensures + - returns a rectangle R such that: + - center(R) == p + - if (width < 1 || height < 1) + - R.width() == 0 + - R.height() == 0 + - R.is_empty() == true + - else + - R.width() == width + - R.height() == height + !*/ + +// ---------------------------------------------------------------------------------------- + + drectangle centered_drect ( + const drectangle& rect, + double width, + double height + ); + /*! + ensures + - returns centered_drect(center(rect), width, height) + !*/ + +// ---------------------------------------------------------------------------------------- + + const drectangle shrink_rect ( + const drectangle& rect, + double num + ); + /*! + ensures + - returns drectangle(rect.left()+num, rect.top()+num, rect.right()-num, rect.bottom()-num) + (i.e. shrinks the given drectangle by shrinking its border by num) + !*/ + +// ---------------------------------------------------------------------------------------- + + const drectangle grow_rect ( + const drectangle& rect, + double num + ); + /*! + ensures + - return shrink_rect(rect, -num) + (i.e. grows the given drectangle by expanding its border by num) + !*/ + +// ---------------------------------------------------------------------------------------- + + const drectangle shrink_rect ( + const drectangle& rect, + double width, + double height + ); + /*! + ensures + - returns drectangle(rect.left()+width, rect.top()+height, rect.right()-width, rect.bottom()-height) + (i.e. shrinks the given drectangle by shrinking its left and right borders by width + and its top and bottom borders by height. ) + !*/ + +// ---------------------------------------------------------------------------------------- + + const drectangle grow_rect ( + const drectangle& rect, + double width, + double height + ); + /*! + ensures + - return shrink_rect(rect, -width, -height) + (i.e. grows the given drectangle by expanding its border) + !*/ + +// ---------------------------------------------------------------------------------------- + + drectangle set_rect_area ( + const drectangle& rect, + double area + ); + /*! + requires + - area >= 0 + ensures + - Returns a rectangle R such that: + - center(R) == center(rect) + - R has the same aspect ratio as rect. If rect.area() == 0 then the + returned rect has a 1:1 aspect ratio. + - R.area() == area + !*/ + +// ---------------------------------------------------------------------------------------- + + drectangle set_aspect_ratio ( + const drectangle& rect, + double ratio + ); + /*! + requires + - ratio > 0 + ensures + - This function reshapes the given rectangle so that it has the given aspect + ratio. In particular, this means we return a rectangle R such that the + following equations are true: + - R.width()/R.height() == ratio + - R.area() == rect.area() + - dcenter(rect) == dcenter(R) + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DRECTANGLe_ABSTRACT_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/geometry/line.h b/lib/3rdParty/dlib/include/dlib/geometry/line.h new file mode 100644 index 00000000..87c8b32f --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/geometry/line.h @@ -0,0 +1,235 @@ +// Copyright (C) 2018 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LInE_H_ +#define DLIB_LInE_H_ + +#include "line_abstract.h" +#include "vector.h" +#include +#include "../numeric_constants.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class line + { + public: + + line() = default; + + line(const dpoint& a, const dpoint& b) : end1(a), end2(b) + { + normal_vector = (end1-end2).cross(dlib::vector(0,0,1)).normalize(); + } + + template + line(const std::pair,vector>& l) : line(l.first, l.second) {} + + const dpoint& p1() const { return end1; } + const dpoint& p2() const { return end2; } + + const dpoint& normal() const { return normal_vector; } + + private: + + dpoint end1; + dpoint end2; + + dpoint normal_vector; + }; + +// ---------------------------------------------------------------------------------------- + + template + double signed_distance_to_line ( + const line& l, + const vector& p + ) + { + return dot(p-l.p1(), l.normal()); + } + + template + double signed_distance_to_line ( + const std::pair,vector >& l, + const vector& p + ) + { + return signed_distance_to_line(line(l),p); + } + + template + double distance_to_line ( + const std::pair,vector >& l, + const vector& p + ) + { + return std::abs(signed_distance_to_line(l,p)); + } + + template + double distance_to_line ( + const line& l, + const vector& p + ) + { + return std::abs(signed_distance_to_line(l,p)); + } + +// ---------------------------------------------------------------------------------------- + + inline line reverse(const line& l) + { + return line(l.p2(), l.p1()); + } + +// ---------------------------------------------------------------------------------------- + + template + inline dpoint intersect( + const std::pair,vector>& a, + const std::pair,vector>& b + ) + { + // convert to homogeneous coordinates + dlib::vector a1 = a.first; + dlib::vector a2 = a.second; + dlib::vector b1 = b.first; + dlib::vector b2 = b.second; + a1.z() = 1; + a2.z() = 1; + b1.z() = 1; + b2.z() = 1; + + // find lines between pairs of points. + auto l1 = a1.cross(a2); + auto l2 = b1.cross(b2); + + // find intersection of the lines. + auto p = l1.cross(l2); + + if (p.z() != 0) + return p/p.z(); + else + return dpoint(std::numeric_limits::infinity(), std::numeric_limits::infinity()); + } + +// ---------------------------------------------------------------------------------------- + + inline dpoint intersect( + const line& a, + const line& b + ) + { + return intersect(std::make_pair(a.p1(),a.p2()), std::make_pair(b.p1(), b.p2())); + } + +// ---------------------------------------------------------------------------------------- + + template + inline size_t count_points_on_side_of_line( + line l, + const dpoint& reference_point, + const std::vector>& pts, + const double& dist_thresh + ) + { + if (signed_distance_to_line(l,reference_point) < 0) + l = reverse(l); + + size_t cnt = 0; + for (auto& p : pts) + { + double dist = signed_distance_to_line(l,p); + if (0 <= dist && dist <= dist_thresh) + ++cnt; + } + return cnt; + } + +// ---------------------------------------------------------------------------------------- + + template + inline double count_points_between_lines( + line l1, + line l2, + const dpoint& reference_point, + const std::vector>& pts + ) + { + if (signed_distance_to_line(l1,reference_point) < 0) + l1 = reverse(l1); + if (signed_distance_to_line(l2,reference_point) < 0) + l2 = reverse(l2); + + size_t cnt = 0; + for (auto& p : pts) + { + if (signed_distance_to_line(l1,p) > 0 && signed_distance_to_line(l2,p) > 0) + ++cnt; + } + return cnt; + } + +// ---------------------------------------------------------------------------------------- + + inline double angle_between_lines ( + const line& a, + const line& b + ) + { + auto tmp = put_in_range(0.0, 1.0, std::abs(dot(a.normal(),b.normal()))); + return std::acos(tmp)*180/pi; + } + +// ---------------------------------------------------------------------------------------- + + struct no_convex_quadrilateral : dlib::error + { + no_convex_quadrilateral() : dlib::error("Lines given to find_convex_quadrilateral() don't form any convex quadrilateral.") {} + }; + + inline std::array find_convex_quadrilateral ( + const std::array& lines + ) + { + const dpoint v01 = intersect(lines[0],lines[1]); + const dpoint v02 = intersect(lines[0],lines[2]); + const dpoint v03 = intersect(lines[0],lines[3]); + const dpoint v12 = intersect(lines[1],lines[2]); + const dpoint v13 = intersect(lines[1],lines[3]); + const dpoint v23 = intersect(lines[2],lines[3]); + const auto& v10 = v01; + const auto& v20 = v02; + const auto& v30 = v03; + const auto& v21 = v12; + const auto& v31 = v13; + const auto& v32 = v23; + + if (is_convex_quadrilateral({v01, v12, v23, v30})) + return {v01, v12, v23, v30}; + if (is_convex_quadrilateral({v01, v13, v32, v20})) + return {v01, v13, v32, v20}; + + if (is_convex_quadrilateral({v02, v23, v31, v10})) + return {v02, v23, v31, v10}; + if (is_convex_quadrilateral({v02, v21, v13, v30})) + return {v02, v21, v13, v30}; + + if (is_convex_quadrilateral({v03, v32, v21, v10})) + return {v03, v32, v21, v10}; + if (is_convex_quadrilateral({v03, v31, v12, v20})) + return {v03, v31, v12, v20}; + + throw no_convex_quadrilateral(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_LInE_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/geometry/line_abstract.h b/lib/3rdParty/dlib/include/dlib/geometry/line_abstract.h new file mode 100644 index 00000000..6aede1bd --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/geometry/line_abstract.h @@ -0,0 +1,236 @@ +// Copyright (C) 2018 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_LInE_ABSTRACT_H_ +#ifdef DLIB_LInE_ABSTRACT_H_ + +#include "../vector_abstract.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class line + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a line in the 2D plane. The line is defined by two + points running through it, p1() and p2(). This object also includes a + unit normal vector that is perpendicular to the line. + !*/ + + public: + + line( + ); + /*! + ensures + - p1(), p2(), and normal() are all the 0 vector. + !*/ + + line( + const dpoint& a, + const dpoint& b + ); + /*! + ensures + - #p1() == a + - #p2() == b + - #normal() == A vector normal to the line passing through points a and b. + In particular, it is given by: (a-b).cross(dlib::vector(0,0,1)).normalize(). + Therefore, the normal vector is the vector (a-b) but unit normalized and rotated clockwise 90 degrees. + !*/ + + template + line( + const std::pair,vector>& l + ); + /*! + ensures + - #*this == line(l.first, l.second) + !*/ + + const dpoint& p1( + ) const; + /*! + ensures + - returns the first endpoint of the line. + !*/ + + const dpoint& p2( + ) const; + /*! + ensures + - returns the second endpoint of the line. + !*/ + + const dpoint& normal( + ) const; + /*! + ensures + - returns a unit vector that is normal to the line passing through p1() and p2(). + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + + template + double signed_distance_to_line ( + const line& l, + const vector& p + ); + /*! + ensures + - returns how far p is from the line l. This is a signed distance. The sign + indicates which side of the line the point is on and the magnitude is the + distance. Moreover, the direction of positive sign is pointed to by the + vector l.normal(). + - To be specific, this routine returns dot(p-l.p1(), l.normal()) + !*/ + + template + double signed_distance_to_line ( + const std::pair,vector >& l, + const vector& p + ); + /*! + ensures + - returns signed_distance_to_line(line(l),p); + !*/ + + template + double distance_to_line ( + const std::pair,vector >& l, + const vector& p + ); + /*! + ensures + - returns abs(signed_distance_to_line(l,p)) + !*/ + + template + double distance_to_line ( + const line& l, + const vector& p + ); + /*! + ensures + - returns abs(signed_distance_to_line(l,p)) + !*/ + +// ---------------------------------------------------------------------------------------- + + line reverse( + const line& l + ); + /*! + ensures + - returns line(l.p2(), l.p1()) + (i.e. returns a line object that represents the same line as l but with the + endpoints, and therefore, the normal vector flipped. This means that the + signed distance of operator() is also flipped). + !*/ + +// ---------------------------------------------------------------------------------------- + + dpoint intersect( + const line& a, + const line& b + ); + /*! + ensures + - returns the point of intersection between lines a and b. If no such point + exists then this function returns a point with Inf values in it. + !*/ + +// ---------------------------------------------------------------------------------------- + + double angle_between_lines ( + const line& a, + const line& b + ); + /*! + ensures + - returns the angle, in degrees, between the given lines. This is a number in + the range [0 90]. + !*/ + +// ---------------------------------------------------------------------------------------- + + template + dpoint intersect( + const std::pair,vector>& a, + const std::pair,vector>& b + ); + /*! + ensures + - returns intersect(line(a), line(b)) + !*/ + +// ---------------------------------------------------------------------------------------- + + template + size_t count_points_on_side_of_line( + const line& l, + const dpoint& reference_point, + const std::vector>& pts, + const double& dist_thresh + ); + /*! + ensures + - Returns a count of how many points in pts are on the same side of l as + reference_point, but also no more than dist_thresh distance from the line. + !*/ + +// ---------------------------------------------------------------------------------------- + + template + double count_points_between_lines( + const line& l1, + const line& l2, + const dpoint& reference_point, + const std::vector>& pts + ); + /*! + ensures + - Counts and returns the number of points in pts that are between lines l1 and + l2. Since a pair of lines will, in the general case, divide the plane into 4 + regions, we identify the region of interest as the one that contains the + reference_point. Therefore, this function counts the number of points in pts + that appear in the same region as reference_point. + !*/ + +// ---------------------------------------------------------------------------------------- + + struct no_convex_quadrilateral : dlib::error + { + /*! + WHAT THIS OBJECT REPRESENTS + This is the exception thrown by find_convex_quadrilateral() if the inputs + can't form a convex quadrilateral. + !*/ + no_convex_quadrilateral( + ) : dlib::error("Lines given to find_convex_quadrilateral() don't form any convex quadrilateral.") + {} + }; + + std::array find_convex_quadrilateral ( + const std::array& lines + ); + /*! + ensures + - Is there a set of 4 points, made up of the intersections of the given lines, + that forms a convex quadrilateral? If yes then this routine returns those 4 + points and if not throws no_convex_quadrilateral. + throws + - no_convex_quadrilateral + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_LInE_ABSTRACT_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/geometry/point_transforms.h b/lib/3rdParty/dlib/include/dlib/geometry/point_transforms.h index 0b59a8df..e789fd2a 100644 --- a/lib/3rdParty/dlib/include/dlib/geometry/point_transforms.h +++ b/lib/3rdParty/dlib/include/dlib/geometry/point_transforms.h @@ -9,6 +9,8 @@ #include "../matrix.h" #include "../matrix/matrix_la.h" #include "../optimization/optimization.h" +#include "rectangle.h" +#include "drectangle.h" #include namespace dlib @@ -190,6 +192,84 @@ namespace dlib dlib::vector b; }; +// ---------------------------------------------------------------------------------------- + + class rectangle_transform + { + public: + + rectangle_transform ( + ) + { + } + + rectangle_transform ( + const point_transform_affine& tform_ + ) :tform(tform_) + { + } + + drectangle operator() ( + const drectangle& r + ) const + { + dpoint tl = r.tl_corner(); + dpoint tr = r.tr_corner(); + dpoint bl = r.bl_corner(); + dpoint br = r.br_corner(); + // The new rectangle wouold ideally have this area if we could actually rotrate + // the box. + double new_area = length(tform(tl)-tform(tr))*length(tform(tl)-tform(bl)); + + // But if we rotate the coners of the rectangle and then find the rectangle + // that contains them we get this, which might have a much larger area than we + // want. + drectangle temp; + temp += tform(tl); + temp += tform(tr); + temp += tform(bl); + temp += tform(br); + // so we adjust the area to match the target area and have the same center as + // the above box. + double scale = std::sqrt(new_area/temp.area()); + + return centered_rect(center(temp), static_cast(temp.width()*scale+0.5), static_cast(temp.height()*scale+0.5)); + } + + rectangle operator() ( + const rectangle& r + ) const + { + return (*this)(drectangle(r)); + } + + const point_transform_affine& get_tform( + ) const { return tform; } + + inline friend void serialize (const rectangle_transform& item, std::ostream& out) + { + serialize(item.tform, out); + } + + inline friend void deserialize (rectangle_transform& item, std::istream& in) + { + deserialize(item.tform, in); + } + + private: + point_transform_affine tform; + }; + +// ---------------------------------------------------------------------------------------- + + inline point_transform_affine operator* ( + const point_transform_affine& lhs, + const point_transform_affine& rhs + ) + { + return point_transform_affine(lhs.get_m()*rhs.get_m(), lhs.get_m()*rhs.get_b()+lhs.get_b()); + } + // ---------------------------------------------------------------------------------------- inline point_transform_affine inv ( @@ -253,7 +333,7 @@ namespace dlib // We use the formulas from the paper: Least-squares estimation of transformation // parameters between two point patterns by Umeyama. They are equations 34 through - // 42. + // 43. dlib::vector mean_from, mean_to; double sigma_from = 0, sigma_to = 0; @@ -282,7 +362,7 @@ namespace dlib matrix u, v, s, d; svd(cov, u,d,v); s = identity_matrix(cov); - if (det(cov) < 0) + if (det(cov) < 0 || (det(cov) == 0 && det(u)*det(v)<0)) { if (d(1,1) < d(0,0)) s(1,1) = -1; @@ -358,6 +438,16 @@ namespace dlib matrix m; }; +// ---------------------------------------------------------------------------------------- + + inline point_transform_projective operator* ( + const point_transform_projective& lhs, + const point_transform_projective& rhs + ) + { + return point_transform_projective(lhs.get_m()*rhs.get_m()); + } + // ---------------------------------------------------------------------------------------- inline point_transform_projective inv ( @@ -390,6 +480,8 @@ namespace dlib find_projective_transform_basic() as a starting point for a BFGS based non-linear optimizer which will optimize the correct mean squared error criterion. + + A great essay on this subject is Homography Estimation by Elan Dubrofsky. !*/ { // make sure requires clause is not broken @@ -607,6 +699,288 @@ namespace dlib return m; } +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class point_transform_affine3d + { + public: + + point_transform_affine3d ( + ) + { + m = identity_matrix(3); + b.x() = 0; + b.y() = 0; + } + + point_transform_affine3d ( + const matrix& m_, + const dlib::vector& b_ + ) :m(m_), b(b_) + { + } + + const dlib::vector operator() ( + const dlib::vector& p + ) const + { + return m*p + b; + } + + const matrix& get_m( + ) const { return m; } + + const dlib::vector& get_b( + ) const { return b; } + + inline friend void serialize (const point_transform_affine3d& item, std::ostream& out) + { + serialize(item.m, out); + serialize(item.b, out); + } + + inline friend void deserialize (point_transform_affine3d& item, std::istream& in) + { + deserialize(item.m, in); + deserialize(item.b, in); + } + + private: + matrix m; + dlib::vector b; + }; + +// ---------------------------------------------------------------------------------------- + + inline point_transform_affine3d operator* ( + const point_transform_affine3d& lhs, + const point_transform_affine& rhs + ) + { + matrix m; + m = 0; + set_subm(m, get_rect(rhs.get_m())) = rhs.get_m(); + vector b = rhs.get_b(); + + return point_transform_affine3d(lhs.get_m()*m, lhs.get_m()*b+lhs.get_b()); + } + +// ---------------------------------------------------------------------------------------- + + inline point_transform_affine3d operator* ( + const point_transform_affine3d& lhs, + const point_transform_affine3d& rhs + ) + { + return point_transform_affine3d(lhs.get_m()*rhs.get_m(), lhs.get_m()*rhs.get_b()+lhs.get_b()); + } + +// ---------------------------------------------------------------------------------------- + + inline point_transform_affine3d inv ( + const point_transform_affine3d& trans + ) + { + matrix im = inv(trans.get_m()); + return point_transform_affine3d(im, -im*trans.get_b()); + } + +// ---------------------------------------------------------------------------------------- + + inline point_transform_affine3d rotate_around_x ( + double angle + ) + { + const double ca = std::cos(angle); + const double sa = std::sin(angle); + + matrix m; + m = 1, 0, 0, + 0, ca, -sa, + 0, sa, ca; + + vector b; + + return point_transform_affine3d(m,b); + } + +// ---------------------------------------------------------------------------------------- + + inline point_transform_affine3d rotate_around_y ( + double angle + ) + { + const double ca = std::cos(angle); + const double sa = std::sin(angle); + + matrix m; + m = ca, 0, sa, + 0, 1, 0, + -sa, 0, ca; + + vector b; + + return point_transform_affine3d(m,b); + } + +// ---------------------------------------------------------------------------------------- + + inline point_transform_affine3d rotate_around_z ( + double angle + ) + { + const double ca = std::cos(angle); + const double sa = std::sin(angle); + + matrix m; + m = ca, -sa, 0, + sa, ca, 0, + 0, 0, 1; + + vector b; + + return point_transform_affine3d(m,b); + } + +// ---------------------------------------------------------------------------------------- + + inline point_transform_affine3d translate_point ( + const vector& delta + ) + { + return point_transform_affine3d(identity_matrix(3),delta); + } + + inline point_transform_affine3d translate_point ( + double x, + double y, + double z + ) + { + return translate_point(vector(x,y,z)); + } + +// ---------------------------------------------------------------------------------------- + + class camera_transform + { + + public: + + camera_transform ( + ) + { + *this = camera_transform(vector(1,1,1), + vector(0,0,0), + vector(0,0,1), + 90, + 1); + } + + camera_transform ( + const vector& camera_pos_, + const vector& camera_looking_at_, + const vector& camera_up_direction_, + const double camera_field_of_view_, + const unsigned long num_pixels_ + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(0 < camera_field_of_view_ && camera_field_of_view_ < 180, + "\t camera_transform::camera_transform()" + << "\n\t Invalid inputs were given to this function." + << "\n\t camera_field_of_view_: " << camera_field_of_view_ + ); + + camera_pos = camera_pos_; + camera_looking_at = camera_looking_at_; + camera_up_direction = camera_up_direction_; + camera_field_of_view = camera_field_of_view_; + num_pixels = num_pixels_; + + dlib::vector X,Y,Z; + Z = (camera_looking_at - camera_pos).normalize(); + Y = camera_up_direction - dot(camera_up_direction,Z)*Z; + Y = Y.normalize(); + X = Z.cross(Y); + + set_rowm(proj,0) = trans(X); + // Minus because images have y axis going down but we want the 3d projection to appear using a normal coordinate system with y going up. + set_rowm(proj,1) = -trans(Y); + set_rowm(proj,2) = trans(Z); + + width = num_pixels/2.0; + dist_scale = width/std::tan(pi/180*camera_field_of_view/2); + } + + vector get_camera_pos() const { return camera_pos; } + vector get_camera_looking_at() const { return camera_looking_at; } + vector get_camera_up_direction()const { return camera_up_direction; } + double get_camera_field_of_view() const { return camera_field_of_view; } + unsigned long get_num_pixels() const { return num_pixels; } + + inline dpoint operator() ( + const vector& p, + double& scale, + double& distance + ) const + { + vector temp = p-camera_pos; + temp = proj*temp; + distance = temp.z(); + scale = dist_scale/(temp.z()>0 ? temp.z() : 1e-9); + temp.x() = temp.x()*scale + width; + temp.y() = temp.y()*scale + width; + return temp; + } + + dpoint operator() ( + const vector& p + ) const + { + double scale, distance; + return (*this)(p,scale,distance); + } + + inline friend void serialize (const camera_transform& item, std::ostream& out) + { + serialize(item.camera_pos, out); + serialize(item.camera_looking_at, out); + serialize(item.camera_up_direction, out); + serialize(item.camera_field_of_view, out); + serialize(item.num_pixels, out); + serialize(item.proj, out); + serialize(item.dist_scale, out); + serialize(item.width, out); + } + + inline friend void deserialize (camera_transform& item, std::istream& in) + { + deserialize(item.camera_pos, in); + deserialize(item.camera_looking_at, in); + deserialize(item.camera_up_direction, in); + deserialize(item.camera_field_of_view, in); + deserialize(item.num_pixels, in); + deserialize(item.proj, in); + deserialize(item.dist_scale, in); + deserialize(item.width, in); + } + + private: + + vector camera_pos; + vector camera_looking_at; + vector camera_up_direction; + double camera_field_of_view; + unsigned long num_pixels; + matrix proj; + double dist_scale; + double width; + + }; + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/geometry/point_transforms_abstract.h b/lib/3rdParty/dlib/include/dlib/geometry/point_transforms_abstract.h index bfc1195f..492ae745 100644 --- a/lib/3rdParty/dlib/include/dlib/geometry/point_transforms_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/geometry/point_transforms_abstract.h @@ -5,6 +5,8 @@ #include "../matrix/matrix_abstract.h" #include "vector_abstract.h" +#include "rectangle_abstract.h" +#include "drectangle_abstract.h" #include namespace dlib @@ -18,6 +20,10 @@ namespace dlib WHAT THIS OBJECT REPRESENTS This is an object that takes 2D points or vectors and applies an affine transformation to them. + + THREAD SAFETY + It is safe for multiple threads to make concurrent accesses to this object + without synchronization. !*/ public: @@ -74,6 +80,18 @@ namespace dlib // ---------------------------------------------------------------------------------------- + point_transform_affine operator* ( + const point_transform_affine& lhs, + const point_transform_affine& rhs + ); + /*! + ensures + - returns a transformation TFORM(x) that is equivalent to lhs(rhs(x)). That + is, for all valid x: TFORM(x) == lhs(rhs(x)). + !*/ + + // ---------------------------------------------------------------------------------------- + point_transform_affine inv ( const point_transform_affine& trans ); @@ -130,6 +148,77 @@ namespace dlib example, an equilateral triangle to turn into an isosceles triangle. !*/ +// ---------------------------------------------------------------------------------------- + + class rectangle_transform + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is just a point_transform_affine wrapped up so that it can + transform rectangle objects. It will take a rectangle and transform it + according to an affine transformation. + + THREAD SAFETY + It is safe for multiple threads to make concurrent accesses to this object + without synchronization. + !*/ + public: + + rectangle_transform ( + ); + /*! + ensures + - This object will perform the identity transform. That is, given a rectangle + as input it will return the same rectangle as output. + !*/ + + rectangle_transform ( + const point_transform_affine& tform + ); + /*! + ensures + - #get_tform() == tform + !*/ + + drectangle operator() ( + const drectangle& r + ) const; + /*! + ensures + - Applies the transformation get_tform() to r and returns the resulting + rectangle. If the transformation doesn't have any rotation then the + transformation simply maps the corners of the rectangle according to + get_tform() and returns the exact result. However, since + dlib::drectangle can't represent rotated rectangles, if there is any + rotation in the affine transform we will attempt to produce the most + faithful possible outputs by ensuring the output rectangle has the + correct center point and that its area and aspect ratio match the correct + rotated rectangle's as much as possible. + !*/ + + rectangle operator() ( + const rectangle& r + ) const; + /*! + ensures + - returns (*this)(drectangle(r)) + !*/ + + const point_transform_affine& get_tform( + ) const; + /*! + ensures + - returns the affine transformation this object uses to transform rectangles. + !*/ + + }; + + void serialize (const rectangle_transform& item, std::ostream& out); + void deserialize (rectangle_transform& item, std::istream& in); + /*! + provides serialization support + !*/ + // ---------------------------------------------------------------------------------------- class point_transform_projective @@ -138,6 +227,10 @@ namespace dlib WHAT THIS OBJECT REPRESENTS This is an object that takes 2D points or vectors and applies a projective transformation to them. + + THREAD SAFETY + It is safe for multiple threads to make concurrent accesses to this object + without synchronization. !*/ public: @@ -197,6 +290,18 @@ namespace dlib provides serialization support !*/ +// ---------------------------------------------------------------------------------------- + + point_transform_projective operator* ( + const point_transform_projective& lhs, + const point_transform_projective& rhs + ); + /*! + ensures + - returns a transformation TFORM(x) that is equivalent to lhs(rhs(x)). That + is, for all valid x: TFORM(x) == lhs(rhs(x)). + !*/ + // ---------------------------------------------------------------------------------------- point_transform_projective inv ( @@ -236,6 +341,10 @@ namespace dlib This is an object that takes 2D points or vectors and rotates them around the origin by a given angle and then translates them. + + THREAD SAFETY + It is safe for multiple threads to make concurrent accesses to this object + without synchronization. !*/ public: @@ -301,6 +410,10 @@ namespace dlib WHAT THIS OBJECT REPRESENTS This is an object that takes 2D points or vectors and rotates them around the origin by a given angle. + + THREAD SAFETY + It is safe for multiple threads to make concurrent accesses to this object + without synchronization. !*/ public: @@ -384,6 +497,297 @@ namespace dlib the origin in a counter-clockwise direction. !*/ +// ---------------------------------------------------------------------------------------- + + class point_transform_affine3d + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an object that takes 3D points or vectors and + applies an affine transformation to them. + + THREAD SAFETY + It is safe for multiple threads to make concurrent accesses to this object + without synchronization. + !*/ + public: + + point_transform_affine3d ( + ); + /*! + ensures + - This object will perform the identity transform. That is, given a point + as input it will return the same point as output. + !*/ + + point_transform_affine3d ( + const matrix& m, + const dlib::vector& b + ); + /*! + ensures + - #get_m() == m + - #get_b() == b + - When (*this)(p) is invoked it will return a point P such that: + - P == m*p + b + !*/ + + const dlib::vector operator() ( + const dlib::vector& p + ) const; + /*! + ensures + - applies the affine transformation defined by this object's constructor + to p and returns the result. + !*/ + + const matrix& get_m( + ) const; + /*! + ensures + - returns the transformation matrix used by this object. + !*/ + + const dlib::vector& get_b( + ) const; + /*! + ensures + - returns the offset vector used by this object. + !*/ + + }; + + void serialize (const point_transform_affine3d& item, std::ostream& out); + void deserialize (point_transform_affine3d& item, std::istream& in); + /*! + provides serialization support + !*/ + +// ---------------------------------------------------------------------------------------- + + point_transform_affine3d operator* ( + const point_transform_affine3d& lhs, + const point_transform_affine3d& rhs + ); + /*! + ensures + - returns a transformation TFORM(x) that is equivalent to lhs(rhs(x)). That + is, for all valid x: TFORM(x) == lhs(rhs(x)). + !*/ + +// ---------------------------------------------------------------------------------------- + + point_transform_affine3d operator* ( + const point_transform_affine3d& lhs, + const point_transform_affine& rhs + ); + /*! + ensures + - returns a transformation TFORM(x) that is equivalent to lhs(rhs(x)). That + is, for all valid x: TFORM(x) == lhs(rhs(x)). + !*/ + +// ---------------------------------------------------------------------------------------- + + point_transform_affine3d inv ( + const point_transform_affine3d& trans + ); + /*! + ensures + - If trans is an invertible transformation then this function returns a new + transformation that is the inverse of trans. + !*/ + +// ---------------------------------------------------------------------------------------- + + point_transform_affine3d rotate_around_x ( + double angle + ); + /*! + ensures + - Returns a transformation that rotates a point around the x axis in a + counter-clockwise direction by angle radians. That is, the rotation appears + counter-clockwise when the x axis points toward the observer, the coordinate + system is right-handed, and the angle is positive. + !*/ + +// ---------------------------------------------------------------------------------------- + + point_transform_affine3d rotate_around_y ( + double angle + ); + /*! + ensures + - Returns a transformation that rotates a point around the y axis in a + counter-clockwise direction by angle radians. That is, the rotation appears + counter-clockwise when the y axis points toward the observer, the coordinate + system is right-handed, and the angle is positive. + !*/ + +// ---------------------------------------------------------------------------------------- + + point_transform_affine3d rotate_around_z ( + double angle + ); + /*! + ensures + - Returns a transformation that rotates a point around the z axis in a + counter-clockwise direction by angle radians. That is, the rotation appears + counter-clockwise when the z axis points toward the observer, the coordinate + system is right-handed, and the angle is positive. + !*/ + +// ---------------------------------------------------------------------------------------- + + point_transform_affine3d translate_point ( + const vector& delta + ); + /*! + ensures + - returns a transformation that simply translates points by adding delta to + them. That is, this function returns: + point_transform_affine3d(identity_matrix(3),delta); + !*/ + + point_transform_affine3d translate_point ( + double x, + double y, + double z + ); + /*! + ensures + - returns translate_point(vector(x,y,z)) + !*/ + +// ---------------------------------------------------------------------------------------- + + class camera_transform + { + /*! + WHAT THIS OBJECT REPRESENTS + This object maps 3D points into the image plane of a camera. Therefore, + you can use it to compute 2D representations of 3D data from the point of + view of some camera in 3D space. + + THREAD SAFETY + It is safe for multiple threads to make concurrent accesses to this object + without synchronization. + !*/ + + public: + + camera_transform ( + ); + /*! + ensures + - #get_camera_pos() == vector(1,1,1) + - #get_camera_looking_at() == vector(0,0,0) + - #get_camera_up_direction() == vector(0,0,1) + - #get_camera_field_of_view() == 90 + - #get_num_pixels() == 1 + !*/ + + camera_transform ( + const vector& camera_pos, + const vector& camera_looking_at, + const vector& camera_up_direction, + const double camera_field_of_view, + const unsigned long num_pixels + ); + /*! + requires + - 0 < camera_field_of_view < 180 + ensures + - #get_camera_pos() == camera_pos + - #get_camera_looking_at() == camera_looking_at + - #get_camera_up_direction() == camera_up_direction + - #get_camera_field_of_view() == camera_field_of_view + - #get_num_pixels() == num_pixels + !*/ + + dpoint operator() ( + const vector& p + ) const; + /*! + ensures + - Maps the given 3D point p into the 2D image plane defined by the camera + parameters given to this object's constructor. The 2D point in the image + plane is returned. + !*/ + + dpoint operator() ( + const vector& p, + double& scale, + double& distance + ) const; + /*! + ensures + - Maps the given 3D point p into the 2D image plane defined by the camera + parameters given to this object's constructor. The 2D point in the image + plane is returned. + - #scale == a number that tells you how large things are at the point p. + Objects further from the camera appear smaller, in particular, they + appear #scale times their normal size. + - #distance == how far away the point is from the image plane. Objects in + front of the camera will have a positive distance and those behind a + negative distance. + !*/ + + vector get_camera_pos( + ) const; + /*! + ensures + - returns the position, in 3D space, of the camera. When operator() is + invoked it maps 3D points into the image plane of this camera. + !*/ + + vector get_camera_looking_at( + ) const; + /*! + ensures + - returns the point in 3D space the camera is pointed at. + !*/ + + vector get_camera_up_direction( + ) const; + /*! + ensures + - returns a vector that defines what direction is "up" for the camera. + This means that as you travel from the bottom of the image plane to the + top you will be traveling in the direction of this vector. Note that + get_camera_up_direction() doesn't need to be orthogonal to the camera's + line of sight (i.e. get_camera_looking_at()-get_camera_pos()), it just + needs to not be an exact multiple of the line of sight. Any necessary + orthogonalization will be taken care of internally. + !*/ + + double get_camera_field_of_view( + ) const; + /*! + ensures + - returns the field of view of the camera in degrees. + !*/ + + unsigned long get_num_pixels( + ) const; + /*! + ensures + - 3D points that fall within the field of view of the camera are mapped by + operator() into the pixel coordinates of a get_num_pixels() by + get_num_pixels() image. Therefore, you can use the output of operator() + to index into an image. However, you still need to perform bounds + checking as there might be 3D points outside the field of view of the + camera and those will be mapped to 2D points outside the image. + !*/ + + }; + + void serialize (const camera_transform& item, std::ostream& out); + void deserialize (camera_transform& item, std::istream& in); + /*! + provides serialization support + !*/ + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/geometry/rectangle.h b/lib/3rdParty/dlib/include/dlib/geometry/rectangle.h index 6d8e9793..ef254196 100644 --- a/lib/3rdParty/dlib/include/dlib/geometry/rectangle.h +++ b/lib/3rdParty/dlib/include/dlib/geometry/rectangle.h @@ -260,6 +260,19 @@ namespace dlib return !(*this == rect); } + inline bool operator< (const dlib::rectangle& b) const + { + if (left() < b.left()) return true; + else if (left() > b.left()) return false; + else if (top() < b.top()) return true; + else if (top() > b.top()) return false; + else if (right() < b.right()) return true; + else if (right() > b.right()) return false; + else if (bottom() < b.bottom()) return true; + else if (bottom() > b.bottom()) return false; + else return false; + } + private: long l; long t; @@ -450,6 +463,103 @@ namespace dlib return temp; } +// ---------------------------------------------------------------------------------------- + + inline size_t nearest_rect ( + const std::vector& rects, + const point& p + ) + { + DLIB_ASSERT(rects.size() > 0); + size_t idx = 0; + double best_dist = std::numeric_limits::infinity(); + + for (size_t i = 0; i < rects.size(); ++i) + { + if (rects[i].contains(p)) + { + return i; + } + else + { + double dist = (nearest_point(rects[i],p)-p).length(); + if (dist < best_dist) + { + best_dist = dist; + idx = i; + } + } + } + return idx; + } + +// ---------------------------------------------------------------------------------------- + + inline void clip_line_to_rectangle ( + const rectangle& box, + point& p1, + point& p2 + ) + { + // Now clip the line segment so it is contained inside box. + if (p1.x() == p2.x()) + { + if (!box.contains(p1)) + p1.y() = box.top(); + if (!box.contains(p2)) + p2.y() = box.bottom(); + } + else if (p1.y() == p2.y()) + { + if (!box.contains(p1)) + p1.x() = box.left(); + if (!box.contains(p2)) + p2.x() = box.right(); + } + else + { + // We use these relations to find alpha values. These values tell us + // how to generate points intersecting the rectangle boundaries. We then + // test the resulting points for ones that are inside the rectangle and output + // those. + //box.left() == alpha1*(p1.x()-p2.x()) + p2.x(); + //box.right() == alpha2*(p1.x()-p2.x()) + p2.x(); + + const point d = p1-p2; + double alpha1 = (box.left() -p2.x())/(double)d.x(); + double alpha2 = (box.right() -p2.x())/(double)d.x(); + double alpha3 = (box.top() -p2.y())/(double)d.y(); + double alpha4 = (box.bottom()-p2.y())/(double)d.y(); + + const point c1 = alpha1*d + p2; + const point c2 = alpha2*d + p2; + const point c3 = alpha3*d + p2; + const point c4 = alpha4*d + p2; + + if (!box.contains(p1)) + p1 = c1; + if (!box.contains(p2)) + p2 = c2; + if (box.contains(c3)) + { + if (!box.contains(p2)) + p2 = c3; + else if (!box.contains(p1)) + p1 = c3; + } + if (box.contains(c4)) + { + if (!box.contains(p2)) + p2 = c4; + else if (!box.contains(p1)) + p1 = c4; + } + } + + p1 = nearest_point(box, p1); + p2 = nearest_point(box, p2); + } + // ---------------------------------------------------------------------------------------- inline const rectangle centered_rect ( @@ -461,6 +571,21 @@ namespace dlib return centered_rect(p.x(),p.y(),width,height); } +// ---------------------------------------------------------------------------------------- + + inline std::vector centered_rects ( + const std::vector& pts, + unsigned long width, + unsigned long height + ) + { + std::vector tmp; + tmp.reserve(pts.size()); + for (auto& p : pts) + tmp.emplace_back(centered_rect(p, width, height)); + return tmp; + } + // ---------------------------------------------------------------------------------------- inline const rectangle centered_rect ( @@ -603,6 +728,29 @@ namespace dlib return rectangle(x, y, x+rect.width()-1, y+rect.height()-1); } +// ---------------------------------------------------------------------------------------- + + inline rectangle set_rect_area ( + const rectangle& rect, + unsigned long area + ) + { + DLIB_ASSERT(area > 0); + + if (rect.area() == 0) + { + // In this case we will make the output rectangle a square with the requested + // area. + unsigned long scale = std::round(std::sqrt(area)); + return centered_rect(rect, scale, scale); + } + else + { + double scale = std::sqrt(area/(double)rect.area()); + return centered_rect(rect, (long)std::round(rect.width()*scale), (long)std::round(rect.height()*scale)); + } + } + // ---------------------------------------------------------------------------------------- inline rectangle set_aspect_ratio ( @@ -673,29 +821,6 @@ namespace dlib } -namespace std -{ - /*! - Define std::less so that you can use rectangles in the associative containers. - !*/ - template<> - struct less : public binary_function - { - inline bool operator() (const dlib::rectangle& a, const dlib::rectangle& b) const - { - if (a.left() < b.left()) return true; - else if (a.left() > b.left()) return false; - else if (a.top() < b.top()) return true; - else if (a.top() > b.top()) return false; - else if (a.right() < b.right()) return true; - else if (a.right() > b.right()) return false; - else if (a.bottom() < b.bottom()) return true; - else if (a.bottom() > b.bottom()) return false; - else return false; - } - }; -} - #endif // DLIB_RECTANGLe_ diff --git a/lib/3rdParty/dlib/include/dlib/geometry/rectangle_abstract.h b/lib/3rdParty/dlib/include/dlib/geometry/rectangle_abstract.h index 118ccd42..ca282bcf 100644 --- a/lib/3rdParty/dlib/include/dlib/geometry/rectangle_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/geometry/rectangle_abstract.h @@ -363,6 +363,16 @@ namespace dlib ensures - returns !(*this == rect) !*/ + + bool operator< ( + const dlib::rectangle& a, + const dlib::rectangle& b + ) const; + /*! + ensures + - Defines a total ordering over rectangles so they can be used in + associative containers. + !*/ }; // ---------------------------------------------------------------------------------------- @@ -442,6 +452,20 @@ namespace dlib - R.tl_corner() == point(p.x()-width/2, p.y()-height/2) !*/ +// ---------------------------------------------------------------------------------------- + + inline std::vector centered_rects ( + const std::vector& pts, + unsigned long width, + unsigned long height + ); + /*! + ensures + - returns an array ARR where: + - #ARR.size() == pts.size() + - #ARR[i] == centered_rect(pts[i], width, height) + !*/ + // ---------------------------------------------------------------------------------------- const rectangle centered_rect ( @@ -477,6 +501,23 @@ namespace dlib and height) !*/ +// ---------------------------------------------------------------------------------------- + + inline rectangle set_rect_area ( + const rectangle& rect, + unsigned long area + ); + /*! + requires + - area > 0 + ensures + - Returns a rectangle R such that: + - center(R) == center(rect) + - R has the same aspect ratio as rect. If rect.area() == 0 then the + returned rect has a 1:1 aspect ratio. + - R.area() == area + !*/ + // ---------------------------------------------------------------------------------------- inline rectangle set_aspect_ratio ( @@ -694,6 +735,22 @@ namespace dlib - returns the point in rect that is closest to p !*/ +// ---------------------------------------------------------------------------------------- + + inline size_t nearest_rect ( + const std::vector& rects, + const point& p + ); + /*! + requires + - rects.size() > 0 + ensures + - returns the index of the rectangle that is closest to the point p. In + particular, this function returns an IDX such that: + length(nearest_point(rects[IDX],p) - p) + is minimized. + !*/ + // ---------------------------------------------------------------------------------------- inline long distance_to_rect_edge ( @@ -705,6 +762,26 @@ namespace dlib - returns the Manhattan distance between the edge of rect and p. !*/ +// ---------------------------------------------------------------------------------------- + + void clip_line_to_rectangle ( + const rectangle& box, + point& p1, + point& p2 + ); + /*! + ensures + - clips the line segment that goes from points p1 to p2 so that it is entirely + within the given box. In particular, we will have: + - box.contains(#p1) == true + - box.contains(#p2) == true + - The line segment #p1 to #p2 is entirely contained within the line segment + p1 to p2. Moreover, #p1 to #p2 is the largest such line segment that + fits within the given box. + - If the line segment does not intersect the box then the result is some + arbitrary line segment inside the box. + !*/ + // ---------------------------------------------------------------------------------------- template < @@ -754,28 +831,5 @@ namespace dlib } -namespace std -{ - /*! - Define std::less so that you can use rectangles in the associative containers. - !*/ - template<> - struct less : public binary_function - { - inline bool operator() (const dlib::rectangle& a, const dlib::rectangle& b) const - { - if (a.left() < b.left()) return true; - else if (a.left() > b.left()) return false; - else if (a.top() < b.top()) return true; - else if (a.top() > b.top()) return false; - else if (a.right() < b.right()) return true; - else if (a.right() > b.right()) return false; - else if (a.bottom() < b.bottom()) return true; - else if (a.bottom() > b.bottom()) return false; - else return false; - } - }; -} - #endif // DLIB_RECTANGLe_ABSTRACT_ diff --git a/lib/3rdParty/dlib/include/dlib/geometry/vector.h b/lib/3rdParty/dlib/include/dlib/geometry/vector.h index 7f2e50c2..e6ec15e4 100644 --- a/lib/3rdParty/dlib/include/dlib/geometry/vector.h +++ b/lib/3rdParty/dlib/include/dlib/geometry/vector.h @@ -11,6 +11,7 @@ #include #include "../matrix/matrix.h" #include +#include #if defined(_MSC_VER) && _MSC_VER < 1400 // Despite my efforts to disabuse visual studio of its usual nonsense I can't find a @@ -345,6 +346,14 @@ namespace dlib // --------------------------------------- + double length_squared( + ) const + { + return (double)(x()*x() + y()*y() + z()*z()); + } + + // --------------------------------------- + typename vc_rebind::type normalize ( ) const { @@ -697,6 +706,13 @@ namespace dlib // --------------------------------------- + double length_squared( + ) const + { + return (double)(x()*x() + y()*y()); + } + + // --------------------------------------- typename vc_rebind::type normalize ( ) const @@ -1257,6 +1273,39 @@ namespace dlib // ---------------------------------------------------------------------------------------- typedef vector point; + typedef vector dpoint; + +// ---------------------------------------------------------------------------------------- + + inline bool is_convex_quadrilateral ( + const std::array& pts + ) + { + auto orientation = [&](size_t i) + { + size_t a = (i+1)%4; + size_t b = (i+3)%4; + return (pts[a]-pts[i]).cross(pts[b]-pts[i]).z(); + }; + + // If pts has any infinite points then this isn't a valid quadrilateral. + for (auto& p : pts) + { + if (p.x() == std::numeric_limits::infinity()) + return false; + if (p.y() == std::numeric_limits::infinity()) + return false; + } + + double s0 = orientation(0); + double s1 = orientation(1); + double s2 = orientation(2); + double s3 = orientation(3); + + // if all these things have the same sign then it's convex. + return (s0>0&&s1>0&&s2>0&&s3>0) || (s0<0&&s1<0&&s2<0&&s3<0); + } + // ---------------------------------------------------------------------------------------- @@ -1268,8 +1317,11 @@ namespace std Define std::less > so that you can use vectors in the associative containers. !*/ template - struct less > : public binary_function ,dlib::vector ,bool> + struct less > { + typedef dlib::vector first_argument_type; + typedef dlib::vector second_argument_type; + typedef bool result_type; inline bool operator() (const dlib::vector & a, const dlib::vector & b) const { if (a.x() < b.x()) return true; @@ -1286,8 +1338,11 @@ namespace std Define std::less > so that you can use vectors in the associative containers. !*/ template - struct less > : public binary_function ,dlib::vector ,bool> + struct less > { + typedef dlib::vector first_argument_type; + typedef dlib::vector second_argument_type; + typedef bool result_type; inline bool operator() (const dlib::vector & a, const dlib::vector & b) const { if (a.x() < b.x()) return true; diff --git a/lib/3rdParty/dlib/include/dlib/geometry/vector_abstract.h b/lib/3rdParty/dlib/include/dlib/geometry/vector_abstract.h index d5c865c9..9c6db109 100644 --- a/lib/3rdParty/dlib/include/dlib/geometry/vector_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/geometry/vector_abstract.h @@ -152,6 +152,13 @@ namespace dlib - returns the length of the vector !*/ + double length_squared( + ) const; + /*! + ensures + - returns length()*length() + !*/ + T& x ( ); /*! @@ -431,6 +438,24 @@ namespace dlib typedef vector point; + /*!A dpoint + This is just a typedef of the vector object. + !*/ + + typedef vector dpoint; + +// ---------------------------------------------------------------------------------------- + + bool is_convex_quadrilateral ( + const std::array& pts + ); + /*! + ensures + - If you walk the points in pts in order pts[0], pts[1], pts[2], pts[3], pts[0] + does it draw a convex quadrilateral? This routine returns true if yes and + false if not. + !*/ + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/global_optimization.h b/lib/3rdParty/dlib/include/dlib/global_optimization.h new file mode 100644 index 00000000..26b40fcd --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/global_optimization.h @@ -0,0 +1,14 @@ +// Copyright (C) 2017 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_GLOBAL_OPTIMIZATIOn_HEADER +#define DLIB_GLOBAL_OPTIMIZATIOn_HEADER + +#include "global_optimization/upper_bound_function.h" +#include "global_optimization/global_function_search.h" +#include "global_optimization/find_max_global.h" + +#endif // DLIB_GLOBAL_OPTIMIZATIOn_HEADER + + + + diff --git a/lib/3rdParty/dlib/include/dlib/global_optimization/find_max_global.h b/lib/3rdParty/dlib/include/dlib/global_optimization/find_max_global.h new file mode 100644 index 00000000..5356129f --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/global_optimization/find_max_global.h @@ -0,0 +1,511 @@ +// Copyright (C) 2017 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_FiND_GLOBAL_MAXIMUM_hH_ +#define DLIB_FiND_GLOBAL_MAXIMUM_hH_ + +#include "find_max_global_abstract.h" +#include "global_function_search.h" +#include "../metaprogramming.h" +#include +#include + +namespace dlib +{ + namespace gopt_impl + { + + // ---------------------------------------------------------------------------------------- + + class disable_decay_to_scalar + { + const matrix& a; + public: + disable_decay_to_scalar(const matrix& a) : a(a){} + operator const matrix&() const { return a;} + }; + + + template + auto _cwv ( + T&& f, + const matrix& a, + compile_time_integer_list + ) -> decltype(f(a(indices-1)...)) + { + DLIB_CASSERT(a.size() == sizeof...(indices), + "You invoked dlib::call_function_and_expand_args(f,a) but the number of arguments expected by f() doesn't match the size of 'a'. " + << "Expected " << sizeof...(indices) << " arguments but got " << a.size() << "." + ); + return f(a(indices-1)...); + } + + // Visual studio, as of November 2017, doesn't support C++11 and can't compile this code. + // So we write the terrible garbage in the #else for visual studio. When Visual Studio supports C++11 I'll update this #ifdef to use the C++11 code. +#ifndef _MSC_VER + template + struct call_function_and_expand_args + { + template + static auto go(T&& f, const matrix& a) -> decltype(_cwv(std::forward(f),a,typename make_compile_time_integer_range::type())) + { + return _cwv(std::forward(f),a,typename make_compile_time_integer_range::type()); + } + + template + static auto go(T&& f, const matrix& a) -> decltype(call_function_and_expand_args::template go(std::forward(f),a)) + { + return call_function_and_expand_args::go(std::forward(f),a); + } + }; + + template <> + struct call_function_and_expand_args<0> + { + template + static auto go(T&& f, const matrix& a) -> decltype(f(disable_decay_to_scalar(a))) + { + return f(disable_decay_to_scalar(a)); + } + }; +#else + template + struct call_function_and_expand_args + { +template static auto go(T&& f, const matrix& a) -> decltype(f(disable_decay_to_scalar(a))) {return f(disable_decay_to_scalar(a)); } +template static auto go(T&& f, const matrix& a) -> decltype(f(a(0))) { DLIB_CASSERT(a.size() == 1); return f(a(0)); } +template static auto go(T&& f, const matrix& a) -> decltype(f(a(0),a(1))) { DLIB_CASSERT(a.size() == 2); return f(a(0),a(1)); } +template static auto go(T&& f, const matrix& a) -> decltype(f(a(0), a(1), a(2))) { DLIB_CASSERT(a.size() == 3); return f(a(0), a(1),a(2)); } +template static auto go(T&& f, const matrix& a) -> decltype(f(a(0), a(1), a(2), a(3))) { DLIB_CASSERT(a.size() == 4); return f(a(0), a(1), a(2), a(3)); } +template static auto go(T&& f, const matrix& a) -> decltype(f(a(0), a(1), a(2), a(3), a(4))) { DLIB_CASSERT(a.size() == 5); return f(a(0), a(1), a(2), a(3), a(4)); } +template static auto go(T&& f, const matrix& a) -> decltype(f(a(0), a(1), a(2), a(3), a(4), a(5))) { DLIB_CASSERT(a.size() == 6); return f(a(0), a(1), a(2), a(3), a(4), a(5)); } +template static auto go(T&& f, const matrix& a) -> decltype(f(a(0), a(1), a(2), a(3), a(4), a(5), a(6))) { DLIB_CASSERT(a.size() == 7); return f(a(0), a(1), a(2), a(3), a(4), a(5), a(6)); } + }; +#endif + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template + auto call_function_and_expand_args( + T&& f, + const matrix& a + ) -> decltype(gopt_impl::call_function_and_expand_args<40>::go(f,a)) + { + // unpack up to 40 parameters when calling f() + return gopt_impl::call_function_and_expand_args<40>::go(std::forward(f),a); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + struct max_function_calls + { + max_function_calls() = default; + explicit max_function_calls(size_t max_calls) : max_calls(max_calls) {} + size_t max_calls = std::numeric_limits::max(); + }; + +// ---------------------------------------------------------------------------------------- + + const auto FOREVER = std::chrono::hours(24*356*290); // 290 years + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template < + typename funct + > + std::pair find_max_global ( + std::vector& functions, + std::vector specs, + const max_function_calls num, + const std::chrono::nanoseconds max_runtime, + double solver_epsilon, + double ymult + ) + { + // Decide which parameters should be searched on a log scale. Basically, it's + // common for machine learning models to have parameters that should be searched on + // a log scale (e.g. SVM C). These parameters are usually identifiable because + // they have bounds like [1e-5 1e10], that is, they span a very large range of + // magnitudes from really small to really big. So there we are going to check for + // that and if we find parameters with that kind of bound constraints we will + // transform them to a log scale automatically. + std::vector> log_scale(specs.size()); + for (size_t i = 0; i < specs.size(); ++i) + { + for (long j = 0; j < specs[i].lower.size(); ++j) + { + if (!specs[i].is_integer_variable[j] && specs[i].lower(j) > 0 && specs[i].upper(j)/specs[i].lower(j) >= 1000) + { + log_scale[i].push_back(true); + specs[i].lower(j) = std::log(specs[i].lower(j)); + specs[i].upper(j) = std::log(specs[i].upper(j)); + } + else + { + log_scale[i].push_back(false); + } + } + } + + global_function_search opt(specs); + opt.set_solver_epsilon(solver_epsilon); + + const auto time_to_stop = std::chrono::steady_clock::now() + max_runtime; + + // Now run the main solver loop. + for (size_t i = 0; i < num.max_calls && std::chrono::steady_clock::now() < time_to_stop; ++i) + { + auto next = opt.get_next_x(); + matrix x = next.x(); + // Undo any log-scaling that was applied to the variables before we pass them + // to the functions being optimized. + for (long j = 0; j < x.size(); ++j) + { + if (log_scale[next.function_idx()][j]) + x(j) = std::exp(x(j)); + } + double y = ymult*call_function_and_expand_args(functions[next.function_idx()], x); + next.set(y); + } + + + matrix x; + double y; + size_t function_idx; + opt.get_best_function_eval(x,y,function_idx); + // Undo any log-scaling that was applied to the variables before we output them. + for (long j = 0; j < x.size(); ++j) + { + if (log_scale[function_idx][j]) + x(j) = std::exp(x(j)); + } + return std::make_pair(function_idx, function_evaluation(x,y/ymult)); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + std::pair find_max_global ( + std::vector& functions, + std::vector specs, + const max_function_calls num, + const std::chrono::nanoseconds max_runtime = FOREVER, + double solver_epsilon = 0 + ) + { + return impl::find_max_global(functions, std::move(specs), num, max_runtime, solver_epsilon, +1); + } + + template < + typename funct + > + std::pair find_min_global ( + std::vector& functions, + std::vector specs, + const max_function_calls num, + const std::chrono::nanoseconds max_runtime = FOREVER, + double solver_epsilon = 0 + ) + { + return impl::find_max_global(functions, std::move(specs), num, max_runtime, solver_epsilon, -1); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + function_evaluation find_max_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const std::vector& is_integer_variable, + const max_function_calls num, + const std::chrono::nanoseconds max_runtime = FOREVER, + double solver_epsilon = 0 + ) + { + std::vector functions(1,std::move(f)); + std::vector specs(1, function_spec(bound1, bound2, is_integer_variable)); + return find_max_global(functions, std::move(specs), num, max_runtime, solver_epsilon).second; + } + + template < + typename funct + > + function_evaluation find_min_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const std::vector& is_integer_variable, + const max_function_calls num, + const std::chrono::nanoseconds max_runtime = FOREVER, + double solver_epsilon = 0 + ) + { + std::vector functions(1,std::move(f)); + std::vector specs(1, function_spec(bound1, bound2, is_integer_variable)); + return find_min_global(functions, std::move(specs), num, max_runtime, solver_epsilon).second; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + function_evaluation find_max_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const std::vector& is_integer_variable, + const max_function_calls num, + double solver_epsilon + ) + { + return find_max_global(std::move(f), bound1, bound2, is_integer_variable, num, FOREVER, solver_epsilon); + } + + template < + typename funct + > + function_evaluation find_min_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const std::vector& is_integer_variable, + const max_function_calls num, + double solver_epsilon + ) + { + return find_min_global(std::move(f), bound1, bound2, is_integer_variable, num, FOREVER, solver_epsilon); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + function_evaluation find_max_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const max_function_calls num, + const std::chrono::nanoseconds max_runtime = FOREVER, + double solver_epsilon = 0 + ) + { + return find_max_global(std::move(f), bound1, bound2, std::vector(bound1.size(),false), num, max_runtime, solver_epsilon); + } + + template < + typename funct + > + function_evaluation find_min_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const max_function_calls num, + const std::chrono::nanoseconds max_runtime = FOREVER, + double solver_epsilon = 0 + ) + { + return find_min_global(std::move(f), bound1, bound2, std::vector(bound1.size(),false), num, max_runtime, solver_epsilon); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + function_evaluation find_max_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const max_function_calls num, + double solver_epsilon + ) + { + return find_max_global(std::move(f), bound1, bound2, std::vector(bound1.size(),false), num, FOREVER, solver_epsilon); + } + + template < + typename funct + > + function_evaluation find_min_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const max_function_calls num, + double solver_epsilon + ) + { + return find_min_global(std::move(f), bound1, bound2, std::vector(bound1.size(),false), num, FOREVER, solver_epsilon); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + function_evaluation find_max_global ( + funct f, + const double bound1, + const double bound2, + const max_function_calls num, + const std::chrono::nanoseconds max_runtime = FOREVER, + double solver_epsilon = 0 + ) + { + return find_max_global(std::move(f), matrix({bound1}), matrix({bound2}), num, max_runtime, solver_epsilon); + } + + template < + typename funct + > + function_evaluation find_min_global ( + funct f, + const double bound1, + const double bound2, + const max_function_calls num, + const std::chrono::nanoseconds max_runtime = FOREVER, + double solver_epsilon = 0 + ) + { + return find_min_global(std::move(f), matrix({bound1}), matrix({bound2}), num, max_runtime, solver_epsilon); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + function_evaluation find_max_global ( + funct f, + const double bound1, + const double bound2, + const max_function_calls num, + double solver_epsilon + ) + { + return find_max_global(std::move(f), matrix({bound1}), matrix({bound2}), num, FOREVER, solver_epsilon); + } + + template < + typename funct + > + function_evaluation find_min_global ( + funct f, + const double bound1, + const double bound2, + const max_function_calls num, + double solver_epsilon + ) + { + return find_min_global(std::move(f), matrix({bound1}), matrix({bound2}), num, FOREVER, solver_epsilon); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + function_evaluation find_max_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const std::chrono::nanoseconds max_runtime, + double solver_epsilon = 0 + ) + { + return find_max_global(std::move(f), bound1, bound2, max_function_calls(), max_runtime, solver_epsilon); + } + + template < + typename funct + > + function_evaluation find_min_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const std::chrono::nanoseconds max_runtime, + double solver_epsilon = 0 + ) + { + return find_min_global(std::move(f), bound1, bound2, max_function_calls(), max_runtime, solver_epsilon); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + function_evaluation find_max_global ( + funct f, + const double bound1, + const double bound2, + const std::chrono::nanoseconds max_runtime, + double solver_epsilon = 0 + ) + { + return find_max_global(std::move(f), bound1, bound2, max_function_calls(), max_runtime, solver_epsilon); + } + + template < + typename funct + > + function_evaluation find_min_global ( + funct f, + const double bound1, + const double bound2, + const std::chrono::nanoseconds max_runtime, + double solver_epsilon = 0 + ) + { + return find_min_global(std::move(f), bound1, bound2, max_function_calls(), max_runtime, solver_epsilon); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + function_evaluation find_max_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const std::vector& is_integer_variable, + const std::chrono::nanoseconds max_runtime, + double solver_epsilon = 0 + ) + { + return find_max_global(std::move(f), bound1, bound2, is_integer_variable, max_function_calls(), max_runtime, solver_epsilon); + } + + template < + typename funct + > + function_evaluation find_min_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const std::vector& is_integer_variable, + const std::chrono::nanoseconds max_runtime, + double solver_epsilon = 0 + ) + { + return find_min_global(std::move(f), bound1, bound2, is_integer_variable, max_function_calls(), max_runtime, solver_epsilon); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_FiND_GLOBAL_MAXIMUM_hH_ + diff --git a/lib/3rdParty/dlib/include/dlib/global_optimization/find_max_global_abstract.h b/lib/3rdParty/dlib/include/dlib/global_optimization/find_max_global_abstract.h new file mode 100644 index 00000000..4be62b15 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/global_optimization/find_max_global_abstract.h @@ -0,0 +1,496 @@ +// Copyright (C) 2017 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_FiND_GLOBAL_MAXIMUM_ABSTRACT_hH_ +#ifdef DLIB_FiND_GLOBAL_MAXIMUM_ABSTRACT_hH_ + +#include "upper_bound_function_abstract.h" +#include "global_function_search_abstract.h" +#include "../metaprogramming.h" +#include "../matrix.h" +#include +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + auto call_function_and_expand_args( + T&& f, + const matrix& args + ) -> decltype(f(args or args expanded out as discussed below)); + /*! + requires + - f is a function object with one of the following signatures: + auto f(matrix) + auto f(double) + auto f(double,double) + auto f(double,double,double) + ... + auto f(double,double,...,double) // up to 40 double arguments + - if (f() explicitly expands its arguments) then + - args.size() == the number of arguments taken by f. + ensures + - This function invokes f() with the given arguments and returns the result. + However, the signature of f() is allowed to vary. In particular, if f() + takes a matrix as a single argument then this function simply + calls f(args). However, if f() takes double arguments then args is expanded + appropriately, i.e. it calls one of the following as appropriate: + f(args(0)) + f(args(0),args(1)) + ... + f(args(0),args(1),...,args(N)) + and the result of f() is returned. + !*/ + +// ---------------------------------------------------------------------------------------- + + struct max_function_calls + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a simple typed integer class used to strongly type the "max number + of function calls" argument to find_max_global() and find_min_global(). + + !*/ + + max_function_calls() = default; + + explicit max_function_calls(size_t max_calls) : max_calls(max_calls) {} + + size_t max_calls = std::numeric_limits::max(); + }; + +// ---------------------------------------------------------------------------------------- + + const auto FOREVER = std::chrono::hours(24*356*290); // 290 years, basically forever + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + std::pair find_max_global ( + std::vector& functions, + const std::vector& specs, + const max_function_calls num, + const std::chrono::nanoseconds max_runtime = FOREVER, + double solver_epsilon = 0 + ); + /*! + requires + - functions.size() != 0 + - functions.size() == specs.size() + - solver_epsilon >= 0 + - for all valid i: + - functions[i] is a real valued multi-variate function object. Moreover, + it must be callable via an expression of the form: + call_function_and_expand_args(functions[i], specs.lower). This means + function[i] should have a signature like one of the following: + double f(matrix) + double f(double) + double f(double,double) + etc. + - The range of inputs defined by specs[i] must be valid inputs to + functions[i]. + ensures + - This function performs global optimization on the set of given functions. + The goal is to maximize the following objective function: + max_{i,x_i}: functions[i](x_i) + subject to the constraints on x_i defined by specs[i]. + Once found, the return value of find_max_global() is: + make_pair(i, function_evaluation(x_i,functions[i](x_i))). + That is, we search for the settings of i and x that return the largest output + and return those settings. + - The search is performed using the global_function_search object. See its + documentation for details of the algorithm. + - We set the global_function_search::get_solver_epsilon() parameter to + solver_epsilon. Therefore, the search will only attempt to find a global + maximizer to at most solver_epsilon accuracy. Once a local maximizer is + found to that accuracy the search will focus entirely on finding other maxima + elsewhere rather than on further improving the current local optima found so + far. That is, once a local maxima is identified to about solver_epsilon + accuracy, the algorithm will spend all its time exploring the functions to + find other local maxima to investigate. An epsilon of 0 means it will keep + solving until it reaches full floating point precision. Larger values will + cause it to switch to pure global exploration sooner and therefore might be + more effective if your objective function has many local maxima and you don't + care about a super high precision solution. + - find_max_global() runs until one of the following is true: + - The total number of calls to the provided functions is == num.max_calls + - More than max_runtime time has elapsed since the start of this function. + - Any variables that satisfy the following conditions are optimized on a log-scale: + - The lower bound on the variable is > 0 + - The ratio of the upper bound to lower bound is >= 1000 + - The variable is not an integer variable + We do this because it's common to optimize machine learning models that have + parameters with bounds in a range such as [1e-5 to 1e10] (e.g. the SVM C + parameter) and it's much more appropriate to optimize these kinds of + variables on a log scale. So we transform them by applying std::log() to + them and then undo the transform via std::exp() before invoking the function + being optimized. Therefore, this transformation is invisible to the user + supplied functions. In most cases, it improves the efficiency of the + optimizer. + !*/ + + template < + typename funct + > + std::pair find_min_global ( + std::vector& functions, + const std::vector& specs, + const max_function_calls num, + const std::chrono::nanoseconds max_runtime = FOREVER, + double solver_epsilon = 0 + ); + /*! + This function is identical to the find_max_global() defined immediately above, + except that we perform minimization rather than maximization. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + function_evaluation find_max_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const std::vector& is_integer_variable, + const max_function_calls num, + const std::chrono::nanoseconds max_runtime = FOREVER, + double solver_epsilon = 0 + ); + /*! + requires + - bound1.size() == bound2.size() == is_integer_variable.size() + - for all valid i: bound1(i) != bound2(i) + - solver_epsilon >= 0 + - f() is a real valued multi-variate function object. Moreover, it must be + callable via an expression of the form: call_function_and_expand_args(f, + bound1). This means f() should have a signature like one of the following: + double f(matrix) + double f(double) + double f(double,double) + etc. + - The range of inputs defined by function_spec(bound1,bound2,is_integer_variable) + must be valid inputs to f(). + ensures + - This function performs global optimization on the given f() function. + The goal is to maximize the following objective function: + f(x) + subject to the constraints on x defined by function_spec(bound1,bound2,is_integer_variable). + Once found, the return value of find_max_global() is: + function_evaluation(x,f(x))). + That is, we search for the setting of x that returns the largest output and + return that setting. + - The search is performed using the global_function_search object. See its + documentation for details of the algorithm. + - We set the global_function_search::get_solver_epsilon() parameter to + solver_epsilon. Therefore, the search will only attempt to find a global + maximizer to at most solver_epsilon accuracy. Once a local maximizer is + found to that accuracy the search will focus entirely on finding other maxima + elsewhere rather than on further improving the current local optima found so + far. That is, once a local maxima is identified to about solver_epsilon + accuracy, the algorithm will spend all its time exploring the function to + find other local maxima to investigate. An epsilon of 0 means it will keep + solving until it reaches full floating point precision. Larger values will + cause it to switch to pure global exploration sooner and therefore might be + more effective if your objective function has many local maxima and you don't + care about a super high precision solution. + - find_max_global() runs until one of the following is true: + - The total number of calls to f() is == num.max_calls + - More than max_runtime time has elapsed since the start of this function. + - Any variables that satisfy the following conditions are optimized on a log-scale: + - The lower bound on the variable is > 0 + - The ratio of the upper bound to lower bound is >= 1000 + - The variable is not an integer variable + We do this because it's common to optimize machine learning models that have + parameters with bounds in a range such as [1e-5 to 1e10] (e.g. the SVM C + parameter) and it's much more appropriate to optimize these kinds of + variables on a log scale. So we transform them by applying std::log() to + them and then undo the transform via std::exp() before invoking the function + being optimized. Therefore, this transformation is invisible to the user + supplied functions. In most cases, it improves the efficiency of the + optimizer. + !*/ + + template < + typename funct + > + function_evaluation find_min_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const std::vector& is_integer_variable, + const max_function_calls num, + const std::chrono::nanoseconds max_runtime = FOREVER, + double solver_epsilon = 0 + ); + /*! + This function is identical to the find_max_global() defined immediately above, + except that we perform minimization rather than maximization. + !*/ + +// ---------------------------------------------------------------------------------------- +// The following functions are just convenient overloads for calling the above defined +// find_max_global() and find_min_global() routines. +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + function_evaluation find_max_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const std::vector& is_integer_variable, + const max_function_calls num, + double solver_epsilon + ) + { + return find_max_global(std::move(f), bound1, bound2, std::vector(bound1.size(),false), num, FOREVER, solver_epsilon); + } + + template < + typename funct + > + function_evaluation find_min_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const std::vector& is_integer_variable, + const max_function_calls num, + double solver_epsilon + ) + { + return find_min_global(std::move(f), bound1, bound2, std::vector(bound1.size(),false), num, FOREVER, solver_epsilon); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + function_evaluation find_max_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const max_function_calls num, + const std::chrono::nanoseconds max_runtime = FOREVER, + double solver_epsilon = 0 + ) + { + return find_max_global(std::move(f), bound1, bound2, std::vector(bound1.size(),false), num, max_runtime, solver_epsilon); + } + + template < + typename funct + > + function_evaluation find_min_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const max_function_calls num, + const std::chrono::nanoseconds max_runtime = FOREVER, + double solver_epsilon = 0 + ) + { + return find_min_global(std::move(f), bound1, bound2, std::vector(bound1.size(),false), num, max_runtime, solver_epsilon); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + function_evaluation find_max_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const max_function_calls num, + double solver_epsilon + ) + { + return find_max_global(std::move(f), bound1, bound2, std::vector(bound1.size(),false), num, FOREVER, solver_epsilon); + } + + template < + typename funct + > + function_evaluation find_min_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const max_function_calls num, + double solver_epsilon + ) + { + return find_min_global(std::move(f), bound1, bound2, std::vector(bound1.size(),false), num, FOREVER, solver_epsilon); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + function_evaluation find_max_global ( + funct f, + const double bound1, + const double bound2, + const max_function_calls num, + const std::chrono::nanoseconds max_runtime = FOREVER, + double solver_epsilon = 0 + ) + { + return find_max_global(std::move(f), matrix({bound1}), matrix({bound2}), num, max_runtime, solver_epsilon); + } + + template < + typename funct + > + function_evaluation find_min_global ( + funct f, + const double bound1, + const double bound2, + const max_function_calls num, + const std::chrono::nanoseconds max_runtime = FOREVER, + double solver_epsilon = 0 + ) + { + return find_min_global(std::move(f), matrix({bound1}), matrix({bound2}), num, max_runtime, solver_epsilon); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + function_evaluation find_max_global ( + funct f, + const double bound1, + const double bound2, + const max_function_calls num, + double solver_epsilon + ) + { + return find_max_global(std::move(f), matrix({bound1}), matrix({bound2}), num, FOREVER, solver_epsilon); + } + + template < + typename funct + > + function_evaluation find_min_global ( + funct f, + const double bound1, + const double bound2, + const max_function_calls num, + double solver_epsilon + ) + { + return find_min_global(std::move(f), matrix({bound1}), matrix({bound2}), num, FOREVER, solver_epsilon); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + function_evaluation find_max_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const std::chrono::nanoseconds max_runtime, + double solver_epsilon = 0 + ) + { + return find_max_global(std::move(f), bound1, bound2, max_function_calls(), max_runtime, solver_epsilon); + } + + template < + typename funct + > + function_evaluation find_min_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const std::chrono::nanoseconds max_runtime, + double solver_epsilon = 0 + ) + { + return find_min_global(std::move(f), bound1, bound2, max_function_calls(), max_runtime, solver_epsilon); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + function_evaluation find_max_global ( + funct f, + const double bound1, + const double bound2, + const std::chrono::nanoseconds max_runtime, + double solver_epsilon = 0 + ) + { + return find_max_global(std::move(f), bound1, bound2, max_function_calls(), max_runtime, solver_epsilon); + } + + template < + typename funct + > + function_evaluation find_min_global ( + funct f, + const double bound1, + const double bound2, + const std::chrono::nanoseconds max_runtime, + double solver_epsilon = 0 + ) + { + return find_min_global(std::move(f), bound1, bound2, max_function_calls(), max_runtime, solver_epsilon); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + function_evaluation find_max_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const std::vector& is_integer_variable, + const std::chrono::nanoseconds max_runtime, + double solver_epsilon = 0 + ) + { + return find_max_global(std::move(f), bound1, bound2, is_integer_variable, max_function_calls(), max_runtime, solver_epsilon); + } + + template < + typename funct + > + function_evaluation find_min_global ( + funct f, + const matrix& bound1, + const matrix& bound2, + const std::vector& is_integer_variable, + const std::chrono::nanoseconds max_runtime, + double solver_epsilon = 0 + ) + { + return find_min_global(std::move(f), bound1, bound2, is_integer_variable, max_function_calls(), max_runtime, solver_epsilon); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_FiND_GLOBAL_MAXIMUM_ABSTRACT_hH_ + + diff --git a/lib/3rdParty/dlib/include/dlib/global_optimization/global_function_search.h b/lib/3rdParty/dlib/include/dlib/global_optimization/global_function_search.h new file mode 100644 index 00000000..fa036884 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/global_optimization/global_function_search.h @@ -0,0 +1,245 @@ +// Copyright (C) 2017 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_GLOBAL_FuNCTION_SEARCH_Hh_ +#define DLIB_GLOBAL_FuNCTION_SEARCH_Hh_ + +#include "global_function_search_abstract.h" +#include +#include "../matrix.h" +#include +#include "../rand.h" +#include "upper_bound_function.h" +#include "../test_for_odr_violations.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + struct function_spec + { + function_spec( + matrix bound1, + matrix bound2 + ); + + function_spec( + matrix bound1, + matrix bound2, + std::vector is_integer + ); + + matrix lower; + matrix upper; + std::vector is_integer_variable; + }; + +// ---------------------------------------------------------------------------------------- + + namespace gopt_impl + { + struct outstanding_function_eval_request + { + size_t request_id = 0; // unique id for this eval request + matrix x; // function x to evaluate + + // trust region specific stuff + bool was_trust_region_generated_request = false; + double predicted_improvement = std::numeric_limits::quiet_NaN(); + double anchor_objective_value = std::numeric_limits::quiet_NaN(); // objective value at center of TR step + + bool operator==(const outstanding_function_eval_request& item) const { return request_id == item.request_id; } + }; + + struct funct_info + { + funct_info() = delete; + funct_info(const funct_info&) = delete; + funct_info& operator=(const funct_info&) = delete; + + funct_info( + const function_spec& spec, + size_t function_idx, + const std::shared_ptr& m + ) : + spec(spec), function_idx(function_idx), m(m) + { + best_x = zeros_matrix(spec.lower); + } + + upper_bound_function build_upper_bound_with_all_function_evals ( + ) const; + + static double find_nn ( + const std::vector& evals, + const matrix& x + ); + + + function_spec spec; + size_t function_idx = 0; + std::shared_ptr m; + upper_bound_function ub; + std::vector outstanding_evals; + matrix best_x; + double best_objective_value = -std::numeric_limits::infinity(); + double radius = 0; + }; + + } + +// ---------------------------------------------------------------------------------------- + + class function_evaluation_request + { + public: + + function_evaluation_request() = delete; + function_evaluation_request(const function_evaluation_request&) = delete; + function_evaluation_request& operator=(const function_evaluation_request&) = delete; + + + function_evaluation_request(function_evaluation_request&& item); + function_evaluation_request& operator=(function_evaluation_request&& item); + + ~function_evaluation_request(); + + size_t function_idx ( + ) const; + + const matrix& x ( + ) const; + + bool has_been_evaluated ( + ) const; + + void set ( + double y + ); + + void swap(function_evaluation_request& item); + + private: + + friend class global_function_search; + + explicit function_evaluation_request( + const gopt_impl::outstanding_function_eval_request& req, + const std::shared_ptr& info + ) : req(req), info(info) {} + + bool m_has_been_evaluated = false; + gopt_impl::outstanding_function_eval_request req; + std::shared_ptr info; + }; + +// ---------------------------------------------------------------------------------------- + + class global_function_search + { + public: + + global_function_search() = default; + + explicit global_function_search( + const function_spec& function + ); + + explicit global_function_search( + const std::vector& functions_ + ); + + global_function_search( + const std::vector& functions_, + const std::vector>& initial_function_evals, + const double relative_noise_magnitude = 0.001 + ); + + global_function_search(const global_function_search&) = delete; + global_function_search& operator=(const global_function_search& item) = delete; + + global_function_search(global_function_search&& item) = default; + global_function_search& operator=(global_function_search&& item) = default; + + size_t num_functions( + ) const; + + void set_seed ( + time_t seed + ); + + void get_function_evaluations ( + std::vector& specs, + std::vector>& function_evals + ) const; + + void get_best_function_eval ( + matrix& x, + double& y, + size_t& function_idx + ) const; + + function_evaluation_request get_next_x ( + ); + + double get_pure_random_search_probability ( + ) const; + + void set_pure_random_search_probability ( + double prob + ); + + double get_solver_epsilon ( + ) const; + + void set_solver_epsilon ( + double eps + ); + + double get_relative_noise_magnitude ( + ) const; + + void set_relative_noise_magnitude ( + double value + ); + + size_t get_monte_carlo_upper_bound_sample_num ( + ) const; + + void set_monte_carlo_upper_bound_sample_num ( + size_t num + ); + + private: + + std::shared_ptr best_function( + ) const; + + std::shared_ptr best_function( + size_t& idx + ) const; + + bool has_outstanding_trust_region_request ( + ) const; + + + dlib::rand rnd; + double pure_random_search_probability = 0.02; + double min_trust_region_epsilon = 0; + double relative_noise_magnitude = 0.001; + size_t num_random_samples = 5000; + bool do_trust_region_step = true; + + size_t next_request_id = 1; + + std::vector> functions; + std::shared_ptr m; + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_GLOBAL_FuNCTION_SEARCH_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/global_optimization/global_function_search_abstract.h b/lib/3rdParty/dlib/include/dlib/global_optimization/global_function_search_abstract.h new file mode 100644 index 00000000..c8bfc399 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/global_optimization/global_function_search_abstract.h @@ -0,0 +1,605 @@ +// Copyright (C) 2017 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_GLOBAL_FuNCTION_SEARCH_ABSTRACT_Hh_ +#ifdef DLIB_GLOBAL_FuNCTION_SEARCH_ABSTRACT_Hh_ + +#include +#include "../matrix.h" +#include "upper_bound_function_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + struct function_spec + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a simple struct that lets you define the valid inputs to a + multivariate function. It lets you define bound constraints for each + variable as well as say if a variable is integer valued or not. Therefore, + an instance of this struct says that a function takes upper.size() input + variables, where the ith variable must be in the range [lower(i) upper(i)] + and be an integer if is_integer_variable[i]==true. + !*/ + + function_spec( + matrix bound1, + matrix bound2 + ); + /*! + requires + - bound1.size() == bound2.size() + - for all valid i: bound1(i) != bound2(i) + ensures + - #is_integer_variable.size() == bound1.size() + - #lower.size() == bound1.size() + - #upper.size() == bound1.size() + - for all valid i: + - #is_integer_variable[i] == false + - #lower(i) == min(bound1(i), bound2(i)) + - #upper(i) == max(bound1(i), bound2(i)) + !*/ + + function_spec( + matrix lower, + matrix upper, + std::vector is_integer + ); + /*! + requires + - bound1.size() == bound2.size() == is_integer.size() + - for all valid i: bound1(i) != bound2(i) + ensures + - #is_integer_variable.size() == bound1.size() + - #lower.size() == bound1.size() + - #upper.size() == bound1.size() + - for all valid i: + - #is_integer_variable[i] == is_integer[i] + - #lower(i) == min(bound1(i), bound2(i)) + - #upper(i) == max(bound1(i), bound2(i)) + !*/ + + matrix lower; + matrix upper; + std::vector is_integer_variable; + }; + +// ---------------------------------------------------------------------------------------- + + class function_evaluation_request + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a request, by the global_function_search object, to + evaluate a real-valued function and report back the results. + + THREAD SAFETY + You shouldn't let more than one thread touch a function_evaluation_request + at the same time. However, it is safe to send instances of this class to + other threads for processing. This lets you evaluate multiple + function_evaluation_requests in parallel. Any appropriate synchronization + with regard to the originating global_function_search instance is handled + automatically. + !*/ + + public: + + // You can't make or copy this object, the only way to get one is from the + // global_function_search class via get_next_x(). + function_evaluation_request() = delete; + function_evaluation_request(const function_evaluation_request&) = delete; + function_evaluation_request& operator=(const function_evaluation_request&) = delete; + + // You can however move and swap this object. + function_evaluation_request(function_evaluation_request&& item); + function_evaluation_request& operator=(function_evaluation_request&& item); + /*! + ensures + - *this takes the state of item. + - #item.has_been_evaluated() == true + !*/ + + ~function_evaluation_request( + ); + /*! + ensures + - frees all resources associated with this object. + - It's fine to destruct function_evaluation_requests even if they haven't + been evaluated yet. If this happens it will simply be as if the request + was never issued. + !*/ + + size_t function_idx ( + ) const; + /*! + ensures + - Returns the function index that identifies which function is to be + evaluated. + !*/ + + const matrix& x ( + ) const; + /*! + ensures + - returns the input parameters to the function to be evaluated. + !*/ + + bool has_been_evaluated ( + ) const; + /*! + ensures + - If this evaluation request is still outstanding then returns false, + otherwise returns true. That is, if the global_function_search is still + waiting for you report back by calling set() then + has_been_evaluated()==false. + !*/ + + void set ( + double y + ); + /*! + requires + - has_been_evaluated() == false + ensures + - #has_been_evaluated() == true + - Notifies the global_function_search instance that created this object + that when the function_idx()th function is evaluated with x() as input + then the output is y. + !*/ + + void swap( + function_evaluation_request& item + ); + /*! + ensures + - swaps the state of *this and item + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + + class global_function_search + { + /*! + WHAT THIS OBJECT REPRESENTS + This object performs global optimization of a set of user supplied + functions. The goal is to maximize the following objective function: + max_{function_i,x_i}: function_i(x_i) + subject to bound constraints on each element of x_i. Moreover, each + element of x_i can be either real valued or integer valued. Each of the + functions can also take a different number of variables. Therefore, the + final result of the optimization tells you which function produced the + largest output and what input (i.e. the x value) to that function is + necessary to obtain that maximal value. + + Importantly, the global_function_search object does not require the user to + supply derivatives. Moreover, the functions may contain discontinuities, + behave stochastically, and have many local maxima. The global_function_search + object will attempt to find the global optima in the face of these challenges. + It is also designed to use as few function evaluations as possible, making + it suitable for optimizing functions that are very expensive to evaluate. + + It does this by alternating between two modes. A global exploration mode + and a local optima refinement mode. This is accomplished by building and + maintaining two models of the objective function: + 1. A global model that upper bounds our objective function. This is a + non-parametric piecewise linear model based on all function + evaluations ever seen by the global_function_search object. + 2. A local quadratic model fit around the best point seen so far. + + The optimization procedure therefore looks like this: + + while(not done) + { + DO GLOBAL EXPLORE STEP: + Find the point that maximizes the upper bounding model since + that is the point with the largest possible improvement in the + objective function. + + Evaluate the new point and incorporate it into our models. + + DO LOCAL REFINEMENT STEP: + Find the optimal solution to the local quadratic model. + + If this point looks like it will improve on the "best point seen + so far" by at least get_solver_epsilon() then we evaluate that + point and incorporate it into our models, otherwise we ignore + it. + } + + You can see that we alternate between global search and local refinement, + except in the case where the local model seems to have converged to within + get_solver_epsilon() accuracy. In that case only global search steps are + used. We do this in the hope that the global search will find a new and + better local optima to explore, which would then reactivate local + refinement when it has something productive to do. + + + Now let's turn our attention to the specific API defined by the + global_function_search object. We will begin by showing a short example of + its use: + + // Suppose we want to find which of these functions, F() and G(), have + // the largest output and what input is necessary to produce the + // maximal output. + auto F = [](double a, double b) { return -std::pow(a-2,2.0) - std::pow(b-4,2.0); }; + auto G = [](double x) { return 2-std::pow(x-5,2.0); }; + + // We first define function_spec objects that specify bounds on the + // inputs to each function. The search process will only search within + // these bounds. + function_spec spec_F({-10,-10}, {10,10}); + function_spec spec_G({-2}, {6}); + // Then we create a global_function_search object with those function specifications. + global_function_search opt({spec_F, spec_G}); + + // Here we run 15 iterations of the search process. Note that the user + // of global_function_search writes the main solver loop, which is + // somewhat unusual. We will discuss why that is in a moment, but for + // now let's look at this example. + for (int i = 0; i < 15; ++i) + { + // All we do here is ask the global_function_search object what to + // evaluate next, then do what it asked, and then report the + // results back by calling function_evaluation_request's set() + // method. + function_evaluation_request next = opt.get_next_x(); + // next.function_idx() tells you which of the functions you should + // evaluate. We have 2 functions here (F and G) so function_idx() + // can take only the values 0 and 1. If, for example, we had 10 + // functions it would take the values 0 through 9. + if (next.function_idx() == 0) + { + // Call F with the inputs requested by the + // global_function_search and report them back. + double a = next.x()(0); + double b = next.x()(1); + next.set(F(a,b)); // Tell the solver what happened. + } + else + { + double x = next.x()(0); + next.set(G(x)); + } + } + + // Find out what point gave the largest outputs: + matrix x; + double y; + size_t function_idx; + opt.get_best_function_eval(x,y,function_idx); + + cout << "function_idx: "<< function_idx << endl; + cout << "y: " << y << endl; + cout << "x: " << x << endl; + + The above cout statements will print this: + + function_idx: 1 + y: 2 + x: 5 + + Which is the correct result since G(5) gives the largest possible output in + our example. + + So why does the user write the main loop? Why isn't it embedded inside + dlib? Well, there are two answers to this. The first is that it is. Most + users should just call dlib::find_max_global() which does exactly that, it + runs the loop for you. However, the API shown above gives you the + opportunity to run multiple function evaluations in parallel. For + instance, it is perfectly valid to call get_next_x() multiple times and + send the resulting function_evaluation_request objects to separate threads + for processing. Those separate threads can run the functions being + optimized (e.g. F and G or whatever) and report back by calling + function_evaluation_request::set(). You could even spread the work across + a compute cluster if you have one. + + So what happens if you have N outstanding function evaluation requests? + Or in other words, what happens if you called get_next_x() N times and + haven't yet called their set() methods? Well, 1 of the N requests will be + a local refinement step while the N-1 other requests will be global + exploration steps generated from the current upper bounding model. This + should give you an idea of the usefulness of this kind of parallelism. If + for example, your functions being optimized were simple convex functions + this kind of parallelism wouldn't help since essentially all the + interesting work in the solver is going to be done by the local optimizer. + However, if your function has a lot of local optima, running many global + exploration steps in parallel might significantly reduce the time it takes + to find a good solution. + + It should also be noted that our upper bounding model is implemented by the + dlib::upper_bound_function object, which is a tool that allows us to create + a tight upper bound on our objective function. This upper bound is + non-parametric and gets progressively more accurate as the optimization + progresses, but also more and more expensive to maintain. It causes the + runtime of the entire optimization procedure to be O(N^2) where N is the + number of objective function evaluations. So problems that require millions + of function evaluations to find a good solution are not appropriate for the + global_function_search tool. However, if your objective function is very + expensive to evaluate then this relatively expensive upper bounding model + is well worth its computational cost. + + Finally, let's introduce some background literature on this algorithm. The + two most relevant papers in the optimization literature are: + Global optimization of Lipschitz functions Malherbe, Cédric and Vayatis, + Nicolas International Conference on Machine Learning - 2017 + and + The NEWUOA software for unconstrained optimization without derivatives By + M.J.D. Powell, 40th Workshop on Large Scale Nonlinear Optimization (Erice, + Italy, 2004) + + Our upper bounding model is an extension of the AdaLIPO method in the + Malherbe. See the documentation of dlib::upper_bound_function for more + details on that, as we make a number of important extensions. The other + part of our method, our local refinement model, is essentially the same + type of trust region model proposed by Powell in the above paper. That is, + each time we do a local refinement step we identify the best point seen so + far, fit a quadratic function around it using the function evaluations we + have collected so far, and then use a simple trust region procedure to + decide the next best point to evaluate based on our quadratic model. + + The method proposed by Malherbe gives excellent global search performance + but has terrible convergence properties in the area around a maxima. + Powell's method on the other hand has excellent convergence in the area + around a local maxima, as expected by a quadratic trust region method, but + is aggressively local maxima seeking. It will simply get stuck in the + nearest local optima. Combining the two together as we do here gives us + excellent performance in both global search and final convergence speed + near a local optima. Causing the global_function_search to perform well + for functions with many local optima while still giving high precision + solutions. For instance, on typical tests problems, like the Holder table + function, the global_function_search object can reliably find the globally + optimal solution to full floating point precision in under a few hundred + steps. + + + THREAD SAFETY + You shouldn't let more than one thread touch a global_function_search + instance at the same time. + !*/ + + public: + + global_function_search( + ); + /*! + ensures + - #num_functions() == 0 + - #get_relative_noise_magnitude() == 0.001 + - #get_solver_epsilon() == 0 + - #get_monte_carlo_upper_bound_sample_num() == 5000 + - #get_pure_random_search_probability() == 0.02 + !*/ + + explicit global_function_search( + const function_spec& function + ); + /*! + ensures + - #num_functions() == 1 + - #get_function_evaluations() will indicate that there are no function evaluations yet. + - #get_relative_noise_magnitude() == 0.001 + - #get_solver_epsilon() == 0 + - #get_monte_carlo_upper_bound_sample_num() == 5000 + - #get_pure_random_search_probability() == 0.02 + !*/ + + explicit global_function_search( + const std::vector& functions + ); + /*! + ensures + - #num_functions() == functions.size() + - #get_function_evaluations() will indicate that there are no function evaluations yet. + - #get_relative_noise_magnitude() == 0.001 + - #get_solver_epsilon() == 0 + - #get_monte_carlo_upper_bound_sample_num() == 5000 + - #get_pure_random_search_probability() == 0.02 + !*/ + + global_function_search( + const std::vector& functions, + const std::vector>& initial_function_evals, + const double relative_noise_magnitude = 0.001 + ); + /*! + requires + - functions.size() == initial_function_evals.size() + - relative_noise_magnitude >= 0 + ensures + - #num_functions() == functions.size() + - #get_function_evaluations() will return the provided initial_function_evals. + - #get_relative_noise_magnitude() == relative_noise_magnitude + - #get_solver_epsilon() == 0 + - #get_monte_carlo_upper_bound_sample_num() == 5000 + - #get_pure_random_search_probability() == 0.02 + !*/ + + // This object can't be copied. + global_function_search(const global_function_search&) = delete; + global_function_search& operator=(const global_function_search& item) = delete; + // But it can be moved + global_function_search(global_function_search&& item) = default; + global_function_search& operator=(global_function_search&& item) = default; + /*! + ensures + - moves the state of item into *this + - #item.num_functions() == 0 + !*/ + + void set_seed ( + time_t seed + ); + /*! + ensures + - Part of this object's algorithm uses random sampling to decide what + points to evaluate next. Calling set_seed() lets you set the seed used + by the random number generator. Note that if you don't call set_seed() + you will always get the same deterministic behavior. + !*/ + + size_t num_functions( + ) const; + /*! + ensures + - returns the number of functions being optimized. + !*/ + + void get_function_evaluations ( + std::vector& specs, + std::vector>& function_evals + ) const; + /*! + ensures + - #specs.size() == num_functions() + - #function_evals.size() == num_functions() + - This function allows you to query the state of the solver. In + particular, you can find the function_specs for each function being + optimized and their recorded evaluations. + - for all valid i: + - function_evals[i] == all the function evaluations that have been + recorded for the ith function (i.e. the function with the + function_spec #specs[i]). That is, this is the record of all the x + and y values reported back by function_evaluation_request::set() + calls. + !*/ + + void get_best_function_eval ( + matrix& x, + double& y, + size_t& function_idx + ) const; + /*! + requires + - num_functions() != 0 + ensures + - if (no function evaluations have been recorded yet) then + - The outputs of this function are in a valid but undefined state. + - else + - This function tells you which function has produced the largest + output seen so far. It also tells you the inputs to that function + that leads to those outputs (x) as well as the output value itself (y). + - 0 <= #function_idx < num_functions() + - #function_idx == the index of the function that produced the largest output seen so far. + - #x == the input parameters to the function that produced the largest outputs seen so far. + - #y == the largest output seen so far. + !*/ + + function_evaluation_request get_next_x ( + ); + /*! + requires + - num_functions() != 0 + ensures + - Generates and returns a function evaluation request. See the discussion + in the WHAT THIS OBJECT REPRESENTS section above for details. + !*/ + + double get_pure_random_search_probability ( + ) const; + /*! + ensures + - When we decide to do a global explore step we will, with probability + get_pure_random_search_probability(), sample a point completely at random + rather than using the upper bounding model. Therefore, if you set this + probability to 0 then we will depend entirely on the upper bounding + model. Alternatively, if you set get_pure_random_search_probability() to + 1 then we won't use the upper bounding model at all and instead use pure + random search to do global exploration. Pure random search is much + faster than using the upper bounding model, so if you know that your + objective function is especially simple it can be faster to use pure + random search. However, if you really know your function that well you + should probably use a gradient based optimizer :) + !*/ + + void set_pure_random_search_probability ( + double prob + ); + /*! + requires + - prob >= 0 + ensures + - #get_pure_random_search_probability() == prob + !*/ + + double get_solver_epsilon ( + ) const; + /*! + ensures + - As discussed in the WHAT THIS OBJECT REPRESENTS section, we only do a + local refinement step if we haven't already found the peak of the current + local optima. get_solver_epsilon() sets the tolerance for deciding if + the local search method has found the local optima. Therefore, when the + local trust region model runs we check if its predicted improvement in + the objective function is greater than get_solver_epsilon(). If it isn't + then we assume it has converged and we should focus entirely on global + search. + + This means that, for instance, setting get_solver_epsilon() to 0 + essentially instructs the solver to find each local optima to full + floating point precision and only then to focus on pure global search. + !*/ + + void set_solver_epsilon ( + double eps + ); + /*! + requires + - eps >= 0 + ensures + - #get_solver_epsilon() == eps + !*/ + + double get_relative_noise_magnitude ( + ) const; + /*! + ensures + - Returns the value of the relative noise magnitude parameter to the + dlib::upper_bound_function's used by this object. See the + upper_bound_function's documentation for a detailed discussion of this + parameter's meaning. Most users should leave this value as its default + setting. + !*/ + + void set_relative_noise_magnitude ( + double value + ); + /*! + requires + - value >= 0 + ensures + - #get_relative_noise_magnitude() == value + !*/ + + size_t get_monte_carlo_upper_bound_sample_num ( + ) const; + /*! + ensures + - To find the point that maximizes the upper bounding model we use + get_monte_carlo_upper_bound_sample_num() random evaluations and select + the largest upper bound from that set. So this parameter influences how + well we estimate the maximum point on the upper bounding model. + !*/ + + void set_monte_carlo_upper_bound_sample_num ( + size_t num + ); + /*! + requires + - num > 0 + ensures + - #get_monte_carlo_upper_bound_sample_num() == num + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_GLOBAL_FuNCTION_SEARCH_ABSTRACT_Hh_ + + diff --git a/lib/3rdParty/dlib/include/dlib/global_optimization/upper_bound_function.h b/lib/3rdParty/dlib/include/dlib/global_optimization/upper_bound_function.h new file mode 100644 index 00000000..d1957623 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/global_optimization/upper_bound_function.h @@ -0,0 +1,286 @@ +// Copyright (C) 2017 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_UPPER_bOUND_FUNCTION_Hh_ +#define DLIB_UPPER_bOUND_FUNCTION_Hh_ + +#include "upper_bound_function_abstract.h" +#include "../svm/svm_c_linear_dcd_trainer.h" +#include "../statistics.h" +#include +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + struct function_evaluation + { + function_evaluation() = default; + function_evaluation(const matrix& x, double y) :x(x), y(y) {} + + matrix x; + double y = std::numeric_limits::quiet_NaN(); + }; + +// ---------------------------------------------------------------------------------------- + + class upper_bound_function + { + + public: + + upper_bound_function( + ) = default; + + upper_bound_function( + const double relative_noise_magnitude, + const double solver_eps + ) : relative_noise_magnitude(relative_noise_magnitude), solver_eps(solver_eps) + { + DLIB_CASSERT(relative_noise_magnitude >= 0); + DLIB_CASSERT(solver_eps > 0); + } + + explicit upper_bound_function( + const std::vector& _points, + const double relative_noise_magnitude = 0.001, + const double solver_eps = 0.0001 + ) : relative_noise_magnitude(relative_noise_magnitude), solver_eps(solver_eps), points(_points) + { + DLIB_CASSERT(relative_noise_magnitude >= 0); + DLIB_CASSERT(solver_eps > 0); + + if (points.size() > 1) + { + DLIB_CASSERT(points[0].x.size() > 0, "The vectors can't be empty."); + + const long dims = points[0].x.size(); + for (auto& p : points) + DLIB_CASSERT(p.x.size() == dims, "All the vectors given to upper_bound_function must have the same dimensionality."); + + learn_params(); + } + + } + + void add ( + const function_evaluation& point + ) + { + DLIB_CASSERT(point.x.size() != 0, "The vectors can't be empty."); + if (points.size() == 0) + { + points.push_back(point); + return; + } + + DLIB_CASSERT(point.x.size() == dimensionality(), "All the vectors given to upper_bound_function must have the same dimensionality."); + + if (points.size() < 4) + { + points.push_back(point); + *this = upper_bound_function(points, relative_noise_magnitude, solver_eps); + return; + } + + points.push_back(point); + // add constraints between the new point and the old points + for (size_t i = 0; i < points.size()-1; ++i) + active_constraints.push_back(std::make_pair(i,points.size()-1)); + + learn_params(); + } + + long num_points( + ) const + { + return points.size(); + } + + long dimensionality( + ) const + { + if (points.size() == 0) + return 0; + else + return points[0].x.size(); + } + + const std::vector& get_points( + ) const + { + return points; + } + + double operator() ( + const matrix& x + ) const + { + DLIB_CASSERT(num_points() > 0); + DLIB_CASSERT(x.size() == dimensionality()); + + + + double upper_bound = std::numeric_limits::infinity(); + + for (size_t i = 0; i < points.size(); ++i) + { + const double local_bound = points[i].y + std::sqrt(offsets[i] + dot(slopes, squared(x-points[i].x))); + upper_bound = std::min(upper_bound, local_bound); + } + + return upper_bound; + } + + private: + + void learn_params ( + ) + { + const long dims = points[0].x.size(); + + using sample_type = std::vector>; + using kernel_type = sparse_linear_kernel; + std::vector x; + std::vector y; + + // We are going to normalize the data so the values aren't extreme. First, we + // collect statistics on our data. + std::vector> x_rs(dims); + running_stats y_rs; + for (auto& v : points) + { + for (long i = 0; i < v.x.size(); ++i) + x_rs[i].add(v.x(i)); + y_rs.add(v.y); + } + + + // compute normalization vectors for the data. The only reason we do this is + // to make the optimization well conditioned. In particular, scaling the y + // values will prevent numerical errors in the 1-diff*diff computation below that + // would otherwise result when diff is really big. Also, scaling the xvalues + // to be about 1 will similarly make the optimization more stable and it also + // has the added benefit of keeping the relative_noise_magnitude's scale + // constant regardless of the size of x values. + const double yscale = 1.0/y_rs.stddev(); + std::vector xscale(dims); + for (size_t i = 0; i < xscale.size(); ++i) + xscale[i] = 1.0/(x_rs[i].stddev()*yscale); // make it so that xscale[i]*yscale == 1/x_rs[i].stddev() + + sample_type samp; + auto add_constraint = [&](long i, long j) { + samp.clear(); + for (long k = 0; k < dims; ++k) + { + double temp = (points[i].x(k) - points[j].x(k))*xscale[k]*yscale; + samp.push_back(std::make_pair(k, temp*temp)); + } + + if (points[i].y > points[j].y) + samp.push_back(std::make_pair(dims + j, relative_noise_magnitude)); + else + samp.push_back(std::make_pair(dims + i, relative_noise_magnitude)); + + const double diff = (points[i].y - points[j].y)*yscale; + samp.push_back(std::make_pair(dims + points.size(), 1-diff*diff)); + + x.push_back(samp); + y.push_back(1); + }; + + if (active_constraints.size() == 0) + { + x.reserve(points.size()*(points.size()-1)/2); + y.reserve(points.size()*(points.size()-1)/2); + for (size_t i = 0; i < points.size(); ++i) + { + for (size_t j = i+1; j < points.size(); ++j) + { + add_constraint(i,j); + } + } + } + else + { + for (auto& p : active_constraints) + add_constraint(p.first, p.second); + } + + + + + svm_c_linear_dcd_trainer trainer; + trainer.set_c(std::numeric_limits::infinity()); + //trainer.be_verbose(); + trainer.force_last_weight_to_1(true); + trainer.set_epsilon(solver_eps); + + svm_c_linear_dcd_trainer::optimizer_state state; + auto df = trainer.train(x,y, state); + + // save the active constraints for later so we can use them inside add() to add + // new points efficiently. + if (active_constraints.size() == 0) + { + long k = 0; + for (size_t i = 0; i < points.size(); ++i) + { + for (size_t j = i+1; j < points.size(); ++j) + { + if (state.get_alpha()[k++] != 0) + active_constraints.push_back(std::make_pair(i,j)); + } + } + } + else + { + DLIB_CASSERT(state.get_alpha().size() == active_constraints.size()); + new_active_constraints.clear(); + for (size_t i = 0; i < state.get_alpha().size(); ++i) + { + if (state.get_alpha()[i] != 0) + new_active_constraints.push_back(active_constraints[i]); + } + active_constraints.swap(new_active_constraints); + } + + //std::cout << "points.size(): " << points.size() << std::endl; + //std::cout << "active_constraints.size(): " << active_constraints.size() << std::endl; + + + const auto& bv = df.basis_vectors(0); + slopes.set_size(dims); + for (long i = 0; i < dims; ++i) + slopes(i) = bv[i].second*xscale[i]*xscale[i]; + + //std::cout << "slopes:" << trans(slopes); + + offsets.assign(points.size(),0); + + + for (size_t i = 0; i < points.size(); ++i) + { + offsets[i] += bv[slopes.size()+i].second*relative_noise_magnitude; + } + } + + + + double relative_noise_magnitude = 0.001; + double solver_eps = 0.0001; + std::vector> active_constraints, new_active_constraints; + + std::vector points; + std::vector offsets; // offsets.size() == points.size() + matrix slopes; // slopes.size() == points[0].first.size() + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_UPPER_bOUND_FUNCTION_Hh_ + + diff --git a/lib/3rdParty/dlib/include/dlib/global_optimization/upper_bound_function_abstract.h b/lib/3rdParty/dlib/include/dlib/global_optimization/upper_bound_function_abstract.h new file mode 100644 index 00000000..56b36159 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/global_optimization/upper_bound_function_abstract.h @@ -0,0 +1,212 @@ +// Copyright (C) 2017 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_UPPER_bOUND_FUNCTION_ABSTRACT_Hh_ +#ifdef DLIB_UPPER_bOUND_FUNCTION_ABSTRACT_Hh_ + +#include "../matrix.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + struct function_evaluation + { + /*! + WHAT THIS OBJECT REPRESENTS + This object records the output of a real valued function in response to + some input. + + In particular, if you have a function F(x) then the function_evaluation is + simply a struct that records x and the scalar value F(x). + !*/ + + function_evaluation() = default; + function_evaluation(const matrix& x, double y) :x(x), y(y) {} + + matrix x; + double y = std::numeric_limits::quiet_NaN(); + }; + +// ---------------------------------------------------------------------------------------- + + class upper_bound_function + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a piecewise linear non-parametric function that can + be used to define an upper bound on some more complex and unknown function. + To describe this precisely, lets assume there is a function F(x) which you + are capable of sampling from but otherwise know nothing about, and that you + would like to find an upper bounding function U(x) such that U(x) >= F(x) + for any x. It would also be good if U(x)-F(x) was minimal. I.e. we would + like U(x) to be a tight upper bound, not something vacuous like U(x) = + infinity. + + The upper_bound_function class is a tool for creating this kind of upper + bounding function from a set of function_evaluations of F(x). We do this + by considering only U(x) of the form: + U = [](matrix x) { + double min_ub = infinity; + for (size_t i = 0; i < POINTS.size(); ++i) { + function_evaluation p = POINTS[i] + double local_bound = p.y + sqrt(noise_terms[i] + trans(p.x-x)*M*(p.x-x)) + min_ub = min(min_ub, local_bound) + } + return min_ub; + } + Where POINTS is an array of function_evaluation instances drawn from F(x), + M is a diagonal matrix, and noise_terms is an array of scalars. + + To create an upper bound U(x), the upper_bound_function takes a POINTS array + containing evaluations of F(x) as input and solves the following quadratic + program to find the parameters of U(x): + + min_{M,noise_terms}: sum(squared(M)) + sum(squared(noise_terms/relative_noise_magnitude)) + s.t. U(POINTS[i].x) >= POINTS[i].y, for all i + noise_terms[i] >= 0 + min(M) >= 0 + M is a diagonal matrix + + Therefore, the quadratic program finds the U(x) that always upper bounds + F(x) on the supplied POINTS, but is otherwise as small as possible. + + + + The inspiration for the upper_bound_function object came from the AdaLIPO + algorithm from this excellent paper: + Global optimization of Lipschitz functions + Malherbe, Cédric and Vayatis, Nicolas + International Conference on Machine Learning - 2017 + In that paper, they propose to use a simpler U(x) where noise_terms is + always 0 and M is a diagonal matrix where each diagonal element is the same + value. Therefore, there is only a single scalar parameter for U(x) in + their formulation of the problem. This causes difficulties if F(x) is + stochastic or has discontinuities since, without the noise term, M will + become really huge and the upper bound becomes vacuously large. It is also + problematic if the gradient of F(x) with respect to x contains elements of + widely varying magnitude since the simpler formulation of U(x) assumes a + uniform rate of change regardless of which dimension is varying. + !*/ + + public: + + upper_bound_function( + ); + /*! + ensures + - #num_points() == 0 + - #dimensionality() == 0 + !*/ + + explicit upper_bound_function( + const std::vector& points, + const double relative_noise_magnitude = 0.001, + const double solver_eps = 0.0001 + ); + /*! + requires + - all the x vectors in points must have the same non-zero dimensionality. + - relative_noise_magnitude >= 0 + - solver_eps > 0 + ensures + - Creates an upper bounding function U(x), as described above, assuming that + the given points are drawn from F(x). + - Uses the provided relative_noise_magnitude when solving the QP, as + described above. Note that relative_noise_magnitude can be set to 0. If + you do this then all the noise terms are constrained to 0. You should + only do this if you know F(x) is non-stochastic and continuous + everywhere. + - When solving the QP used to find the parameters of U(x), the upper + bounding function, we solve the QP to solver_eps accuracy. It's + possible that large enough solver_eps can lead to upper bounds that don't + upper bound all the supplied points. But for reasonable epsilon values + this shouldn't be a problem. + - #num_points() == points.size() + - #dimensionality() == points[0].x.size() + !*/ + + upper_bound_function( + const double relative_noise_magnitude, + const double solver_eps + ); + /*! + requires + - relative_noise_magnitude >= 0 + - solver_eps > 0 + ensures + - #num_points() == 0 + - #dimensionality() == 0 + - This destructor is the same as calling the above constructor with points.size()==0 + !*/ + + + void add ( + const function_evaluation& point + ); + /*! + requires + - num_points() == 0 || point.x.size() == dimensionality() + - point.x.size() != 0 + ensures + - Adds point to get_points(). + - Incrementally updates the upper bounding function with the given function + evaluation. That is, we assume that F(point.x)==point.y and solve the QP + described above to find the new U(x) that upper bounds all the points + this object knows about (i.e. all the points in get_points() and the new point). + - Calling add() is much faster than recreating the upper_bound_function + from scratch with all the points. This is because we warm start with the + previous solution to the QP. This is done by discarding any non-active + constraints and solving the QP again with only the previously active + constraints and the new constraints formed by all the pairs of the new + point and the old points. This means the QP solved by add() is much + smaller than the QP that would be solved by a fresh call to the + upper_bound_function constructor. + !*/ + + const std::vector& get_points( + ) const; + /*! + ensures + - returns the points from F(x) used to define this upper bounding function. + These are all the function_evaluation objects given to this object via + its constructor and add(). + !*/ + + long num_points( + ) const; + /*! + ensures + - returns the number of points used to define the upper bounding function. + (i.e. returns get_points().size()) + !*/ + + long dimensionality( + ) const; + /*! + ensures + - returns the dimensionality of the input vectors to the upper bounding function. + !*/ + + double operator() ( + const matrix& x + ) const; + /*! + requires + - num_points() > 0 + - x.size() == dimensionality() + ensures + - return U(x) + (i.e. returns the upper bound on F(x) at x given by our upper bounding function) + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_UPPER_bOUND_FUNCTION_ABSTRACT_Hh_ + + diff --git a/lib/3rdParty/dlib/include/dlib/graph/graph_kernel_1.h b/lib/3rdParty/dlib/include/dlib/graph/graph_kernel_1.h index 60157f6d..fb0d6e7a 100644 --- a/lib/3rdParty/dlib/include/dlib/graph/graph_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/graph/graph_kernel_1.h @@ -3,12 +3,13 @@ #ifndef DLIB_GRAPH_KERNEl_1_ #define DLIB_GRAPH_KERNEl_1_ +#include +#include + #include "../serialize.h" #include "../noncopyable.h" #include "../std_allocator.h" -#include "../smart_pointers.h" #include "../algs.h" -#include #include "graph_kernel_abstract.h" #include "../is_kind.h" @@ -291,16 +292,16 @@ namespace dlib private: friend class graph_kernel_1; typedef std_allocator alloc_type; - typedef std_allocator,mem_manager> alloc_edge_type; + typedef std_allocator,mem_manager> alloc_edge_type; std::vector neighbors; - std::vector,alloc_edge_type> edges; + std::vector,alloc_edge_type> edges; unsigned long idx; }; private: - typedef std_allocator,mem_manager> alloc_type; - typedef std::vector, alloc_type> vector_type; + typedef std_allocator,mem_manager> alloc_type; + typedef std::vector, alloc_type> vector_type; vector_type nodes; }; @@ -506,7 +507,7 @@ namespace dlib n1.neighbors.push_back(&n2); - shared_ptr e(new E); + std::shared_ptr e(new E); n1.edges.push_back(e); // don't add this twice if this is an edge from node_index1 back to itself @@ -571,7 +572,7 @@ namespace dlib { try { - shared_ptr n(new node_type); + std::shared_ptr n(new node_type); n->idx = nodes.size(); nodes.push_back(n); return n->idx; diff --git a/lib/3rdParty/dlib/include/dlib/graph_cuts/min_cut.h b/lib/3rdParty/dlib/include/dlib/graph_cuts/min_cut.h index 205b46c4..6bbb5760 100644 --- a/lib/3rdParty/dlib/include/dlib/graph_cuts/min_cut.h +++ b/lib/3rdParty/dlib/include/dlib/graph_cuts/min_cut.h @@ -162,9 +162,9 @@ namespace dlib g.set_label(sink_node, SINK_CUT); // used to indicate "no parent" - const unsigned long nil = g.number_of_nodes(); + const unsigned long no_parent = g.number_of_nodes(); - parent.assign(g.number_of_nodes(), nil); + parent.assign(g.number_of_nodes(), no_parent); time = 1; dist.assign(g.number_of_nodes(), 0); @@ -194,14 +194,14 @@ namespace dlib private: unsigned long distance_to_origin ( - const unsigned long nil, + const unsigned long no_parent, unsigned long p, unsigned long ) const { unsigned long start = p; unsigned long count = 0; - while (p != nil) + while (p != no_parent) { if (ts[p] == time) { @@ -237,7 +237,7 @@ namespace dlib typedef typename flow_graph::in_edge_iterator in_edge_iterator; // used to indicate "no parent" - const unsigned long nil = g.number_of_nodes(); + const unsigned long no_parent = g.number_of_nodes(); while (orphans.size() > 0) { @@ -260,7 +260,7 @@ namespace dlib if (g.get_label(id) != label_p || g.get_flow(q) <= 0 ) continue; - unsigned long temp = distance_to_origin(nil, id,source); + unsigned long temp = distance_to_origin(no_parent, id,source); if (temp < best_dist) { best_dist = temp; @@ -276,7 +276,7 @@ namespace dlib } // if we didn't find a parent for p - if (parent[p] == nil) + if (parent[p] == no_parent) { for(in_edge_iterator q = begin; q != end; ++q) { @@ -290,7 +290,7 @@ namespace dlib if (parent[id] == p) { - parent[id] = nil; + parent[id] = no_parent; orphans.push_back(id); } } @@ -309,7 +309,7 @@ namespace dlib if (g.get_label(id) != label_p || g.get_flow(q) <= 0) continue; - unsigned long temp = distance_to_origin(nil, id,sink); + unsigned long temp = distance_to_origin(no_parent, id,sink); if (temp < best_dist) { @@ -326,7 +326,7 @@ namespace dlib } // if we didn't find a parent for p - if (parent[p] == nil) + if (parent[p] == no_parent) { for(out_edge_iterator q = begin; q != end; ++q) { @@ -340,7 +340,7 @@ namespace dlib if (parent[id] == p) { - parent[id] = nil; + parent[id] = no_parent; orphans.push_back(id); } } @@ -366,7 +366,7 @@ namespace dlib typedef typename flow_graph::edge_type edge_type; // used to indicate "no parent" - const unsigned long nil = g.number_of_nodes(); + const unsigned long no_parent = g.number_of_nodes(); unsigned long s = source_side; unsigned long t = sink_side; @@ -414,7 +414,7 @@ namespace dlib g.adjust_flow(t,s, min_cap); if (g.get_flow(s,t) <= 0) { - parent[t] = nil; + parent[t] = no_parent; orphans.push_back(t); } @@ -429,7 +429,7 @@ namespace dlib g.adjust_flow(t,s, min_cap); if (g.get_flow(s,t) <= 0) { - parent[s] = nil; + parent[s] = no_parent; orphans.push_back(s); } s = t; diff --git a/lib/3rdParty/dlib/include/dlib/graph_utils/edge_list_graphs.h b/lib/3rdParty/dlib/include/dlib/graph_utils/edge_list_graphs.h index c298b232..d2447acd 100644 --- a/lib/3rdParty/dlib/include/dlib/graph_utils/edge_list_graphs.h +++ b/lib/3rdParty/dlib/include/dlib/graph_utils/edge_list_graphs.h @@ -286,7 +286,7 @@ namespace dlib // Hold the length for the longest edge for each node. Initially they are all infinity. std::vector worst_dists(samples.size(), std::numeric_limits::infinity()); - std::vector::iterator begin_i, end_i, begin_j, end_j, itr; + std::vector::iterator begin_i, end_i, begin_j, end_j; begin_i = edges.begin(); end_i = begin_i + k; diff --git a/lib/3rdParty/dlib/include/dlib/gui_core/gui_core_kernel_1.cpp b/lib/3rdParty/dlib/include/dlib/gui_core/gui_core_kernel_1.cpp deleted file mode 100644 index 3e219ff5..00000000 --- a/lib/3rdParty/dlib/include/dlib/gui_core/gui_core_kernel_1.cpp +++ /dev/null @@ -1,2184 +0,0 @@ -// Copyright (C) 2005 Davis E. King (davis@dlib.net), Keita Mochizuki -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_GUI_CORE_KERNEL_1_CPp_ -#define DLIB_GUI_CORE_KERNEL_1_CPp_ -#include "../platform.h" - -#ifdef WIN32 - -#include "gui_core_kernel_1.h" - -// tell visual studio to link to the libraries we need if we are -// in fact using visual studio -#ifdef _MSC_VER -#pragma comment (lib, "gdi32.lib") -#pragma comment (lib, "comctl32.lib") -#pragma comment (lib, "user32.lib") -#pragma comment (lib, "imm32.lib") -#endif - - -#include -#include "../threads.h" -#include "../assert.h" -#include "../queue.h" -#include "../sync_extension.h" -#include "../queue.h" -#include "../logger.h" -#include -#include - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - namespace gui_core_kernel_1_globals - { - - - struct user_event_type - { - HWND w; - void* p; - int i; - }; - - typedef sync_extension::kernel_1a>::kernel_1a window_table_type; - typedef sync_extension::kernel_1b>::kernel_2a_c>::kernel_1a queue_of_user_events; - - - enum USER_OFFSETS - { - CREATE_WINDOW, - DESTROY_WINDOW, - SET_ACTIVE_WINDOW, - QUIT_EVENT_HANDLER_THREAD, - USER_EVENTS_READY, - CALL_MOVE_WINDOW, - SHOW_WINDOW_SHOW, - SHOW_WINDOW_HIDE, - CALL_SET_WINDOW_TITLE - }; - - // ---------------------------------------------------------------------------------------- - - const shared_ptr_thread_safe& global_mutex() - { - static shared_ptr_thread_safe m(new dlib::mutex); - return m; - } - - class event_handler_thread : public threaded_object - { - public: - - enum et_state - { - uninitialized, - initialized, - failure_to_init - }; - - et_state status; - - queue_of_user_events user_events; - queue_of_user_events user_events_temp; - logger dlog; - - HINSTANCE hInstance; - HWND helper_window; - const TCHAR* window_class_name; - - bool quit_windows_loop; - bool set_window_title_done; - std::wstring window_title; - bool move_window_done; - HWND move_window_hwnd; - int move_window_width; - int move_window_height; - int move_window_x; - int move_window_y; - bool request_new_window; - DWORD dwStyle; - HWND new_window; - bool in_ime_composition; - bool event_thread_started; - // the window_table.get_mutex() mutex locks the above 11 variables - - - // this variable holds a mapping from window handles to the base_window - // objects which represent them. Note that this objects mutex is always locked - // when inside the event loop. - window_table_type window_table; - rsignaler window_close_signaler; - rsignaler et_signaler; - - // note that this is the thread that will perform all the event - // processing. - thread_id_type event_thread_id; - - shared_ptr_thread_safe reference_to_global_mutex; - - event_handler_thread( - ) : - dlog("dlib.gui_core"), - hInstance(0), - helper_window(0), - window_class_name(TEXT ("w3049u6qc2d94thw9m34f4we0gvwa3-tgkser0-b9gm 05")), - quit_windows_loop(false), - set_window_title_done(true), - move_window_done(true), - move_window_hwnd(0), - move_window_width(0), - move_window_height(0), - move_window_x(0), - move_window_y(0), - request_new_window(false), - dwStyle(0), - new_window(0), - in_ime_composition(false), - event_thread_started(false), - window_close_signaler(window_table.get_mutex()), - et_signaler(window_table.get_mutex()), - reference_to_global_mutex(global_mutex()) - { - status = uninitialized; - } - - void start_event_thread ( - ) - /*! - we can't call this function from this objects constructor because - starting the event thread in windows involves sending messages to the - WndProc() and that requires this object to be fully constructed. - !*/ - { - - if (event_thread_started == false) - { - auto_mutex M(window_table.get_mutex()); - if (event_thread_started == false) - { - event_thread_started = true; - // start up the event handler thread - start(); - - // wait for the event thread to get up and running - while (status == uninitialized) - et_signaler.wait(); - - if (status == failure_to_init) - throw gui_error("Failed to start event thread"); - } - } - } - - ~event_handler_thread () - { - using namespace gui_core_kernel_1_globals; - - if (is_alive()) - { - if (PostMessage(helper_window,WM_USER+QUIT_EVENT_HANDLER_THREAD,0,0)==0) - { - dlog << LWARN << "Unable to schedule function for execution in event handling thread."; - // No point calling wait() here since the thread isn't going to - // terminate gracefully in this case. So we just let the program - // end as it will and hope for the best. - } - else - { - // wait for the event handler thread to terminate. - wait(); - } - } - - } - - private: - - void thread ( - ) - { - event_thread_id = get_thread_id(); - - hInstance = GetModuleHandle(NULL); - if (hInstance == NULL) - { - dlog << LFATAL << "Error gathering needed resources"; - - // signal that an error has occurred - window_table.get_mutex().lock(); - status = failure_to_init; - et_signaler.broadcast(); - window_table.get_mutex().unlock(); - return; - } - - // register the main window class - WNDCLASS wndclass ; - - wndclass.style = CS_DBLCLKS; - wndclass.lpfnWndProc = dlib::gui_core_kernel_1_globals::WndProc ; - wndclass.cbClsExtra = 0 ; - wndclass.cbWndExtra = 0 ; - wndclass.hInstance = hInstance ; - wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; - wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; - wndclass.hbrBackground = 0; - wndclass.lpszMenuName = NULL ; - wndclass.lpszClassName = window_class_name ; - - if (!RegisterClass (&wndclass)) - { - dlog << LFATAL << "Error registering window class"; - - // signal that an error has occurred - window_table.get_mutex().lock(); - status = failure_to_init; - et_signaler.broadcast(); - window_table.get_mutex().unlock(); - return; - } - - - // make the helper window that is used to trigger events in the - // event handler loop from other threads - TCHAR nothing[] = TEXT(""); - helper_window = CreateWindow(window_class_name,nothing,WS_DISABLED,0,0,0,0,HWND_MESSAGE,NULL,hInstance,NULL); - if (helper_window == NULL) - { - dlog << LFATAL << "Error gathering needed resources"; - - // signal that an error has occurred - window_table.get_mutex().lock(); - status = failure_to_init; - et_signaler.broadcast(); - window_table.get_mutex().unlock(); - return; - } - - // signal that the event thread is now up and running - window_table.get_mutex().lock(); - status = initialized; - et_signaler.broadcast(); - window_table.get_mutex().unlock(); - - // start the event handler loop. - /* - A note about this quit_windows_loop thing. If the user is holding - the mouse button down on the title bar of a window it will cause - the PostQuitMessage() function to be ignored!! This extra bool - is a work around to prevent that from happening. - */ - MSG msg; - while (GetMessage (&msg, NULL, 0, 0) && - quit_windows_loop == false) - { - TranslateMessage (&msg) ; - DispatchMessage (&msg) ; - } - } - }; - - // Do all this just to make sure global_mutex() is initialized at program start - // and thus hopefully before any threads have the chance to startup and call - // global_data() concurrently. - struct call_global_mutex { call_global_mutex() { global_mutex(); } }; - static call_global_mutex call_global_mutex_instance; - - const shared_ptr_thread_safe& global_data() - { - auto_mutex M(*global_mutex()); - static shared_ptr_thread_safe p; - if (p.get() == 0) - { - p.reset(new event_handler_thread()); - M.unlock(); - p->start_event_thread(); - } - return p; - } - - // ---------------------------------------------------------------------------------------- - - struct ebh_param - { - std::string text; - std::string title; - }; - - static void error_box_helper(void* param) - { - ebh_param& p = *static_cast(param); -#ifdef UNICODE - MessageBox (NULL, convert_mbstring_to_wstring(p.text).c_str(), - convert_mbstring_to_wstring(p.title).c_str(), MB_OK|MB_ICONERROR|MB_SYSTEMMODAL - ); -#else - MessageBox (NULL, p.text.c_str(), - p.title.c_str(), MB_OK|MB_ICONERROR|MB_SYSTEMMODAL - ); -#endif - delete &p; - } - - static void error_box ( - const char* title, - const char* text, - bool nonblocking = false - ) - { - try - { - if (nonblocking) - { - ebh_param* param = new ebh_param; - param->text = text; - param->title = title; - dlib::create_new_thread(error_box_helper,param); - } - else - { -#ifdef UNICODE - MessageBox (NULL, convert_mbstring_to_wstring(text).c_str(), - convert_mbstring_to_wstring(title).c_str(), - MB_OK|MB_ICONERROR|MB_SYSTEMMODAL - ); -#else - MessageBox (NULL, text, - title, MB_OK|MB_ICONERROR|MB_SYSTEMMODAL - ); -#endif - } - } - catch (...) - { - // we are totally screwed if this happens so just quit - exit(0); - } - } - - // ---------------------------------------------------------------------------------------- - - static bool map_keys ( - unsigned long keycode, - bool shift, - bool caps, - unsigned long& result, - bool& is_printable - ) - /*! - requires - - if (shift was down for this key) then - - shift == true - - if (caps lock was on for this key) then - - caps == true - - keycode == the keycode from windows that we are to process - - keycode < keyboard_keys_size - ensures - - if (this key should be ignored) then - - returns false - - else - - returns true - - #is_printable == true if result is a printable ascii character - - #result == the keycode converted into the proper number to tbe - returned by the event handler. - !*/ - { - is_printable = true; - - if (keycode <= '9' && keycode >= '0') - { - result = keycode; - if (shift) - { - switch (result) - { - case '0': result = ')'; break; - case '1': result = '!'; break; - case '2': result = '@'; break; - case '3': result = '#'; break; - case '4': result = '$'; break; - case '5': result = '%'; break; - case '6': result = '^'; break; - case '7': result = '&'; break; - case '8': result = '*'; break; - case '9': result = '('; break; - } - } - } - else if (keycode <= 'Z' && keycode >= 'A') - { - result = keycode; - - // make the result lower case if we need to. - if ((shift && caps) || (!caps && !shift)) - result = result - 'A' + 'a'; - } - else - { - switch (keycode) - { - case VK_BACK: - is_printable = false; - result = base_window::KEY_BACKSPACE; - break; - - case VK_SHIFT: - is_printable = false; - result = base_window::KEY_SHIFT; - break; - - case VK_CONTROL: - is_printable = false; - result = base_window::KEY_CTRL; - break; - - case VK_MENU: - is_printable = false; - result = base_window::KEY_ALT; - break; - - case VK_PAUSE: - is_printable = false; - result = base_window::KEY_PAUSE; - break; - - case VK_CAPITAL: - is_printable = false; - result = base_window::KEY_CAPS_LOCK; - break; - - case VK_ESCAPE: - is_printable = false; - result = base_window::KEY_ESC; - break; - - case VK_PRIOR: - is_printable = false; - result = base_window::KEY_PAGE_UP; - break; - - case VK_NEXT: - is_printable = false; - result = base_window::KEY_PAGE_DOWN; - break; - - case VK_END: - is_printable = false; - result = base_window::KEY_END; - break; - - case VK_HOME: - is_printable = false; - result = base_window::KEY_HOME; - break; - - case VK_LEFT: - is_printable = false; - result = base_window::KEY_LEFT; - break; - - case VK_RIGHT: - is_printable = false; - result = base_window::KEY_RIGHT; - break; - - case VK_UP: - is_printable = false; - result = base_window::KEY_UP; - break; - - case VK_DOWN: - is_printable = false; - result = base_window::KEY_DOWN; - break; - - case VK_INSERT: - is_printable = false; - result = base_window::KEY_INSERT; - break; - - case VK_DELETE: - is_printable = false; - result = base_window::KEY_DELETE; - break; - - case 0x91: - is_printable = false; - result = base_window::KEY_SCROLL_LOCK; - break; - - case VK_F1: - is_printable = false; - result = base_window::KEY_F1; - break; - - case VK_F2: - is_printable = false; - result = base_window::KEY_F2; - break; - - case VK_F3: - is_printable = false; - result = base_window::KEY_F3; - break; - - case VK_F4: - is_printable = false; - result = base_window::KEY_F4; - break; - - case VK_F5: - is_printable = false; - result = base_window::KEY_F5; - break; - - case VK_F6: - is_printable = false; - result = base_window::KEY_F6; - break; - - case VK_F7: - is_printable = false; - result = base_window::KEY_F7; - break; - - case VK_F8: - is_printable = false; - result = base_window::KEY_F8; - break; - - case VK_F9: - is_printable = false; - result = base_window::KEY_F9; - break; - - case VK_F10: - is_printable = false; - result = base_window::KEY_F10; - break; - - case VK_F11: - is_printable = false; - result = base_window::KEY_F11; - break; - - case VK_F12: - is_printable = false; - result = base_window::KEY_F12; - break; - - - case VK_SPACE: result = ' '; break; - case VK_TAB: result = '\t'; break; - case VK_RETURN: result = '\n'; break; - case VK_NUMPAD0: result = '0'; break; - case VK_NUMPAD1: result = '1'; break; - case VK_NUMPAD2: result = '2'; break; - case VK_NUMPAD3: result = '3'; break; - case VK_NUMPAD4: result = '4'; break; - case VK_NUMPAD5: result = '5'; break; - case VK_NUMPAD6: result = '6'; break; - case VK_NUMPAD7: result = '7'; break; - case VK_NUMPAD8: result = '8'; break; - case VK_NUMPAD9: result = '9'; break; - - case VK_MULTIPLY: result = '*'; break; - case VK_ADD: result = '+'; break; - case VK_SUBTRACT: result = '-'; break; - case VK_DECIMAL: result = '.'; break; - case VK_DIVIDE: result = '/'; break; - - case VK_OEM_1: - if (shift) result = ':'; - else result = ';'; - break; - - case VK_OEM_PLUS: - if (shift) result = '+'; - else result = '='; - break; - - case VK_OEM_COMMA: - if (shift) result = '<'; - else result = ','; - break; - - case VK_OEM_MINUS: - if (shift) result = '_'; - else result = '-'; - break; - - case VK_OEM_PERIOD: - if (shift) result = '>'; - else result = '.'; - break; - - case VK_OEM_2: - if (shift) result = '?'; - else result = '/'; - break; - - case VK_OEM_3: - if (shift) result = '~'; - else result = '`'; - break; - - case VK_OEM_4: - if (shift) result = '{'; - else result = '['; - break; - - case VK_OEM_5: - if (shift) result = '|'; - else result = '\\'; - break; - - case VK_OEM_6: - if (shift) result = '}'; - else result = ']'; - break; - - case VK_OEM_7: - if (shift) result = '"'; - else result = '\''; - break; - - default: - return false; - } - } - - return true; - } - - // ------------------------------------------------------------------------------------ - - LRESULT CALLBACK WndProc ( - HWND hwnd, - UINT message, - WPARAM wParam, - LPARAM lParam - ) - { - using namespace gui_core_kernel_1_globals; - // Make the event processing thread have a priority slightly above normal. - // This makes the GUI smother if you do heavy processing in other threads. - HANDLE hand = OpenThread(THREAD_ALL_ACCESS,FALSE,GetCurrentThreadId()); - SetThreadPriority(hand,THREAD_PRIORITY_ABOVE_NORMAL); - CloseHandle(hand); - - shared_ptr_thread_safe globals(global_data()); - - window_table_type& window_table = globals->window_table; - HWND& helper_window = globals->helper_window; - - auto_mutex M(window_table.get_mutex()); - - try - { - std::vector bitmap_buffer; - - bool is_double = false; - unsigned long btn = base_window::NONE; - - switch (message) - { - case WM_USER+QUIT_EVENT_HANDLER_THREAD: - if (hwnd == helper_window) - { - globals->quit_windows_loop = true; - PostQuitMessage(0); - } - return 0; - - case WM_USER+DESTROY_WINDOW: - if (hwnd == helper_window) - { - DestroyWindow((HWND)wParam); - } - return 0; - - case WM_USER+CALL_MOVE_WINDOW: - if (hwnd == helper_window) - { - MoveWindow( - globals->move_window_hwnd, - globals->move_window_x, - globals->move_window_y, - globals->move_window_width, - globals->move_window_height, - TRUE); - globals->move_window_done = true; - globals->et_signaler.broadcast(); - } - return 0; - - case WM_USER+USER_EVENTS_READY: - if (hwnd == helper_window) - { - // this is the signal to look in the user_events queue - globals->user_events.lock(); - globals->user_events.swap(globals->user_events_temp); - globals->user_events.unlock(); - globals->user_events_temp.reset(); - // now dispatch all these user events - while (globals->user_events_temp.move_next()) - { - base_window** win_ = window_table[globals->user_events_temp.element().w]; - base_window* win; - // if this window exists in the window table then dispatch - // its event. - if (win_) - { - win = *win_; - win->on_user_event( - globals->user_events_temp.element().p, - globals->user_events_temp.element().i - ); - } - } - globals->user_events_temp.clear(); - } - return 0; - - case WM_USER+SET_ACTIVE_WINDOW: - if (hwnd == helper_window) - { - SetActiveWindow((HWND)wParam); - } - return 0; - - case WM_USER+SHOW_WINDOW_SHOW: - if (hwnd == helper_window) - { - ShowWindow((HWND)wParam,SW_SHOW); - BringWindowToTop((HWND)wParam); - } - return 0; - - case WM_USER+SHOW_WINDOW_HIDE: - if (hwnd == helper_window) - { - ShowWindow((HWND)wParam,SW_HIDE); - } - return 0; - - case WM_USER+CALL_SET_WINDOW_TITLE: - if (hwnd == helper_window) - { - SetWindowTextW((HWND)wParam,globals->window_title.c_str()); - globals->set_window_title_done = true; - globals->et_signaler.broadcast(); - } - return 0; - - - case WM_USER+CREATE_WINDOW: - if (hwnd == helper_window) - { - - // if this is stupposed to be a popup window then do the popup window thing - if (globals->dwStyle == WS_CHILD) - { - TCHAR nothing[] = TEXT(""); - globals->new_window = CreateWindowEx (WS_EX_TOOLWINDOW,globals->window_class_name, nothing, - globals->dwStyle, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - helper_window, NULL, globals->hInstance, NULL); - SetParent(globals->new_window,NULL); - } - else - { - TCHAR nothing[] = TEXT(""); - globals->new_window = CreateWindow (globals->window_class_name, nothing, - globals->dwStyle, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - NULL, NULL, globals->hInstance, NULL); - } - // use the helper_window to indicate that CreateWindow failed - if (globals->new_window == NULL) - globals->new_window = helper_window; - globals->et_signaler.broadcast(); - } - return 0; - - case WM_SYSKEYDOWN: - case WM_KEYDOWN: - { - if (globals->in_ime_composition) break; - - base_window** win_ = window_table[hwnd]; - base_window* win; - if (win_) - win = *win_; - else - break; - - unsigned long state = 0; - - bool shift = ((GetKeyState(VK_SHIFT)&0x8000)!=0); - bool ctrl = ((GetKeyState(VK_CONTROL)&0x8000)!=0); - bool caps = ((GetKeyState(VK_CAPITAL)&0x0001)!=0); - if(shift) - state = base_window::KBD_MOD_SHIFT; - if(ctrl) - state |= base_window::KBD_MOD_CONTROL; - if(caps) - state |= base_window::KBD_MOD_CAPS_LOCK; - if((GetKeyState(VK_MENU)&0x8000)!=0) - state |= base_window::KBD_MOD_ALT; - if((GetKeyState(VK_NUMLOCK)&0x0001)!=0) - state |= base_window::KBD_MOD_NUM_LOCK; - if((GetKeyState(VK_SCROLL)&0x0001)!=0) - state |= base_window::KBD_MOD_SCROLL_LOCK; - - - bool is_printable; - unsigned long result; - - if (map_keys(wParam,shift,caps,result,is_printable)) - { - // signal the keyboard event - win->on_keydown(result,is_printable,state); - } - - } - break; - - // treat the user releasing the mouse button on the non client area (e.g. the title bar) - // like focus being lost since that is what X11 does - case WM_NCLBUTTONUP: - case WM_NCMBUTTONUP: - case WM_NCRBUTTONUP: - case WM_SETFOCUS: - { - base_window** win_ = window_table[hwnd]; - base_window* win; - if (win_) - win = *win_; - else - break; - - // signal that the window is gaining focus - win->on_focus_gained(); - } - break; - - // treat the user clicking on the non client area (e.g. the title bar) - // like focus being lost since that is what X11 does - case WM_NCLBUTTONDBLCLK: - case WM_NCMBUTTONDBLCLK: - case WM_NCRBUTTONDBLCLK: - case WM_NCLBUTTONDOWN: - case WM_NCMBUTTONDOWN: - case WM_NCRBUTTONDOWN: - case WM_KILLFOCUS: - { - base_window** win_ = window_table[hwnd]; - base_window* win; - if (win_) - win = *win_; - else - break; - - // signal that the window is gaining focus - win->on_focus_lost(); - } - break; - - case WM_SIZE: - { - base_window** win_ = window_table[hwnd]; - base_window* win; - if (win_) - win = *win_; - else - break; - - - // signal that the window has been resized - win->on_window_resized(); - - } - return 0; - - case WM_MOVE: - { - base_window** win_ = window_table[hwnd]; - base_window* win; - if (win_) - win = *win_; - else - break; - - - // signal that the window has moved - win->on_window_moved(); - - } - return 0; - - case WM_MOUSELEAVE: - { - base_window** win_ = window_table[hwnd]; - base_window* win; - if (win_) - win = *win_; - else - break; - - - // signal that the mouse has left the window - if (win->mouse_in) - { - win->on_mouse_leave(); - win->mouse_in = false; - } - - } - return 0; - - case WM_MOUSEWHEEL: - { - base_window** win_ = window_table[hwnd]; - base_window* win; - if (win_) - win = *win_; - else - break; - - unsigned long state = 0; - if (wParam & MK_CONTROL) - state |= base_window::CONTROL; - if (wParam & MK_LBUTTON) - state |= base_window::LEFT; - if (wParam & MK_MBUTTON) - state |= base_window::MIDDLE; - if (wParam & MK_RBUTTON) - state |= base_window::RIGHT; - if (wParam & MK_SHIFT) - state |= base_window::SHIFT; - - // signal the mouse wheel event - if (GET_WHEEL_DELTA_WPARAM(wParam) > 0) - { - win->on_wheel_up(state); - } - else - { - win->on_wheel_down(state); - } - - } - return 0; - - case WM_LBUTTONUP: - btn = base_window::LEFT; - case WM_MBUTTONUP: - if (btn == base_window::NONE) - btn = base_window::MIDDLE; - case WM_RBUTTONUP: - if (btn == base_window::NONE) - btn = base_window::RIGHT; - { - // release the mouse capture if the user isn't holding any - // other mouse buttons - if (!((wParam & MK_LBUTTON) | (wParam & MK_MBUTTON) | (wParam & MK_RBUTTON))) - ReleaseCapture(); - - base_window** win_ = window_table[hwnd]; - base_window* win; - if (win_) - win = *win_; - else - break; - - unsigned long state = 0; - if (wParam & MK_CONTROL) - state |= base_window::CONTROL; - if (wParam & MK_LBUTTON) - state |= base_window::LEFT; - if (wParam & MK_MBUTTON) - state |= base_window::MIDDLE; - if (wParam & MK_RBUTTON) - state |= base_window::RIGHT; - if (wParam & MK_SHIFT) - state |= base_window::SHIFT; - - // remove the clicked button from the state - state &= (~btn); - - // signal the mouse click - win->on_mouse_up(btn,state,GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)); - - } - return 0; - - - - case WM_LBUTTONDBLCLK: - if (btn == base_window::NONE) - btn = base_window::LEFT; - case WM_MBUTTONDBLCLK: - if (btn == base_window::NONE) - btn = base_window::MIDDLE; - case WM_RBUTTONDBLCLK: - if (btn == base_window::NONE) - btn = base_window::RIGHT; - is_double = true; - case WM_LBUTTONDOWN: - if (btn == base_window::NONE) - btn = base_window::LEFT; - case WM_MBUTTONDOWN: - if (btn == base_window::NONE) - btn = base_window::MIDDLE; - case WM_RBUTTONDOWN: - if (btn == base_window::NONE) - btn = base_window::RIGHT; - { - SetCapture(hwnd); - - - base_window** win_ = window_table[hwnd]; - base_window* win; - if (win_) - win = *win_; - else - break; - - unsigned long state = 0; - if (wParam & MK_CONTROL) - state |= base_window::CONTROL; - if (wParam & MK_LBUTTON) - state |= base_window::LEFT; - if (wParam & MK_MBUTTON) - state |= base_window::MIDDLE; - if (wParam & MK_RBUTTON) - state |= base_window::RIGHT; - if (wParam & MK_SHIFT) - state |= base_window::SHIFT; - - // remove the clicked button from the state - state &= (~btn); - - // signal the mouse click - win->on_mouse_down(btn,state,GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam),is_double); - - } - return 0; - - case WM_MOUSEMOVE: - { - base_window** win_ = window_table[hwnd]; - base_window* win; - if (win_) - win = *win_; - else - break; - - unsigned long state = 0; - bool mouse_button_down = false; - if (wParam & MK_CONTROL) - state |= base_window::CONTROL; - if (wParam & MK_LBUTTON) - { - state |= base_window::LEFT; - mouse_button_down = true; - } - if (wParam & MK_MBUTTON) - { - mouse_button_down = true; - state |= base_window::MIDDLE; - } - if (wParam & MK_RBUTTON) - { - state |= base_window::RIGHT; - mouse_button_down = true; - } - if (wParam & MK_SHIFT) - state |= base_window::SHIFT; - - // signal the mouse movement if this mouse event isn't identical to the - // last one we got - if ( GET_X_LPARAM(lParam) != win->prevx || - GET_Y_LPARAM(lParam) != win->prevy || - state != win->prev_state) - { - win->on_mouse_move(state,GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)); - } - - // save the event data into the prev* member variables - win->prevx = GET_X_LPARAM(lParam); - win->prevy = GET_Y_LPARAM(lParam); - win->prev_state = state; - - // The following block of code checks if the mouse is moving - // into or out of the window. - if (mouse_button_down == false) - { - // if there isn't any mouse button down then the fact that - // we are getting a mouse move message means it is in the - // window - if (win->mouse_in == false) - { - win->on_mouse_enter(); - win->mouse_in = true; - - // set the tracker for the mouse - TRACKMOUSEEVENT tm; - tm.hwndTrack = hwnd; - tm.cbSize = sizeof(tm); - tm.dwFlags = TME_LEAVE; - _TrackMouseEvent(&tm); - } - } - else if (win->mouse_in) - { - // check if the mouse is currently outside the window - const long mouse_x = GET_X_LPARAM(lParam); - const long mouse_y = GET_Y_LPARAM(lParam); - if (mouse_x < 0 || mouse_y < 0) - { - // the mouse is not in the window - win->mouse_in = false; - win->on_mouse_leave(); - } - else - { - unsigned long width, height; - win->get_size(width,height); - if (mouse_x >= static_cast(width) || - mouse_y >= static_cast(height)) - { - // the mouse is not in the window - win->mouse_in = false; - win->on_mouse_leave(); - } - } - } - else if (win->mouse_in == false) - { - // at this point we know that the mouse is moving around - // with some of its buttons down. So it might be outside the window. - // get the window size and see if the mouse is outside - // it. - const long mouse_x = GET_X_LPARAM(lParam); - const long mouse_y = GET_Y_LPARAM(lParam); - unsigned long width, height; - win->get_size(width,height); - if (mouse_x < static_cast(width) && - mouse_y < static_cast(height) && - mouse_x >= 0 && - mouse_y >= 0) - { - // The mouse has gone inside the window - win->mouse_in = true; - win->on_mouse_enter(); - - // set the tracker for the mouse - TRACKMOUSEEVENT tm; - tm.hwndTrack = hwnd; - tm.cbSize = sizeof(tm); - tm.dwFlags = TME_LEAVE; - _TrackMouseEvent(&tm); - } - - } - - - } - return 0; - - case WM_PAINT : - { - - PAINTSTRUCT ps; - HDC hdc = NULL; - - hdc = BeginPaint (hwnd, &ps) ; - - try - { - base_window** win_ = window_table[hwnd]; - base_window* win; - if (win_) - win = *win_; - else - break; - - - - - LONG x = ps.rcPaint.left; - LONG y = ps.rcPaint.top; - LONG width = ps.rcPaint.right - x; - LONG height = ps.rcPaint.bottom - y; - - if (width != 0 && height != 0) - { - - BITMAPINFO bmap_info; - bmap_info.bmiColors[0].rgbBlue = 0; - bmap_info.bmiColors[0].rgbGreen = 0; - bmap_info.bmiColors[0].rgbRed = 0; - bmap_info.bmiColors[0].rgbReserved = 0; - bmap_info.bmiHeader.biSize = sizeof(bmap_info.bmiHeader); - bmap_info.bmiHeader.biWidth = width; - bmap_info.bmiHeader.biHeight = -1*height; - bmap_info.bmiHeader.biPlanes = 1; - bmap_info.bmiHeader.biBitCount = 24; - bmap_info.bmiHeader.biCompression = BI_RGB; - bmap_info.bmiHeader.biSizeImage = 0; - bmap_info.bmiHeader.biXPelsPerMeter = 0; - bmap_info.bmiHeader.biYPelsPerMeter = 0; - bmap_info.bmiHeader.biClrUsed = 0; - bmap_info.bmiHeader.biClrImportant = 0; - - - - unsigned char* bitmap ; - unsigned long size; - unsigned long padding = 0; - if ((width*3)%sizeof(LONG) != 0) - { - padding = sizeof(LONG) - (width*3)%sizeof(LONG); - size = (width*3+padding)*height; - } - else - { - size = width*height*3; - } - - if (bitmap_buffer.size() < size) - bitmap_buffer.resize(size); - bitmap = &bitmap_buffer[0]; - - canvas bits(bitmap,padding,x,y,x+width-1,y+height-1); - - - - win->paint(bits); - - - - SetDIBitsToDevice ( - hdc, - ps.rcPaint.left, - ps.rcPaint.top, - width, - height, - 0, - 0, - 0, - height, - bitmap, - &bmap_info, - DIB_RGB_COLORS - ); - } - - EndPaint (hwnd, &ps) ; - - } - catch (...) - { - // make sure EndPaint is called even if an exception - // is thrown. - if (hdc != NULL) - EndPaint (hwnd, &ps); - throw; - } - } - return 0 ; - - case WM_ERASEBKGND: - return 1; - - - - - case WM_CLOSE: - { - base_window** win_ = window_table[hwnd]; - base_window* win; - if (win_) - win = *win_; - else - break; - - - // signal that the window is being closed - if (win->on_window_close() == base_window::DO_NOT_CLOSE_WINDOW) - { - DLIB_ASSERT(win->has_been_destroyed == false, - "\tYou called close_window() inside the on_window_close() event but" - << "\n\tthen returned DO_NOT_CLOSE_WINDOW. You can do one or the other but not both." - << "\n\tthis: " << win - ); - // this happens if the on_window_close() callback - // tells us to ignore the close event. - return 0; - } - else - { - if (window_table[hwnd]) - { - window_table.destroy(hwnd); - win->has_been_destroyed = true; - win->hwnd = 0; - globals->window_close_signaler.broadcast(); - } - else - { - // in this case the window must have self destructed by - // calling delete this; - return 0; - } - } - - } - return DefWindowProc (hwnd, message, wParam, lParam); - - case WM_IME_STARTCOMPOSITION: - globals->in_ime_composition = true; - break; - - case WM_IME_COMPOSITION: - { - globals->in_ime_composition = false; - base_window** win_ = window_table[hwnd]; - base_window* win; - if (win_) - win = *win_; - else - break; - HIMC hImc = ImmGetContext(hwnd); - if (lParam & GCS_RESULTSTR){ - WCHAR wc; - LONG bufbyte = ImmGetCompositionStringW(hImc, GCS_RESULTSTR, &wc, 0); - if (bufbyte != IMM_ERROR_NODATA && bufbyte != IMM_ERROR_GENERAL){ - bufbyte += sizeof(WCHAR); - - - WCHAR *buf = new WCHAR[bufbyte / sizeof(WCHAR)]; - ImmGetCompositionStringW(hImc, GCS_RESULTSTR, buf, bufbyte); - buf[bufbyte / sizeof(WCHAR) - 1] = L'\0'; - - // signal the putstring event - win->on_string_put(std::wstring(buf)); - delete [] buf; - } - } - ImmReleaseContext(hwnd, hImc); - } - break; - - default: - break; - - } // switch (message) - - - } - catch (std::exception& e) - { - error_box("Exception thrown in event handler",e.what()); - globals->quit_windows_loop = true; - } - catch (...) - { - error_box("Exception thrown in event handler","Unknown Exception type."); - globals->quit_windows_loop = true; - } - - return DefWindowProc (hwnd, message, wParam, lParam) ; - - } - - // ---------------------------------------------------------------------------------------- - - void show_window ( - HWND hwnd - ) - { - using namespace gui_core_kernel_1_globals; - PostMessage(global_data()->helper_window,WM_USER+SHOW_WINDOW_SHOW,(WPARAM)hwnd,0); - } - - // ---------------------------------------------------------------------------------------- - - void hide_window ( - HWND hwnd - ) - { - using namespace gui_core_kernel_1_globals; - PostMessage(global_data()->helper_window,WM_USER+SHOW_WINDOW_HIDE,(WPARAM)hwnd,0); - } - - // ---------------------------------------------------------------------------------------- - - void give_window_focus ( - HWND hwnd - ) - /*! - ensures - - calls SetActiveWindow(hwnd) from the event handling thread. - !*/ - { - using namespace gui_core_kernel_1_globals; - PostMessage(global_data()->helper_window,WM_USER+SET_ACTIVE_WINDOW,(WPARAM)hwnd,0); - } - - // ---------------------------------------------------------------------------------------- - - void destroy_window ( - HWND hwnd - ) - /*! - ensures - - calls DestroyWindow(hwnd) from the event handling thread. - !*/ - { - using namespace gui_core_kernel_1_globals; - PostMessage(global_data()->helper_window,WM_USER+DESTROY_WINDOW,(WPARAM)hwnd,0); - } - - // ---------------------------------------------------------------------------------------- - - HWND make_window ( - DWORD dwStyle_ - ) - /*! - ensures - - creates a window by calling CreateWindow and passes on the - dwStyle argument. - - returns the HWND that is returned by CreateWindow - - ensures that CreateWindow is called from the event handler thread - - if (it was unable to create a window) then - - returns NULL or helper_window - !*/ - { - using namespace gui_core_kernel_1_globals; - shared_ptr_thread_safe globals(global_data()); - // if we are running in the event handling thread then just call - // CreateWindow directly - if (get_thread_id() == globals->event_thread_id) - { - // if this is stupposed to be a popup window then do the popup window thing - if (dwStyle_ == WS_CHILD) - { - TCHAR nothing[] = TEXT(""); - HWND tmp = CreateWindowEx (WS_EX_TOOLWINDOW|WS_EX_TOPMOST, globals->window_class_name, nothing, - dwStyle_, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - globals->helper_window, NULL, globals->hInstance, NULL); - SetParent(tmp,NULL); - return tmp; - } - else - { - TCHAR nothing[] = TEXT(""); - return CreateWindow (globals->window_class_name, nothing, - dwStyle_, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - NULL, NULL, globals->hInstance, NULL); - } - } - else - { - auto_mutex M(globals->window_table.get_mutex()); - // wait for our chance to make a new window request - while (globals->request_new_window) - globals->et_signaler.wait(); - - - globals->dwStyle = dwStyle_; - if (PostMessage(globals->helper_window,WM_USER+CREATE_WINDOW,0,0)==0) - { - throw gui_error("Unable to schedule function for execution in event handling thread."); - } - - // wait for our request to be serviced - while (globals->new_window == NULL) - globals->et_signaler.wait(); - - HWND temp = globals->new_window; - globals->new_window = NULL; - globals->request_new_window = false; - globals->et_signaler.broadcast(); - - // if make_window() returns the helper_window then it means it failed - // to make a new window - if (temp == globals->helper_window) - temp = NULL; - - return temp; - } - } - - // ------------------------------------------------------------------------------------ - - - } // end namespace gui_core_kernel_1_globals - -// ---------------------------------------------------------------------------------------- - - void canvas:: - fill ( - unsigned char red_, - unsigned char green_, - unsigned char blue_ - ) const - { - const unsigned long red = red_; - const unsigned long green = green_; - const unsigned long blue = blue_; - - const LONG block1 = (blue<<24) | (red<<16) | (green<<8) | blue; - const LONG block2 = (green<<24) | (blue<<16) | (red<<8) | green; - const LONG block3 = (red<<24) | (green<<16) | (blue<<8) | red; - - // remember that row_width is a multiple of 4 because windows - // requires that all bitmaps have row widths that are multiples of 4. - unsigned long size = row_width/4; - for (unsigned long i = 0; i < height_; ++i) - { - unsigned long padding = size%3; - LONG* start = reinterpret_cast(bits+row_width*i); - LONG* end = reinterpret_cast(start) + size - padding; - while (start != end) - { - *start = block1; - ++start; - *start = block2; - ++start; - *start = block3; - ++start; - } - if (padding) - { - *start = block1; - ++start; - --padding; - } - if (padding) - { - *start = block2; - } - } - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - trigger_user_event ( - void* p, - int i - ) - { - using namespace gui_core_kernel_1_globals; - - user_event_type e; - e.w = hwnd; - e.p = p; - e.i = i; - { - auto_mutex M(globals->user_events.get_mutex()); - globals->user_events.enqueue(e); - } - - if (PostMessage(globals->helper_window,WM_USER+USER_EVENTS_READY,0,0)==0) - { - throw gui_error("Unable to schedule function for execution in event handling thread."); - } - } - -// ---------------------------------------------------------------------------------------- - - base_window:: - base_window ( - bool resizable, - bool undecorated - ) : - globals(gui_core_kernel_1_globals::global_data()), - has_been_destroyed(false), - prevx(-1), - prevy(-1), - prev_state(0), - wm(globals->window_table.get_mutex()) - { - using namespace gui_core_kernel_1_globals; - DLIB_ASSERT(!(undecorated == true && resizable == true), - "\tbase_window::base_window()" - << "\n\tThere is no such thing as an undecorated window that is resizable by the user." - << "\n\tthis: " << this - ); - - if (resizable) - style = WS_OVERLAPPEDWINDOW; - else if (undecorated) - style = WS_CHILD; - else - style = WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME ^ WS_MAXIMIZEBOX; - - hwnd = gui_core_kernel_1_globals::make_window(style); - - if (hwnd == NULL) - throw gui_error("unable to create base_window"); - - auto_mutex M(wm); - - mouse_in = false; - - HWND temp = hwnd; - base_window* ttemp = this; - globals->window_table.add(temp,ttemp); - } - -// ---------------------------------------------------------------------------------------- - - base_window:: - ~base_window ( - ) - { - using namespace gui_core_kernel_1_globals; - close_window(); - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - close_window ( - ) - { - using namespace gui_core_kernel_1_globals; - auto_mutex M(wm); - if (has_been_destroyed == false) - { - // do this just to make sure no one tries to call this window's - // calbacks. - globals->window_table.destroy(hwnd); - gui_core_kernel_1_globals::destroy_window(hwnd); - hwnd = 0; - has_been_destroyed = true; - globals->window_close_signaler.broadcast(); - } - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - wait_until_closed ( - ) const - { - using namespace gui_core_kernel_1_globals; - auto_mutex M(wm); - while (has_been_destroyed == false) - globals->window_close_signaler.wait(); - } - -// ---------------------------------------------------------------------------------------- - - bool base_window:: - is_closed ( - ) const - { - auto_mutex M(wm); - return has_been_destroyed; - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - set_title ( - const std::string &title - ) - { - set_title(convert_mbstring_to_wstring(title)); - } - - void base_window:: - set_title ( - const ustring &title - ) - { - set_title(convert_utf32_to_wstring(title)); - } - - void base_window:: - set_title ( - const std::wstring& title - ) - { - using namespace gui_core_kernel_1_globals; - - auto_mutex M(wm); - if (has_been_destroyed == true) - return; - - - // call the SetWindowText function with our arguments but make sure it is from - // the event thread. We have to do this because the SetWindowText() apparently blocks - // until something happens in the event thread so we have to - // do this to avoid possible deadlocks. - if (get_thread_id() == globals->event_thread_id) - { - SetWindowTextW(hwnd,title.c_str()); - } - else - { - globals->window_title = title; - globals->set_window_title_done = false; - - if (PostMessage(globals->helper_window,WM_USER+CALL_SET_WINDOW_TITLE,(WPARAM)hwnd,0)==0) - { - throw gui_error("Unable to schedule SetWindowText function for execution in event handling thread."); - } - - // wait for any SetWindowText() calls to finish - while (globals->set_window_title_done == false) - globals->et_signaler.wait(); - } - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - show ( - ) - { - using namespace gui_core_kernel_1_globals; - auto_mutex M(wm); - if (has_been_destroyed == true) - return; - - show_window(hwnd); - if (style != WS_CHILD) - give_window_focus(hwnd); - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - hide( - ) - { - using namespace gui_core_kernel_1_globals; - auto_mutex M(wm); - if (has_been_destroyed == true) - return; - - hide_window(hwnd); - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - set_size ( - int width_, - int height_ - ) - { - using namespace gui_core_kernel_1_globals; - auto_mutex M(wm); - if (has_been_destroyed == true) - return; - - if (get_thread_id() == globals->event_thread_id) - { - RECT info; - GetWindowRect(hwnd,&info); - - int x = info.left; - int y = info.top; - int width; - int height; - - RECT rect; - rect.top = 0; - rect.left = 0; - rect.bottom = height_; - rect.right = width_; - AdjustWindowRectEx(&rect,style,FALSE,0); - - width = std::abs(rect.right - rect.left); - height = std::abs(rect.bottom - rect.top); - - MoveWindow( - hwnd, - x, - y, - width, - height, - TRUE); - } - else - { - RECT info; - GetWindowRect(hwnd,&info); - - int x = info.left; - int y = info.top; - int width; - int height; - - RECT rect; - rect.top = 0; - rect.left = 0; - rect.bottom = height_; - rect.right = width_; - AdjustWindowRectEx(&rect,style,FALSE,0); - - width = std::abs(rect.right - rect.left); - height = std::abs(rect.bottom - rect.top); - - // call the MoveWindow function with our arguments. We - // have to do this because the MoveWindow() apparently blocks - // until something happens in the event thread so we have to - // do this to avoid possible deadlocks. - globals->move_window_hwnd = hwnd; - globals->move_window_x = x; - globals->move_window_y = y; - globals->move_window_width = width; - globals->move_window_height = height; - globals->move_window_done = false; - - if (PostMessage(globals->helper_window,WM_USER+CALL_MOVE_WINDOW,0,0)==0) - { - throw gui_error("Unable to schedule MoveWindow function for execution in event handling thread."); - } - - // wait for any MoveWindow calls to finish - while (globals->move_window_done == false) - globals->et_signaler.wait(); - } - - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - set_pos ( - long x_, - long y_ - ) - { - using namespace gui_core_kernel_1_globals; - auto_mutex M(wm); - if (has_been_destroyed == true) - return; - - if (get_thread_id() == globals->event_thread_id) - { - RECT info; - GetWindowRect(hwnd,&info); - int width = info.right - info.left; - int height = info.bottom - info.top; - - MoveWindow( - hwnd, - x_, - y_, - width, - height, - TRUE); - - } - else - { - RECT info; - GetWindowRect(hwnd,&info); - int width = info.right - info.left; - int height = info.bottom - info.top; - - - - // call the MoveWindow function with our arguments. We - // have to do this because the MoveWindow() apparently blocks - // until something happens in the event thread so we have to - // do this to avoid possible deadlocks. - globals->move_window_hwnd = hwnd; - globals->move_window_x = x_; - globals->move_window_y = y_; - globals->move_window_width = width; - globals->move_window_height = height; - globals->move_window_done = false; - - if (PostMessage(globals->helper_window,WM_USER+CALL_MOVE_WINDOW,0,0)==0) - { - throw gui_error("Unable to schedule MoveWindow function for execution in event handling thread."); - } - - // wait for any MoveWindow calls to finish - while (globals->move_window_done == false) - globals->et_signaler.wait(); - } - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - get_pos ( - long& x_, - long& y_ - ) - { - auto_mutex M(wm); - x_ = 0; - y_ = 0; - if (has_been_destroyed == true) - return; - - POINT p; - p.x = 0; - p.y = 0; - ClientToScreen(hwnd,&p); - - x_ = p.x; - y_ = p.y; - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - get_display_size ( - unsigned long& width, - unsigned long& height - ) const - { - auto_mutex M(wm); - width = 0; - height = 0; - if (has_been_destroyed == true) - return; - - - RECT rc; - GetWindowRect(hwnd, &rc); - - HMONITOR hMonitor; - MONITORINFO mi; - // - // get the nearest monitor to the passed rect. - // - hMonitor = MonitorFromRect(&rc, MONITOR_DEFAULTTONEAREST); - - // - // get the work area or entire monitor rect. - // - mi.cbSize = sizeof(mi); - GetMonitorInfo(hMonitor, &mi); - - rc = mi.rcMonitor; - - width = static_cast(rc.right - rc.left); - height = static_cast(rc.bottom - rc.top); - - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - get_size ( - unsigned long& width, - unsigned long& height - ) const - { - auto_mutex M(wm); - width = 0; - height = 0; - if (has_been_destroyed == true) - return; - - - RECT r; - GetClientRect(hwnd,&r); - - width = r.right - r.left; - height = r.bottom - r.top; - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - invalidate_rectangle ( - const rectangle& rect - ) - { - auto_mutex M(wm); - if (rect.is_empty() == false && !has_been_destroyed) - { - RECT info; - info.top = rect.top(); - info.left = rect.left(); - info.right = rect.right()+1; - info.bottom = rect.bottom()+1; - - InvalidateRect(hwnd,&info,FALSE); - } - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - set_im_pos ( - long x, - long y - ) - { - auto_mutex M(wm); - if (has_been_destroyed == true) - return; - - HIMC hImc = ImmGetContext(hwnd); - - COMPOSITIONFORM cf; - cf.dwStyle = CFS_POINT; - cf.ptCurrentPos.x = x; - cf.ptCurrentPos.y = y; - ImmSetCompositionWindow(hImc, &cf); - ImmReleaseContext(hwnd, hImc); - } - -// ---------------------------------------------------------------------------------------- - - void put_on_clipboard ( - const std::string& str - ) - { - put_on_clipboard(convert_mbstring_to_wstring(str)); - } - - void put_on_clipboard ( - const dlib::ustring& str - ) - { - put_on_clipboard(convert_utf32_to_wstring(str)); - } - - void put_on_clipboard ( - const std::wstring& str - ) - { - using namespace gui_core_kernel_1_globals; - using namespace std; - - shared_ptr_thread_safe globals(global_data()); - - if (OpenClipboard(globals->helper_window)) - { - EmptyClipboard(); - auto_mutex M(globals->window_table.get_mutex()); - - const unsigned long newlines = count(str.begin(),str.end(),L'\n'); - - HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE,(str.size()+newlines+1)*sizeof(wchar_t)); - if (mem != NULL) - { - wchar_t* buf = reinterpret_cast(GlobalLock(mem)); - - if (buf != NULL) - { - // copy str into buf while also replacing all the \n with \r\n - for (wstring::size_type i = 0; i < str.size(); ++i) - { - if (str[i] != L'\n') - { - *buf = str[i]; - ++buf; - } - else - { - *buf = L'\r'; - ++buf; - *buf = L'\n'; - ++buf; - } - } - *buf = L'\0'; - GlobalUnlock(mem); - SetClipboardData(CF_UNICODETEXT,mem); - } - } - CloseClipboard(); - } - } - -// ---------------------------------------------------------------------------------------- - - void get_from_clipboard ( - std::string& str - ) - { - std::wstring wstr; - get_from_clipboard(wstr); - str = convert_wstring_to_mbstring(wstr); - } - - void get_from_clipboard ( - dlib::ustring& str - ) - { - std::wstring wstr; - get_from_clipboard(wstr); - str = convert_wstring_to_utf32(wstr); - } - - void get_from_clipboard ( - std::wstring& str - ) - { - using namespace gui_core_kernel_1_globals; - using namespace std; - shared_ptr_thread_safe globals(global_data()); - - auto_mutex M(globals->window_table.get_mutex()); - if (OpenClipboard(globals->helper_window)) - { - - HANDLE data = GetClipboardData(CF_UNICODETEXT); - if (data != NULL) - { - wchar_t* buf = reinterpret_cast(GlobalLock(data)); - if (buf != 0) - { - str.clear(); - - // copy the data from buf into str while also removing any '\r' - // characters. - while (*buf != L'\0') - { - if (*buf != L'\r') - str += *buf; - ++buf; - } - - GlobalUnlock(data); - } - else - { - Beep(500,500); - } - } - - CloseClipboard(); - } - } - -// ---------------------------------------------------------------------------------------- - -} - - -#endif // WIN32 - -#endif // DLIB_GUI_CORE_KERNEL_1_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/gui_core/gui_core_kernel_1.h b/lib/3rdParty/dlib/include/dlib/gui_core/gui_core_kernel_1.h index 8b1b28b4..b7077ac0 100644 --- a/lib/3rdParty/dlib/include/dlib/gui_core/gui_core_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/gui_core/gui_core_kernel_1.h @@ -12,6 +12,7 @@ #endif #include + #include "../windows_magic.h" @@ -39,8 +40,7 @@ #include "../queue.h" #include "../pixel.h" #include "../unicode.h" -#include "../smart_pointers_thread_safe.h" - +#include "../smart_pointers/shared_ptr_thread_safe.h" namespace dlib { @@ -124,16 +124,16 @@ namespace dlib template <> struct pixel_traits { - const static bool rgb = true; - const static bool rgb_alpha = false; - const static bool grayscale = false; - const static bool hsi = false; - const static long num = 3; + constexpr static bool rgb = true; + constexpr static bool rgb_alpha = false; + constexpr static bool grayscale = false; + constexpr static bool hsi = false; + constexpr static long num = 3; typedef unsigned char basic_pixel_type; static basic_pixel_type min() { return 0;} static basic_pixel_type max() { return 255;} - const static bool is_unsigned = true; - const static bool has_alpha = false; + constexpr static bool is_unsigned = true; + constexpr static bool has_alpha = false; }; // ---------------------------------------------------------------------------------------- @@ -169,7 +169,7 @@ namespace dlib class base_window { friend LRESULT CALLBACK gui_core_kernel_1_globals::WndProc (HWND, UINT, WPARAM, LPARAM); - shared_ptr_thread_safe globals; + dlib::shared_ptr_thread_safe globals; HWND hwnd; DWORD style; diff --git a/lib/3rdParty/dlib/include/dlib/gui_core/gui_core_kernel_2.cpp b/lib/3rdParty/dlib/include/dlib/gui_core/gui_core_kernel_2.cpp deleted file mode 100644 index cd9ab07b..00000000 --- a/lib/3rdParty/dlib/include/dlib/gui_core/gui_core_kernel_2.cpp +++ /dev/null @@ -1,1995 +0,0 @@ -// Copyright (C) 2005 Davis E. King (davis@dlib.net), Keita Mochizuki -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_GUI_CORE_KERNEL_2_CPp_ -#define DLIB_GUI_CORE_KERNEL_2_CPp_ -#include "../platform.h" - -#ifdef POSIX - -#include "gui_core_kernel_2.h" - - -#include -#include -#include -#include -#include -#include -#include -#include "../assert.h" -#include "../queue.h" -#include -#include -#include -#include "../sync_extension.h" -#include "../logger.h" -#include -#include -#include "../smart_pointers_thread_safe.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - namespace gui_core_kernel_2_globals - { - void init_keyboard_mod_masks(); - struct user_event_type - { - Window w; - void* p; - int i; - }; - - typedef sync_extension::kernel_1b>::kernel_2a_c>::kernel_1a queue_of_user_events; - - typedef sync_extension::kernel_1a>::kernel_1a - window_table_type; - - // ---------------------------------------------------------------------------------------- - - const shared_ptr_thread_safe& global_mutex() - { - static shared_ptr_thread_safe m(new dlib::mutex); - return m; - } - - class event_handler_thread : public threaded_object - { - public: - - enum et_state - { - uninitialized, - initialized, - failure_to_init - }; - - et_state status; - logger dlog; - - - int depth; - Display* disp; - XIM xim; - XIMStyle xim_style; - Screen* screen; - - Atom delete_window; - Window exit_window; - std::wstring clipboard; - - int alt_mask; - int meta_mask; - int num_lock_mask; - int scroll_lock_mask; - - // the mutex in this object is the global mutex used to protect everything - // in the gui_core and gui_widgets components. - window_table_type window_table; - - rsignaler window_close_signaler; - rsignaler et_signaler; - - queue_of_user_events user_events; - queue_of_user_events user_events_temp; - - shared_ptr_thread_safe reference_to_global_mutex; - - event_handler_thread( - ) : - dlog("dlib.gui_core"), - depth(0), - disp(0), - xim(0), - screen(0), - alt_mask(0), - meta_mask(0), - num_lock_mask(0), - scroll_lock_mask(0), - window_close_signaler(window_table.get_mutex()), - et_signaler(window_table.get_mutex()), - reference_to_global_mutex(global_mutex()) - { - auto_mutex M(window_table.get_mutex()); - - status = uninitialized; - - // start up the event handler thread - start(); - - // wait for the event thread to get up and running - while (status == uninitialized) - et_signaler.wait(); - - if (status == failure_to_init) - throw gui_error("Failed to initialize X11 resources"); - - init_keyboard_mod_masks(); - } - - ~event_handler_thread () - { - - if (is_alive()) - { - - if (status != failure_to_init) - { - XConfigureEvent event; - event.type = ConfigureNotify; - event.send_event = True; - event.display = disp; - event.window = exit_window; - event.x = 1; - XFlush(disp); - XPutBackEvent(disp,reinterpret_cast(&event)); - XFlush(disp); - - // This should cause XNextEvent() to unblock so that it will see - // this ConfigureNotify event we are putting onto the event queue. - XSendEvent(disp,exit_window,False,0,reinterpret_cast(&event)); - XFlush(disp); - - wait(); - - if (xim != NULL) - { - XCloseIM(xim); - } - - XCloseDisplay(disp); - - - } - else - { - - wait(); - } - } - - - } - - private: - - void thread ( - ) - { - using namespace std; - using namespace dlib; - try - { - - // You are supposed to call this if using XLib in a threaded program. Note - // however that at one point I noticed that calling this causes a dead-lock - // when using XIM. But I can't reproduce that anymore and not calling it - // sometimes causes XCloseDisplay() to hang. - if (XInitThreads() == 0) - { - dlog << LFATAL << "Unable to initialize threading support."; - // signal that an error has occurred - window_table.get_mutex().lock(); - status = failure_to_init; - et_signaler.broadcast(); - window_table.get_mutex().unlock(); - return; - } - - window_table.get_mutex().lock(); - disp = XOpenDisplay(NULL); - window_table.get_mutex().unlock(); - if (disp == 0) - { - window_table.get_mutex().lock(); - disp = XOpenDisplay(":0.0"); - window_table.get_mutex().unlock(); - if (disp == 0) - { - dlog << LFATAL << "Unable to connect to the X display."; - // signal that an error has occurred - window_table.get_mutex().lock(); - status = failure_to_init; - et_signaler.broadcast(); - window_table.get_mutex().unlock(); - return; - } - } - - window_table.get_mutex().lock(); - screen = DefaultScreenOfDisplay(disp); - depth = DefaultDepthOfScreen(screen); - delete_window = XInternAtom(disp,"WM_DELETE_WINDOW",1); - window_table.get_mutex().unlock(); - - xim = NULL; - // I'm disabling XIM usage all together because calling XSetICValues() - // in set_im_pos() randomly hangs the application (on Ubuntu 13.10 at - // least). - /* - window_table.get_mutex().lock(); - std::string saved_locale(setlocale (LC_CTYPE, NULL)); - if (setlocale( LC_CTYPE, "" ) && XSupportsLocale() && XSetLocaleModifiers("")) - xim = XOpenIM(disp, NULL, NULL, NULL); - else - setlocale( LC_CTYPE, saved_locale.c_str() ); - window_table.get_mutex().unlock(); - */ - if (xim) - { - const static XIMStyle preedit_styles[] = - {XIMPreeditPosition, XIMPreeditNothing, XIMPreeditNone, 0}; - const static XIMStyle status_styles[] = - {XIMStatusNothing, XIMStatusNone, 0}; - xim_style = 0; - - XIMStyles *xim_styles; - window_table.get_mutex().lock(); - - XGetIMValues (xim, XNQueryInputStyle, &xim_styles, (const void*)NULL); - window_table.get_mutex().unlock(); - std::set xims; - for (int i = 0; i < xim_styles->count_styles; ++i){ - xims.insert(xim_styles->supported_styles[i]); - } - for (int j = 0; status_styles[j]; ++j){ - for (int i = 0; preedit_styles[i]; ++i){ - xim_style = (status_styles[j] | preedit_styles[i]); - if (xims.count(xim_style)) break; - } - if (xim_style) break; - } - XFree(xim_styles); - } - - // make this window just so we can send messages to it and trigger - // events in the event thread - XSetWindowAttributes attr; - window_table.get_mutex().lock(); - exit_window = XCreateWindow( - disp, - DefaultRootWindow(disp), - 0, - 0, - 10, // this is the default width of a window - 10, // this is the default width of a window - 0, - depth, - InputOutput, - CopyFromParent, - 0, - &attr - ); - window_table.get_mutex().unlock(); - - // signal that the event thread is now up and running - window_table.get_mutex().lock(); - status = initialized; - et_signaler.broadcast(); - window_table.get_mutex().unlock(); - - // start the event handler - event_handler(); - } - catch (std::exception& e) - { - cout << "\nEXCEPTION THROWN: \n" << e.what() << endl; - abort(); - } - catch (...) - { - cout << "UNKNOWN EXCEPTION THROWN.\n" << endl; - abort(); - } - } - - void event_handler(); - void init_keyboard_mod_masks(); - }; - - struct x11_base_windowstuff - { - Window hwnd; - Time last_click_time; - XIC xic; - XFontSet fs; - shared_ptr_thread_safe globals; - }; - - // Do all this just to make sure global_mutex() is initialized at program start - // and thus hopefully before any threads have the chance to startup and call - // global_data() concurrently. - struct call_global_mutex { call_global_mutex() { global_mutex(); } }; - static call_global_mutex call_global_mutex_instance; - - const shared_ptr_thread_safe& global_data() - { - auto_mutex M(*global_mutex()); - static shared_ptr_thread_safe p; - if (p.get() == 0) - p.reset(new event_handler_thread()); - return p; - } - - // ---------------------------------------------------------------------------------------- - - Bool XCheckIfEventPredicate ( - Display* , - XEvent* event, - XPointer arg - ) - /*! - ensures - - if (event is an Expose event for the window pointed to by arg) then - - returns true - - else - - returns false - !*/ - { - if (event->type == Expose) - { - XExposeEvent* e = reinterpret_cast(event); - Window* win= reinterpret_cast(arg); - if (e->window == *win) - { - return 1; - } - } - return 0; - } - - // ---------------------------------------------------------------------------------------- - - static bool map_keys ( - KeySym keycode, - bool , - bool , - unsigned long& result, - bool& is_printable - ) - /*! - requires - - if (shift was down for this key) then - - shift == true - - if (caps lock was on for this key) then - - caps == true - - keycode == the keycode from windows that we are to process - - keycode < keyboard_keys_size - ensures - - if (this key should be ignored) then - - returns false - - else - - returns true - - #is_printable == true if result is a printable ascii character - - #result == the keycode converted into the proper number to tbe - returned by the event handler. - !*/ - { - is_printable = true; - if ((keycode <= 'z' && keycode >= 'a') || - (keycode <= 'Z' && keycode >= 'A') || - (keycode <= '9' && keycode >= '0')) - { - result = keycode; - } - else - { - is_printable = false; - switch (keycode) - { - case XK_Home: result = base_window::KEY_HOME; break; - case XK_Left: result = base_window::KEY_LEFT; break; - case XK_Right: result = base_window::KEY_RIGHT; break; - case XK_Down: result = base_window::KEY_DOWN; break; - case XK_Up: result = base_window::KEY_UP; break; - case XK_Prior: result = base_window::KEY_PAGE_UP; break; - case XK_Next: result = base_window::KEY_PAGE_DOWN; break; - case XK_End: result = base_window::KEY_END; break; - case XK_Escape: result = base_window::KEY_ESC; break; - - case XK_KP_Delete: result = base_window::KEY_DELETE; break; - case XK_KP_Prior: result = base_window::KEY_PAGE_UP; break; - case XK_KP_Next: result = base_window::KEY_PAGE_DOWN; break; - - - case XK_F1: result = base_window::KEY_F1; break; - case XK_F2: result = base_window::KEY_F2; break; - case XK_F3: result = base_window::KEY_F3; break; - case XK_F4: result = base_window::KEY_F4; break; - case XK_F5: result = base_window::KEY_F5; break; - case XK_F6: result = base_window::KEY_F6; break; - case XK_F7: result = base_window::KEY_F7; break; - case XK_F8: result = base_window::KEY_F8; break; - case XK_F9: result = base_window::KEY_F9; break; - case XK_F10: result = base_window::KEY_F10; break; - case XK_F11: result = base_window::KEY_F11; break; - case XK_F12: result = base_window::KEY_F12; break; - - - case XK_Shift_L: result = base_window::KEY_SHIFT; break; - case XK_Shift_R: result = base_window::KEY_SHIFT; break; - case XK_Control_L: result = base_window::KEY_CTRL; break; - case XK_Control_R: result = base_window::KEY_CTRL; break; - case XK_Caps_Lock: result = base_window::KEY_CAPS_LOCK; break; - case XK_Alt_L: result = base_window::KEY_ALT; break; - case XK_Alt_R: result = base_window::KEY_ALT; break; - - - case XK_BackSpace: result = base_window::KEY_BACKSPACE; break; - case XK_Delete: result = base_window::KEY_DELETE; break; - case XK_Scroll_Lock: result = base_window::KEY_SCROLL_LOCK; break; - case XK_Pause: result = base_window::KEY_PAUSE; break; - case XK_Insert: result = base_window::KEY_INSERT; break; - case XK_KP_Insert: result = base_window::KEY_INSERT; break; - - - - - case XK_exclam: - is_printable = true; - result = '!'; break; - case XK_quotedbl: - is_printable = true; - result = '"'; break; - case XK_numbersign: - is_printable = true; - result = '#'; break; - case XK_dollar: - is_printable = true; - result = '$'; break; - case XK_percent: - is_printable = true; - result = '%'; break; - case XK_ampersand: - is_printable = true; - result = '&'; break; - case XK_apostrophe: - is_printable = true; - result = '\''; break; - case XK_parenleft: - is_printable = true; - result = '('; break; - case XK_parenright: - is_printable = true; - result = ')'; break; - case XK_asterisk: - is_printable = true; - result = '*'; break; - case XK_plus: - is_printable = true; - result = '+'; break; - case XK_comma: - is_printable = true; - result = ','; break; - case XK_minus: - is_printable = true; - result = '-'; break; - case XK_period: - is_printable = true; - result = '.'; break; - case XK_slash: - is_printable = true; - result = '/'; break; - case XK_colon: - is_printable = true; - result = ':'; break; - case XK_semicolon: - is_printable = true; - result = ';'; break; - case XK_less: - is_printable = true; - result = '<'; break; - case XK_equal: - is_printable = true; - result = '='; break; - case XK_greater: - is_printable = true; - result = '>'; break; - case XK_question: - is_printable = true; - result = '?'; break; - case XK_at: - is_printable = true; - result = '@'; break; - case XK_grave: - is_printable = true; - result = '`'; break; - case XK_underscore: - is_printable = true; - result = '_'; break; - case XK_asciicircum: - is_printable = true; - result = '^'; break; - case XK_bracketleft: - is_printable = true; - result = '['; break; - case XK_backslash: - is_printable = true; - result = '\\'; break; - case XK_bracketright: - is_printable = true; - result = ']'; break; - case XK_asciitilde: - is_printable = true; - result = '~'; break; - case XK_braceleft: - is_printable = true; - result = '{'; break; - case XK_bar: - is_printable = true; - result = '|'; break; - case XK_braceright: - is_printable = true; - result = '}'; break; - - - - - case XK_space: - is_printable = true; - result = ' '; break; - case XK_Return: - is_printable = true; - result = '\n'; break; - case XK_Tab: - is_printable = true; - result = '\t'; break; - case XK_KP_Divide: - is_printable = true; - result = '/'; break; - case XK_KP_Decimal: - is_printable = true; - result = '.'; break; - case XK_KP_Subtract: - is_printable = true; - result = '-'; break; - case XK_KP_Add: - is_printable = true; - result = '+'; break; - case XK_KP_Multiply: - is_printable = true; - result = '*'; break; - case XK_KP_Equal: - is_printable = true; - result = '='; break; - - case XK_KP_0: - is_printable = true; - result = '0'; break; - case XK_KP_1: - is_printable = true; - result = '1'; break; - case XK_KP_2: - is_printable = true; - result = '2'; break; - case XK_KP_3: - is_printable = true; - result = '3'; break; - case XK_KP_4: - is_printable = true; - result = '4'; break; - case XK_KP_5: - is_printable = true; - result = '5'; break; - case XK_KP_6: - is_printable = true; - result = '6'; break; - case XK_KP_7: - is_printable = true; - result = '7'; break; - case XK_KP_8: - is_printable = true; - result = '8'; break; - case XK_KP_9: - is_printable = true; - result = '9'; break; - - default: - return false; - } - } - - return true; - } - - // ---------------------------------------------------------------------------------------- - - void event_handler_thread:: - event_handler ( - ) - /*! - ensures - - will handle all events and event dispatching - !*/ - { - try - { - std::vector bitmap_buffer; - bool quit_event_loop = false; - while (quit_event_loop == false) - { - // get a lock on the window_table's mutex - auto_mutex window_table_locker(window_table.get_mutex()); - - XEvent ev; - memset(&ev, 0, sizeof(ev)); - while (XPending(disp) == 0){ - window_table.get_mutex().unlock(); - // wait until receiving X11 next event - struct pollfd pfd; - pfd.fd = ConnectionNumber(disp); - pfd.events = POLLIN | POLLPRI; - poll(&pfd, 1, -1); - - window_table.get_mutex().lock(); - } - XNextEvent(disp,&ev); - - // pass events to input method. - // if this event is needed by input method, XFilterEvent returns True - if (XFilterEvent(&ev, None) == True){ - continue; - } - - // if this event is for one of the windows in the window_table - // then get that window out of the table and put it into win. - XAnyEvent* _ae = reinterpret_cast(&ev); - base_window** win_ = window_table[_ae->window]; - base_window* win = 0; - if (win_) - win = *win_; - - - // ignore messages for unmapped windows - if (ev.type != MapNotify && win != 0) - { - if (win->is_mapped == false) - continue; - } - - - switch (ev.type) - { - - case SelectionRequest: - { - Atom a_ct = XInternAtom(disp, "COMPOUND_TEXT", False); - XSelectionRequestEvent* req = reinterpret_cast(&ev.xselectionrequest); - XEvent respond; - - if (req->target == XA_STRING) - { - XChangeProperty (disp, - req->requestor, - req->property, - XA_STRING, - 8, - PropModeReplace, - reinterpret_cast(convert_wstring_to_mbstring(clipboard).c_str()), - clipboard.size()+1); - respond.xselection.property=req->property; - } - else if (req->target == a_ct) - { - XChangeProperty (disp, - req->requestor, - req->property, - a_ct, - sizeof(wchar_t)*8, - PropModeReplace, - reinterpret_cast(clipboard.c_str()), - clipboard.size()+1); - respond.xselection.property=req->property; - } - else - { - respond.xselection.property= None; - } - respond.xselection.type= SelectionNotify; - respond.xselection.display= req->display; - respond.xselection.requestor= req->requestor; - respond.xselection.selection=req->selection; - respond.xselection.target= req->target; - respond.xselection.time = req->time; - XSendEvent (disp, req->requestor,0,0,&respond); - XFlush (disp); - - } break; - - case MapNotify: - { - if (win == 0) - break; - - win->is_mapped = true; - - if (win->resizable == false) - { - XSizeHints* hints = XAllocSizeHints(); - hints->flags = PMinSize|PMaxSize; - hints->min_width = win->width; - hints->max_width = win->width; - hints->max_height = win->height; - hints->min_height = win->height; - XSetNormalHints(disp,win->x11_stuff.hwnd,hints); - XFree(hints); - } - - - - if (win->has_been_resized) - { - XResizeWindow(disp,win->x11_stuff.hwnd,win->width,win->height); - win->has_been_resized = false; - win->on_window_resized(); - } - - if (win->has_been_moved) - { - XMoveWindow(disp,win->x11_stuff.hwnd,win->x,win->y); - win->has_been_moved = false; - win->on_window_moved(); - } - XFlush(disp); - - - } break; - - - case KeyPress: - { - XKeyPressedEvent* e = reinterpret_cast(&ev); - - if (win == 0) - break; - - unsigned long state = 0; - bool shift = ((e->state & ShiftMask)!=0); - bool ctrl = ((e->state & ControlMask)!=0); - bool caps = ((e->state & LockMask)!=0); - if(shift) - state |= base_window::KBD_MOD_SHIFT; - if(ctrl) - state |= base_window::KBD_MOD_CONTROL; - if(caps) - state |= base_window::KBD_MOD_CAPS_LOCK; - if((e->state & alt_mask)!=0) - state |= base_window::KBD_MOD_ALT; - if((e->state & meta_mask)!=0) - state |= base_window::KBD_MOD_META; - if((e->state & num_lock_mask)!=0) - state |= base_window::KBD_MOD_NUM_LOCK; - if((e->state & scroll_lock_mask)!=0) - state |= base_window::KBD_MOD_SCROLL_LOCK; - - KeySym key; - Status status; - - if (win->x11_stuff.xic) { - std::wstring wstr; - wstr.resize(2); - int len = XwcLookupString(win->x11_stuff.xic,e,&wstr[0],wstr.size(),&key,&status); - if (status == XBufferOverflow){ - wstr.resize(len); - len = XwcLookupString(win->x11_stuff.xic,e,&wstr[0],wstr.size(),&key,&status); - } - if (status == XLookupChars){ - win->on_string_put(wstr); - } - } else { - char buffer[2]; - XLookupString(e, buffer, sizeof(buffer), &key, NULL); - status = XLookupKeySym; - } - - if (status == XLookupKeySym || status == XLookupBoth){ - - bool is_printable; - unsigned long result; - - if (map_keys(key,shift,caps,result,is_printable)) - { - // signal the keyboard event - win->on_keydown(result,is_printable,state); - } - } - - } break; - - case FocusIn: - { - if (win == 0) - break; - - // signal the focus event - win->on_focus_gained(); - } break; - - case FocusOut: - { - if (win == 0) - break; - - // signal the focus event - win->on_focus_lost(); - } break; - - case ButtonPress: - case ButtonRelease: - { - XButtonEvent* e = reinterpret_cast(&ev); - - if (win == 0) - break; - - unsigned long btn = base_window::NONE; - if (e->button == Button1) - btn = base_window::LEFT; - else if (e->button == Button3) - btn = base_window::RIGHT; - else if (e->button == Button2) - btn = base_window::MIDDLE; - - unsigned long state = 0; - if (e->state & ControlMask) - state |= base_window::CONTROL; - if (e->state & Button1Mask) - state |= base_window::LEFT; - if (e->state & Button2Mask) - state |= base_window::MIDDLE; - if (e->state & Button3Mask) - state |= base_window::RIGHT; - if (e->state & ShiftMask) - state |= base_window::SHIFT; - - // only send the event if this is a button we support - if (btn != (unsigned long)base_window::NONE) - { - - - if (ev.type == ButtonPress) - { - bool is_double_click = false; - if (win->last_click_button == btn && - std::abs((long)win->last_click_x - (long)e->x) < 5 && - std::abs((long)win->last_click_y - (long)e->y) < 5 && - e->time - win->x11_stuff.last_click_time <= 400) - { - // this is a double click - is_double_click = true; - // set this to make sure the next click can't be - // interpreted as a double click - win->last_click_button = base_window::NONE; - } - else - { - win->last_click_button = btn; - win->last_click_x = e->x; - win->last_click_y = e->y; - win->x11_stuff.last_click_time = e->time; - } - - // remove the clicked button from the state - state &= (~btn); - win->on_mouse_down(btn,state,e->x,e->y,is_double_click); - - } - else - { - // remove the clicked button from the state - state &= (~btn); - win->on_mouse_up(btn,state,e->x,e->y); - } - } - else if (e->button == Button4 && ev.type == ButtonPress) - { - win->on_wheel_up(state); - } - else if (e->button == Button5 && ev.type == ButtonPress) - { - win->on_wheel_down(state); - } - - } break; - - case LeaveNotify: - { - if (win == 0) - break; - - win->on_mouse_leave(); - - } break; - - case EnterNotify: - { - if (win == 0) - break; - - win->on_mouse_enter(); - } break; - - case MotionNotify: - { - XMotionEvent* e = reinterpret_cast(&ev); - - if (win == 0) - break; - - unsigned long state = 0; - if (e->state & ControlMask) - state |= base_window::CONTROL; - if (e->state & Button1Mask) - state |= base_window::LEFT; - if (e->state & Button2Mask) - state |= base_window::MIDDLE; - if (e->state & Button3Mask) - state |= base_window::RIGHT; - if (e->state & ShiftMask) - state |= base_window::SHIFT; - - win->on_mouse_move(state,e->x,e->y); - - } break; - - case ConfigureNotify: - { - XConfigureEvent* e = reinterpret_cast(&ev); - if (e->window == exit_window) - { - // this is the signal to quit the event handler - quit_event_loop = true; - break; - } - - if (win == 0) - break; - - if (win->width != e->width || - win->height != e->height || - win->has_been_resized) - { - win->has_been_resized = false; - // this is a resize - win->width = e->width; - win->height = e->height; - win->on_window_resized(); - } - if (win->x != e->x || - win->y != e->y || - win->has_been_moved) - { - win->has_been_moved = false; - // this is a move - win->x = e->x; - win->y = e->y; - win->on_window_moved(); - } - - } break; - - case ClientMessage: - { - XClientMessageEvent* e = reinterpret_cast(&ev); - if ((Atom)e->data.l[0] == delete_window) - { - if (win == 0) - break; - - - if (win->on_window_close() == base_window::DO_NOT_CLOSE_WINDOW) - { - DLIB_ASSERT(win->has_been_destroyed == false, - "\tYou called close_window() inside the on_window_close() event but" - << "\n\tthen returned DO_NOT_CLOSE_WINDOW. You can do one or the other but not both." - << "\n\tthis: " << win - ); - // the client has decided not to close the window - // after all - } - else - { - if (window_table[e->window]) - { - window_table.destroy(e->window); - XDestroyWindow(disp,e->window); - win->has_been_destroyed = true; - window_close_signaler.broadcast(); - } - else - { - // in this case the window must have self destructed by - // calling delete this; so we don't have to do anything. - } - } - } - } break; - - case Expose: - { - XExposeEvent* e = reinterpret_cast(&ev); - - if (win == 0) - break; - - // take all the expose events for this window out - XEvent etemp; - int x = e->x; - int y = e->y; - int width = e->width; - int height = e->height; - - - - // What we are doing here with this loop is we are combining - // all of the Expose events for this window that are - // currently in the queue. - while (XCheckIfEvent(disp,&etemp,XCheckIfEventPredicate,reinterpret_cast(&(e->window)))) - { - XExposeEvent* e2 = reinterpret_cast(&etemp); - if (e2->x < x) - { - width += x - e2->x; - x = e2->x; - } - if (e2->y < y) - { - height += y - e2->y; - y = e2->y; - } - if (e2->width + e2->x > width + x) - { - width = e2->width + e2->x - x; - } - if (e2->height + e2->y > height + y) - { - height = e2->height + e2->y - y; - } - } - - // I'm not sure if this sort of thing can happen but - // if it does then just ignore this entire event. - if (width == 0 || height == 0) - { - break; - } - - if (bitmap_buffer.size() < static_cast(width*height*4)) - bitmap_buffer.resize(width*height*4); - - unsigned char* const bitmap = &bitmap_buffer[0]; - unsigned char* const end = bitmap + width*height*4; - - unsigned char* temp; - canvas c(bitmap,x,y,x+width-1,y+height-1); - - - win->paint(c); - - // the user might have called win->close_window() and if they did - // then just stop right here. We don't want to paint the window. - if (win->has_been_destroyed) - break; - - // if the color depth we are working with isn't 24bits then we need - // to transform our image into whatever it is supposed to be. - if (depth != 24) - { - // convert this image into an 8 bit image - unsigned int red_bits = 0; - unsigned int green_bits = 0; - unsigned int blue_bits = 0; - if (depth != 16) - { - unsigned int bits = depth/3; - unsigned int extra = depth%3; - red_bits = bits; - green_bits = bits; - blue_bits = bits; - if (extra) - { - ++red_bits; - --extra; - } - if (extra) - { - ++green_bits; - } - } - else if (depth == 16) - { - red_bits = 5; - green_bits = 6; - blue_bits = 5; - } - - if (depth == 16) - { - temp = bitmap; - unsigned char *red, *green, *blue; - while (temp != end) - { - blue = temp; - ++temp; - green = temp; - ++temp; - red = temp; - ++temp; - ++temp; - - const unsigned long r = static_cast(*red)>>(8-red_bits); - const unsigned long g = static_cast(*green)>>(8-green_bits); - const unsigned long b = static_cast(*blue)>>(8-blue_bits); - - unsigned long color = (r<<(depth-red_bits))| (g<<(depth-red_bits-green_bits))| b; - - *blue = (color>>0)&0xFF; - *green = (color>>8)&0xFF; - } - } - else if (depth < 24) - { - temp = bitmap; - unsigned char *red, *green, *blue; - while (temp != end) - { - blue = temp; - ++temp; - green = temp; - ++temp; - red = temp; - ++temp; - ++temp; - - const unsigned long r = static_cast(*red)>>(8-red_bits); - const unsigned long g = static_cast(*green)>>(8-green_bits); - const unsigned long b = static_cast(*blue)>>(8-blue_bits); - - unsigned long color = (b<<(depth-blue_bits))| (g<<(depth-blue_bits-green_bits))| r; - - *blue = (color>>0)&0xFF; - *green = (color>>8)&0xFF; - *red = (color>>16)&0xFF; - } - } - else if (depth > 24) - { - temp = bitmap; - unsigned char *red, *green, *blue, *four; - while (temp != end) - { - blue = temp; - ++temp; - green = temp; - ++temp; - red = temp; - ++temp; - four = temp; - ++temp; - - const unsigned long r = static_cast(*red)<<(red_bits-8); - const unsigned long g = static_cast(*green)<<(green_bits-8); - const unsigned long b = static_cast(*blue)<<(blue_bits-8); - - unsigned long color = (b<<(depth-blue_bits))| (g<<(depth-blue_bits-green_bits))| r; - - *blue = (color>>0)&0xFF; - *green = (color>>8)&0xFF; - *red = (color>>16)&0xFF; - *four = (color>>24)&0xFF; - } - } - } // if (depth != 24) - - - - XImage img; - memset(&img,0,sizeof(img)); - img.width = width; - img.height = height; - img.depth = depth; - img.data = reinterpret_cast(bitmap); - img.bitmap_bit_order = LSBFirst; - img.byte_order = LSBFirst; - img.format = ZPixmap; - img.bitmap_pad = 32; - img.bitmap_unit = 32; - img.bits_per_pixel = 32; - - - XInitImage(&img); - - GC gc = XCreateGC(disp, e->window, 0, NULL); - - XPutImage(disp,e->window,gc,&img,0,0,x,y,width,height); - - XFreeGC(disp,gc); - } break; - } // switch (ev.type) - } - } - catch (std::exception& e) - { - dlog << LFATAL << "Exception thrown in event handler: " << e.what(); - } - catch (...) - { - dlog << LFATAL << "Unknown exception thrown in event handler."; - } - } - - // ---------------------------------------------------------------------------------------- - - - int index_to_modmask(unsigned long n) - { - switch ( n ) - { - case 0: - return Mod1Mask; - case 1: - return Mod2Mask; - case 2: - return Mod3Mask; - case 3: - return Mod4Mask; - } - return Mod5Mask; - } - - void event_handler_thread:: - init_keyboard_mod_masks() - { - XModifierKeymap* map = XGetModifierMapping( disp ); - KeyCode* codes = map->modifiermap + map->max_keypermod * Mod1MapIndex; - for (int n = 0; n < 5 * map->max_keypermod; n++ ) - { - if ( codes[n] == 0 ) - continue; - switch(XkbKeycodeToKeysym( disp, codes[n], 0, 0 )) - { - case XK_Alt_L: - alt_mask = index_to_modmask(n / map->max_keypermod); - continue; - case XK_Alt_R: - if(alt_mask == 0) - alt_mask = index_to_modmask(n / map->max_keypermod); - continue; - case XK_Meta_L: - case XK_Meta_R: - meta_mask = index_to_modmask(n / map->max_keypermod); - continue; - case XK_Scroll_Lock: - scroll_lock_mask = index_to_modmask(n / map->max_keypermod); - continue; - case XK_Num_Lock: - num_lock_mask = index_to_modmask(n / map->max_keypermod); - default: - continue; - } - } - XFreeModifiermap( map ); - if ( alt_mask == 0 ) - { - dlog << LWARN << "Search for Alt-key faild."; - if ( meta_mask != 0 ) - alt_mask = meta_mask; - else - alt_mask = Mod1Mask; // resort to guessing - } - } - - // ---------------------------------------------------------------------------------------- - - - - - - } // namespace gui_core_kernel_2_globals - -// ---------------------------------------------------------------------------------------- - - void canvas:: - fill ( - unsigned char red_, - unsigned char green_, - unsigned char blue_ - ) const - { - pixel pixel_value; - pixel_value.red = red_; - pixel_value.green = green_; - pixel_value.blue = blue_; - pixel_value._padding = 0; - - pixel* start = reinterpret_cast(bits); - pixel* end = start + width_*height_; - - while (start != end) - { - *start = pixel_value; - ++start; - } - } - -// ---------------------------------------------------------------------------------------- - - void put_on_clipboard ( - const std::string& str - ) - { - put_on_clipboard(convert_mbstring_to_wstring(str)); - } - - void put_on_clipboard ( - const dlib::ustring& str - ) - { - put_on_clipboard(convert_utf32_to_wstring(str)); - } - - void put_on_clipboard ( - const std::wstring& str - ) - { - using namespace gui_core_kernel_2_globals; - - shared_ptr_thread_safe globals(global_data()); - - auto_mutex M(globals->window_table.get_mutex()); - globals->clipboard = str.c_str(); - - XSetSelectionOwner(globals->disp,XA_PRIMARY,globals->exit_window,CurrentTime); - } - -// ---------------------------------------------------------------------------------------- - - Bool clip_peek_helper ( - Display*, - XEvent* event, - XPointer - ) - { - if ( event->type == SelectionNotify) - { - return True; - } - else - { - return False; - } - } - - void get_from_clipboard ( - std::string& str - ) - { - std::wstring wstr; - get_from_clipboard(wstr); - str = convert_wstring_to_mbstring(wstr); - } - - void get_from_clipboard ( - dlib::ustring& str - ) - { - std::wstring wstr; - get_from_clipboard(wstr); - str = convert_wstring_to_utf32(wstr); - } - - void get_from_clipboard ( - std::wstring& str - ) - { - using namespace gui_core_kernel_2_globals; - shared_ptr_thread_safe globals(global_data()); - - auto_mutex M(globals->window_table.get_mutex()); - str.clear(); - unsigned char *data = 0; - wchar_t **plist = 0; - Window sown; - Atom type; - int format, result; - unsigned long len, bytes_left, dummy; - XEvent e; - - try - { - Atom atom_ct = XInternAtom(globals->disp, "COMPOUND_TEXT", False); - sown = XGetSelectionOwner (globals->disp, XA_PRIMARY); - if (sown == globals->exit_window) - { - // if we are copying from ourselfs then don't fool with the Xwindows junk. - str = globals->clipboard.c_str(); - } - else if (sown != None) - { - // request that the selection be copied into the XA_PRIMARY property - // of the exit_window. It doesn't matter what window we put it in - // so long as it is one under the control of this process and exit_window - // is easy to use here so that is what I'm using. - XConvertSelection (globals->disp, XA_PRIMARY, atom_ct, XA_PRIMARY, - globals->exit_window, CurrentTime); - - // This will wait until we get a SelectionNotify event which should happen - // really soon. - XPeekIfEvent(globals->disp,&e,clip_peek_helper,0); - - // See how much data we got - XGetWindowProperty (globals->disp, globals->exit_window, - XA_PRIMARY, // Tricky.. - 0, 0, // offset - len - 0, // Delete 0==FALSE - AnyPropertyType, //flag - &type, // return type - &format, // return format - &len, &bytes_left, //that - &data); - if (data) - { - XFree(data); - data = 0; - } - if (bytes_left > 0 && type == atom_ct) - { - XTextProperty p; - result = XGetWindowProperty (globals->disp, globals->exit_window, - XA_PRIMARY, 0,bytes_left,0, - AnyPropertyType, &p.encoding,&p.format, - &p.nitems, &dummy, &p.value); - if (result == Success && p.encoding == atom_ct) - { - int n; - XwcTextPropertyToTextList(globals->disp, &p, &plist, &n); - str = plist[0]; - } - if (plist) - { - XwcFreeStringList(plist); - plist = 0; - } - } - } - } - catch (...) - { - if (data) - XFree(data); - if (plist) - { - XwcFreeStringList(plist); - plist = 0; - } - } - } - -// ---------------------------------------------------------------------------------------- - - namespace gui_core_kernel_2_globals - { - void trigger_user_event_threadproc ( - void* - ) - { - shared_ptr_thread_safe globals(global_data()); - auto_mutex M(globals->window_table.get_mutex()); - - globals->user_events.lock(); - globals->user_events.swap(globals->user_events_temp); - globals->user_events.unlock(); - - - globals->user_events_temp.reset(); - // now dispatch all these user events - while (globals->user_events_temp.move_next()) - { - base_window** win_ = globals->window_table[globals->user_events_temp.element().w]; - base_window* win; - // if this window exists in the window table then dispatch - // its event. - if (win_) - { - win = *win_; - win->on_user_event( - globals->user_events_temp.element().p, - globals->user_events_temp.element().i - ); - } - } - globals->user_events_temp.clear(); - } - } - - void base_window:: - trigger_user_event ( - void* p, - int i - ) - { - using namespace gui_core_kernel_2_globals; - user_event_type e; - e.w = x11_stuff.hwnd; - e.p = p; - e.i = i; - { - shared_ptr_thread_safe globals(global_data()); - auto_mutex M(globals->user_events.get_mutex()); - globals->user_events.enqueue(e); - - // we only need to start a thread to deal with this if there isn't already - // one out working on the queue - if (globals->user_events.size() == 1) - create_new_thread (trigger_user_event_threadproc,0); - } - } - -// ---------------------------------------------------------------------------------------- - - base_window:: - base_window ( - bool resizable_, - bool undecorated - ) : - x11_stuff(*(new gui_core_kernel_2_globals::x11_base_windowstuff)), - is_mapped(false), - resizable(resizable_), - has_been_destroyed(false), - has_been_resized(false), - has_been_moved(false), - wm(gui_core_kernel_2_globals::global_data()->window_table.get_mutex()) - { - DLIB_ASSERT(!(undecorated == true && resizable_ == true), - "\tbase_window::base_window()" - << "\n\tThere is no such thing as an undecorated window that is resizable by the user." - << "\n\tthis: " << this - ); - using namespace gui_core_kernel_2_globals; - - auto_mutex M(wm); - - x11_stuff.globals = global_data(); - - x11_stuff.last_click_time = 0; - last_click_x = 0; - last_click_y = 0; - last_click_button = NONE; - - XSetWindowAttributes attr; - memset(&attr,'\0',sizeof(attr)); - - unsigned long valuemask = 0; - if (undecorated) - { - attr.override_redirect = True; - valuemask = CWOverrideRedirect; - } - - - x11_stuff.hwnd = XCreateWindow( - x11_stuff.globals->disp, - DefaultRootWindow(x11_stuff.globals->disp), - 0, - 0, - 10, // this is the default width of a window - 10, // this is the default width of a window - 0, - x11_stuff.globals->depth, - InputOutput, - CopyFromParent, - valuemask, - &attr - ); - - x11_stuff.xic = NULL; - if (x11_stuff.globals->xim) - { - XVaNestedList xva_nlist; - XPoint xpoint; - - char **mlist; - int mcount; - char *def_str; - char fontset[256]; - const long native_font_height = 12; - sprintf(fontset, "-*-*-medium-r-normal--%lu-*-*-*-", native_font_height); - x11_stuff.fs = XCreateFontSet(x11_stuff.globals->disp, fontset, &mlist, &mcount, &def_str); - xpoint.x = 0; - xpoint.y = 0; - xva_nlist = XVaCreateNestedList(0, XNSpotLocation, &xpoint, XNFontSet, x11_stuff.fs, (const void*)NULL); - x11_stuff.xic = XCreateIC( - x11_stuff.globals->xim, - XNInputStyle, x11_stuff.globals->xim_style, - XNClientWindow, x11_stuff.hwnd, - XNPreeditAttributes, xva_nlist, - (const void*)NULL - ); - XFree(xva_nlist); - XFreeStringList(mlist); - } - - Window temp = x11_stuff.hwnd; - base_window* ttemp = this; - x11_stuff.globals->window_table.add(temp,ttemp); - - // query event mask required by input method - unsigned long event_xim = 0; - if (x11_stuff.xic) - XGetICValues( x11_stuff.xic, XNFilterEvents, &event_xim, (const void*)NULL ); - - XSelectInput( - x11_stuff.globals->disp, - x11_stuff.hwnd, - StructureNotifyMask|ExposureMask|ButtonPressMask|ButtonReleaseMask| - PointerMotionMask|LeaveWindowMask|EnterWindowMask|KeyPressMask| - KeyReleaseMask| FocusChangeMask | event_xim - ); - - XSetWMProtocols( - x11_stuff.globals->disp, - x11_stuff.hwnd, - &x11_stuff.globals->delete_window, - 1 - ); - - - // these are just default values - x = 0; - y = 0; - width = 10; - height = 10; - - if (resizable == false) - { - XSizeHints* hints = XAllocSizeHints(); - hints->flags = PMinSize|PMaxSize; - hints->min_width = width; - hints->max_width = width; - hints->max_height = height; - hints->min_height = height; - XSetNormalHints(x11_stuff.globals->disp,x11_stuff.hwnd,hints); - XFree(hints); - } - } - -// ---------------------------------------------------------------------------------------- - - base_window:: - ~base_window ( - ) - { - using namespace gui_core_kernel_2_globals; - close_window(); - - if (x11_stuff.globals->xim != NULL) - { - XDestroyIC(x11_stuff.xic); - x11_stuff.xic = 0; - XFreeFontSet(x11_stuff.globals->disp,x11_stuff.fs); - } - - delete &x11_stuff; - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - close_window ( - ) - { - using namespace gui_core_kernel_2_globals; - auto_mutex M(wm); - if (has_been_destroyed == false) - { - has_been_destroyed = true; - - x11_stuff.globals->window_table.destroy(x11_stuff.hwnd); - - XDestroyWindow(x11_stuff.globals->disp,x11_stuff.hwnd); - x11_stuff.hwnd = 0; - x11_stuff.globals->window_close_signaler.broadcast(); - } - } - -// ---------------------------------------------------------------------------------------- - - bool base_window:: - is_closed ( - ) const - { - auto_mutex M(wm); - return has_been_destroyed; - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - set_title ( - const std::string& title_ - ) - { - set_title(convert_mbstring_to_wstring(title_)); - } - - void base_window:: - set_title ( - const ustring& title_ - ) - { - set_title(convert_utf32_to_wstring(title_)); - } - - void base_window:: - set_title ( - const std::wstring& title_ - ) - { - using namespace gui_core_kernel_2_globals; - auto_mutex M(wm); - if (has_been_destroyed == true) - return; - - // I'm pretty sure the pointer won't be modified even though - // it isn't const anymore. - wchar_t *title = const_cast(title_.c_str()); - XTextProperty property; - XwcTextListToTextProperty(x11_stuff.globals->disp,&title,1,XStdICCTextStyle, &property); - XSetWMName(x11_stuff.globals->disp,x11_stuff.hwnd,&property); - XFree(property.value); - XFlush(x11_stuff.globals->disp); - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - show ( - ) - { - using namespace gui_core_kernel_2_globals; - auto_mutex M(wm); - if (has_been_destroyed == true) - return; - - XMapRaised(x11_stuff.globals->disp,x11_stuff.hwnd); - XFlush(x11_stuff.globals->disp); - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - wait_until_closed ( - ) const - { - using namespace gui_core_kernel_2_globals; - auto_mutex M(wm); - while (has_been_destroyed == false) - x11_stuff.globals->window_close_signaler.wait(); - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - hide ( - ) - { - using namespace gui_core_kernel_2_globals; - auto_mutex M(wm); - if (has_been_destroyed == true) - return; - - XUnmapWindow(x11_stuff.globals->disp,x11_stuff.hwnd); - XFlush(x11_stuff.globals->disp); - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - set_size ( - int width_, - int height_ - ) - { - using namespace gui_core_kernel_2_globals; - auto_mutex a(wm); - if (has_been_destroyed == true) - return; - - - // do some sanity checking on these values - if (width_ < 1) - width_ = 1; - if (height_ < 1) - height_ = 1; - - width = width_; - height = height_; - has_been_resized = true; - - if (resizable == false) - { - XSizeHints* hints = XAllocSizeHints(); - hints->flags = PMinSize|PMaxSize; - hints->min_width = width; - hints->max_width = width; - hints->max_height = height; - hints->min_height = height; - XSetNormalHints(x11_stuff.globals->disp,x11_stuff.hwnd,hints); - XFree(hints); - } - - XResizeWindow(x11_stuff.globals->disp,x11_stuff.hwnd,width,height); - - XFlush(x11_stuff.globals->disp); - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - set_pos ( - long x_, - long y_ - ) - { - using namespace gui_core_kernel_2_globals; - auto_mutex a(wm); - if (has_been_destroyed == true) - return; - - - x = x_; - y = y_; - - has_been_moved = true; - - XMoveWindow(x11_stuff.globals->disp,x11_stuff.hwnd,x,y); - XFlush(x11_stuff.globals->disp); - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - get_pos ( - long& x_, - long& y_ - ) - { - using namespace gui_core_kernel_2_globals; - auto_mutex a(wm); - x_ = 0; - y_ = 0; - if (has_been_destroyed == true) - return; - - // we can't really trust the values we have for x and y because some window managers - // will have reported bogus values back in the ConfigureNotify event. So just to be - // on the safe side we will use XTranslateCoordinates() - int rx, ry; - Window desktop_window = DefaultRootWindow(x11_stuff.globals->disp); - Window junk; - XTranslateCoordinates(x11_stuff.globals->disp,x11_stuff.hwnd,desktop_window,0,0,&rx, &ry, &junk); - x_ = rx; - y_ = ry; - x = rx; - y = ry; - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - get_size ( - unsigned long& width_, - unsigned long& height_ - ) const - { - auto_mutex M(wm); - width_ = 0; - height_ = 0; - if (has_been_destroyed == true) - return; - - - width_ = width; - height_ = height; - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - get_display_size ( - unsigned long& width_, - unsigned long& height_ - ) const - { - using namespace gui_core_kernel_2_globals; - auto_mutex M(wm); - width_ = 0; - height_ = 0; - if (has_been_destroyed == true) - return; - - int screen_number = XScreenNumberOfScreen(x11_stuff.globals->screen); - width_ = DisplayWidth(x11_stuff.globals->disp, screen_number); - height_ = DisplayHeight(x11_stuff.globals->disp, screen_number); - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - invalidate_rectangle ( - const rectangle& rect - ) - { - using namespace gui_core_kernel_2_globals; - auto_mutex a(wm); - if (is_mapped == false) - return; - - if (rect.is_empty() == false && !has_been_destroyed) - { - const long x = rect.left(); - const long y = rect.top(); - const unsigned long width = rect.width(); - const unsigned long height = rect.height(); - - XClearArea(x11_stuff.globals->disp,x11_stuff.hwnd,x,y,width,height,1); - XFlush(x11_stuff.globals->disp); - } - } - -// ---------------------------------------------------------------------------------------- - - void base_window:: - set_im_pos ( - long x, - long y - ) - { - using namespace gui_core_kernel_2_globals; - auto_mutex a(wm); - if (has_been_destroyed == true) - return; - - if (!x11_stuff.xic || !(x11_stuff.globals->xim_style & XIMPreeditPosition)) return; - - XVaNestedList xva_nlist; - XPoint xpoint; - - xpoint.x = x; - xpoint.y = y; - - xva_nlist = XVaCreateNestedList(0, XNSpotLocation, &xpoint, (const void*)NULL); - XSetICValues(x11_stuff.xic, XNPreeditAttributes, xva_nlist, (const void*)NULL); - XFree(xva_nlist); - } - -} - -// ---------------------------------------------------------------------------------------- - -#endif // POSIX - -#endif // DLIB_GUI_CORE_KERNEL_2_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/gui_core/gui_core_kernel_2.h b/lib/3rdParty/dlib/include/dlib/gui_core/gui_core_kernel_2.h index 72f87baa..efcd4ba1 100644 --- a/lib/3rdParty/dlib/include/dlib/gui_core/gui_core_kernel_2.h +++ b/lib/3rdParty/dlib/include/dlib/gui_core/gui_core_kernel_2.h @@ -140,16 +140,16 @@ namespace dlib template <> struct pixel_traits { - const static bool rgb = true; - const static bool rgb_alpha = false; - const static bool grayscale = false; - const static bool hsi = false; - const static long num = 3; + constexpr static bool rgb = true; + constexpr static bool rgb_alpha = false; + constexpr static bool grayscale = false; + constexpr static bool hsi = false; + constexpr static long num = 3; typedef unsigned char basic_pixel_type; static basic_pixel_type min() { return 0;} static basic_pixel_type max() { return 255;} - const static bool is_unsigned = true; - const static bool has_alpha = false; + constexpr static bool is_unsigned = true; + constexpr static bool has_alpha = false; }; // ----------------- diff --git a/lib/3rdParty/dlib/include/dlib/gui_widgets.h b/lib/3rdParty/dlib/include/dlib/gui_widgets.h index b73d94b4..5b243ef8 100644 --- a/lib/3rdParty/dlib/include/dlib/gui_widgets.h +++ b/lib/3rdParty/dlib/include/dlib/gui_widgets.h @@ -1,5 +1,10 @@ // Copyright (C) 2005 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. + +#ifdef DLIB_ALL_SOURCE_END +#include "dlib_basic_cpp_build_tutorial.txt" +#endif + #ifndef DLIB_GUI_WIDGETs_ #define DLIB_GUI_WIDGETs_ diff --git a/lib/3rdParty/dlib/include/dlib/gui_widgets/base_widgets.cpp b/lib/3rdParty/dlib/include/dlib/gui_widgets/base_widgets.cpp deleted file mode 100644 index 7ac584c1..00000000 --- a/lib/3rdParty/dlib/include/dlib/gui_widgets/base_widgets.cpp +++ /dev/null @@ -1,3342 +0,0 @@ -// Copyright (C) 2005 Davis E. King (davis@dlib.net), Keita Mochizuki -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_BASE_WIDGETs_CPP_ -#define DLIB_BASE_WIDGETs_CPP_ - -#include "base_widgets.h" -#include "../assert.h" -#include - - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // button object methods -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void button:: - set_size ( - unsigned long width, - unsigned long height - ) - { - auto_mutex M(m); - rectangle min_rect = style->get_min_size(name_,*mfont); - // only change the size if it isn't going to be too small to fit the name - if (height >= min_rect.height() && - width >= min_rect.width()) - { - rectangle old(rect); - rect = resize_rect(rect,width,height); - parent.invalidate_rectangle(style->get_invalidation_rect(rect+old)); - btn_tooltip.set_size(width,height); - } - } - -// ---------------------------------------------------------------------------------------- - - void button:: - show ( - ) - { - button_action::show(); - btn_tooltip.show(); - } - -// ---------------------------------------------------------------------------------------- - - void button:: - hide ( - ) - { - button_action::hide(); - btn_tooltip.hide(); - } - -// ---------------------------------------------------------------------------------------- - - void button:: - enable ( - ) - { - button_action::enable(); - btn_tooltip.enable(); - } - -// ---------------------------------------------------------------------------------------- - - void button:: - disable ( - ) - { - button_action::disable(); - btn_tooltip.disable(); - } - -// ---------------------------------------------------------------------------------------- - - void button:: - set_tooltip_text ( - const std::string& text - ) - { - btn_tooltip.set_text(text); - } - -// ---------------------------------------------------------------------------------------- - - void button:: - set_tooltip_text ( - const std::wstring& text - ) - { - btn_tooltip.set_text(text); - } - -// ---------------------------------------------------------------------------------------- - - void button:: - set_tooltip_text ( - const ustring& text - ) - { - btn_tooltip.set_text(text); - } - -// ---------------------------------------------------------------------------------------- - - const std::string button:: - tooltip_text ( - ) const - { - return btn_tooltip.text(); - } - - const std::wstring button:: - tooltip_wtext ( - ) const - { - return btn_tooltip.wtext(); - } - - const dlib::ustring button:: - tooltip_utext ( - ) const - { - return btn_tooltip.utext(); - } - -// ---------------------------------------------------------------------------------------- - - void button:: - set_main_font ( - const shared_ptr_thread_safe& f - ) - { - auto_mutex M(m); - mfont = f; - set_name(name_); - } - -// ---------------------------------------------------------------------------------------- - - void button:: - set_pos ( - long x, - long y - ) - { - auto_mutex M(m); - button_action::set_pos(x,y); - btn_tooltip.set_pos(x,y); - } - -// ---------------------------------------------------------------------------------------- - - void button:: - set_name ( - const std::string& name - ) - { - set_name(convert_mbstring_to_wstring(name)); - } - - void button:: - set_name ( - const std::wstring& name - ) - { - set_name(convert_wstring_to_utf32(name)); - } - - void button:: - set_name ( - const ustring& name - ) - { - auto_mutex M(m); - name_ = name; - // do this to get rid of any reference counting that may be present in - // the std::string implementation. - name_[0] = name_[0]; - - rectangle old(rect); - rect = move_rect(style->get_min_size(name,*mfont),rect.left(),rect.top()); - btn_tooltip.set_size(rect.width(),rect.height()); - - parent.invalidate_rectangle(style->get_invalidation_rect(rect+old)); - } - -// ---------------------------------------------------------------------------------------- - - const std::string button:: - name ( - ) const - { - auto_mutex M(m); - std::string temp = convert_wstring_to_mbstring(wname()); - // do this to get rid of any reference counting that may be present in - // the std::string implementation. - char c = temp[0]; - temp[0] = c; - return temp; - } - - const std::wstring button:: - wname ( - ) const - { - auto_mutex M(m); - std::wstring temp = convert_utf32_to_wstring(uname()); - // do this to get rid of any reference counting that may be present in - // the std::wstring implementation. - wchar_t w = temp[0]; - temp[0] = w; - return temp; - } - - const dlib::ustring button:: - uname ( - ) const - { - auto_mutex M(m); - dlib::ustring temp = name_; - // do this to get rid of any reference counting that may be present in - // the dlib::ustring implementation. - temp[0] = name_[0]; - return temp; - } - -// ---------------------------------------------------------------------------------------- - - void button:: - on_button_up ( - bool mouse_over - ) - { - if (mouse_over) - { - // this is a valid button click - if (event_handler.is_set()) - event_handler(); - if (event_handler_self.is_set()) - event_handler_self(*this); - } - if (button_up_handler.is_set()) - button_up_handler(mouse_over); - if (button_up_handler_self.is_set()) - button_up_handler_self(mouse_over,*this); - } - -// ---------------------------------------------------------------------------------------- - - void button:: - on_button_down ( - ) - { - if (button_down_handler.is_set()) - button_down_handler(); - if (button_down_handler_self.is_set()) - button_down_handler_self(*this); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // draggable object methods -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - draggable::~draggable() {} - -// ---------------------------------------------------------------------------------------- - - void draggable:: - on_mouse_move ( - unsigned long state, - long x, - long y - ) - { - if (drag && (state & base_window::LEFT) && enabled && !hidden) - { - // the user is trying to drag this object. we should calculate the new - // x and y positions for the upper left corner of this object's rectangle - - long new_x = x - this->x; - long new_y = y - this->y; - - // make sure these points are inside the draggable area. - if (new_x < area.left()) - new_x = area.left(); - if (new_x + static_cast(rect.width()) - 1 > area.right()) - new_x = area.right() - rect.width() + 1; - - if (new_y + static_cast(rect.height()) - 1 > area.bottom()) - new_y = area.bottom() - rect.height() + 1; - if (new_y < area.top()) - new_y = area.top(); - - // now make the new rectangle for this object - rectangle new_rect( - new_x, - new_y, - new_x + rect.width() - 1, - new_y + rect.height() - 1 - ); - - // only do anything if this is a new rectangle and it is inside area - if (new_rect != rect && area.intersect(new_rect) == new_rect) - { - parent.invalidate_rectangle(new_rect + rect); - rect = new_rect; - - // call the on_drag() event handler - on_drag(); - } - } - else - { - drag = false; - on_drag_stop(); - } - } - -// ---------------------------------------------------------------------------------------- - - void draggable:: - on_mouse_up ( - unsigned long , - unsigned long state, - long , - long - ) - { - if (drag && (state & base_window::LEFT) == 0) - { - drag = false; - on_drag_stop(); - } - } - -// ---------------------------------------------------------------------------------------- - - void draggable:: - on_mouse_down ( - unsigned long btn, - unsigned long , - long x, - long y, - bool - ) - { - if (enabled && !hidden && rect.contains(x,y) && btn == base_window::LEFT) - { - drag = true; - this->x = x - rect.left(); - this->y = y - rect.top(); - } - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // mouse_over_event object methods -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - mouse_over_event::~mouse_over_event() {} - -// ---------------------------------------------------------------------------------------- - - void mouse_over_event:: - on_mouse_leave ( - ) - { - if (is_mouse_over_) - { - is_mouse_over_ = false; - on_mouse_not_over(); - } - } - -// ---------------------------------------------------------------------------------------- - - void mouse_over_event:: - on_mouse_move ( - unsigned long , - long x, - long y - ) - { - if (rect.contains(x,y) == false) - { - if (is_mouse_over_) - { - is_mouse_over_ = false; - on_mouse_not_over(); - } - } - else if (is_mouse_over_ == false) - { - is_mouse_over_ = true; - if (enabled && !hidden) - on_mouse_over(); - } - } - -// ---------------------------------------------------------------------------------------- - - bool mouse_over_event:: - is_mouse_over ( - ) const - { - // check if the mouse is still really over this button - if (is_mouse_over_ && rect.contains(lastx,lasty) == false) - { - // trigger a user event to call on_mouse_not_over() and repaint this object. - // we must do this in another event because someone might call is_mouse_over() - // from draw() and you don't want this function to end up calling - // parent.invalidate_rectangle(). It would lead to draw() being called over - // and over. - parent.trigger_user_event((void*)this,drawable::next_free_user_event_number()); - return false; - } - - return is_mouse_over_; - } - -// ---------------------------------------------------------------------------------------- - - void mouse_over_event:: - on_user_event ( - int num - ) - { - if (is_mouse_over_ && num == drawable::next_free_user_event_number()) - { - is_mouse_over_ = false; - on_mouse_not_over(); - } - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // button_action object methods -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - button_action::~button_action() {} - -// ---------------------------------------------------------------------------------------- - - void button_action:: - on_mouse_down ( - unsigned long btn, - unsigned long , - long x, - long y, - bool - ) - { - if (enabled && !hidden && btn == base_window::LEFT && rect.contains(x,y)) - { - is_depressed_ = true; - seen_click = true; - parent.invalidate_rectangle(rect); - on_button_down(); - } - } - -// ---------------------------------------------------------------------------------------- - - void button_action:: - on_mouse_not_over ( - ) - { - if (is_depressed_) - { - is_depressed_ = false; - parent.invalidate_rectangle(rect); - on_button_up(false); - } - } - -// ---------------------------------------------------------------------------------------- - - void button_action:: - on_mouse_move ( - unsigned long state, - long x, - long y - ) - { - // forward event to the parent class so it can do it's thing as well as us - mouse_over_event::on_mouse_move(state,x,y); - - if (enabled == false || hidden == true) - return; - - - if ((state & base_window::LEFT) == 0) - { - seen_click = false; - if (is_depressed_) - { - is_depressed_ = false; - parent.invalidate_rectangle(rect); - on_button_up(false); - } - - // the left button isn't down so we don't care about anything else - return; - } - - if (rect.contains(x,y) == false) - { - if (is_depressed_) - { - is_depressed_ = false; - parent.invalidate_rectangle(rect); - on_button_up(false); - } - } - else if (is_depressed_ == false && seen_click) - { - is_depressed_ = true; - parent.invalidate_rectangle(rect); - on_button_down(); - } - } - -// ---------------------------------------------------------------------------------------- - - void button_action:: - on_mouse_up ( - unsigned long btn, - unsigned long, - long x, - long y - ) - { - if (enabled && !hidden && btn == base_window::LEFT) - { - if (is_depressed_) - { - is_depressed_ = false; - parent.invalidate_rectangle(rect); - - if (rect.contains(x,y)) - { - on_button_up(true); - } - else - { - on_button_up(false); - } - } - else if (seen_click && rect.contains(x,y)) - { - // this case here covers the unlikly event that you click on a button, - // move the mouse off the button and then move it back very quickly and - // release the mouse button. It is possible that this mouse up event - // will occurr before any mouse move event so you might not have set - // that the button is depressed yet. - - // So we should say that this triggers an on_button_down() event and - // then an on_button_up(true) event. - - parent.invalidate_rectangle(rect); - - on_button_down(); - on_button_up(true); - } - - seen_click = false; - } - } - -// ---------------------------------------------------------------------------------------- - - bool button_action:: - is_depressed ( - ) const - { - // check if the mouse is still really over this button - if (enabled && !hidden && is_depressed_ && rect.contains(lastx,lasty) == false) - { - // trigger a user event to call on_button_up() and repaint this object. - // we must do this in another event because someone might call is_depressed() - // from draw() and you don't want this function to end up calling - // parent.invalidate_rectangle(). It would lead to draw() being called over - // and over. - parent.trigger_user_event((void*)this,mouse_over_event::next_free_user_event_number()); - return false; - } - - return is_depressed_; - } - -// ---------------------------------------------------------------------------------------- - - void button_action:: - on_user_event ( - int num - ) - { - // forward event to the parent class so it can do it's thing as well as us - mouse_over_event::on_user_event(num); - - if (is_depressed_ && num == mouse_over_event::next_free_user_event_number()) - { - is_depressed_ = false; - parent.invalidate_rectangle(rect); - on_button_up(false); - } - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // scroll_bar object methods -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - scroll_bar:: - scroll_bar( - drawable_window& w, - bar_orientation orientation - ) : - drawable(w), - b1(w), - b2(w), - slider(w,*this,&scroll_bar::on_slider_drag), - ori(orientation), - top_filler(w,*this,&scroll_bar::top_filler_down,&scroll_bar::top_filler_up), - bottom_filler(w,*this,&scroll_bar::bottom_filler_down,&scroll_bar::bottom_filler_up), - pos(0), - max_pos(0), - js(10), - b1_timer(*this,&scroll_bar::b1_down_t), - b2_timer(*this,&scroll_bar::b2_down_t), - top_filler_timer(*this,&scroll_bar::top_filler_down_t), - bottom_filler_timer(*this,&scroll_bar::bottom_filler_down_t) - { - set_style(scroll_bar_style_default()); - - // don't show the slider when there is no place it can move. - slider.hide(); - - set_length(100); - - b1.set_button_down_handler(*this,&scroll_bar::b1_down); - b2.set_button_down_handler(*this,&scroll_bar::b2_down); - - b1.set_button_up_handler(*this,&scroll_bar::b1_up); - b2.set_button_up_handler(*this,&scroll_bar::b2_up); - b1.disable(); - b2.disable(); - enable_events(); - } - -// ---------------------------------------------------------------------------------------- - - scroll_bar:: - ~scroll_bar( - ) - { - disable_events(); - parent.invalidate_rectangle(rect); - // wait for all the timers to be stopped - b1_timer.stop_and_wait(); - b2_timer.stop_and_wait(); - top_filler_timer.stop_and_wait(); - bottom_filler_timer.stop_and_wait(); - } - -// ---------------------------------------------------------------------------------------- - - scroll_bar::bar_orientation scroll_bar:: - orientation ( - ) const - { - auto_mutex M(m); - return ori; - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - set_length ( - unsigned long length - ) - { - auto_mutex M(m); - // make the min length be at least 1 - if (length == 0) - { - length = 1; - } - - - parent.invalidate_rectangle(rect); - - if (ori == HORIZONTAL) - { - rect.set_right(rect.left() + length - 1); - rect.set_bottom(rect.top() + style->get_width() - 1); - - const long btn_size = style->get_button_length(rect.width(), max_pos); - - b1.set_size(btn_size,style->get_width()); - b2.set_size(btn_size,style->get_width()); - - slider.set_size(get_slider_size(),style->get_width()); - } - else - { - rect.set_right(rect.left() + style->get_width() - 1); - rect.set_bottom(rect.top() + length - 1); - - const long btn_size = style->get_button_length(rect.height(), max_pos); - - b1.set_size(style->get_width(),btn_size); - b2.set_size(style->get_width(),btn_size); - - slider.set_size(style->get_width(),get_slider_size()); - } - - // call this to put everything is in the right spot. - set_pos (rect.left(),rect.top()); - - if ((b2.get_rect().top() - b1.get_rect().bottom() - 1 <= 8 && ori == VERTICAL) || - (b2.get_rect().left() - b1.get_rect().right() - 1 <= 8 && ori == HORIZONTAL) || - max_pos == 0) - { - hide_slider(); - } - else if (enabled && !hidden) - { - show_slider(); - } - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - set_pos ( - long x, - long y - ) - { - auto_mutex M(m); - drawable::set_pos(x,y); - - b1.set_pos(rect.left(),rect.top()); - if (ori == HORIZONTAL) - { - // make the b2 button appear at the end of the scroll_bar - b2.set_pos(rect.right()-b2.get_rect().width() + 1,rect.top()); - - if (max_pos != 0) - { - double range = b2.get_rect().left() - b1.get_rect().right() - slider.get_rect().width() - 1; - double slider_pos = pos; - slider_pos /= max_pos; - slider_pos *= range; - slider.set_pos( - static_cast(slider_pos)+rect.left() + b1.get_rect().width(), - rect.top() - ); - - // move the draggable area for the slider to the new location - rectangle area = rect; - area.set_left(area.left() + style->get_width()); - area.set_right(area.right() - style->get_width()); - slider.set_draggable_area(area); - - } - - - } - else - { - // make the b2 button appear at the end of the scroll_bar - b2.set_pos(rect.left(), rect.bottom() - b2.get_rect().height() + 1); - - if (max_pos != 0) - { - double range = b2.get_rect().top() - b1.get_rect().bottom() - slider.get_rect().height() - 1; - double slider_pos = pos; - slider_pos /= max_pos; - slider_pos *= range; - slider.set_pos( - rect.left(), - static_cast(slider_pos) + rect.top() + b1.get_rect().height() - ); - - // move the draggable area for the slider to the new location - rectangle area = rect; - area.set_top(area.top() + style->get_width()); - area.set_bottom(area.bottom() - style->get_width()); - slider.set_draggable_area(area); - } - } - - adjust_fillers(); - } - -// ---------------------------------------------------------------------------------------- - - unsigned long scroll_bar:: - get_slider_size ( - ) const - { - if (ori == HORIZONTAL) - return style->get_slider_length(rect.width(),max_pos); - else - return style->get_slider_length(rect.height(),max_pos); - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - adjust_fillers ( - ) - { - rectangle top(rect), bottom(rect); - - if (ori == HORIZONTAL) - { - if (slider.is_hidden()) - { - top.set_left(b1.get_rect().right()+1); - top.set_right(b2.get_rect().left()-1); - bottom.set_left(1); - bottom.set_right(-1); - } - else - { - top.set_left(b1.get_rect().right()+1); - top.set_right(slider.get_rect().left()-1); - bottom.set_left(slider.get_rect().right()+1); - bottom.set_right(b2.get_rect().left()-1); - } - } - else - { - if (slider.is_hidden()) - { - top.set_top(b1.get_rect().bottom()+1); - top.set_bottom(b2.get_rect().top()-1); - bottom.set_top(1); - bottom.set_bottom(-1); - } - else - { - top.set_top(b1.get_rect().bottom()+1); - top.set_bottom(slider.get_rect().top()-1); - bottom.set_top(slider.get_rect().bottom()+1); - bottom.set_bottom(b2.get_rect().top()-1); - } - } - - top_filler.rect = top; - bottom_filler.rect = bottom; - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - hide_slider ( - ) - { - rectangle top(rect), bottom(rect); - slider.hide(); - top_filler.disable(); - bottom_filler.disable(); - bottom_filler.hide(); - if (ori == HORIZONTAL) - { - top.set_left(b1.get_rect().right()+1); - top.set_right(b2.get_rect().left()-1); - } - else - { - top.set_top(b1.get_rect().bottom()+1); - top.set_bottom(b2.get_rect().top()-1); - } - top_filler.rect = top; - bottom_filler.rect = bottom; - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - show_slider ( - ) - { - if ((b2.get_rect().top() - b1.get_rect().bottom() - 1 <= 8 && ori == VERTICAL) || - (b2.get_rect().left() - b1.get_rect().right() - 1 <= 8 && ori == HORIZONTAL) || - max_pos == 0) - return; - - rectangle top(rect), bottom(rect); - slider.show(); - top_filler.enable(); - bottom_filler.enable(); - bottom_filler.show(); - if (ori == HORIZONTAL) - { - top.set_left(b1.get_rect().right()+1); - top.set_right(slider.get_rect().left()-1); - bottom.set_left(slider.get_rect().right()+1); - bottom.set_right(b2.get_rect().left()-1); - } - else - { - top.set_top(b1.get_rect().bottom()+1); - top.set_bottom(slider.get_rect().top()-1); - bottom.set_top(slider.get_rect().bottom()+1); - bottom.set_bottom(b2.get_rect().top()-1); - } - top_filler.rect = top; - bottom_filler.rect = bottom; - } - -// ---------------------------------------------------------------------------------------- - - long scroll_bar:: - max_slider_pos ( - ) const - { - auto_mutex M(m); - return max_pos; - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - set_max_slider_pos ( - long mpos - ) - { - auto_mutex M(m); - max_pos = mpos; - if (pos > mpos) - pos = mpos; - - if (ori == HORIZONTAL) - set_length(rect.width()); - else - set_length(rect.height()); - - if (mpos != 0 && enabled) - { - b1.enable(); - b2.enable(); - } - else - { - b1.disable(); - b2.disable(); - } - - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - set_slider_pos ( - long pos - ) - { - auto_mutex M(m); - if (pos < 0) - pos = 0; - if (pos > max_pos) - pos = max_pos; - - this->pos = pos; - - // move the slider object to its new position - set_pos(rect.left(),rect.top()); - } - -// ---------------------------------------------------------------------------------------- - - long scroll_bar:: - slider_pos ( - ) const - { - auto_mutex M(m); - return pos; - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - on_slider_drag ( - ) - { - if (ori == HORIZONTAL) - { - double slider_pos = slider.get_rect().left() - b1.get_rect().right() - 1; - double range = b2.get_rect().left() - b1.get_rect().right() - slider.get_rect().width() - 1; - slider_pos /= range; - slider_pos *= max_pos; - pos = static_cast(slider_pos); - } - else - { - double slider_pos = slider.get_rect().top() - b1.get_rect().bottom() - 1; - double range = b2.get_rect().top() - b1.get_rect().bottom() - slider.get_rect().height() - 1; - slider_pos /= range; - slider_pos *= max_pos; - pos = static_cast(slider_pos); - } - - adjust_fillers(); - - if (scroll_handler.is_set()) - scroll_handler(); - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - draw ( - const canvas& - ) const - { - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - b1_down ( - ) - { - if (pos != 0) - { - set_slider_pos(pos-1); - if (scroll_handler.is_set()) - scroll_handler(); - - if (b1_timer.delay_time() == 1000) - b1_timer.set_delay_time(500); - else - b1_timer.set_delay_time(50); - b1_timer.start(); - } - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - b1_up ( - bool - ) - { - b1_timer.stop(); - b1_timer.set_delay_time(1000); - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - b2_down ( - ) - { - if (pos != max_pos) - { - set_slider_pos(pos+1); - if (scroll_handler.is_set()) - scroll_handler(); - - if (b2_timer.delay_time() == 1000) - b2_timer.set_delay_time(500); - else - b2_timer.set_delay_time(50); - b2_timer.start(); - } - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - b2_up ( - bool - ) - { - b2_timer.stop(); - b2_timer.set_delay_time(1000); - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - top_filler_down ( - ) - { - // ignore this if the mouse is now outside this object. This could happen - // since the timers are also calling this function. - if (top_filler.rect.contains(lastx,lasty) == false) - { - top_filler_up(false); - return; - } - - if (pos != 0) - { - if (pos < js) - { - // if there is less than jump_size() space left then jump the remaining - // amount. - delayed_set_slider_pos(0); - } - else - { - delayed_set_slider_pos(pos-js); - } - - if (top_filler_timer.delay_time() == 1000) - top_filler_timer.set_delay_time(500); - else - top_filler_timer.set_delay_time(50); - top_filler_timer.start(); - } - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - top_filler_up ( - bool - ) - { - top_filler_timer.stop(); - top_filler_timer.set_delay_time(1000); - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - bottom_filler_down ( - ) - { - // ignore this if the mouse is now outside this object. This could happen - // since the timers are also calling this function. - if (bottom_filler.rect.contains(lastx,lasty) == false) - { - bottom_filler_up(false); - return; - } - - if (pos != max_pos) - { - if (max_pos - pos < js) - { - // if there is less than jump_size() space left then jump the remaining - // amount. - delayed_set_slider_pos(max_pos); - } - else - { - delayed_set_slider_pos(pos+js); - } - - if (bottom_filler_timer.delay_time() == 1000) - bottom_filler_timer.set_delay_time(500); - else - bottom_filler_timer.set_delay_time(50); - bottom_filler_timer.start(); - } - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - bottom_filler_up ( - bool - ) - { - bottom_filler_timer.stop(); - bottom_filler_timer.set_delay_time(1000); - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - set_jump_size ( - long js_ - ) - { - auto_mutex M(m); - if (js_ < 1) - js = 1; - else - js = js_; - } - -// ---------------------------------------------------------------------------------------- - - long scroll_bar:: - jump_size ( - ) const - { - auto_mutex M(m); - return js; - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - on_user_event ( - int i - ) - { - switch (i) - { - case 0: - b1_down(); - break; - case 1: - b2_down(); - break; - case 2: - top_filler_down(); - break; - case 3: - bottom_filler_down(); - break; - case 4: - // if the position we are supposed to switch the slider too isn't - // already set - if (delayed_pos != pos) - { - set_slider_pos(delayed_pos); - if (scroll_handler.is_set()) - scroll_handler(); - } - break; - default: - break; - } - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - delayed_set_slider_pos ( - unsigned long dpos - ) - { - delayed_pos = dpos; - parent.trigger_user_event(this,4); - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - b1_down_t ( - ) - { - parent.trigger_user_event(this,0); - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - b2_down_t ( - ) - { - parent.trigger_user_event(this,1); - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - top_filler_down_t ( - ) - { - parent.trigger_user_event(this,2); - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar:: - bottom_filler_down_t ( - ) - { - parent.trigger_user_event(this,3); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// widget_group object methods -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void widget_group:: - empty ( - ) - { - auto_mutex M(m); - widgets.clear(); - wg_widgets.clear(); - } - -// ---------------------------------------------------------------------------------------- - - void widget_group:: - add ( - drawable& widget, - unsigned long x, - unsigned long y - ) - { - auto_mutex M(m); - drawable* w = &widget; - relpos rp; - rp.x = x; - rp.y = y; - if (widgets.is_in_domain(w)) - { - widgets[w].x = x; - widgets[w].y = y; - } - else - { - widgets.add(w,rp); - } - if (is_hidden()) - widget.hide(); - else - widget.show(); - - if (is_enabled()) - widget.enable(); - else - widget.disable(); - - widget.set_z_order(z_order()); - widget.set_pos(x+rect.left(),y+rect.top()); - } - -// ---------------------------------------------------------------------------------------- - - void widget_group:: - add ( - widget_group& widget, - unsigned long x, - unsigned long y - ) - { - auto_mutex M(m); - drawable& w = widget; - add(w, x, y); - - widget_group* wg = &widget; - wg_widgets.add(wg); - } - -// ---------------------------------------------------------------------------------------- - - bool widget_group:: - is_member ( - const drawable& widget - ) const - { - auto_mutex M(m); - drawable* w = const_cast(&widget); - return widgets.is_in_domain(w); - } - -// ---------------------------------------------------------------------------------------- - - void widget_group:: - remove ( - const drawable& widget - ) - { - auto_mutex M(m); - drawable* w = const_cast(&widget); - if (widgets.is_in_domain(w)) - { - widgets.destroy(w); - - // check if we also have an entry in the wg_widgets set and if - // so then remove that too - widget_group* wg = reinterpret_cast(w); - if (wg_widgets.is_member(wg)) - { - wg_widgets.destroy(wg); - } - } - } - -// ---------------------------------------------------------------------------------------- - - unsigned long widget_group:: - size ( - ) const - { - auto_mutex M(m); - return widgets.size(); - } - -// ---------------------------------------------------------------------------------------- - - void widget_group:: - set_pos ( - long x, - long y - ) - { - auto_mutex M(m); - widgets.reset(); - while (widgets.move_next()) - { - const unsigned long rx = widgets.element().value().x; - const unsigned long ry = widgets.element().value().y; - widgets.element().key()->set_pos(x+rx,y+ry); - } - drawable::set_pos(x,y); - } - -// ---------------------------------------------------------------------------------------- - - void widget_group:: - set_z_order ( - long order - ) - { - auto_mutex M(m); - widgets.reset(); - while (widgets.move_next()) - widgets.element().key()->set_z_order(order); - drawable::set_z_order(order); - } - -// ---------------------------------------------------------------------------------------- - - void widget_group:: - show ( - ) - { - auto_mutex M(m); - widgets.reset(); - while (widgets.move_next()) - widgets.element().key()->show(); - drawable::show(); - } - -// ---------------------------------------------------------------------------------------- - - void widget_group:: - hide ( - ) - { - auto_mutex M(m); - widgets.reset(); - while (widgets.move_next()) - widgets.element().key()->hide(); - drawable::hide(); - } - -// ---------------------------------------------------------------------------------------- - - void widget_group:: - enable ( - ) - { - auto_mutex M(m); - widgets.reset(); - while (widgets.move_next()) - widgets.element().key()->enable(); - drawable::enable(); - } - -// ---------------------------------------------------------------------------------------- - - void widget_group:: - disable () - { - auto_mutex M(m); - widgets.reset(); - while (widgets.move_next()) - widgets.element().key()->disable(); - drawable::disable(); - } - -// ---------------------------------------------------------------------------------------- - - void widget_group:: - fit_to_contents ( - ) - { - auto_mutex M(m); - - // call fit_to_contents on all the widget_groups we contain - wg_widgets.reset(); - while (wg_widgets.move_next()) - wg_widgets.element()->fit_to_contents(); - - // now accumulate a rectangle that contains everything in this widget_group - rectangle r; - widgets.reset(); - while (widgets.move_next()) - r = r + widgets.element().key()->get_rect(); - - if (r.is_empty()) - { - // make sure it is still empty after we set it at the correct position - r.set_right(rect.left()-1); - r.set_bottom(rect.top()-1); - } - - r.set_left(rect.left()); - r.set_top(rect.top()); - rect = r; - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// class popup_menu -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - popup_menu:: - popup_menu ( - ) : - base_window(false,true), - pad(2), - item_pad(3), - cur_rect(pad,pad,pad-1,pad-1), - left_width(0), - middle_width(0), - selected_item(0), - submenu_open(false) - { - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu:: - enable_menu_item ( - unsigned long idx - ) - { - DLIB_ASSERT ( idx < size() , - "\tvoid popup_menu::enable_menu_item()" - << "\n\tidx: " << idx - << "\n\tsize(): " << size() - ); - auto_mutex M(wm); - item_enabled[idx] = true; - invalidate_rectangle(cur_rect); - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu:: - disable_menu_item ( - unsigned long idx - ) - { - DLIB_ASSERT ( idx < size() , - "\tvoid popup_menu::enable_menu_item()" - << "\n\tidx: " << idx - << "\n\tsize(): " << size() - ); - auto_mutex M(wm); - item_enabled[idx] = false; - invalidate_rectangle(cur_rect); - } - -// ---------------------------------------------------------------------------------------- - - unsigned long popup_menu:: - size ( - ) const - { - auto_mutex M(wm); - return items.size(); - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu:: - clear ( - ) - { - auto_mutex M(wm); - hide(); - cur_rect = rectangle(pad,pad,pad-1,pad-1); - win_rect = rectangle(); - left_width = 0; - middle_width = 0; - items.clear(); - item_enabled.clear(); - left_rects.clear(); - middle_rects.clear(); - right_rects.clear(); - line_rects.clear(); - submenus.clear(); - selected_item = 0; - submenu_open = false; - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu:: - show ( - ) - { - auto_mutex M(wm); - selected_item = submenus.size(); - base_window::show(); - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu:: - hide ( - ) - { - auto_mutex M(wm); - // hide ourselves - close_submenu(); - selected_item = submenus.size(); - base_window::hide(); - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu:: - select_first_item ( - ) - { - auto_mutex M(wm); - close_submenu(); - selected_item = items.size(); - for (unsigned long i = 0; i < items.size(); ++i) - { - if ((items[i]->has_click_event() || submenus[i]) && item_enabled[i]) - { - selected_item = i; - break; - } - } - invalidate_rectangle(cur_rect); - } - -// ---------------------------------------------------------------------------------------- - - bool popup_menu:: - forwarded_on_keydown ( - unsigned long key, - bool is_printable, - unsigned long state - ) - { - auto_mutex M(wm); - // do nothing if this popup menu is empty - if (items.size() == 0) - return false; - - - // check if the selected item is a submenu - if (selected_item != submenus.size() && submenus[selected_item] != 0 && submenu_open) - { - // send the key to the submenu and return if that menu used the key - if (submenus[selected_item]->forwarded_on_keydown(key,is_printable,state) == true) - return true; - } - - if (key == KEY_UP) - { - for (unsigned long i = 0; i < items.size(); ++i) - { - selected_item = (selected_item + items.size() - 1)%items.size(); - // only stop looking if this one is enabled and has a click event or is a submenu - if (item_enabled[selected_item] && (items[selected_item]->has_click_event() || submenus[selected_item]) ) - break; - } - invalidate_rectangle(cur_rect); - return true; - } - else if (key == KEY_DOWN) - { - for (unsigned long i = 0; i < items.size(); ++i) - { - selected_item = (selected_item + 1)%items.size(); - // only stop looking if this one is enabled and has a click event or is a submenu - if (item_enabled[selected_item] && (items[selected_item]->has_click_event() || submenus[selected_item])) - break; - } - invalidate_rectangle(cur_rect); - return true; - } - else if (key == KEY_RIGHT && submenu_open == false && display_selected_submenu()) - { - submenus[selected_item]->select_first_item(); - return true; - } - else if (key == KEY_LEFT && selected_item != submenus.size() && - submenus[selected_item] != 0 && submenu_open) - { - close_submenu(); - return true; - } - else if (key == '\n') - { - if (selected_item != submenus.size() && (items[selected_item]->has_click_event() || submenus[selected_item])) - { - const long idx = selected_item; - // only hide this popup window if this isn't a submenu - if (submenus[idx] == 0) - { - hide(); - hide_handlers.reset(); - while (hide_handlers.move_next()) - hide_handlers.element()(); - } - else - { - display_selected_submenu(); - submenus[idx]->select_first_item(); - } - items[idx]->on_click(); - return true; - } - } - else if (is_printable) - { - // check if there is a hotkey for this key - for (unsigned long i = 0; i < items.size(); ++i) - { - if (std::tolower(key) == std::tolower(items[i]->get_hot_key()) && - (items[i]->has_click_event() || submenus[i]) && item_enabled[i] ) - { - // only hide this popup window if this isn't a submenu - if (submenus[i] == 0) - { - hide(); - hide_handlers.reset(); - while (hide_handlers.move_next()) - hide_handlers.element()(); - } - else - { - if (selected_item != items.size()) - invalidate_rectangle(line_rects[selected_item]); - - selected_item = i; - display_selected_submenu(); - invalidate_rectangle(line_rects[i]); - submenus[i]->select_first_item(); - } - items[i]->on_click(); - } - } - - // always say we use a printable key for hotkeys - return true; - } - - return false; - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu:: - on_submenu_hide ( - ) - { - hide(); - hide_handlers.reset(); - while (hide_handlers.move_next()) - hide_handlers.element()(); - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu:: - on_window_resized( - ) - { - invalidate_rectangle(win_rect); - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu:: - on_mouse_up ( - unsigned long btn, - unsigned long, - long x, - long y - ) - { - if (cur_rect.contains(x,y) && btn == LEFT) - { - // figure out which item this was on - for (unsigned long i = 0; i < items.size(); ++i) - { - if (line_rects[i].contains(x,y) && item_enabled[i] && items[i]->has_click_event()) - { - // only hide this popup window if this isn't a submenu - if (submenus[i] == 0) - { - hide(); - hide_handlers.reset(); - while (hide_handlers.move_next()) - hide_handlers.element()(); - } - items[i]->on_click(); - break; - } - } - } - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu:: - on_mouse_move ( - unsigned long , - long x, - long y - ) - { - if (cur_rect.contains(x,y)) - { - // check if the mouse is still in the same rect it was in last time - rectangle last_rect; - if (selected_item != submenus.size()) - { - last_rect = line_rects[selected_item]; - } - - // if the mouse isn't in the same rectangle any more - if (last_rect.contains(x,y) == false) - { - if (selected_item != submenus.size()) - { - invalidate_rectangle(last_rect); - close_submenu(); - selected_item = submenus.size(); - } - - - // figure out if we should redraw any menu items - for (unsigned long i = 0; i < items.size(); ++i) - { - if (items[i]->has_click_event() || submenus[i]) - { - if (line_rects[i].contains(x,y)) - { - selected_item = i; - break; - } - } - } - - // if we found a rectangle that contains the mouse then - // tell it to redraw itself - if (selected_item != submenus.size()) - { - display_selected_submenu(); - invalidate_rectangle(line_rects[selected_item]); - } - } - } - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu:: - close_submenu ( - ) - { - if (selected_item != submenus.size() && submenus[selected_item] && submenu_open) - { - submenus[selected_item]->hide(); - submenu_open = false; - } - } - -// ---------------------------------------------------------------------------------------- - - bool popup_menu:: - display_selected_submenu ( - ) - { - // show the submenu if one exists - if (selected_item != submenus.size() && submenus[selected_item]) - { - long wx, wy; - get_pos(wx,wy); - wx += line_rects[selected_item].right(); - wy += line_rects[selected_item].top(); - submenus[selected_item]->set_pos(wx+1,wy-2); - submenus[selected_item]->show(); - submenu_open = true; - return true; - } - return false; - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu:: - on_mouse_leave ( - ) - { - if (selected_item != submenus.size()) - { - // only unhighlight a menu item if it isn't a submenu item - if (submenus[selected_item] == 0) - { - invalidate_rectangle(line_rects[selected_item]); - selected_item = submenus.size(); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu:: - paint ( - const canvas& c - ) - { - c.fill(200,200,200); - draw_rectangle(c, win_rect); - for (unsigned long i = 0; i < items.size(); ++i) - { - bool is_selected = false; - if (selected_item != submenus.size() && i == selected_item && - item_enabled[i]) - is_selected = true; - - items[i]->draw_background(c,line_rects[i], item_enabled[i], is_selected); - items[i]->draw_left(c,left_rects[i], item_enabled[i], is_selected); - items[i]->draw_middle(c,middle_rects[i], item_enabled[i], is_selected); - items[i]->draw_right(c,right_rects[i], item_enabled[i], is_selected); - } - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// class zoomable_region -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - zoomable_region:: - zoomable_region ( - drawable_window& w, - unsigned long events - ) : - drawable(w,MOUSE_CLICK | MOUSE_WHEEL | MOUSE_MOVE | events), - min_scale(0.15), - max_scale(1.0), - zoom_increment_(0.90), - vsb(w, scroll_bar::VERTICAL), - hsb(w, scroll_bar::HORIZONTAL) - { - scale = 1; - mouse_drag_screen = false; - style.reset(new scrollable_region_style_default()); - - hsb.set_scroll_handler(*this,&zoomable_region::on_h_scroll); - vsb.set_scroll_handler(*this,&zoomable_region::on_v_scroll); - } - -// ---------------------------------------------------------------------------------------- - - zoomable_region:: - ~zoomable_region() - { - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - set_pos ( - long x, - long y - ) - { - auto_mutex M(m); - drawable::set_pos(x,y); - const long border_size = style->get_border_size(); - vsb.set_pos(rect.right()-border_size+1-vsb.width(),rect.top()+border_size); - hsb.set_pos(rect.left()+border_size,rect.bottom()-border_size+1-hsb.height()); - - display_rect_ = rectangle(rect.left()+border_size, - rect.top()+border_size, - rect.right()-border_size-vsb.width(), - rect.bottom()-border_size-hsb.height()); - - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - set_zoom_increment ( - double zi - ) - { - DLIB_ASSERT(0.0 < zi && zi < 1.0, - "\tvoid zoomable_region::set_zoom_increment(zi)" - << "\n\t the zoom increment must be between 0 and 1" - << "\n\t zi: " << zi - << "\n\t this: " << this - ); - - auto_mutex M(m); - zoom_increment_ = zi; - } - -// ---------------------------------------------------------------------------------------- - - double zoomable_region:: - zoom_increment ( - ) const - { - auto_mutex M(m); - return zoom_increment_; - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - set_max_zoom_scale ( - double ms - ) - { - DLIB_ASSERT(ms > 0, - "\tvoid zoomable_region::set_max_zoom_scale(ms)" - << "\n\t the max zoom scale must be greater than 0" - << "\n\t ms: " << ms - << "\n\t this: " << this - ); - - auto_mutex M(m); - max_scale = ms; - if (scale > ms) - { - scale = max_scale; - lr_point = gui_to_graph_space(point(display_rect_.right(),display_rect_.bottom())); - redraw_graph(); - } - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - set_min_zoom_scale ( - double ms - ) - { - DLIB_ASSERT(ms > 0, - "\tvoid zoomable_region::set_min_zoom_scale(ms)" - << "\n\t the min zoom scale must be greater than 0" - << "\n\t ms: " << ms - << "\n\t this: " << this - ); - - auto_mutex M(m); - min_scale = ms; - - if (scale < ms) - { - scale = min_scale; - } - - // just call set_size so that everything gets redrawn right - set_size(rect.width(), rect.height()); - } - -// ---------------------------------------------------------------------------------------- - - double zoomable_region:: - min_zoom_scale ( - ) const - { - auto_mutex M(m); - return min_scale; - } - -// ---------------------------------------------------------------------------------------- - - double zoomable_region:: - max_zoom_scale ( - ) const - { - auto_mutex M(m); - return max_scale; - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - set_size ( - unsigned long width, - unsigned long height - ) - { - auto_mutex M(m); - rectangle old(rect); - const long border_size = style->get_border_size(); - rect = resize_rect(rect,width,height); - vsb.set_pos(rect.right()-border_size+1-vsb.width(), rect.top()+border_size); - hsb.set_pos(rect.left()+border_size, rect.bottom()-border_size+1-hsb.height()); - - display_rect_ = rectangle(rect.left()+border_size, - rect.top()+border_size, - rect.right()-border_size-vsb.width(), - rect.bottom()-border_size-hsb.height()); - vsb.set_length(display_rect_.height()); - hsb.set_length(display_rect_.width()); - parent.invalidate_rectangle(rect+old); - - const double old_scale = scale; - const vector old_gr_orig(gr_orig); - scale = min_scale; - gr_orig = vector(0,0); - lr_point = gui_to_graph_space(point(display_rect_.right(),display_rect_.bottom())); - scale = old_scale; - - // call adjust_origin() so that the scroll bars get their max slider positions - // setup right - const point rect_corner(display_rect_.left(), display_rect_.top()); - adjust_origin(rect_corner, old_gr_orig); - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - show ( - ) - { - auto_mutex M(m); - drawable::show(); - hsb.show(); - vsb.show(); - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - hide ( - ) - { - auto_mutex M(m); - drawable::hide(); - hsb.hide(); - vsb.hide(); - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - enable ( - ) - { - auto_mutex M(m); - drawable::enable(); - hsb.enable(); - vsb.enable(); - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - disable ( - ) - { - auto_mutex M(m); - drawable::disable(); - hsb.disable(); - vsb.disable(); - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - set_z_order ( - long order - ) - { - auto_mutex M(m); - drawable::set_z_order(order); - hsb.set_z_order(order); - vsb.set_z_order(order); - } - -// ---------------------------------------------------------------------------------------- - - point zoomable_region:: - graph_to_gui_space ( - const vector& p - ) const - { - const point rect_corner(display_rect_.left(), display_rect_.top()); - return (p - gr_orig)*scale + rect_corner; - } - -// ---------------------------------------------------------------------------------------- - - vector zoomable_region:: - gui_to_graph_space ( - const point& p - ) const - { - const point rect_corner(display_rect_.left(), display_rect_.top()); - return (p - rect_corner)/scale + gr_orig; - } - -// ---------------------------------------------------------------------------------------- - - point zoomable_region:: - max_graph_point ( - ) const - { - return lr_point; - } - -// ---------------------------------------------------------------------------------------- - - rectangle zoomable_region:: - display_rect ( - ) const - { - return display_rect_; - } - -// ---------------------------------------------------------------------------------------- - - double zoomable_region:: - zoom_scale ( - ) const - { - return scale; - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - set_zoom_scale ( - double new_scale - ) - { - // if new_scale isn't in the right range then put it back in range before we do the - // rest of this function - if (!(min_scale <= new_scale && new_scale <= max_scale)) - { - if (new_scale > max_scale) - new_scale = max_scale; - else - new_scale = min_scale; - } - - // find the point in the center of the graph area - point center((display_rect_.left()+display_rect_.right())/2, (display_rect_.top()+display_rect_.bottom())/2); - point graph_p(gui_to_graph_space(center)); - scale = new_scale; - adjust_origin(center, graph_p); - redraw_graph(); - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - center_display_at_graph_point ( - const vector& p - ) - { - // find the point in the center of the graph area - point center((display_rect_.left()+display_rect_.right())/2, (display_rect_.top()+display_rect_.bottom())/2); - adjust_origin(center, p); - redraw_graph(); - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - on_wheel_down ( - unsigned long - ) - { - // zoom out - if (enabled && !hidden && scale > min_scale && display_rect_.contains(lastx,lasty)) - { - point gui_p(lastx,lasty); - point graph_p(gui_to_graph_space(gui_p)); - const double old_scale = scale; - scale *= zoom_increment_; - if (scale < min_scale) - scale = min_scale; - redraw_graph(); - adjust_origin(gui_p, graph_p); - - if (scale != old_scale) - on_view_changed(); - } - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - on_wheel_up ( - unsigned long - ) - { - // zoom in - if (enabled && !hidden && scale < max_scale && display_rect_.contains(lastx,lasty)) - { - point gui_p(lastx,lasty); - point graph_p(gui_to_graph_space(gui_p)); - const double old_scale = scale; - scale /= zoom_increment_; - if (scale > max_scale) - scale = max_scale; - redraw_graph(); - adjust_origin(gui_p, graph_p); - - if (scale != old_scale) - on_view_changed(); - } - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - on_mouse_move ( - unsigned long state, - long x, - long y - ) - { - if (enabled && !hidden && mouse_drag_screen) - { - adjust_origin(point(x,y), drag_screen_point); - redraw_graph(); - on_view_changed(); - } - - // check if the mouse isn't being dragged anymore - if ((state & base_window::LEFT) == 0) - { - mouse_drag_screen = false; - } - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - on_mouse_up ( - unsigned long , - unsigned long , - long , - long - ) - { - mouse_drag_screen = false; - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - on_mouse_down ( - unsigned long btn, - unsigned long , - long x, - long y, - bool - ) - { - if (enabled && !hidden && display_rect_.contains(x,y) && btn == base_window::LEFT) - { - mouse_drag_screen = true; - drag_screen_point = gui_to_graph_space(point(x,y)); - } - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - draw ( - const canvas& c - ) const - { - style->draw_scrollable_region_border(c, rect, enabled); - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - on_h_scroll ( - ) - { - gr_orig.x() = hsb.slider_pos(); - redraw_graph(); - - on_view_changed(); - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - on_v_scroll ( - ) - { - gr_orig.y() = vsb.slider_pos(); - redraw_graph(); - - on_view_changed(); - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - redraw_graph ( - ) - { - parent.invalidate_rectangle(display_rect_); - } - -// ---------------------------------------------------------------------------------------- - - void zoomable_region:: - adjust_origin ( - const point& gui_p, - const vector& graph_p - ) - { - const point rect_corner(display_rect_.left(), display_rect_.top()); - const dlib::vector v(gui_p - rect_corner); - gr_orig = graph_p - v/scale; - - - // make sure the origin isn't outside the point (0,0) - if (gr_orig.x() < 0) - gr_orig.x() = 0; - if (gr_orig.y() < 0) - gr_orig.y() = 0; - - // make sure the lower right corner of the display_rect_ doesn't map to a point beyond lr_point - point lr_rect_corner(display_rect_.right(), display_rect_.bottom()); - point p = graph_to_gui_space(lr_point); - vector lr_rect_corner_graph_space(gui_to_graph_space(lr_rect_corner)); - vector delta(lr_point - lr_rect_corner_graph_space); - if (lr_rect_corner.x() > p.x()) - { - gr_orig.x() += delta.x(); - } - - if (lr_rect_corner.y() > p.y()) - { - gr_orig.y() += delta.y(); - } - - - const vector ul_rect_corner_graph_space(gui_to_graph_space(rect_corner)); - lr_rect_corner_graph_space = gui_to_graph_space(lr_rect_corner); - // now adjust the scroll bars - - hsb.set_max_slider_pos((unsigned long)std::max(lr_point.x()-(lr_rect_corner_graph_space.x()-ul_rect_corner_graph_space.x()),0.0)); - vsb.set_max_slider_pos((unsigned long)std::max(lr_point.y()-(lr_rect_corner_graph_space.y()-ul_rect_corner_graph_space.y()),0.0)); - // adjust slider position now. - hsb.set_slider_pos(static_cast(ul_rect_corner_graph_space.x())); - vsb.set_slider_pos(static_cast(ul_rect_corner_graph_space.y())); - - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// class scrollable_region -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - scrollable_region:: - scrollable_region ( - drawable_window& w, - unsigned long events - ) : - drawable(w, MOUSE_WHEEL|events|MOUSE_CLICK|MOUSE_MOVE), - hsb(w,scroll_bar::HORIZONTAL), - vsb(w,scroll_bar::VERTICAL), - hscroll_bar_inc(1), - vscroll_bar_inc(1), - h_wheel_scroll_bar_inc(1), - v_wheel_scroll_bar_inc(1), - mouse_drag_enabled_(false), - user_is_dragging_mouse(false) - { - style.reset(new scrollable_region_style_default()); - - hsb.set_scroll_handler(*this,&scrollable_region::on_h_scroll); - vsb.set_scroll_handler(*this,&scrollable_region::on_v_scroll); - } - -// ---------------------------------------------------------------------------------------- - - scrollable_region:: - ~scrollable_region ( - ) - { - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - show ( - ) - { - auto_mutex M(m); - drawable::show(); - if (need_h_scroll()) - hsb.show(); - if (need_v_scroll()) - vsb.show(); - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - hide ( - ) - { - auto_mutex M(m); - drawable::hide(); - hsb.hide(); - vsb.hide(); - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - enable ( - ) - { - auto_mutex M(m); - drawable::enable(); - hsb.enable(); - vsb.enable(); - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - disable ( - ) - { - auto_mutex M(m); - drawable::disable(); - hsb.disable(); - vsb.disable(); - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - set_z_order ( - long order - ) - { - auto_mutex M(m); - drawable::set_z_order(order); - hsb.set_z_order(order); - vsb.set_z_order(order); - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - set_size ( - unsigned long width, - unsigned long height - ) - { - auto_mutex M(m); - rectangle old(rect); - rect = resize_rect(rect,width,height); - vsb.set_pos(rect.right()-style->get_border_size()-vsb.width()+1, rect.top()+style->get_border_size()); - hsb.set_pos(rect.left()+style->get_border_size(), rect.bottom()-style->get_border_size()-hsb.height()+1); - - // adjust the display_rect_ - if (need_h_scroll() && need_v_scroll()) - { - // both scroll bars aren't hidden - if (!hidden) - { - vsb.show(); - hsb.show(); - } - display_rect_ = rectangle( rect.left()+style->get_border_size(), - rect.top()+style->get_border_size(), - rect.right()-style->get_border_size()-vsb.width(), - rect.bottom()-style->get_border_size()-hsb.height()); - - // figure out how many scroll bar positions there should be - unsigned long hdelta = total_rect_.width()-display_rect_.width(); - unsigned long vdelta = total_rect_.height()-display_rect_.height(); - hdelta = (hdelta+hscroll_bar_inc-1)/hscroll_bar_inc; - vdelta = (vdelta+vscroll_bar_inc-1)/vscroll_bar_inc; - - hsb.set_max_slider_pos(hdelta); - vsb.set_max_slider_pos(vdelta); - - vsb.set_jump_size((display_rect_.height()+vscroll_bar_inc-1)/vscroll_bar_inc/2+1); - hsb.set_jump_size((display_rect_.width()+hscroll_bar_inc-1)/hscroll_bar_inc/2+1); - } - else if (need_h_scroll()) - { - // only hsb is hidden - if (!hidden) - { - hsb.show(); - vsb.hide(); - } - display_rect_ = rectangle( rect.left()+style->get_border_size(), - rect.top()+style->get_border_size(), - rect.right()-style->get_border_size(), - rect.bottom()-style->get_border_size()-hsb.height()); - - // figure out how many scroll bar positions there should be - unsigned long hdelta = total_rect_.width()-display_rect_.width(); - hdelta = (hdelta+hscroll_bar_inc-1)/hscroll_bar_inc; - - hsb.set_max_slider_pos(hdelta); - vsb.set_max_slider_pos(0); - - hsb.set_jump_size((display_rect_.width()+hscroll_bar_inc-1)/hscroll_bar_inc/2+1); - } - else if (need_v_scroll()) - { - // only vsb is hidden - if (!hidden) - { - hsb.hide(); - vsb.show(); - } - display_rect_ = rectangle( rect.left()+style->get_border_size(), - rect.top()+style->get_border_size(), - rect.right()-style->get_border_size()-vsb.width(), - rect.bottom()-style->get_border_size()); - - unsigned long vdelta = total_rect_.height()-display_rect_.height(); - vdelta = (vdelta+vscroll_bar_inc-1)/vscroll_bar_inc; - - hsb.set_max_slider_pos(0); - vsb.set_max_slider_pos(vdelta); - - vsb.set_jump_size((display_rect_.height()+vscroll_bar_inc-1)/vscroll_bar_inc/2+1); - } - else - { - // both are hidden - if (!hidden) - { - hsb.hide(); - vsb.hide(); - } - display_rect_ = rectangle( rect.left()+style->get_border_size(), - rect.top()+style->get_border_size(), - rect.right()-style->get_border_size(), - rect.bottom()-style->get_border_size()); - - hsb.set_max_slider_pos(0); - vsb.set_max_slider_pos(0); - } - - vsb.set_length(display_rect_.height()); - hsb.set_length(display_rect_.width()); - - // adjust the total_rect_ position by trigging the scroll events - on_h_scroll(); - on_v_scroll(); - - parent.invalidate_rectangle(rect+old); - } - -// ---------------------------------------------------------------------------------------- - - unsigned long scrollable_region:: - horizontal_mouse_wheel_scroll_increment ( - ) const - { - auto_mutex M(m); - return h_wheel_scroll_bar_inc; - } - -// ---------------------------------------------------------------------------------------- - - unsigned long scrollable_region:: - vertical_mouse_wheel_scroll_increment ( - ) const - { - auto_mutex M(m); - return v_wheel_scroll_bar_inc; - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - set_horizontal_mouse_wheel_scroll_increment ( - unsigned long inc - ) - { - auto_mutex M(m); - h_wheel_scroll_bar_inc = inc; - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - set_vertical_mouse_wheel_scroll_increment ( - unsigned long inc - ) - { - auto_mutex M(m); - v_wheel_scroll_bar_inc = inc; - } - -// ---------------------------------------------------------------------------------------- - - unsigned long scrollable_region:: - horizontal_scroll_increment ( - ) const - { - auto_mutex M(m); - return hscroll_bar_inc; - } - -// ---------------------------------------------------------------------------------------- - - unsigned long scrollable_region:: - vertical_scroll_increment ( - ) const - { - auto_mutex M(m); - return vscroll_bar_inc; - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - set_horizontal_scroll_increment ( - unsigned long inc - ) - { - auto_mutex M(m); - hscroll_bar_inc = inc; - // call set_size to reset the scroll bars - set_size(rect.width(),rect.height()); - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - set_vertical_scroll_increment ( - unsigned long inc - ) - { - auto_mutex M(m); - vscroll_bar_inc = inc; - // call set_size to reset the scroll bars - set_size(rect.width(),rect.height()); - } - -// ---------------------------------------------------------------------------------------- - - long scrollable_region:: - horizontal_scroll_pos ( - ) const - { - auto_mutex M(m); - return hsb.slider_pos(); - } - -// ---------------------------------------------------------------------------------------- - - long scrollable_region:: - vertical_scroll_pos ( - ) const - { - auto_mutex M(m); - return vsb.slider_pos(); - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - set_horizontal_scroll_pos ( - long pos - ) - { - auto_mutex M(m); - - hsb.set_slider_pos(pos); - on_h_scroll(); - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - set_vertical_scroll_pos ( - long pos - ) - { - auto_mutex M(m); - - vsb.set_slider_pos(pos); - on_v_scroll(); - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - set_pos ( - long x, - long y - ) - { - auto_mutex M(m); - drawable::set_pos(x,y); - vsb.set_pos(rect.right()-style->get_border_size()-vsb.width()+1, rect.top()+style->get_border_size()); - hsb.set_pos(rect.left()+style->get_border_size(), rect.bottom()-style->get_border_size()-hsb.height()+1); - - const long delta_x = total_rect_.left() - display_rect_.left(); - const long delta_y = total_rect_.top() - display_rect_.top(); - - display_rect_ = move_rect(display_rect_, rect.left()+style->get_border_size(), rect.top()+style->get_border_size()); - - total_rect_ = move_rect(total_rect_, display_rect_.left()+delta_x, display_rect_.top()+delta_y); - } - -// ---------------------------------------------------------------------------------------- - - bool scrollable_region:: - mouse_drag_enabled ( - ) const - { - auto_mutex M(m); - return mouse_drag_enabled_; - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - enable_mouse_drag ( - ) - { - auto_mutex M(m); - mouse_drag_enabled_ = true; - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - disable_mouse_drag ( - ) - { - auto_mutex M(m); - mouse_drag_enabled_ = false; - } - -// ---------------------------------------------------------------------------------------- - - const rectangle& scrollable_region:: - display_rect ( - ) const - { - return display_rect_; - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - set_total_rect_size ( - unsigned long width, - unsigned long height - ) - { - DLIB_ASSERT((width > 0 && height > 0) || (width == 0 && height == 0), - "\tvoid scrollable_region::set_total_rect_size(width,height)" - << "\n\twidth and height must be > 0 or both == 0" - << "\n\twidth: " << width - << "\n\theight: " << height - << "\n\tthis: " << this - ); - - total_rect_ = move_rect(rectangle(width,height), - display_rect_.left()-static_cast(hsb.slider_pos()), - display_rect_.top()-static_cast(vsb.slider_pos())); - - // call this just to reconfigure the scroll bars - set_size(rect.width(),rect.height()); - } - -// ---------------------------------------------------------------------------------------- - - const rectangle& scrollable_region:: - total_rect ( - ) const - { - return total_rect_; - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - scroll_to_rect ( - const rectangle& r_ - ) - { - const rectangle r(total_rect_.intersect(r_)); - const rectangle old(total_rect_); - // adjust the horizontal scroll bar so that r fits as best as possible - if (r.left() < display_rect_.left()) - { - long distance = (r.left()-total_rect_.left())/hscroll_bar_inc; - hsb.set_slider_pos(distance); - } - else if (r.right() > display_rect_.right()) - { - long distance = (r.right()-total_rect_.left()-display_rect_.width()+hscroll_bar_inc)/hscroll_bar_inc; - hsb.set_slider_pos(distance); - } - - // adjust the vertical scroll bar so that r fits as best as possible - if (r.top() < display_rect_.top()) - { - long distance = (r.top()-total_rect_.top())/vscroll_bar_inc; - vsb.set_slider_pos(distance); - } - else if (r.bottom() > display_rect_.bottom()) - { - long distance = (r.bottom()-total_rect_.top()-display_rect_.height()+vscroll_bar_inc)/vscroll_bar_inc; - vsb.set_slider_pos(distance); - } - - - // adjust total_rect_ so that it matches where the scroll bars are now - total_rect_ = move_rect(total_rect_, - display_rect_.left()-hscroll_bar_inc*hsb.slider_pos(), - display_rect_.top()-vscroll_bar_inc*vsb.slider_pos()); - - // only redraw if we actually changed something - if (total_rect_ != old) - { - parent.invalidate_rectangle(display_rect_); - } - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - on_wheel_down ( - unsigned long - ) - { - if (rect.contains(lastx,lasty) && enabled && !hidden) - { - if (need_v_scroll()) - { - long pos = vsb.slider_pos(); - vsb.set_slider_pos(pos+(long)v_wheel_scroll_bar_inc); - on_v_scroll(); - } - else if (need_h_scroll()) - { - long pos = hsb.slider_pos(); - hsb.set_slider_pos(pos+(long)h_wheel_scroll_bar_inc); - on_h_scroll(); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - on_mouse_move ( - unsigned long state, - long x, - long y - ) - { - if (enabled && !hidden && user_is_dragging_mouse && state==base_window::LEFT) - { - point current_delta = point(x,y) - point(total_rect().left(), total_rect().top()); - rectangle new_rect(translate_rect(display_rect(), drag_origin - current_delta)); - new_rect = centered_rect(new_rect, new_rect.width()-hscroll_bar_inc, new_rect.height()-vscroll_bar_inc); - scroll_to_rect(new_rect); - on_view_changed(); - } - else - { - user_is_dragging_mouse = false; - } - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - on_mouse_down ( - unsigned long btn, - unsigned long , - long x, - long y, - bool - ) - { - if (mouse_drag_enabled_ && enabled && !hidden && display_rect().contains(x,y) && (btn==base_window::LEFT)) - { - drag_origin = point(x,y) - point(total_rect().left(), total_rect().top()); - user_is_dragging_mouse = true; - } - else - { - user_is_dragging_mouse = false; - } - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - on_mouse_up ( - unsigned long , - unsigned long , - long , - long - ) - { - user_is_dragging_mouse = false; - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - on_wheel_up ( - unsigned long - ) - { - if (rect.contains(lastx,lasty) && enabled && !hidden) - { - if (need_v_scroll()) - { - long pos = vsb.slider_pos(); - vsb.set_slider_pos(pos-(long)v_wheel_scroll_bar_inc); - on_v_scroll(); - } - else if (need_h_scroll()) - { - long pos = hsb.slider_pos(); - hsb.set_slider_pos(pos-(long)h_wheel_scroll_bar_inc); - on_h_scroll(); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - draw ( - const canvas& c - ) const - { - style->draw_scrollable_region_border(c, rect, enabled); - } - -// ---------------------------------------------------------------------------------------- - - bool scrollable_region:: - need_h_scroll ( - ) const - { - if (total_rect_.width() > rect.width()-style->get_border_size()*2) - { - return true; - } - else - { - // check if we would need a vertical scroll bar and if adding one would make us need - // a horizontal one - if (total_rect_.height() > rect.height()-style->get_border_size()*2 && - total_rect_.width() > rect.width()-style->get_border_size()*2-vsb.width()) - return true; - else - return false; - } - } - -// ---------------------------------------------------------------------------------------- - - bool scrollable_region:: - need_v_scroll ( - ) const - { - if (total_rect_.height() > rect.height()-style->get_border_size()*2) - { - return true; - } - else - { - // check if we would need a horizontal scroll bar and if adding one would make us need - // a vertical_scroll_pos one - if (total_rect_.width() > rect.width()-style->get_border_size()*2 && - total_rect_.height() > rect.height()-style->get_border_size()*2-hsb.height()) - return true; - else - return false; - } - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - on_h_scroll ( - ) - { - total_rect_ = move_rect(total_rect_, display_rect_.left()-hscroll_bar_inc*hsb.slider_pos(), total_rect_.top()); - parent.invalidate_rectangle(display_rect_); - if (events_are_enabled()) - on_view_changed(); - } - -// ---------------------------------------------------------------------------------------- - - void scrollable_region:: - on_v_scroll ( - ) - { - total_rect_ = move_rect(total_rect_, total_rect_.left(), display_rect_.top()-vscroll_bar_inc*vsb.slider_pos()); - parent.invalidate_rectangle(display_rect_); - if (events_are_enabled()) - on_view_changed(); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// class popup_menu_region -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - popup_menu_region:: - popup_menu_region( - drawable_window& w - ) : - drawable(w,MOUSE_CLICK | KEYBOARD_EVENTS | FOCUS_EVENTS | WINDOW_MOVED), - popup_menu_shown(false) - { - - menu_.set_on_hide_handler(*this,&popup_menu_region::on_menu_becomes_hidden); - enable_events(); - } - -// ---------------------------------------------------------------------------------------- - - popup_menu_region:: - ~popup_menu_region( - ) - { - disable_events(); - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu_region:: - set_size ( - unsigned long width, - unsigned long height - ) - { - auto_mutex M(m); - rect = resize_rect(rect,width,height); - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu_region:: - set_rect ( - const rectangle& new_rect - ) - { - auto_mutex M(m); - rect = new_rect; - } - -// ---------------------------------------------------------------------------------------- - - popup_menu& popup_menu_region:: - menu ( - ) - { - return menu_; - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu_region:: - hide ( - ) - { - auto_mutex M(m); - drawable::hide(); - menu_.hide(); - popup_menu_shown = false; - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu_region:: - disable ( - ) - { - auto_mutex M(m); - drawable::disable(); - menu_.hide(); - popup_menu_shown = false; - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu_region:: - on_keydown ( - unsigned long key, - bool is_printable, - unsigned long state - ) - { - if (enabled && !hidden && popup_menu_shown) - { - menu_.forwarded_on_keydown(key, is_printable, state); - } - else if (popup_menu_shown) - { - menu_.hide(); - popup_menu_shown = false; - } - - if (key == (unsigned long)base_window::KEY_ESC) - { - menu_.hide(); - popup_menu_shown = false; - } - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu_region:: - on_menu_becomes_hidden ( - ) - { - popup_menu_shown = false; - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu_region:: - on_focus_lost ( - ) - { - if (popup_menu_shown) - { - menu_.hide(); - popup_menu_shown = false; - } - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu_region:: - on_focus_gained ( - ) - { - if (popup_menu_shown) - { - menu_.hide(); - popup_menu_shown = false; - } - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu_region:: - on_window_moved( - ) - { - if (popup_menu_shown) - { - menu_.hide(); - popup_menu_shown = false; - } - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu_region:: - on_mouse_down ( - unsigned long btn, - unsigned long , - long x, - long y, - bool - ) - { - if (enabled && !hidden && rect.contains(x,y) && btn == base_window::RIGHT) - { - long orig_x, orig_y; - parent.get_pos(orig_x, orig_y); - menu_.set_pos(orig_x+x, orig_y+y); - menu_.show(); - popup_menu_shown = true; - } - else if (popup_menu_shown) - { - menu_.hide(); - popup_menu_shown = false; - } - } - -// ---------------------------------------------------------------------------------------- - - void popup_menu_region:: - draw ( - const canvas& - ) const - { - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_BASE_WIDGETs_CPP_ - diff --git a/lib/3rdParty/dlib/include/dlib/gui_widgets/base_widgets.h b/lib/3rdParty/dlib/include/dlib/gui_widgets/base_widgets.h index 781226b1..7c6d2509 100644 --- a/lib/3rdParty/dlib/include/dlib/gui_widgets/base_widgets.h +++ b/lib/3rdParty/dlib/include/dlib/gui_widgets/base_widgets.h @@ -4,6 +4,9 @@ #ifndef DLIB_BASE_WIDGETs_ #define DLIB_BASE_WIDGETs_ +#include +#include + #include "base_widgets_abstract.h" #include "drawable.h" #include "../gui_core.h" @@ -17,9 +20,7 @@ #include "../image_transforms/assign_image.h" #include "../array.h" #include "style.h" -#include "../smart_pointers.h" #include "../unicode.h" -#include #include "../any.h" @@ -328,7 +329,7 @@ namespace dlib const drawable& widget ); - unsigned long size ( + size_t size ( ) const; void set_pos ( @@ -409,8 +410,8 @@ namespace dlib auto_mutex M(m); assign_image_scaled(img,new_img); rectangle old(rect); - rect.set_right(rect.left()+img.nc()-1); - rect.set_bottom(rect.top()+img.nr()-1); + rect.set_right(rect.left()+num_columns(img)-1); + rect.set_bottom(rect.top()+num_rows(img)-1); parent.invalidate_rectangle(rect+old); } @@ -586,7 +587,7 @@ namespace dlib class tooltip_window : public base_window { public: - tooltip_window (const shared_ptr_thread_safe& f) : base_window(false,true), pad(3), mfont(f) + tooltip_window (const std::shared_ptr& f) : base_window(false,true), pad(3), mfont(f) { } @@ -594,7 +595,7 @@ namespace dlib rectangle rect_all; rectangle rect_text; const unsigned long pad; - const shared_ptr_thread_safe mfont; + const std::shared_ptr mfont; void set_text ( const std::string& str @@ -694,7 +695,7 @@ namespace dlib }; friend struct data; - scoped_ptr stuff; + std::unique_ptr stuff; @@ -777,7 +778,7 @@ namespace dlib ) const; void set_main_font ( - const shared_ptr_thread_safe& f + const std::shared_ptr& f ); void show ( @@ -952,7 +953,7 @@ namespace dlib any_function button_down_handler_self; any_function button_up_handler_self; - scoped_ptr style; + std::unique_ptr style; protected: @@ -1415,7 +1416,7 @@ namespace dlib timer top_filler_timer; timer bottom_filler_timer; long delayed_pos; - scoped_ptr style; + std::unique_ptr style; // restricted functions scroll_bar(scroll_bar&); // copy constructor @@ -1623,7 +1624,7 @@ namespace dlib private: dlib::ustring text; - const shared_ptr_thread_safe f; + const std::shared_ptr f; any_function action; unichar hotkey; point underline_p1; @@ -1801,7 +1802,7 @@ namespace dlib private: dlib::ustring text; - const shared_ptr_thread_safe f; + const std::shared_ptr f; any_function action; unichar hotkey; point underline_p1; @@ -1925,7 +1926,7 @@ namespace dlib { auto_mutex M(wm); bool t = true; - scoped_ptr item(new menu_item_type(new_item)); + std::unique_ptr item(new menu_item_type(new_item)); items.push_back(item); item_enabled.push_back(t); @@ -2038,7 +2039,7 @@ namespace dlib unsigned long idx ); - unsigned long size ( + size_t size ( ) const; void clear ( @@ -2135,7 +2136,7 @@ namespace dlib rectangle win_rect; unsigned long left_width; unsigned long middle_width; - array > items; + array > items; array item_enabled; array left_rects; array middle_rects; @@ -2356,7 +2357,7 @@ namespace dlib scroll_bar vsb; scroll_bar hsb; - scoped_ptr style; + std::unique_ptr style; // restricted functions zoomable_region(zoomable_region&); // copy constructor @@ -2576,7 +2577,7 @@ namespace dlib bool mouse_drag_enabled_; bool user_is_dragging_mouse; point drag_origin; - scoped_ptr style; + std::unique_ptr style; }; diff --git a/lib/3rdParty/dlib/include/dlib/gui_widgets/base_widgets_abstract.h b/lib/3rdParty/dlib/include/dlib/gui_widgets/base_widgets_abstract.h index f9a6b92f..3dcee0d5 100644 --- a/lib/3rdParty/dlib/include/dlib/gui_widgets/base_widgets_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/gui_widgets/base_widgets_abstract.h @@ -967,7 +967,7 @@ namespace dlib widgets in this group and the upper left corner of get_rect(). !*/ - unsigned long size ( + size_t size ( ) const; /*! ensures @@ -1561,7 +1561,7 @@ namespace dlib - the menu_item in this with the index idx has been disabled !*/ - unsigned long size ( + size_t size ( ) const; /*! ensures @@ -2061,8 +2061,8 @@ namespace dlib - #height() == height_ - #top() == top() - #left() == left() - - i.e. The location of the upper left corner of this button stays the - same but its width and height are modified + - i.e. The location of the upper left corner of this widget stays the + same but its width and height are modified. !*/ long horizontal_scroll_pos ( diff --git a/lib/3rdParty/dlib/include/dlib/gui_widgets/canvas_drawing.cpp b/lib/3rdParty/dlib/include/dlib/gui_widgets/canvas_drawing.cpp deleted file mode 100644 index 0fecd1cd..00000000 --- a/lib/3rdParty/dlib/include/dlib/gui_widgets/canvas_drawing.cpp +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (C) 2005 Davis E. King (davis@dlib.net), and Nils Labugt -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_CANVAS_DRAWINg_CPP_ -#define DLIB_CANVAS_DRAWINg_CPP_ - -#include "canvas_drawing.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - void draw_sunken_rectangle ( - const canvas& c, - const rectangle& border, - unsigned char alpha - ) - { - rectangle area = border.intersect(c); - if (area.is_empty() == false) - { - const rgb_alpha_pixel dark_gray(64,64,64,alpha); - const rgb_alpha_pixel gray(128,128,128,alpha); - const rgb_alpha_pixel white(255,255,255,alpha); - const rgb_alpha_pixel background(212,208,200,alpha); - - draw_line(c,point(border.left(),border.top()),point(border.right()-1,border.top()),gray); - - draw_line(c,point(border.left(),border.bottom()),point(border.right(),border.bottom()),white); - draw_line(c,point(border.left()+1,border.bottom()-1),point(border.right()-1,border.bottom()-1),background); - - draw_line(c,point(border.left(),border.top()+1),point(border.left(),border.bottom()-1),gray); - - draw_line(c,point(border.right(),border.top()),point(border.right(),border.bottom()-1),white); - draw_line(c,point(border.right()-1,border.top()+1),point(border.right()-1,border.bottom()-2),background); - - draw_line(c,point(border.left()+1,border.top()+1),point(border.left()+1,border.bottom()-2),dark_gray); - draw_line(c,point(border.left()+1,border.top()+1),point(border.right()-2,border.top()+1),dark_gray); - } - } - -// ---------------------------------------------------------------------------------------- - - void draw_button_down ( - const canvas& c, - const rectangle& btn, - unsigned char alpha - ) - { - rectangle area = btn.intersect(c); - if (area.is_empty() == false) - { - const rgb_alpha_pixel dark_gray(64,64,64,alpha); - const rgb_alpha_pixel gray(128,128,128,alpha); - const rgb_alpha_pixel black(0,0,0,alpha); - - draw_line(c,point(btn.left(),btn.top()),point(btn.right(),btn.top()),black); - - draw_line(c,point(btn.left()+1,btn.bottom()),point(btn.right(),btn.bottom()),dark_gray); - draw_line(c,point(btn.left()+1,btn.top()+1),point(btn.right()-1,btn.top()+1),gray); - - draw_line(c,point(btn.left(),btn.top()+1),point(btn.left(),btn.bottom()),black); - - draw_line(c,point(btn.right(),btn.top()+1),point(btn.right(),btn.bottom()-1),dark_gray); - draw_line(c,point(btn.left()+1,btn.top()+1),point(btn.left()+1,btn.bottom()-1),gray); - } - } - -// ---------------------------------------------------------------------------------------- - - void draw_button_up ( - const canvas& c, - const rectangle& btn, - unsigned char alpha - ) - { - rectangle area = btn.intersect(c); - if (area.is_empty() == false) - { - const rgb_alpha_pixel dark_gray(64,64,64,alpha); - const rgb_alpha_pixel gray(128,128,128,alpha); - const rgb_alpha_pixel white(255,255,255,alpha); - - draw_line(c,point(btn.left(),btn.top()),point(btn.right()-1,btn.top()),white); - - draw_line(c,point(btn.left(),btn.bottom()),point(btn.right(),btn.bottom()),dark_gray); - draw_line(c,point(btn.left()+1,btn.bottom()-1),point(btn.right()-1,btn.bottom()-1),gray); - - draw_line(c,point(btn.left(),btn.top()+1),point(btn.left(),btn.bottom()-1),white); - - draw_line(c,point(btn.right(),btn.top()),point(btn.right(),btn.bottom()-1),dark_gray); - draw_line(c,point(btn.right()-1,btn.top()+1),point(btn.right()-1,btn.bottom()-2),gray); - } - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_CANVAS_DRAWINg_CPP_ - diff --git a/lib/3rdParty/dlib/include/dlib/gui_widgets/canvas_drawing.h b/lib/3rdParty/dlib/include/dlib/gui_widgets/canvas_drawing.h index 1a077d42..61f68811 100644 --- a/lib/3rdParty/dlib/include/dlib/gui_widgets/canvas_drawing.h +++ b/lib/3rdParty/dlib/include/dlib/gui_widgets/canvas_drawing.h @@ -681,7 +681,7 @@ namespace dlib { const long x = p.x(); const long y = p.y(); - rectangle rect(x,y,img.nc()+x-1,img.nr()+y-1); + rectangle rect(x,y,num_columns(img)+x-1,num_rows(img)+y-1); rectangle area = c.intersect(rect).intersect(area_); if (area.is_empty()) return; @@ -709,11 +709,11 @@ namespace dlib ) { const rectangle area = c.intersect(rect).intersect(area_); - if (area.is_empty() || img.size() == 0) + if (area.is_empty() || num_columns(img) * num_rows(img) == 0) return; - const matrix x = matrix_cast(round(linspace(0, img.nc()-1, rect.width()))); - const matrix y = matrix_cast(round(linspace(0, img.nr()-1, rect.height()))); + const matrix x = matrix_cast(round(linspace(0, num_columns(img)-1, rect.width()))); + const matrix y = matrix_cast(round(linspace(0, num_rows(img)-1, rect.height()))); for (long row = area.top(); row <= area.bottom(); ++row) { diff --git a/lib/3rdParty/dlib/include/dlib/gui_widgets/drawable.cpp b/lib/3rdParty/dlib/include/dlib/gui_widgets/drawable.cpp deleted file mode 100644 index 1106bf0d..00000000 --- a/lib/3rdParty/dlib/include/dlib/gui_widgets/drawable.cpp +++ /dev/null @@ -1,534 +0,0 @@ -// Copyright (C) 2005 Davis E. King (davis@dlib.net), Keita Mochizuki -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_DRAWABLe_CPP_ -#define DLIB_DRAWABLe_CPP_ - -#include "drawable.h" - -#include - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ----------- drawable_window object ------------------------------------------------------------ -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - rgb_pixel drawable_window:: - background_color ( - ) const - { - auto_mutex M(wm); - return bg_color; - } - -// ---------------------------------------------------------------------------------------- - - void drawable_window:: - set_background_color ( - unsigned long red_, - unsigned long green_, - unsigned long blue_ - ) - { - wm.lock(); - bg_color.red = red_; - bg_color.green = green_; - bg_color.blue = blue_; - wm.unlock(); - // now repaint the window - unsigned long width,height; - get_size(width,height); - rectangle rect(0,0,width-1,height-1); - invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - void drawable_window:: - paint ( - const canvas& c - ) - { - ++event_id; - c.fill(bg_color.red,bg_color.green,bg_color.blue); - - widgets.reset(); - while (widgets.move_next()) - { - widgets.element().value().reset(); - while (widgets.element().value().move_next()) - { - // only dispatch a draw() call if this widget isn't hidden - if (widgets.element().value().element()->hidden == false && - widgets.element().value().element()->event_id != event_id) - { - widgets.element().value().element()->event_id = event_id; - widgets.element().value().element()->draw(c); - } - } - } - } - -// ---------------------------------------------------------------------------------------- - - void drawable_window:: - on_user_event ( - void* p, - int i - ) - { - drawable* d = static_cast(p); - if (widget_set.is_member(d)) - { - d->on_user_event(i); - } - } - -// ---------------------------------------------------------------------------------------- - - void drawable_window:: - on_window_moved( - ) - { - ++event_id; - window_moved.reset(); - while (window_moved.move_next()) - { - if (window_moved.element()->event_id != event_id) - { - window_moved.element()->event_id = event_id; - window_moved.element()->on_window_moved(); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void drawable_window:: - on_window_resized( - ) - { - ++event_id; - window_resized.reset(); - while (window_resized.move_next()) - { - if (window_resized.element()->event_id != event_id) - { - window_resized.element()->event_id = event_id; - window_resized.element()->on_window_resized(); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void drawable_window:: - on_keydown ( - unsigned long key, - bool is_printable, - unsigned long state - ) - { - ++event_id; - keyboard.reset(); - while (keyboard.move_next()) - { - if (keyboard.element()->event_id != event_id) - { - keyboard.element()->event_id = event_id; - keyboard.element()->on_keydown(key,is_printable,state); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void drawable_window:: - on_focus_gained ( - ) - { - ++event_id; - focus.reset(); - while (focus.move_next()) - { - if (focus.element()->event_id != event_id) - { - focus.element()->event_id = event_id; - focus.element()->on_focus_gained(); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void drawable_window:: - on_focus_lost ( - ) - { - ++event_id; - focus.reset(); - while (focus.move_next()) - { - if (focus.element()->event_id != event_id) - { - focus.element()->event_id = event_id; - focus.element()->on_focus_lost(); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void drawable_window:: - on_mouse_down ( - unsigned long btn, - unsigned long state, - long x, - long y, - bool is_double_click - ) - { - lastx = x; - lasty = y; - - ++event_id; - mouse_click.reset(); - while (mouse_click.move_next()) - { - if (mouse_click.element()->event_id != event_id) - { - mouse_click.element()->event_id = event_id; - mouse_click.element()->on_mouse_down(btn,state,x,y,is_double_click); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void drawable_window:: - on_mouse_up ( - unsigned long btn, - unsigned long state, - long x, - long y - ) - { - lastx = x; - lasty = y; - - ++event_id; - mouse_click.reset(); - while (mouse_click.move_next()) - { - if (mouse_click.element()->event_id != event_id) - { - mouse_click.element()->event_id = event_id; - mouse_click.element()->on_mouse_up(btn,state,x,y); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void drawable_window:: - on_mouse_move ( - unsigned long state, - long x, - long y - ) - { - lastx = x; - lasty = y; - - ++event_id; - mouse_move.reset(); - while (mouse_move.move_next()) - { - if (mouse_move.element()->event_id != event_id) - { - mouse_move.element()->event_id = event_id; - mouse_move.element()->on_mouse_move(state,x,y); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void drawable_window:: - on_mouse_leave ( - ) - { - lastx = -1; - lasty = -1; - - ++event_id; - mouse_move.reset(); - while (mouse_move.move_next()) - { - if (mouse_move.element()->event_id != event_id) - { - mouse_move.element()->event_id = event_id; - mouse_move.element()->on_mouse_leave(); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void drawable_window:: - on_mouse_enter ( - ) - { - ++event_id; - mouse_move.reset(); - while (mouse_move.move_next()) - { - if (mouse_move.element()->event_id != event_id) - { - mouse_move.element()->event_id = event_id; - mouse_move.element()->on_mouse_enter(); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void drawable_window:: - on_wheel_up ( - unsigned long state - ) - { - ++event_id; - mouse_wheel.reset(); - while (mouse_wheel.move_next()) - { - if (mouse_wheel.element()->event_id != event_id) - { - mouse_wheel.element()->event_id = event_id; - mouse_wheel.element()->on_wheel_up(state); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void drawable_window:: - on_wheel_down ( - unsigned long state - ) - { - ++event_id; - mouse_wheel.reset(); - while (mouse_wheel.move_next()) - { - if (mouse_wheel.element()->event_id != event_id) - { - mouse_wheel.element()->event_id = event_id; - mouse_wheel.element()->on_wheel_down(state); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void drawable_window:: - on_string_put ( - const std::wstring &str - ) - { - ++event_id; - string_put.reset(); - while (string_put.move_next()) - { - if (string_put.element()->event_id != event_id) - { - string_put.element()->event_id = event_id; - string_put.element()->on_string_put(str); - } - } - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ----------- drawable object ---------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void drawable:: - enable_events ( - ) - { - auto_mutex M(m); - if (enabled_events == false) - { - enabled_events = true; - drawable* temp = this; - long zo = z_order_value; - - drawable_window::set_of_drawables* sod = parent.widgets[zo]; - if (sod == 0) - { - // this drawable is the first widget at this z order so we need - // to make its containing set - drawable_window::set_of_drawables s; - s.add(temp); - parent.widgets.add(zo,s); - } - else - { - sod->add(temp); - } - - temp = this; - parent.widget_set.add(temp); - - if (events & MOUSE_MOVE) - { - temp = this; - parent.mouse_move.add(temp); - } - if (events & MOUSE_CLICK) - { - temp = this; - parent.mouse_click.add(temp); - } - if (events & MOUSE_WHEEL) - { - temp = this; - parent.mouse_wheel.add(temp); - } - if (events & WINDOW_RESIZED) - { - temp = this; - parent.window_resized.add(temp); - } - if (events & KEYBOARD_EVENTS) - { - temp = this; - parent.keyboard.add(temp); - } - if (events & FOCUS_EVENTS) - { - temp = this; - parent.focus.add(temp); - } - if (events & WINDOW_MOVED) - { - temp = this; - parent.window_moved.add(temp); - } - if (events & STRING_PUT) - { - temp = this; - parent.string_put.add(temp); - } - parent.invalidate_rectangle(rect); - } - } - -// ---------------------------------------------------------------------------------------- - - void drawable:: - set_z_order ( - long order - ) - { - auto_mutex M(m); - if (order != z_order_value && enabled_events) - { - // first remove this drawable from widgets - drawable_window::set_of_drawables* sod = parent.widgets[z_order_value]; - drawable* junk; - sod->remove(this,junk); - - // if there are no more drawables at this z order then destroy the - // set for this order - if (sod->size() == 0) - parent.widgets.destroy(z_order_value); - - // now add this drawable to its new z order - sod = parent.widgets[order]; - if (sod == 0) - { - // this drawable is the first widget at this z order so we need - // to make its containing set - drawable_window::set_of_drawables s, x; - s.add(junk); - long temp_order = order; - parent.widgets.add(temp_order,s); - } - else - { - sod->add(junk); - } - parent.invalidate_rectangle(rect); - - } - z_order_value = order; - } - -// ---------------------------------------------------------------------------------------- - - void drawable:: - disable_events ( - ) - { - auto_mutex M(m); - if (enabled_events) - { - enabled_events = false; - // first remove this drawable from widgets - drawable_window::set_of_drawables* sod = parent.widgets[z_order_value]; - drawable* junk; - sod->remove(this,junk); - - // if there are no more drawables at this z order then destroy the - // set for this order - if (sod->size() == 0) - parent.widgets.destroy(z_order_value); - - parent.widget_set.remove(this,junk); - - // now unregister this drawable from all the events it has registered for. - if (events & MOUSE_MOVE) - parent.mouse_move.remove(this,junk); - if (events & MOUSE_CLICK) - parent.mouse_click.remove(this,junk); - if (events & MOUSE_WHEEL) - parent.mouse_wheel.remove(this,junk); - if (events & WINDOW_RESIZED) - parent.window_resized.remove(this,junk); - if (events & KEYBOARD_EVENTS) - parent.keyboard.remove(this,junk); - if (events & FOCUS_EVENTS) - parent.focus.remove(this,junk); - if (events & WINDOW_MOVED) - parent.window_moved.remove(this,junk); - if (events & STRING_PUT) - parent.string_put.remove(this,junk); - } - } - -// ---------------------------------------------------------------------------------------- - - drawable:: - ~drawable ( - ) - { - DLIB_ASSERT(events_are_enabled() == false, - "\tdrawable::~drawable()" - << "\n\tYou must disable events for drawable objects in their destructor by calling disable_events()." - << "\n\tthis: " << this - ); - disable_events(); - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_DRAWABLe_CPP_ - diff --git a/lib/3rdParty/dlib/include/dlib/gui_widgets/drawable.h b/lib/3rdParty/dlib/include/dlib/gui_widgets/drawable.h index 2327b067..a270b53c 100644 --- a/lib/3rdParty/dlib/include/dlib/gui_widgets/drawable.h +++ b/lib/3rdParty/dlib/include/dlib/gui_widgets/drawable.h @@ -4,6 +4,8 @@ #ifndef DLIB_DRAWABLe_ #define DLIB_DRAWABLe_ +#include + #include "drawable_abstract.h" #include "../gui_core.h" #include "../set.h" @@ -33,7 +35,7 @@ namespace dlib - event_id == 1 CONVENTION - - bg_color == backgroud_color() + - bg_color == background_color() - widgets == this binary search tree contains every drawable that is in this window. It is a mapping of each drawable's z-order to a pointer @@ -344,7 +346,7 @@ namespace dlib } virtual void set_main_font ( - const shared_ptr_thread_safe& f + const std::shared_ptr& f ) { auto_mutex M(m); @@ -352,7 +354,7 @@ namespace dlib parent.invalidate_rectangle(rect); } - const shared_ptr_thread_safe main_font ( + const std::shared_ptr main_font ( ) const { auto_mutex M(m); @@ -420,7 +422,7 @@ namespace dlib bool enabled; const long& lastx; const long& lasty; - shared_ptr_thread_safe mfont; + std::shared_ptr mfont; void enable_events ( diff --git a/lib/3rdParty/dlib/include/dlib/gui_widgets/fonts.cpp b/lib/3rdParty/dlib/include/dlib/gui_widgets/fonts.cpp deleted file mode 100644 index ab2fad7f..00000000 --- a/lib/3rdParty/dlib/include/dlib/gui_widgets/fonts.cpp +++ /dev/null @@ -1,671 +0,0 @@ -// Copyright (C) 2005 Davis E. King (davis@dlib.net), and Nils Labugt, Keita Mochizuki -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_FONTs_CPP_ -#define DLIB_FONTs_CPP_ - -#include "fonts.h" - -#include "../serialize.h" -#include -#include "../base64.h" -#include "../compress_stream.h" -#include -#include "../tokenizer.h" -#include "nativefont.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - const std::string get_decoded_string_with_default_font_data() - { - dlib::base64::kernel_1a base64_coder; - dlib::compress_stream::kernel_1ea compressor; - std::ostringstream sout; - std::istringstream sin; - - /* - SOURCE BDF FILE (helvR12.bdf) COMMENTS - COMMENT $XConsortium: helvR12.bdf,v 1.15 95/01/26 18:02:58 gildea Exp $ - COMMENT $Id: helvR12.bdf,v 1.26 2004-11-28 20:08:46+00 mgk25 Rel $ - COMMENT - COMMENT + - COMMENT Copyright 1984-1989, 1994 Adobe Systems Incorporated. - COMMENT Copyright 1988, 1994 Digital Equipment Corporation. - COMMENT - COMMENT Adobe is a trademark of Adobe Systems Incorporated which may be - COMMENT registered in certain jurisdictions. - COMMENT Permission to use these trademarks is hereby granted only in - COMMENT association with the images described in this file. - COMMENT - COMMENT Permission to use, copy, modify, distribute and sell this software - COMMENT and its documentation for any purpose and without fee is hereby - COMMENT granted, provided that the above copyright notices appear in all - COMMENT copies and that both those copyright notices and this permission - COMMENT notice appear in supporting documentation, and that the names of - COMMENT Adobe Systems and Digital Equipment Corporation not be used in - COMMENT advertising or publicity pertaining to distribution of the software - COMMENT without specific, written prior permission. Adobe Systems and - COMMENT Digital Equipment Corporation make no representations about the - COMMENT suitability of this software for any purpose. It is provided "as - COMMENT is" without express or implied warranty. - COMMENT - - */ - - // The base64 encoded data we want to decode and return. - sout << "AXF+zOQzCgGitrKiOCGEL4hlIv1ZenWJyjMQ4rJ6f/oPMeHqsZn+8XnpehwFQTz3dtUGlZRAUoOa"; - sout << "uVo8UiplcFxuK69A+94rpMCMAyEeeOwZ/tRzkX4eKuU3L4xtsJDknMiYUNKaMrYimb1QJ0E+SRqQ"; - sout << "wATrMTecYNZvJJm02WibiwE4cJ5scvkHNl4KJT5QfdwRdGopTyUVdZvRvtbTLLjsJP0fQEQLqemf"; - sout << "qPE4kDD79ehrBIwLO1Y6TzxtrrIoQR57zlwTUyLenqRtSN3VLtjWYd82cehRIlTLtuxBg2s+zZVq"; - sout << "jNlNnYTSM+Swy06qnQgg+Dt0lhtlB9shR1OAlcfCtTW6HKoBk/FGeDmjTGW4bNCGv7RjgM6TlLDg"; - sout << "ZYSSA6ZCCAKBgE++U32gLHCCiVkPTkkp9P6ioR+e3SSKRNm9p5MHf+ZQ3LJkW8KFJ/K9gKT1yvyv"; - sout << "F99pAvOOq16tHRFvzBs+xZj/mUpH0lGIS7kLWr9oP2KuccVrz25aJn3kDruwTYoD+CYlOqtPO0Mv"; - sout << "dEI0LUR0Ykp1M2rWo76fJ/fpzHjV7737hjkNPJ13nO72RMDr4R5V3uG7Dw7Ng+vGX3WgJZ4wh1JX"; - sout << "pl2VMqC5JXccctzvnQvnuvBvRm7THgwQUgMKKT3WK6afUUVlJy8DHKuU4k1ibfVMxAmrwKdTUX2w"; - sout << "cje3A05Qji3aop65qEdwgI5O17HIVoRQOG/na+XRMowOfUvI4H8Z4+JGACfRrQctgYDAM9eJzm8i"; - sout << "PibyutmJfZBGg0a3oC75S5R9lTxEjPocnEyJRYNnmVnVAmKKbTbTsznuaD+D1XhPdr2t3A4bRTsp"; - sout << "toKKtlFnd9YGwLWwONDwLnoQ/IXwyF7txrRHNSVToh772U0Aih/yn5vnmcMF750eiMzRAgXu5sbR"; - sout << "VXEOVCiLgVevN5umkvjZt1eGTSSzDMrIvnv4nyOfaFsD+I76wQfgLqd71rheozGtjNc0AOTx4Ggc"; - sout << "eUSFHTDAVfTExBzckurtyuIAqF986a0JLHCtsDpBa2wWNuiQYOH3/LX1zkdU2hdamhBW774bpEwr"; - sout << "dguMxxOeDGOBgIlM5gxXGYXSf5IN3fUAEPfOPRxB7T+tpjFnWd7cg+JMabci3zhJ9ANaYT7HGeTX"; - sout << "bulKnGHjYrR1BxdK3YeliogQRU4ytmxlyL5zlNFU/759mA8XSfIPMEZn9Vxkb00q1htF7REiDcr3"; - sout << "kW1rtPAc7VQNEhT54vK/YF6rMvjO7kBZ/vLYo7E8e8hDKEnY8ucrC3KGmeo31Gei74BBcEbvJBd3"; - sout << "/YAaIKgXWwU2wSUw9wLq2RwGwyguvKBx0J/gn27tjcVAHorRBwxzPpk8r+YPyN+SifSzEL7LEy1G"; - sout << "lPHxmXTrcqnH9qraeAqXJUJvU8SJJpf/tmsAE+XSKD/kpVBnT5qXsJ1SRFS7MtfPjE1j/NYbaQBI"; - sout << "bOrh81zaYCEJR0IKHWCIsu/MC3zKXfkxFgQ9XpYAuWjSSK64YpgkxSMe8VG8yYvigOw2ODg/z4FU"; - sout << "+HpnEKF/M/mKfLKK1i/8BV7xcYVHrhEww1QznoFklJs/pEg3Kd5PE1lRii6hvTn6McVAkw+YbH9q"; - sout << "/sg4gFIAvai64hMcZ1oIZYppj3ZN6KMdyhK5s4++ZS/YOV2nNhW73ovivyi2Tjg7lxjJJtsYrLKb"; - sout << "zIN1slOICKYwBq42TFBcFXaZ6rf0Czd09tL+q6A1Ztgr3BNuhCenjhWN5ji0LccGYZo6bLTggRG/"; - sout << "Uz6K3CBBU/byLs79c5qCohrr7rlpDSdbuR+aJgNiWoU6T0i2Tvua6h51LcWEHy5P2n146/Ae2di4"; - sout << "eh20WQvclrsgm1oFTGD0Oe85GKOTA7vvwKmLBc1wwA0foTuxzVgj0TMTFBiYLTLG4ujUyBYy1N6e"; - sout << "H8EKi8H+ZAlqezrjABO3BQr33ewdZL5IeJ4w7gdGUDA6+P+7cODcBW50X9++6YTnKctuEw6aXBpy"; - sout << "GgcMfPE61G8YKBbFGFic3TVvGCLvre1iURv+F+hU4/ee6ILuPnpYnSXX2iCIK/kmkBse8805d4Qe"; - sout << "DG/8rBW9ojvAgc0jX7CatPEMHGkcz+KIZoKMI7XXK4PJpGQUdq6EdIhJC4koXEynjwwXMeC+jJqH"; - sout << "agwrlDNssq/8AA=="; - - - - // Put the data into the istream sin - sin.str(sout.str()); - sout.str(""); - - // Decode the base64 text into its compressed binary form - base64_coder.decode(sin,sout); - sin.clear(); - sin.str(sout.str()); - sout.str(""); - - // Decompress the data into its original form - compressor.decompress(sin,sout); - - // Return the decoded and decompressed data - return sout.str(); - } - - - default_font:: - default_font ( - ) - { - using namespace std; - l = new letter[256]; - - try - { - istringstream sin(get_decoded_string_with_default_font_data()); - - for (int i = 0; i < 256; ++i) - { - deserialize(l[i],sin); - } - - } - catch (...) - { - delete [] l; - throw; - } - } - -// ---------------------------------------------------------------------------------------- - - void serialize ( - const letter& item, - std::ostream& out - ) - { - try - { - serialize(item.w,out); - serialize(item.count,out); - - for (unsigned long i = 0; i < item.count; ++i) - { - serialize(item.points[i].x,out); - serialize(item.points[i].y,out); - } - } - catch (serialization_error e) - { - throw serialization_error(e.info + "\n while serializing object of type letter"); - } - } - - void deserialize ( - letter& item, - std::istream& in - ) - { - try - { - if (item.points) - delete [] item.points; - - deserialize(item.w,in); - deserialize(item.count,in); - - if (item.count > 0) - item.points = new letter::point[item.count]; - else - item.points = 0; - - for (unsigned long i = 0; i < item.count; ++i) - { - deserialize(item.points[i].x,in); - deserialize(item.points[i].y,in); - } - } - catch (serialization_error e) - { - item.w = 0; - item.count = 0; - item.points = 0; - throw serialization_error(e.info + "\n while deserializing object of type letter"); - } - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - namespace bdf_font_helpers - { - class bdf_parser - { - public: - bdf_parser( std::istream& in ) : in_( in ) - { - std::string str_tmp; - int int_tmp; - - str_tmp = "STARTFONT"; int_tmp = STARTFONT; keyword_map.add( str_tmp, int_tmp ); - str_tmp = "FONTBOUNDINGBOX";int_tmp = FONTBOUNDINGBOX; keyword_map.add( str_tmp, int_tmp ); - str_tmp = "DWIDTH"; int_tmp = DWIDTH; keyword_map.add( str_tmp, int_tmp ); - str_tmp = "CHARS"; int_tmp = CHARS; keyword_map.add( str_tmp, int_tmp ); - str_tmp = "STARTCHAR"; int_tmp = STARTCHAR; keyword_map.add( str_tmp, int_tmp ); - str_tmp = "ENCODING"; int_tmp = ENCODING; keyword_map.add( str_tmp, int_tmp ); - str_tmp = "BBX"; int_tmp = BBX; keyword_map.add( str_tmp, int_tmp ); - str_tmp = "BITMAP"; int_tmp = BITMAP; keyword_map.add( str_tmp, int_tmp ); - str_tmp = "ENDCHAR"; int_tmp = ENDCHAR; keyword_map.add( str_tmp, int_tmp ); - str_tmp = "ENDFONT"; int_tmp = ENDFONT; keyword_map.add( str_tmp, int_tmp ); - str_tmp = "DEFAULT_CHAR"; int_tmp = DEFAULT_CHAR; keyword_map.add( str_tmp, int_tmp ); - - tokzr.set_identifier_token( tokzr.uppercase_letters(), tokzr.uppercase_letters() + "_" ); - tokzr.set_stream( in ); - - } - - enum bdf_enums - { - NO_KEYWORD = 0, - STARTFONT = 1, - FONTBOUNDINGBOX = 2, - DWIDTH = 4, - DEFAULT_CHAR = 8, - CHARS = 16, - STARTCHAR = 32, - ENCODING = 64, - BBX = 128, - BITMAP = 256, - ENDCHAR = 512, - ENDFONT = 1024 - - }; - struct header_info - { - int FBBx, FBBy, Xoff, Yoff; - int dwx0, dwy0; - bool has_global_dw; - long default_char; - }; - struct char_info - { - int dwx0, dwy0; - int BBw, BBh, BBxoff0x, BByoff0y; - array2d bitmap; - bool has_dw; - }; - bool parse_header( header_info& info ) - { - if ( required_keyword( STARTFONT ) == false ) - return false; // parse_error: required keyword missing - info.has_global_dw = false; - int find = FONTBOUNDINGBOX | DWIDTH | DEFAULT_CHAR; - int stop = CHARS | STARTCHAR | ENCODING | BBX | BITMAP | ENDCHAR | ENDFONT; - int res; - while ( 1 ) - { - res = find_keywords( find | stop ); - if ( res & FONTBOUNDINGBOX ) - { - in_ >> info.FBBx >> info.FBBy >> info.Xoff >> info.Yoff; - if ( in_.fail() ) - return false; // parse_error - find &= ~FONTBOUNDINGBOX; - continue; - } - if ( res & DWIDTH ) - { - in_ >> info.dwx0 >> info.dwy0; - if ( in_.fail() ) - return false; // parse_error - find &= ~DWIDTH; - info.has_global_dw = true; - continue; - } - if ( res & DEFAULT_CHAR ) - { - in_ >> info.default_char; - if ( in_.fail() ) - return false; // parse_error - find &= ~DEFAULT_CHAR; - continue; - } - if ( res & NO_KEYWORD ) - return false; // parse_error: unexpected EOF - break; - } - if ( res != CHARS || ( find & FONTBOUNDINGBOX ) ) - return false; // parse_error: required keyword missing or unexpeced keyword - return true; - } - int parse_glyph( char_info& info, unichar& enc ) - { - info.has_dw = false; - int e; - int res; - while ( 1 ) - { - res = find_keywords( ENCODING ); - if ( res != ENCODING ) - return 0; // no more glyphs - in_ >> e; - if ( in_.fail() ) - return -1; // parse_error - if ( e >= static_cast(enc) ) - break; - } - int find = BBX | DWIDTH; - int stop = STARTCHAR | ENCODING | BITMAP | ENDCHAR | ENDFONT; - while ( 1 ) - { - res = find_keywords( find | stop ); - if ( res & BBX ) - { - in_ >> info.BBw >> info.BBh >> info.BBxoff0x >> info.BByoff0y; - if ( in_.fail() ) - return -1; // parse_error - find &= ~BBX; - continue; - } - if ( res & DWIDTH ) - { - in_ >> info.dwx0 >> info.dwy0; - if ( in_.fail() ) - return -1; // parse_error - find &= ~DWIDTH; - info.has_dw = true; - continue; - } - if ( res & NO_KEYWORD ) - return -1; // parse_error: unexpected EOF - break; - } - if ( res != BITMAP || ( find != NO_KEYWORD ) ) - return -1; // parse_error: required keyword missing or unexpeced keyword - unsigned h = info.BBh; - unsigned w = ( info.BBw + 7 ) / 8 * 2; - info.bitmap.set_size( h, w ); - for ( unsigned r = 0;r < h;r++ ) - { - trim(); - std::string str = ""; - extract_hex(str); - if(str.size() < w) - return -1; // parse_error - for ( unsigned c = 0;c < w;c++ ) - info.bitmap[r][c] = str[c]; - } - if ( in_.fail() ) - return -1; // parse_error - if ( required_keyword( ENDCHAR ) == false ) - return -1; // parse_error: required keyword missing - enc = e; - return 1; - } - private: - map::kernel_1a_c keyword_map; - tokenizer::kernel_1a_c tokzr; - std::istream& in_; - void extract_hex(std::string& str) - { - int type; - std::string token; - while ( 1 ) - { - type = tokzr.peek_type(); - if ( type == tokenizer::kernel_1a_c::IDENTIFIER || type == tokenizer::kernel_1a_c::NUMBER ) - { - tokzr.get_token( type, token ); - str += token; - continue; - } - break; - } - } - void trim() - { - int type; - std::string token; - while ( 1 ) - { - type = tokzr.peek_type(); - if ( type == tokenizer::kernel_1a_c::WHITE_SPACE || type == tokenizer::kernel_1a_c::END_OF_LINE ) - { - tokzr.get_token( type, token ); - continue; - } - break; - } - } - bool required_keyword( int kw ) - { - int type; - std::string token; - while ( 1 ) - { - tokzr.get_token( type, token ); - if ( type == tokenizer::kernel_1a_c::WHITE_SPACE || type == tokenizer::kernel_1a_c::END_OF_LINE ) - continue; - if ( type != tokenizer::kernel_1a_c::IDENTIFIER || keyword_map.is_in_domain( token ) == false || ( keyword_map[token] & kw ) == 0 ) - return false; - break; - } - return true; - } - int find_keywords( int find ) - { - int type; - std::string token; - while ( 1 ) - { - tokzr.get_token( type, token ); - if ( type == tokenizer::kernel_1a_c::END_OF_FILE ) - return NO_KEYWORD; - if ( type == tokenizer::kernel_1a_c::IDENTIFIER && keyword_map.is_in_domain( token ) == true ) - { - int kw = keyword_map[token]; - if ( kw & find ) - return kw; - } - } - return true; - } - - }; - - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// bdf_font functions -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - bdf_font::bdf_font( - long default_char_ - ) : - default_char(0), - is_initialized( false ), - right_overflow_( 0 ), - has_global_width( false ), - specified_default_char( default_char_ ) - { - // make sure gl contains at least one letter - gl.resize(1); - } - -// ---------------------------------------------------------------------------------------- - - void bdf_font::adjust_metrics( - ) - { - if ( is_initialized == false ) - return; - // set starting values for fbb - if ( gl[default_char].num_of_points() > 0 ) - { - letter& g = gl[default_char]; - fbb.set_top( g[0].y ); - fbb.set_bottom( g[0].y ); - fbb.set_left( g[0].x ); - fbb.set_right( g[0].x ); - } - else - { - // ok, the default char was a space - // let's just choose some safe arbitrary values then... - fbb.set_top( 10000 ); - fbb.set_bottom( -10000 ); - fbb.set_left( 10000 ); - fbb.set_right( -10000 ); - } - right_overflow_ = 0; - for ( unichar n = 0; n < gl.size(); n++ ) - { - letter& g = gl[n]; - unsigned short nr_pts = g.num_of_points(); - for ( unsigned short k = 0;k < nr_pts;k++ ) - { - fbb.set_top( std::min( fbb.top(), (long)g[k].y ) ); - fbb.set_left( std::min( fbb.left(), (long)g[k].x ) ); - fbb.set_bottom( std::max( fbb.bottom(), (long)g[k].y ) ); - fbb.set_right( std::max( fbb.right(), (long)g[k].x ) ); - right_overflow_ = std::max( right_overflow_, (unsigned long)(g[k].x - g.width()) ); // superfluous? - } - } - } - -// ---------------------------------------------------------------------------------------- - - long bdf_font:: - read_bdf_file( - std::istream& in, - unichar max_enc, - unichar min_enc - ) - { - using namespace bdf_font_helpers; - - bdf_parser parser( in ); - bdf_parser::header_info hinfo; - bdf_parser::char_info cinfo; - - gl.resize(max_enc+1); - hinfo.default_char = - 1; - if ( is_initialized == false || static_cast(in.tellg()) == std::ios::beg ) - { - if ( parser.parse_header( hinfo ) == false ) - return 0; // parse_error: invalid or missing header - } - else - { - // not start of file, so use values from previous read. - hinfo.has_global_dw = has_global_width; - hinfo.dwx0 = global_width; - } - int res; - unichar nr_letters_added = 0; - unsigned width; - for ( unichar n = min_enc; n <= max_enc; n++ ) - { - if ( in.eof() ) - break; - long pos = in.tellg(); - res = parser.parse_glyph( cinfo, n ); - if ( res < 0 ) - return 0; // parse_error - if ( res == 0 ) - continue; - if ( n > max_enc ) - { - in.seekg( pos ); - break; - } - - if ( cinfo.has_dw == false ) - { - if ( hinfo.has_global_dw == false ) - return 0; // neither width info for the glyph, nor for the font as a whole (monospace). - width = hinfo.dwx0; - } - else - width = cinfo.dwx0; - - - if ( bitmap_to_letter( cinfo.bitmap, n, width, cinfo.BBxoff0x, cinfo.BByoff0y ) == false ) - return 0; - nr_letters_added++; - - if ( is_initialized == false ) - { - // Bonding rectangle for the font. - fbb.set_top( -( hinfo.Yoff + hinfo.FBBy - 1 ) ); - fbb.set_bottom( -hinfo.Yoff ); - fbb.set_left( hinfo.Xoff ); - fbb.set_right( hinfo.Xoff + hinfo.FBBx - 1 ); - // We need to compute this after all the glyphs are loaded. - right_overflow_ = 0; - // set this to something valid now, just in case. - default_char = n; - // Save any global width in case we later read from the same file. - has_global_width = hinfo.has_global_dw; - if ( has_global_width ) - global_width = hinfo.dwx0; - // dont override value specified in the constructor with value specified in the file - if ( specified_default_char < 0 && hinfo.default_char >= 0 ) - specified_default_char = hinfo.default_char; - - is_initialized = true; - } - } - if ( is_initialized == false ) - return 0; // Not a single glyph was found within the specified range. - - if ( specified_default_char >= 0 ) - default_char = specified_default_char; - // no default char specified, try find something sane. - else - default_char = 0; - - return nr_letters_added; - } - -// ---------------------------------------------------------------------------------------- - - bool bdf_font:: - bitmap_to_letter( - array2d& bitmap, - unichar enc, - unsigned long width, - int x_offset, - int y_offset - ) - { - unsigned nr_points = 0; - bitmap.reset(); - while ( bitmap.move_next() ) - { - unsigned char ch = bitmap.element(); - if ( ch > '9' ) - ch -= 'A' - '9' - 1; - ch -= '0'; - if ( ch > 0xF ) - return false; // parse error: invalid hex digit - bitmap.element() = ch; - if ( ch & 8 ) - nr_points++; - if ( ch & 4 ) - nr_points++; - if ( ch & 2 ) - nr_points++; - if ( ch & 1 ) - nr_points++; - } - - letter( width, nr_points ).swap(gl[enc]); - - unsigned index = 0; - for ( int r = 0;r < bitmap.nr();r++ ) - { - for ( int c = 0;c < bitmap.nc();c++ ) - { - int x = x_offset + c * 4; - int y = -( y_offset + bitmap.nr() - r - 1 ); - char ch = bitmap[r][c]; - letter& glyph = gl[enc]; - if ( ch & 8 ) - { - glyph[index] = letter::point( x, y ); - right_overflow_ = std::max( right_overflow_, x - width ); - index++; - } - if ( ch & 4 ) - { - glyph[index] = letter::point( x + 1, y ); - right_overflow_ = std::max( right_overflow_, x + 1 - width ); - index++; - } - if ( ch & 2 ) - { - glyph[index] = letter::point( x + 2, y ); - right_overflow_ = std::max( right_overflow_, x + 2 - width ); - index++; - } - if ( ch & 1 ) - { - glyph[index] = letter::point( x + 3, y ); - right_overflow_ = std::max( right_overflow_, x + 3 - width ); - index++; - } - } - } - return true; - } - -// ---------------------------------------------------------------------------------------- - - const shared_ptr_thread_safe get_native_font ( - ) - { - return nativefont::native_font::get_font(); - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_FONTs_CPP_ - diff --git a/lib/3rdParty/dlib/include/dlib/gui_widgets/fonts.h b/lib/3rdParty/dlib/include/dlib/gui_widgets/fonts.h index f8123934..5d3181aa 100644 --- a/lib/3rdParty/dlib/include/dlib/gui_widgets/fonts.h +++ b/lib/3rdParty/dlib/include/dlib/gui_widgets/fonts.h @@ -4,16 +4,17 @@ #ifndef DLIB_FONTs_ #define DLIB_FONTs_ +#include +#include + #include "fonts_abstract.h" #include "../gui_core.h" -#include #include "../algs.h" #include "../serialize.h" #include "../unicode.h" #include "../array.h" #include "../array2d.h" #include "../threads.h" -#include "../smart_pointers_thread_safe.h" namespace dlib { @@ -483,7 +484,7 @@ namespace dlib // ---------------------------------------------------------------------------------------- - const shared_ptr_thread_safe get_native_font (); + const std::shared_ptr get_native_font (); // ---------------------------------------------------------------------------------------- @@ -500,11 +501,11 @@ namespace dlib public: - static const shared_ptr_thread_safe& get_font ( + static const std::shared_ptr& get_font ( ) { static mutex m; - static shared_ptr_thread_safe f; + static std::shared_ptr f; auto_mutex M(m); if (f.get() == 0) f.reset(new default_font); diff --git a/lib/3rdParty/dlib/include/dlib/gui_widgets/nativefont.h b/lib/3rdParty/dlib/include/dlib/gui_widgets/nativefont.h index 3ca5f2b2..2de0edfa 100644 --- a/lib/3rdParty/dlib/include/dlib/gui_widgets/nativefont.h +++ b/lib/3rdParty/dlib/include/dlib/gui_widgets/nativefont.h @@ -7,10 +7,10 @@ #include "../gui_widgets.h" #include "../unicode.h" -#include "../smart_pointers_thread_safe.h" #include "../uintn.h" #include +#include #include #include @@ -546,10 +546,10 @@ namespace nativefont return (*this)[ch].width() > 0; } - static const dlib::shared_ptr_thread_safe& get_font ( + static const std::shared_ptr& get_font ( ) { - static dlib::shared_ptr_thread_safe f(new native_font); + static std::shared_ptr f(new native_font); return f; } diff --git a/lib/3rdParty/dlib/include/dlib/gui_widgets/style.cpp b/lib/3rdParty/dlib/include/dlib/gui_widgets/style.cpp deleted file mode 100644 index a3d22d10..00000000 --- a/lib/3rdParty/dlib/include/dlib/gui_widgets/style.cpp +++ /dev/null @@ -1,998 +0,0 @@ -// Copyright (C) 2008 Davis E. King (davis@dlib.net), and Nils Labugt -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_WIDGETs_STYLE_CPP_ -#define DLIB_WIDGETs_STYLE_CPP_ - -#include "style.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // button style stuff -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void button_style_default::draw_button ( - const canvas& c, - const rectangle& rect, - const bool enabled, - const font& mfont, - const long , - const long , - const ustring& name, - const bool is_depressed - ) const - { - rectangle area = rect.intersect(c); - if (area.is_empty()) - return; - - fill_rect(c,rect,rgb_pixel(212,208,200)); - - unsigned char red, green, blue; - if (enabled) - { - red = 0; - green = 0; - blue = 0; - } - else - { - red = 128; - green = 128; - blue = 128; - } - - // compute the name length if it hasn't already been computed - if (name_width == 0) - { - unsigned long height; - mfont.compute_size(name,name_width,height); - } - - // figure out where the name string should appear - rectangle name_rect; - const unsigned long width = name_width; - const unsigned long height = mfont.height(); - name_rect.set_left((rect.right() + rect.left() - width)/2); - name_rect.set_top((rect.bottom() + rect.top() - height)/2 + 1); - name_rect.set_right(name_rect.left()+width-1); - name_rect.set_bottom(name_rect.top()+height); - - - if (is_depressed) - { - name_rect.set_left(name_rect.left()+1); - name_rect.set_right(name_rect.right()+1); - name_rect.set_top(name_rect.top()+1); - name_rect.set_bottom(name_rect.bottom()+1); - - mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue)); - - draw_button_down(c,rect); - } - else - { - mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue)); - - // now draw the edge of the button - draw_button_up(c,rect); - } - } - -// ---------------------------------------------------------------------------------------- - - rectangle button_style_default:: - get_min_size ( - const ustring& name, - const font& mfont - ) const - { - - unsigned long width; - unsigned long height; - mfont.compute_size(name,width,height); - name_width = width; - - return rectangle(width+2*padding, height+2*padding); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void button_style_toolbar1::draw_button ( - const canvas& c, - const rectangle& rect, - const bool enabled, - const font& mfont, - const long lastx, - const long lasty, - const ustring& name, - const bool is_depressed - ) const - { - rectangle area = rect.intersect(c); - if (area.is_empty()) - return; - - const long radius = 4; - - unsigned char red, green, blue; - if (enabled) - { - red = 0; - green = 0; - blue = 0; - - long d = 0; - if (rect.contains(lastx,lasty)) - d = -70; - - if (is_depressed) - d = 20; - - if (d != 0) - { - rectangle temp(rect); - temp.left()--; temp.top()--; temp.right()++; temp.bottom()++; - draw_rounded_rectangle(c, temp, radius, rgb_alpha_pixel(255,255,0,120)); - temp.left()--; temp.top()--; temp.right()++; temp.bottom()++; - draw_rounded_rectangle(c, temp, radius, rgb_alpha_pixel(255,255,0,40)); - } - - fill_gradient_rounded(c,rect,radius,rgb_alpha_pixel(255, 255, 255,120-d), - rgb_alpha_pixel(255, 255, 255,0)); - draw_rounded_rectangle(c,rect,radius, rgb_alpha_pixel(30,30,30,200)); - } - else - { - red = 128; - green = 128; - blue = 128; - draw_rounded_rectangle(c,rect,radius, rgb_alpha_pixel(red,green,blue,210)); - } - - - // compute the name length if it hasn't already been computed - if (name_width == 0) - { - unsigned long height; - mfont.compute_size(name,name_width,height); - } - - // figure out where the name string should appear - rectangle name_rect; - const unsigned long width = name_width; - const unsigned long height = mfont.height(); - name_rect.set_left((rect.right() + rect.left() - width)/2); - name_rect.set_top((rect.bottom() + rect.top() - height)/2 + 1); - name_rect.set_right(name_rect.left()+width-1); - name_rect.set_bottom(name_rect.top()+height); - - - if (is_depressed) - { - name_rect.set_left(name_rect.left()+1); - name_rect.set_right(name_rect.right()+1); - name_rect.set_top(name_rect.top()+1); - name_rect.set_bottom(name_rect.bottom()+1); - - mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue)); - - } - else - { - mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue)); - } - } - -// ---------------------------------------------------------------------------------------- - - rectangle button_style_toolbar1:: - get_min_size ( - const ustring& name, - const font& mfont - ) const - { - - unsigned long width; - unsigned long height; - mfont.compute_size(name,width,height); - name_width = width; - - return rectangle(width+2*padding, height+2*padding); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void button_style_toolbar_icon1::draw_button ( - const canvas& c, - const rectangle& rect, - const bool enabled, - const font& , - const long lastx, - const long lasty, - const ustring& , - const bool is_depressed - ) const - { - rectangle area = rect.intersect(c); - if (area.is_empty()) - return; - - const long radius = padding; - - if (enabled) - { - if (rect.contains(lastx,lasty)) - { - if (is_depressed) - { - fill_gradient_rounded(c,rect,radius,rgb_alpha_pixel(100,100,200,150), - rgb_alpha_pixel(50,50,100,100)); - draw_rounded_rectangle(c,rect,radius, rgb_alpha_pixel(150,150,30,200)); - } - else - { - fill_gradient_rounded(c,rect,radius,rgb_alpha_pixel(150,150,250,130), - rgb_alpha_pixel(100,100,150,90)); - draw_rounded_rectangle(c,rect,radius, rgb_alpha_pixel(150,150,30,200)); - } - } - - if (is_depressed) - { - rectangle img_rect(translate_rect(centered_rect(rect,img_mouseover.nc(),img_mouseover.nr()),1,1)); - point p(img_rect.left(),img_rect.top()); - draw_image(c,p,img_mouseover); - } - else - { - rectangle img_rect(centered_rect(rect,img_normal.nc(),img_normal.nr())); - point p(img_rect.left(),img_rect.top()); - if (rect.contains(lastx,lasty)) - draw_image(c,p,img_mouseover); - else - draw_image(c,p,img_normal); - } - - } - else - { - rectangle img_rect(centered_rect(rect,img_normal.nc(),img_normal.nr())); - point p(img_rect.left(),img_rect.top()); - draw_image(c,p,img_disabled); - } - } - -// ---------------------------------------------------------------------------------------- - - rectangle button_style_toolbar_icon1:: - get_min_size ( - const ustring& , - const font& - ) const - { - return rectangle(img_normal.nc()+2*padding, img_normal.nr()+2*padding); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void button_style_arrow:: - draw_button ( - const canvas& c, - const rectangle& rect, - const bool enabled, - const font& , - const long , - const long , - const ustring& , - const bool is_depressed - ) const - { - rectangle area = rect.intersect(c); - if (area.is_empty()) - return; - - fill_rect(c,rect,rgb_pixel(212,208,200)); - - const long height = rect.height(); - const long width = rect.width(); - - const long smallest = (width < height) ? width : height; - - const long rows = (smallest+3)/4; - const long start = rows + rows/2-1; - long dep; - - long tip_x = 0; - long tip_y = 0; - long wy = 0; - long hy = 0; - long wx = 0; - long hx = 0; - - if (is_depressed) - { - dep = 0; - - // draw the button's border - draw_button_down(c,rect); - } - else - { - dep = -1; - - // draw the button's border - draw_button_up(c,rect); - } - - - switch (dir) - { - case UP: - tip_x = width/2 + rect.left() + dep; - tip_y = (height - start)/2 + rect.top() + dep + 1; - wy = 0; - hy = 1; - wx = 1; - hx = 0; - break; - - case DOWN: - tip_x = width/2 + rect.left() + dep; - tip_y = rect.bottom() - (height - start)/2 + dep; - wy = 0; - hy = -1; - wx = 1; - hx = 0; - break; - - case LEFT: - tip_x = rect.left() + (width - start)/2 + dep + 1; - tip_y = height/2 + rect.top() + dep; - wy = 1; - hy = 0; - wx = 0; - hx = 1; - break; - - case RIGHT: - tip_x = rect.right() - (width - start)/2 + dep; - tip_y = height/2 + rect.top() + dep; - wy = 1; - hy = 0; - wx = 0; - hx = -1; - break; - } - - - rgb_pixel color; - if (enabled) - { - color.red = 0; - color.green = 0; - color.blue = 0; - } - else - { - color.red = 128; - color.green = 128; - color.blue = 128; - } - - - - for (long i = 0; i < rows; ++i) - { - draw_line(c,point(tip_x + wx*i + hx*i, tip_y + wy*i + hy*i), - point(tip_x + wx*i*-1 + hx*i, tip_y + wy*i*-1 + hy*i), - color); - } - - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // toggle button style stuff -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void toggle_button_style_default::draw_toggle_button ( - const canvas& c, - const rectangle& rect, - const bool enabled, - const font& mfont, - const long , - const long , - const ustring& name, - const bool is_depressed, - const bool is_checked - ) const - { - rectangle area = rect.intersect(c); - if (area.is_empty()) - return; - - fill_rect(c,rect,rgb_pixel(212,208,200)); - - unsigned char red, green, blue; - if (enabled) - { - red = 0; - green = 0; - blue = 0; - } - else - { - red = 128; - green = 128; - blue = 128; - } - - // compute the name length if it hasn't already been computed - if (name_width == 0) - { - unsigned long height; - mfont.compute_size(name,name_width,height); - } - - // figure out where the name string should appear - rectangle name_rect; - const unsigned long width = name_width; - const unsigned long height = mfont.height(); - name_rect.set_left((rect.right() + rect.left() - width)/2); - name_rect.set_top((rect.bottom() + rect.top() - height)/2 + 1); - name_rect.set_right(name_rect.left()+width-1); - name_rect.set_bottom(name_rect.top()+height); - - long d = 0; - if (is_checked) - d = 1; - - if (is_depressed) - d = 2; - - name_rect.set_left(name_rect.left()+d); - name_rect.set_right(name_rect.right()+d); - name_rect.set_top(name_rect.top()+d); - name_rect.set_bottom(name_rect.bottom()+d); - - mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue)); - - // now draw the edge of the button - if (is_checked || is_depressed) - draw_button_down(c,rect); - else - draw_button_up(c,rect); - } - -// ---------------------------------------------------------------------------------------- - - rectangle toggle_button_style_default:: - get_min_size ( - const ustring& name, - const font& mfont - ) const - { - - unsigned long width; - unsigned long height; - mfont.compute_size(name,width,height); - name_width = width; - - return rectangle(width+2*padding, height+2*padding); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void toggle_button_style_check_box::draw_toggle_button ( - const canvas& c, - const rectangle& rect, - const bool enabled, - const font& mfont, - const long , - const long , - const ustring& name, - const bool is_depressed, - const bool is_checked - ) const - { - rectangle area = rect.intersect(c); - if (area.is_empty()) - return; - - - rgb_pixel color; - if (enabled) - { - color.red = 0; - color.green = 0; - color.blue = 0; - } - else - { - color.red = 128; - color.green = 128; - color.blue = 128; - } - - - // figure out where the name string should appear - rectangle name_rect, box_rect; - unsigned long padding = 0; - if (mfont.height() < 13) - padding = (rect.height() - mfont.height())/2; - - name_rect = rect; - name_rect.set_left(rect.left() + 17-1); - name_rect.set_top(rect.top() + padding); - name_rect.set_bottom(rect.bottom() - padding); - - box_rect = rect; - box_rect.set_right(rect.left() + 12); - box_rect.set_bottom(rect.top() + 12); - - mfont.draw_string(c,name_rect,name,color); - - if (enabled && is_depressed == false) - fill_rect(c, box_rect,rgb_pixel(255,255,255)); - else - fill_rect(c, box_rect,rgb_pixel(212,208,200)); - - draw_sunken_rectangle(c, box_rect); - - - if (is_checked) - { - const long x = box_rect.left(); - const long y = box_rect.top(); - draw_line(c,point(3+x,5+y),point(6+x,8+y),color); - draw_line(c,point(3+x,6+y),point(5+x,8+y),color); - draw_line(c,point(3+x,7+y),point(5+x,9+y),color); - draw_line(c,point(6+x,6+y),point(9+x,3+y),color); - draw_line(c,point(6+x,7+y),point(9+x,4+y),color); - draw_line(c,point(6+x,8+y),point(9+x,5+y),color); - } - } - -// ---------------------------------------------------------------------------------------- - - rectangle toggle_button_style_check_box:: - get_min_size ( - const ustring& name, - const font& mfont - ) const - { - unsigned long width; - unsigned long height; - mfont.compute_size(name,width,height); - - if (height < 13) - height = 13; - - return rectangle(width + 17 -1, height -1); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void toggle_button_style_radio_button::draw_toggle_button ( - const canvas& c, - const rectangle& rect, - const bool enabled, - const font& mfont, - const long , - const long , - const ustring& name, - const bool is_depressed, - const bool is_checked - ) const - { - rectangle area = rect.intersect(c); - if (area.is_empty()) - return; - - - rgb_pixel color; - - // figure out where the name string should appear - rectangle name_rect, box_rect; - unsigned long padding = 0; - if (mfont.height() < 13) - padding = (rect.height() - mfont.height())/2; - - name_rect = rect; - name_rect.set_left(rect.left() + 17-1); - name_rect.set_top(rect.top() + padding); - name_rect.set_bottom(rect.bottom() - padding); - - box_rect = rect; - box_rect.set_right(rect.left() + 12); - box_rect.set_bottom(rect.top() + 12); - - - const long x = box_rect.left(); - const long y = box_rect.top(); - - if (enabled && is_depressed == false) - draw_solid_circle(c,point(rect.left()+5,rect.top()+5),4.5,rgb_pixel(255,255,255)); - else - draw_solid_circle(c,point(rect.left()+5,rect.top()+5),4.5,rgb_pixel(212,208,200)); - - - color = rgb_pixel(128,128,128); - draw_line(c,point(0+x,4+y),point(0+x,7+y),color); - draw_line(c,point(1+x,2+y),point(1+x,9+y),color); - draw_line(c,point(2+x,1+y),point(9+x,1+y),color); - draw_line(c,point(4+x,0+y),point(7+x,0+y),color); - - color = rgb_pixel(255,255,255); - draw_line(c,point(4+x,11+y),point(7+x,11+y),color); - draw_line(c,point(2+x,10+y),point(9+x,10+y),color); - draw_line(c,point(10+x,2+y),point(10+x,9+y),color); - draw_line(c,point(11+x,4+y),point(11+x,7+y),color); - - color = rgb_pixel(64,64,64); - draw_line(c,point(1+x,4+y),point(1+x,7+y),color); - draw_line(c,point(4+x,1+y),point(7+x,1+y),color); - draw_pixel(c,point(2+x,3+y),color); - draw_pixel(c,point(3+x,2+y),color); - draw_pixel(c,point(2+x,2+y),color); - draw_pixel(c,point(2+x,8+y),color); - draw_pixel(c,point(8+x,2+y),color); - draw_pixel(c,point(9+x,2+y),color); - - color = rgb_pixel(212,208,200); - draw_line(c,point(4+x,10+y),point(7+x,10+y),color); - draw_line(c,point(10+x,4+y),point(10+x,7+y),color); - draw_pixel(c,point(3+x,9+y),color); - draw_pixel(c,point(9+x,3+y),color); - - if (enabled) - { - color.red = 0; - color.green = 0; - color.blue = 0; - } - else - { - color.red = 128; - color.green = 128; - color.blue = 128; - } - - mfont.draw_string(c,name_rect,name,color); - - if (is_checked) - { - draw_line(c,point(5+x,4+y),point(6+x,4+y),color); - draw_line(c,point(4+x,5+y),point(7+x,5+y),color); - draw_line(c,point(4+x,6+y),point(7+x,6+y),color); - draw_line(c,point(5+x,7+y),point(6+x,7+y),color); - } - - } - -// ---------------------------------------------------------------------------------------- - - rectangle toggle_button_style_radio_button:: - get_min_size ( - const ustring& name, - const font& mfont - ) const - { - unsigned long width; - unsigned long height; - mfont.compute_size(name,width,height); - - if (height < 13) - height = 13; - - return rectangle(width + 17 -1, height -1); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // scroll bar style stuff -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - long scroll_bar_style_default:: - get_slider_length ( - long total_length, - long max_pos - ) const - { - // if the length is too small then we have to smash up the arrow buttons - // and hide the slider. - if (total_length <= get_width()*2) - { - return 0; - } - else - { - double range = total_length - get_button_length(total_length, max_pos)*2; - - double scale_factor = 30.0/(max_pos + 30.0); - - if (scale_factor < 0.1) - scale_factor = 0.1; - - - double fraction = range/(max_pos + range)*scale_factor; - double result = fraction * range; - long res = static_cast(result); - if (res < 8) - res = 8; - return res; - } - } - -// ---------------------------------------------------------------------------------------- - - long scroll_bar_style_default:: - get_button_length ( - long total_length, - long - ) const - { - // if the length is too small then we have to smash up the arrow buttons - // and hide the slider. - if (total_length <= get_width()*2) - { - return total_length/2; - } - else - { - return get_width(); - } - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar_style_default:: - draw_scroll_bar_background ( - const canvas& c, - const rectangle& rect, - const bool , - const long , - const long , - const bool is_depressed - ) const - { - if (is_depressed) - draw_checkered(c, rect,rgb_pixel(0,0,0),rgb_pixel(43,47,55)); - else - draw_checkered(c, rect,rgb_pixel(255,255,255),rgb_pixel(212,208,200)); - } - -// ---------------------------------------------------------------------------------------- - - void scroll_bar_style_default:: - draw_scroll_bar_slider ( - const canvas& c, - const rectangle& rect, - const bool , - const long , - const long , - const bool - ) const - { - fill_rect(c, rect, rgb_pixel(212,208,200)); - draw_button_up(c, rect); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // text_field styles -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - unsigned long text_field_style_default:: - get_padding ( - const font& mfont - ) const - { - return mfont.height()-mfont.ascender(); - } - -// ---------------------------------------------------------------------------------------- - - void text_field_style_default:: - draw_text_field ( - const canvas& c, - const rectangle& rect, - const rectangle& text_rect, - const bool enabled, - const font& mfont, - const ustring& text, - const unsigned long cursor_x, - const unsigned long text_pos, - const rgb_pixel& text_color, - const rgb_pixel& bg_color, - const bool has_focus, - const bool cursor_visible, - const long highlight_start, - const long highlight_end - ) const - { - rectangle area = rect.intersect(c); - - if (enabled) - { - // first fill our area with the bg_color - fill_rect(c, area,bg_color); - } - else - { - // first fill our area with gray - fill_rect(c, area,rgb_pixel(212,208,200)); - } - - - if (enabled) - mfont.draw_string(c,text_rect,text,text_color,text_pos); - else - mfont.draw_string(c,text_rect,text,rgb_pixel(128,128,128),text_pos); - - // now draw the edge of the text_field - draw_sunken_rectangle(c, rect); - - if (highlight_start <= highlight_end && enabled) - { - rectangle highlight_rect = text_rect; - unsigned long left_pad = 0, right_pad = mfont.left_overflow(); - - long i; - for (i = text_pos; i <= highlight_end; ++i) - { - if (i == highlight_start) - left_pad = right_pad; - - right_pad += mfont[text[i]].width(); - } - - highlight_rect.set_left(text_rect.left()+left_pad); - highlight_rect.set_right(text_rect.left()+right_pad); - - // highlight the highlight_rect area - highlight_rect = highlight_rect.intersect(c); - for (long row = highlight_rect.top(); row <= highlight_rect.bottom(); ++row) - { - for (long col = highlight_rect.left(); col <= highlight_rect.right(); ++col) - { - canvas::pixel& pixel = c[row-c.top()][col-c.left()]; - if (pixel.red == 255 && pixel.green == 255 && pixel.blue == 255) - { - // this is a background (and white) pixel so set it to a dark - // blueish color. - pixel.red = 10; - pixel.green = 36; - pixel.blue = 106; - } - else - { - // this should be a pixel that is part of a letter so set it to white - pixel.red = 255; - pixel.green = 255; - pixel.blue = 255; - } - } - } - } - - // now draw the cursor if we need to - if (cursor_visible && has_focus && enabled) - { - const unsigned long top = rect.top()+3; - const unsigned long bottom = rect.bottom()-3; - draw_line(c, point(rect.left()+cursor_x,top),point(rect.left()+cursor_x,bottom)); - } - - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // text_box styles -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void text_box_style_default:: - draw_text_box ( - const canvas& c, - const rectangle& display_rect, - const rectangle& text_rect, - const bool enabled, - const font& mfont, - const ustring& text, - const rectangle& cursor_rect, - const rgb_pixel& text_color, - const rgb_pixel& bg_color, - const bool has_focus, - const bool cursor_visible, - const long highlight_start, - const long highlight_end - ) const - { - rectangle area = display_rect.intersect(c); - - if (enabled) - { - // first fill our area with the bg_color - fill_rect(c, area,bg_color); - } - else - { - // first fill our area with gray - fill_rect(c, area,rgb_pixel(212,208,200)); - } - - - if (enabled) - mfont.draw_string(c,text_rect,text,text_color, 0, ustring::npos, area); - else - mfont.draw_string(c,text_rect,text,rgb_pixel(128,128,128), 0, ustring::npos, area); - - - // now draw the highlight if there is any - if (highlight_start <= highlight_end && enabled) - { - const rectangle first_pos = mfont.compute_cursor_rect(text_rect, text, highlight_start); - const rectangle last_pos = mfont.compute_cursor_rect(text_rect, text, highlight_end+1); - - const rgb_alpha_pixel color(10, 30, 106, 90); - - // if the highlighted text is all on one line - if (first_pos.top() == last_pos.top()) - { - fill_rect(c, (first_pos + last_pos).intersect(display_rect), color); - } - else - { - const rectangle min_boundary(display_rect.left()+4, display_rect.top()+4, - display_rect.right()-4, display_rect.bottom()-4); - const rectangle boundary( display_rect.intersect(text_rect) + min_boundary); - - rectangle first_row, last_row, middle_rows; - first_row += first_pos; - first_row += point(boundary.right(), first_pos.top()); - last_row += last_pos; - last_row += point(boundary.left(), last_pos.bottom()); - - middle_rows.left() = boundary.left(); - middle_rows.right() = boundary.right(); - middle_rows.top() = first_row.bottom()+1; - middle_rows.bottom() = last_row.top()-1; - - fill_rect(c, first_row.intersect(display_rect), color); - fill_rect(c, middle_rows, color); - fill_rect(c, last_row.intersect(display_rect), color); - } - } - - // now draw the cursor if we need to - if (cursor_visible && has_focus && enabled) - { - draw_line(c, point(cursor_rect.left(), cursor_rect.top()),point(cursor_rect.left(), cursor_rect.bottom()), 0, area); - } - - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_WIDGETs_STYLE_CPP_ - diff --git a/lib/3rdParty/dlib/include/dlib/gui_widgets/widgets.cpp b/lib/3rdParty/dlib/include/dlib/gui_widgets/widgets.cpp deleted file mode 100644 index a8bef972..00000000 --- a/lib/3rdParty/dlib/include/dlib/gui_widgets/widgets.cpp +++ /dev/null @@ -1,6798 +0,0 @@ -// Copyright (C) 2005 Davis E. King (davis@dlib.net), Keita Mochizuki -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_WIDGETs_CPP_ -#define DLIB_WIDGETs_CPP_ - -#include "widgets.h" -#include -#include "../string.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // toggle_button object methods -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void toggle_button:: - set_size ( - unsigned long width, - unsigned long height - ) - { - auto_mutex M(m); - rectangle min_rect = style->get_min_size(name_,*mfont); - // only change the size if it isn't going to be too small to fit the name - if (height >= min_rect.height() && - width >= min_rect.width()) - { - rectangle old(rect); - rect = resize_rect(rect,width,height); - parent.invalidate_rectangle(rect+old); - btn_tooltip.set_size(width,height); - } - } - -// ---------------------------------------------------------------------------------------- - - void toggle_button:: - set_checked ( - ) - { - auto_mutex M(m); - checked = true; - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - void toggle_button:: - set_unchecked ( - ) - { - auto_mutex M(m); - checked = false; - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - bool toggle_button:: - is_checked ( - ) const - { - auto_mutex M(m); - return checked; - } - -// ---------------------------------------------------------------------------------------- - - void toggle_button:: - show ( - ) - { - button_action::show(); - btn_tooltip.show(); - } - -// ---------------------------------------------------------------------------------------- - - void toggle_button:: - hide ( - ) - { - button_action::hide(); - btn_tooltip.hide(); - } - -// ---------------------------------------------------------------------------------------- - - void toggle_button:: - enable ( - ) - { - button_action::enable(); - btn_tooltip.enable(); - } - -// ---------------------------------------------------------------------------------------- - - void toggle_button:: - disable ( - ) - { - button_action::disable(); - btn_tooltip.disable(); - } - -// ---------------------------------------------------------------------------------------- - - void toggle_button:: - set_tooltip_text ( - const std::string& text - ) - { - btn_tooltip.set_text(text); - } - - void toggle_button:: - set_tooltip_text ( - const std::wstring& text - ) - { - btn_tooltip.set_text(text); - } - - void toggle_button:: - set_tooltip_text ( - const dlib::ustring& text - ) - { - btn_tooltip.set_text(text); - } - -// ---------------------------------------------------------------------------------------- - - const std::string toggle_button:: - tooltip_text ( - ) const - { - return btn_tooltip.text(); - } - - const std::wstring toggle_button:: - tooltip_wtext ( - ) const - { - return btn_tooltip.wtext(); - } - - const dlib::ustring toggle_button:: - tooltip_utext ( - ) const - { - return btn_tooltip.utext(); - } - -// ---------------------------------------------------------------------------------------- - - void toggle_button:: - set_main_font ( - const shared_ptr_thread_safe& f - ) - { - auto_mutex M(m); - mfont = f; - set_name(name_); - } - -// ---------------------------------------------------------------------------------------- - - void toggle_button:: - set_pos ( - long x, - long y - ) - { - auto_mutex M(m); - button_action::set_pos(x,y); - btn_tooltip.set_pos(x,y); - } - -// ---------------------------------------------------------------------------------------- - - void toggle_button:: - set_name ( - const std::string& name - ) - { - set_name(convert_mbstring_to_wstring(name)); - } - - void toggle_button:: - set_name ( - const std::wstring& name - ) - { - set_name(convert_wstring_to_utf32(name)); - } - - void toggle_button:: - set_name ( - const dlib::ustring& name - ) - { - auto_mutex M(m); - name_ = name; - // do this to get rid of any reference counting that may be present in - // the std::string implementation. - name_[0] = name_[0]; - - rectangle old(rect); - rect = move_rect(style->get_min_size(name,*mfont),rect.left(),rect.top()); - btn_tooltip.set_size(rect.width(),rect.height()); - - parent.invalidate_rectangle(rect+old); - } - -// ---------------------------------------------------------------------------------------- - - const std::string toggle_button:: - name ( - ) const - { - return convert_wstring_to_mbstring(wname()); - } - - const std::wstring toggle_button:: - wname ( - ) const - { - return convert_utf32_to_wstring(uname()); - } - - const dlib::ustring toggle_button:: - uname ( - ) const - { - auto_mutex M(m); - dlib::ustring temp = name_; - // do this to get rid of any reference counting that may be present in - // the std::string implementation. - temp[0] = name_[0]; - return temp; - } - -// ---------------------------------------------------------------------------------------- - - void toggle_button:: - on_button_up ( - bool mouse_over - ) - { - if (mouse_over) - { - checked = !checked; - // this is a valid toggle_button click - if (event_handler.is_set()) - event_handler(); - else if (event_handler_self.is_set()) - event_handler_self(*this); - } - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // label object methods -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void label:: - draw ( - const canvas& c - ) const - { - rectangle area = rect.intersect(c); - if (area.is_empty() || text_.size() == 0) - return; - - using namespace std; - unsigned char r = text_color_.red; - unsigned char g = text_color_.green; - unsigned char b = text_color_.blue; - if (!enabled) - { - r = 128; - g = 128; - b = 128; - } - - rectangle text_rect(rect); - - string::size_type first, last; - first = 0; - last = text_.find_first_of('\n'); - mfont->draw_string(c,text_rect,text_,rgb_pixel(r,g,b),first,last); - - while (last != string::npos) - { - first = last+1; - last = text_.find_first_of('\n',first); - text_rect.set_top(text_rect.top()+mfont->height()); - mfont->draw_string(c,text_rect,text_,rgb_pixel(r,g,b),first,last); - } - } - -// ---------------------------------------------------------------------------------------- - - void label:: - set_main_font ( - const shared_ptr_thread_safe& f - ) - { - auto_mutex M(m); - mfont = f; - set_text(text_); - } - -// ---------------------------------------------------------------------------------------- - - - void label:: - set_text ( - const std::string& text - ) - { - set_text(convert_mbstring_to_wstring(text)); - } - - void label:: - set_text ( - const std::wstring& text - ) - { - set_text(convert_wstring_to_utf32(text)); - } - - void label:: - set_text ( - const dlib::ustring& text - ) - { - using namespace std; - auto_mutex M(m); - text_ = text; - // do this to get rid of any reference counting that may be present in - // the std::string implementation. - text_[0] = text[0]; - - rectangle old(rect); - - unsigned long width; - unsigned long height; - mfont->compute_size(text,width,height); - - rect.set_right(rect.left() + width - 1); - rect.set_bottom(rect.top() + height - 1); - - parent.invalidate_rectangle(rect+old); - } - -// ---------------------------------------------------------------------------------------- - - const std::string label:: - text ( - ) const - { - return convert_wstring_to_mbstring(wtext()); - } - - const std::wstring label:: - wtext ( - ) const - { - return convert_utf32_to_wstring(utext()); - } - - const dlib::ustring label:: - utext ( - ) const - { - auto_mutex M(m); - dlib::ustring temp = text_; - // do this to get rid of any reference counting that may be present in - // the std::string implementation. - temp[0] = text_[0]; - return temp; - } - -// ---------------------------------------------------------------------------------------- - - void label:: - set_text_color ( - const rgb_pixel color - ) - { - m.lock(); - text_color_ = color; - parent.invalidate_rectangle(rect); - m.unlock(); - } - -// ---------------------------------------------------------------------------------------- - - const rgb_pixel label:: - text_color ( - ) const - { - auto_mutex M(m); - return text_color_; - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // text_field object methods -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - rectangle text_field:: - get_text_rect ( - ) const - { - // figure out where the text string should appear - unsigned long vertical_pad = (rect.height() - mfont->height())/2+1; - - rectangle text_rect; - text_rect.set_left(rect.left()+style->get_padding(*mfont)); - text_rect.set_top(rect.top()+vertical_pad); - text_rect.set_right(rect.right()-style->get_padding(*mfont)); - text_rect.set_bottom(text_rect.top()+mfont->height()-1); - return text_rect; - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - enable ( - ) - { - drawable::enable(); - right_click_menu.enable(); - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - give_input_focus ( - ) - { - auto_mutex M(m); - has_focus = true; - cursor_visible = true; - parent.invalidate_rectangle(rect); - t.start(); - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - select_all_text ( - ) - { - auto_mutex M(m); - on_select_all(); - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - on_cut ( - ) - { - on_copy(); - on_delete_selected(); - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - on_copy ( - ) - { - if (highlight_start <= highlight_end) - { - put_on_clipboard(text_.substr(highlight_start, highlight_end-highlight_start+1)); - } - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - on_paste ( - ) - { - ustring temp_str; - get_from_clipboard(temp_str); - - // If this is a multi line string then just take the first line. - ustring::size_type pos = temp_str.find_first_of('\n'); - if (pos != ustring::npos) - { - temp_str = temp_str.substr(0,pos); - } - - if (highlight_start <= highlight_end) - { - text_ = text_.substr(0,highlight_start) + temp_str + - text_.substr(highlight_end+1,text_.size()-highlight_end-1); - move_cursor(highlight_start+temp_str.size()); - highlight_start = 0; - highlight_end = -1; - parent.invalidate_rectangle(rect); - on_no_text_selected(); - - // send out the text modified event - if (text_modified_handler.is_set()) - text_modified_handler(); - } - else - { - text_ = text_.substr(0,cursor_pos) + temp_str + - text_.substr(cursor_pos,text_.size()-cursor_pos); - move_cursor(cursor_pos+temp_str.size()); - - // send out the text modified event - if (temp_str.size() != 0 && text_modified_handler.is_set()) - text_modified_handler(); - } - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - on_select_all ( - ) - { - move_cursor(static_cast(text_.size())); - highlight_start = 0; - highlight_end = static_cast(text_.size()-1); - if (highlight_start <= highlight_end) - on_text_is_selected(); - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - on_delete_selected ( - ) - { - if (highlight_start <= highlight_end) - { - text_ = text_.erase(highlight_start,highlight_end-highlight_start+1); - move_cursor(highlight_start); - highlight_start = 0; - highlight_end = -1; - - on_no_text_selected(); - // send out the text modified event - if (text_modified_handler.is_set()) - text_modified_handler(); - - parent.invalidate_rectangle(rect); - } - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - on_text_is_selected ( - ) - { - right_click_menu.menu().enable_menu_item(0); - right_click_menu.menu().enable_menu_item(1); - right_click_menu.menu().enable_menu_item(3); - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - on_no_text_selected ( - ) - { - right_click_menu.menu().disable_menu_item(0); - right_click_menu.menu().disable_menu_item(1); - right_click_menu.menu().disable_menu_item(3); - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - show ( - ) - { - drawable::show(); - right_click_menu.show(); - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - disable ( - ) - { - auto_mutex M(m); - drawable::disable(); - t.stop(); - has_focus = false; - cursor_visible = false; - right_click_menu.disable(); - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - hide ( - ) - { - auto_mutex M(m); - drawable::hide(); - t.stop(); - has_focus = false; - cursor_visible = false; - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - set_main_font ( - const shared_ptr_thread_safe& f - ) - { - auto_mutex M(m); - mfont = f; - // adjust the height of this text field so that it is appropriate for the current - // font size - rect.set_bottom(rect.top() + mfont->height()+ (style->get_padding(*mfont))*2); - set_text(text_); - right_click_menu.set_rect(get_text_rect()); - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - draw ( - const canvas& c - ) const - { - rectangle area = rect.intersect(c); - if (area.is_empty()) - return; - - style->draw_text_field(c,rect,get_text_rect(), enabled, *mfont, text_, cursor_x, text_pos, - text_color_, bg_color_, has_focus, cursor_visible, highlight_start, - highlight_end); - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - set_text ( - const std::string& text - ) - { - set_text(convert_mbstring_to_wstring(text)); - } - - void text_field:: - set_text ( - const std::wstring& text - ) - { - set_text(convert_wstring_to_utf32(text)); - } - - void text_field:: - set_text ( - const dlib::ustring& text - ) - { - DLIB_ASSERT ( text.find_first_of('\n') == std::string::npos , - "\tvoid text_field::set_text()" - << "\n\ttext: " << narrow(text) ); - auto_mutex M(m); - // do this to get rid of any reference counting that may be present in - // the std::string implementation. - text_ = text.c_str(); - - move_cursor(0); - - highlight_start = 0; - highlight_end = -1; - - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - const std::string text_field:: - text ( - ) const - { - std::string temp = convert_wstring_to_mbstring(wtext()); - return temp; - } - - const std::wstring text_field:: - wtext ( - ) const - { - std::wstring temp = convert_utf32_to_wstring(utext()); - return temp; - } - - const dlib::ustring text_field:: - utext ( - ) const - { - auto_mutex M(m); - // do this to get rid of any reference counting that may be present in - // the dlib::ustring implementation. - dlib::ustring temp = text_.c_str(); - return temp; - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - set_width ( - unsigned long width - ) - { - auto_mutex M(m); - if (width < style->get_padding(*mfont)*2) - return; - - rectangle old(rect); - - rect.set_right(rect.left() + width - 1); - - right_click_menu.set_rect(get_text_rect()); - parent.invalidate_rectangle(rect+old); - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - set_pos ( - long x, - long y - ) - { - drawable::set_pos(x,y); - right_click_menu.set_rect(get_text_rect()); - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - set_background_color ( - const rgb_pixel color - ) - { - auto_mutex M(m); - bg_color_ = color; - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - const rgb_pixel text_field:: - background_color ( - ) const - { - auto_mutex M(m); - return bg_color_; - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - set_text_color ( - const rgb_pixel color - ) - { - auto_mutex M(m); - text_color_ = color; - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - const rgb_pixel text_field:: - text_color ( - ) const - { - auto_mutex M(m); - return text_color_; - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - on_mouse_move ( - unsigned long state, - long x, - long y - ) - { - if (!enabled || hidden || !has_focus) - { - return; - } - - if (state & base_window::LEFT) - { - if (highlight_start <= highlight_end) - { - if (highlight_start == cursor_pos) - shift_pos = highlight_end + 1; - else - shift_pos = highlight_start; - } - - unsigned long new_pos = mfont->compute_cursor_pos(get_text_rect(),text_,x,y,text_pos); - if (static_cast(new_pos) != cursor_pos) - { - move_cursor(new_pos); - parent.invalidate_rectangle(rect); - } - } - else if (shift_pos != -1) - { - shift_pos = -1; - } - - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - on_mouse_up ( - unsigned long btn, - unsigned long, - long , - long - ) - { - if (!enabled || hidden) - return; - - if (btn == base_window::LEFT) - shift_pos = -1; - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - on_mouse_down ( - unsigned long btn, - unsigned long state, - long x, - long y, - bool double_clicked - ) - { - using namespace std; - if (!enabled || hidden || btn != (unsigned long)base_window::LEFT) - return; - - if (rect.contains(x,y)) - { - has_focus = true; - cursor_visible = true; - parent.invalidate_rectangle(rect); - t.start(); - - if (double_clicked) - { - // highlight the double clicked word - string::size_type first, last; - const ustring ustr = convert_utf8_to_utf32(std::string(" \t\n")); - first = text_.substr(0,cursor_pos).find_last_of(ustr.c_str()); - last = text_.find_first_of(ustr.c_str(),cursor_pos); - long f = static_cast(first); - long l = static_cast(last); - if (first == string::npos) - f = -1; - if (last == string::npos) - l = static_cast(text_.size()); - - ++f; - --l; - - move_cursor(l+1); - highlight_start = f; - highlight_end = l; - on_text_is_selected(); - } - else - { - if (state & base_window::SHIFT) - { - if (highlight_start <= highlight_end) - { - if (highlight_start == cursor_pos) - shift_pos = highlight_end + 1; - else - shift_pos = highlight_start; - } - else - { - shift_pos = cursor_pos; - } - } - - bool at_end = false; - if (cursor_pos == 0 || cursor_pos == static_cast(text_.size())) - at_end = true; - const long old_pos = cursor_pos; - - unsigned long new_pos = mfont->compute_cursor_pos(get_text_rect(),text_,x,y,text_pos); - if (static_cast(new_pos) != cursor_pos) - { - move_cursor(new_pos); - parent.invalidate_rectangle(rect); - } - shift_pos = cursor_pos; - - if (at_end && cursor_pos == old_pos) - { - highlight_start = 0; - highlight_end = -1; - on_no_text_selected(); - parent.invalidate_rectangle(rect); - } - } - - } - else if (has_focus) - { - t.stop(); - has_focus = false; - cursor_visible = false; - shift_pos = -1; - highlight_start = 0; - highlight_end = -1; - on_no_text_selected(); - - if (focus_lost_handler.is_set()) - focus_lost_handler(); - parent.invalidate_rectangle(rect); - } - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - on_keydown ( - unsigned long key, - bool is_printable, - unsigned long state - ) - { - // If the right click menu is up then we don't want to do anything with - // the keyboard ourselves. Let the popup menu use the keyboard for now. - if (right_click_menu.popup_menu_visible()) - return; - - const ustring space_str = convert_utf8_to_utf32(std::string(" \t\n")); - const bool shift = (state&base_window::KBD_MOD_SHIFT) != 0; - const bool ctrl = (state&base_window::KBD_MOD_CONTROL) != 0; - if (has_focus && enabled && !hidden) - { - if (shift && is_printable == false) - { - if (shift_pos == -1) - { - if (highlight_start <= highlight_end) - { - if (highlight_start == cursor_pos) - shift_pos = highlight_end + 1; - else - shift_pos = highlight_start; - } - else - { - shift_pos = cursor_pos; - } - } - } - else - { - shift_pos = -1; - } - - if (key == base_window::KEY_LEFT || - key == base_window::KEY_UP) - { - if (cursor_pos != 0) - { - unsigned long new_pos; - if (ctrl) - { - // find the first non-whitespace to our left - std::string::size_type pos = text_.find_last_not_of(space_str.c_str(),cursor_pos); - if (pos != std::string::npos) - { - pos = text_.find_last_of(space_str.c_str(),pos); - if (pos != std::string::npos) - new_pos = static_cast(pos); - else - new_pos = 0; - } - else - { - new_pos = 0; - } - } - else - { - new_pos = cursor_pos-1; - } - - move_cursor(new_pos); - } - else if (shift_pos == -1) - { - highlight_start = 0; - highlight_end = -1; - on_no_text_selected(); - parent.invalidate_rectangle(rect); - } - - } - else if (key == base_window::KEY_RIGHT || - key == base_window::KEY_DOWN) - { - if (cursor_pos != static_cast(text_.size())) - { - unsigned long new_pos; - if (ctrl) - { - // find the first non-whitespace to our left - std::string::size_type pos = text_.find_first_not_of(space_str.c_str(),cursor_pos); - if (pos != std::string::npos) - { - pos = text_.find_first_of(space_str.c_str(),pos); - if (pos != std::string::npos) - new_pos = static_cast(pos+1); - else - new_pos = static_cast(text_.size()); - } - else - { - new_pos = static_cast(text_.size()); - } - } - else - { - new_pos = cursor_pos+1; - } - - move_cursor(new_pos); - } - else if (shift_pos == -1) - { - highlight_start = 0; - highlight_end = -1; - on_no_text_selected(); - parent.invalidate_rectangle(rect); - } - } - else if (is_printable) - { - if (ctrl) - { - if (key == 'a') - { - on_select_all(); - } - else if (key == 'c') - { - on_copy(); - } - else if (key == 'v') - { - on_paste(); - } - else if (key == 'x') - { - on_cut(); - } - } - else if (key != '\n') - { - if (highlight_start <= highlight_end) - { - text_ = text_.substr(0,highlight_start) + static_cast(key) + - text_.substr(highlight_end+1,text_.size()-highlight_end-1); - move_cursor(highlight_start+1); - highlight_start = 0; - highlight_end = -1; - on_no_text_selected(); - parent.invalidate_rectangle(rect); - } - else - { - text_ = text_.substr(0,cursor_pos) + static_cast(key) + - text_.substr(cursor_pos,text_.size()-cursor_pos); - move_cursor(cursor_pos+1); - } - unsigned long height; - mfont->compute_size(text_,text_width,height,text_pos); - - // send out the text modified event - if (text_modified_handler.is_set()) - text_modified_handler(); - } - else if (key == '\n') - { - if (enter_key_handler.is_set()) - enter_key_handler(); - } - } - else if (key == base_window::KEY_BACKSPACE) - { - // if something is highlighted then delete that - if (highlight_start <= highlight_end) - { - on_delete_selected(); - } - else if (cursor_pos != 0) - { - text_ = text_.erase(cursor_pos-1,1); - move_cursor(cursor_pos-1); - - // send out the text modified event - if (text_modified_handler.is_set()) - text_modified_handler(); - } - else - { - // do this just so it repaints itself right - move_cursor(cursor_pos); - } - unsigned long height; - mfont->compute_size(text_,text_width,height,text_pos); - parent.invalidate_rectangle(rect); - } - else if (key == base_window::KEY_DELETE) - { - // if something is highlighted then delete that - if (highlight_start <= highlight_end) - { - on_delete_selected(); - } - else if (cursor_pos != static_cast(text_.size())) - { - text_ = text_.erase(cursor_pos,1); - - // send out the text modified event - if (text_modified_handler.is_set()) - text_modified_handler(); - } - else - { - // do this just so it repaints itself right - move_cursor(cursor_pos); - } - parent.invalidate_rectangle(rect); - - unsigned long height; - mfont->compute_size(text_,text_width,height,text_pos); - } - else if (key == base_window::KEY_HOME) - { - move_cursor(0); - if (shift_pos == -1) - { - highlight_start = 0; - highlight_end = -1; - on_no_text_selected(); - parent.invalidate_rectangle(rect); - } - } - else if (key == base_window::KEY_END) - { - move_cursor(static_cast(text_.size())); - if (shift_pos == -1) - { - highlight_start = 0; - highlight_end = -1; - on_no_text_selected(); - parent.invalidate_rectangle(rect); - } - } - cursor_visible = true; - recent_movement = true; - - } - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - on_string_put( - const std::wstring &str - ) - { - if (has_focus && enabled && !hidden){ - ustring ustr = convert_wstring_to_utf32(str); - if (highlight_start <= highlight_end) - { - text_ = text_.substr(0,highlight_start) + ustr + - text_.substr(highlight_end+1,text_.size()-highlight_end-1); - move_cursor(highlight_start+ustr.size()); - highlight_start = 0; - highlight_end = -1; - on_no_text_selected(); - parent.invalidate_rectangle(rect); - } - else - { - text_ = text_.substr(0,cursor_pos) + ustr + - text_.substr(cursor_pos,text_.size()-cursor_pos); - move_cursor(cursor_pos+ustr.size()); - } - unsigned long height; - mfont->compute_size(text_,text_width,height,text_pos); - - // send out the text modified event - if (text_modified_handler.is_set()) - text_modified_handler(); - } - } - -// ---------------------------------------------------------------------------------------- - - void text_field:: - move_cursor ( - unsigned long pos - ) - { - using namespace std; - const long old_cursor_pos = cursor_pos; - - if (text_pos >= pos) - { - // the cursor should go all the way to the left side of the text - if (pos >= 6) - text_pos = pos-6; - else - text_pos = 0; - - cursor_pos = pos; - unsigned long height; - mfont->compute_size(text_,text_width,height,text_pos); - - unsigned long width; - unsigned long new_x = style->get_padding(*mfont); - if (static_cast(cursor_pos)-1 >= static_cast(text_pos)) - { - mfont->compute_size(text_,width,height,text_pos,cursor_pos-1); - if (cursor_pos != 0) - new_x += width - mfont->right_overflow(); - } - - cursor_x = new_x; - } - else - { - unsigned long height; - unsigned long width; - mfont->compute_size(text_,width,height,text_pos,pos-1); - - unsigned long new_x = style->get_padding(*mfont) + - width - mfont->right_overflow(); - - // move the text to the left if necessary - if (new_x + 4 > rect.width()) - { - while (new_x > rect.width() - rect.width()/5) - { - new_x -= (*mfont)[text_[text_pos]].width(); - ++text_pos; - } - } - - cursor_x = new_x; - cursor_pos = pos; - mfont->compute_size(text_,text_width,height,text_pos); - } - - parent.set_im_pos(rect.left()+cursor_x, rect.top()); - - if (old_cursor_pos != cursor_pos) - { - if (shift_pos != -1) - { - highlight_start = std::min(shift_pos,cursor_pos); - highlight_end = std::max(shift_pos,cursor_pos)-1; - } - else - { - highlight_start = 0; - highlight_end = -1; - } - - if (highlight_start > highlight_end) - on_no_text_selected(); - else - on_text_is_selected(); - - recent_movement = true; - cursor_visible = true; - parent.invalidate_rectangle(rect); - } - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// tabbed_display object methods -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - tabbed_display:: - tabbed_display( - drawable_window& w - ) : - drawable(w,MOUSE_CLICK), - selected_tab_(0), - left_pad(6), - right_pad(4), - top_pad(3), - bottom_pad(3) - { - rect = rectangle(0,0,40,mfont->height()+top_pad+bottom_pad); - enable_events(); - tabs.set_max_size(1); - tabs.set_size(1); - } - -// ---------------------------------------------------------------------------------------- - - tabbed_display:: - ~tabbed_display( - ) - { - disable_events(); - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - void tabbed_display:: - set_pos ( - long x, - long y - ) - { - auto_mutex M(m); - // we have to adjust the positions of all the tab rectangles - const long xdelta = rect.left() - x; - const long ydelta = rect.top() - y; - for (unsigned long i = 0; i < tabs.size(); ++i) - { - tabs[i].rect.set_left(tabs[i].rect.left()+xdelta); - tabs[i].rect.set_right(tabs[i].rect.right()+xdelta); - - tabs[i].rect.set_top(tabs[i].rect.top()+ydelta); - tabs[i].rect.set_bottom(tabs[i].rect.bottom()+ydelta); - - - // adjust the position of the group associated with this tab if it exists - if (tabs[i].group) - tabs[i].group->set_pos(x+3, y+mfont->height()+top_pad+bottom_pad+3); - } - drawable::set_pos(x,y); - recompute_tabs(); - } - -// ---------------------------------------------------------------------------------------- - - void tabbed_display:: - fit_to_contents ( - ) - { - auto_mutex M(m); - rectangle new_rect; - point p(rect.left(),rect.top()); - new_rect += p; - - for (unsigned long i = 0; i < tabs.size(); ++i) - { - if (tabs[i].group) - { - tabs[i].group->fit_to_contents(); - new_rect += tabs[i].group->get_rect(); - } - } - - // and give the new rect an additional 4 pixels on the bottom and right sides - // so that the contents to hit the edge of the tabbed display - new_rect = resize_rect(new_rect, new_rect.width()+4, new_rect.height()+4); - - parent.invalidate_rectangle(new_rect+rect); - rect = new_rect; - } - -// ---------------------------------------------------------------------------------------- - - void tabbed_display:: - set_size ( - unsigned long width, - unsigned long height - ) - { - auto_mutex M(m); - rectangle old(rect); - const long x = rect.left(); - const long y = rect.top(); - rect.set_right(x+width-1); - rect.set_bottom(y+height-1); - - recompute_tabs(); - - parent.invalidate_rectangle(rect+old); - } - -// ---------------------------------------------------------------------------------------- - - void tabbed_display:: - set_number_of_tabs ( - unsigned long num - ) - { - auto_mutex M(m); - - DLIB_ASSERT ( num > 0 , - "\tvoid tabbed_display::set_number_of_tabs()" - << "\n\tnum: " << num ); - - tabs.set_max_size(num); - tabs.set_size(num); - - selected_tab_ = 0; - - recompute_tabs(); - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - unsigned long tabbed_display:: - number_of_tabs ( - ) const - { - auto_mutex M(m); - return tabs.size(); - } - -// ---------------------------------------------------------------------------------------- - - const std::string tabbed_display:: - tab_name ( - unsigned long idx - ) const - { - return convert_wstring_to_mbstring(tab_wname(idx)); - } - - const std::wstring tabbed_display:: - tab_wname ( - unsigned long idx - ) const - { - return convert_utf32_to_wstring(tab_uname(idx)); - } - - const dlib::ustring& tabbed_display:: - tab_uname ( - unsigned long idx - ) const - { - auto_mutex M(m); - - DLIB_ASSERT ( idx < number_of_tabs() , - "\tvoid tabbed_display::tab_name()" - << "\n\tidx: " << idx - << "\n\tnumber_of_tabs(): " << number_of_tabs() ); - - return tabs[idx].name; - } - -// ---------------------------------------------------------------------------------------- - - void tabbed_display:: - set_tab_name ( - unsigned long idx, - const std::string& new_name - ) - { - set_tab_name(idx, convert_mbstring_to_wstring(new_name)); - } - - void tabbed_display:: - set_tab_name ( - unsigned long idx, - const std::wstring& new_name - ) - { - set_tab_name(idx, convert_wstring_to_utf32(new_name)); - } - - void tabbed_display:: - set_tab_name ( - unsigned long idx, - const dlib::ustring& new_name - ) - { - auto_mutex M(m); - - - DLIB_ASSERT ( idx < number_of_tabs() , - "\tvoid tabbed_display::set_tab_name()" - << "\n\tidx: " << idx - << "\n\tnumber_of_tabs(): " << number_of_tabs() ); - - - tabs[idx].name = new_name; - // do this so that there isn't any reference counting going on - tabs[idx].name[0] = tabs[idx].name[0]; - unsigned long height; - mfont->compute_size(new_name,tabs[idx].width,height); - - - recompute_tabs(); - - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - void tabbed_display:: - on_mouse_down ( - unsigned long btn, - unsigned long, - long x, - long y, - bool - ) - { - if (rect.contains(x,y) && btn == base_window::LEFT && enabled && !hidden) - { - rectangle temp = rect; - const long offset = mfont->height() + bottom_pad + top_pad; - temp.set_bottom(rect.top()+offset); - if (temp.contains(x,y)) - { - // now we have to figure out which tab was clicked - for (unsigned long i = 0; i < tabs.size(); ++i) - { - if (selected_tab_ != i && tabs[i].rect.contains(x,y) && - tabs[selected_tab_].rect.contains(x,y) == false) - { - unsigned long old_idx = selected_tab_; - selected_tab_ = i; - recompute_tabs(); - parent.invalidate_rectangle(temp); - - // adjust the widget_group objects for these tabs if they exist - if (tabs[i].group) - tabs[i].group->show(); - if (tabs[old_idx].group) - tabs[old_idx].group->hide(); - - if (event_handler.is_set()) - event_handler(i,old_idx); - break; - } - } - } - } - } - -// ---------------------------------------------------------------------------------------- - - void tabbed_display:: - set_tab_group ( - unsigned long idx, - widget_group& group - ) - { - auto_mutex M(m); - - DLIB_ASSERT ( idx < number_of_tabs() , - "\tvoid tabbed_display::set_tab_group()" - << "\n\tidx: " << idx - << "\n\tnumber_of_tabs(): " << number_of_tabs() ); - - - tabs[idx].group = &group; - group.set_pos(rect.left()+3,rect.top()+mfont->height()+top_pad+bottom_pad+2); - if (idx == selected_tab_) - group.show(); - else - group.hide(); - } - -// ---------------------------------------------------------------------------------------- - - void tabbed_display:: - disable ( - ) - { - auto_mutex M(m); - if (tabs[selected_tab_].group) - tabs[selected_tab_].group->disable(); - drawable::disable(); - } - -// ---------------------------------------------------------------------------------------- - - void tabbed_display:: - enable ( - ) - { - auto_mutex M(m); - if (tabs[selected_tab_].group) - tabs[selected_tab_].group->enable(); - drawable::enable(); - } - -// ---------------------------------------------------------------------------------------- - - void tabbed_display:: - hide ( - ) - { - auto_mutex M(m); - if (tabs[selected_tab_].group) - tabs[selected_tab_].group->hide(); - drawable::hide(); - } - -// ---------------------------------------------------------------------------------------- - - void tabbed_display:: - show ( - ) - { - auto_mutex M(m); - if (tabs[selected_tab_].group) - tabs[selected_tab_].group->show(); - drawable::show(); - } - -// ---------------------------------------------------------------------------------------- - - void tabbed_display:: - draw ( - const canvas& c - ) const - { - rectangle area = rect.intersect(c); - if (area.is_empty()) - return; - - // draw the main border first - rectangle main_box(rect.left(),rect.top()+mfont->height()+top_pad+bottom_pad,rect.right(),rect.bottom()); - draw_button_up(c,main_box); - draw_pixel(c,point(main_box.right()-1,main_box.top()),rgb_pixel(128,128,128)); - - rgb_pixel color; - if (enabled) - { - color.red = 0; - color.green = 0; - color.blue = 0; - } - else - { - color.red = 128; - color.green = 128; - color.blue = 128; - } - - // draw the tabs - for (unsigned long i = 0; i < tabs.size(); ++i) - { - if (selected_tab_ != i) - draw_tab(tabs[i].rect,c); - - // draw the name string - rectangle temp = tabs[i].rect; - temp.set_top(temp.top()+top_pad); - temp.set_bottom(temp.bottom()+bottom_pad); - temp.set_left(temp.left()+left_pad); - temp.set_right(temp.right()+right_pad); - mfont->draw_string(c,temp,tabs[i].name,color); - } - draw_tab(tabs[selected_tab_].rect,c); - draw_line(c, - point(tabs[selected_tab_].rect.left()+1, - tabs[selected_tab_].rect.bottom()), - point(tabs[selected_tab_].rect.right()-2, - tabs[selected_tab_].rect.bottom()), - rgb_pixel(212,208,200)); - } - -// ---------------------------------------------------------------------------------------- - - void tabbed_display:: - draw_tab ( - const rectangle& tab, - const canvas& c - ) const - { - const rgb_pixel white(255,255,255); - const rgb_pixel background(212,208,200); - const rgb_pixel dark_gray(64,64,64); - const rgb_pixel gray(128,128,128); - draw_line(c,point(tab.left(),tab.top()+2),point(tab.left(),tab.bottom()),white); - draw_line(c,point(tab.left()+1,tab.top()+2),point(tab.left()+1,tab.bottom()),background); - draw_line(c,point(tab.right(),tab.top()+2),point(tab.right(),tab.bottom()),dark_gray); - draw_line(c,point(tab.right()-1,tab.top()+2),point(tab.right()-1,tab.bottom()),gray); - draw_line(c,point(tab.left()+2,tab.top()),point(tab.right()-2,tab.top()),white); - draw_pixel(c,point(tab.left()+1,tab.top()+1),white); - draw_pixel(c,point(tab.right()-1,tab.top()+1),dark_gray); - } - -// ---------------------------------------------------------------------------------------- - - void tabbed_display:: - set_main_font ( - const shared_ptr_thread_safe& f - ) - { - auto_mutex M(m); - mfont = f; - - for (unsigned long i = 0; i < tabs.size(); ++i) - { - unsigned long height; - mfont->compute_size(tabs[i].name,tabs[i].width,height); - } - - recompute_tabs(); - set_pos(rect.left(), rect.top()); - - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - void tabbed_display:: - recompute_tabs ( - ) - { - const long offset = mfont->height() + bottom_pad + top_pad; - - - // figure out the size and position of all the tabs - rectangle sel_tab_rect, other_tab; - sel_tab_rect.set_top(rect.top()); - sel_tab_rect.set_bottom(rect.top()+offset); - - other_tab.set_top(rect.top()+2); - other_tab.set_bottom(rect.top()+offset-1); - - long cur_x = rect.left(); - for (unsigned long i = 0; i < tabs.size(); ++i) - { - const unsigned long str_width = tabs[i].width; - if (selected_tab_ != i) - { - other_tab.set_left(cur_x); - cur_x += left_pad + str_width + right_pad; - other_tab.set_right(cur_x); - tabs[i].rect = other_tab; - ++cur_x; - - } - else - { - if (i != 0) - sel_tab_rect.set_left(cur_x-2); - else - sel_tab_rect.set_left(cur_x); - - cur_x += left_pad + str_width + right_pad; - - if (i != tabs.size()-1) - sel_tab_rect.set_right(cur_x+2); - else - sel_tab_rect.set_right(cur_x); - ++cur_x; - - tabs[i].rect = sel_tab_rect; - } - } - - // make sure this object is wide enough - const rectangle& last = tabs[tabs.size()-1].rect; - const rectangle& first = tabs[0].rect; - rect = last + rect + first; - - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// named_rectangle object methods -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - named_rectangle:: - named_rectangle( - drawable_window& w - ) : - drawable(w), - name_width(0), - name_height(0) - { - make_name_fit_in_rect(); - enable_events(); - } - -// ---------------------------------------------------------------------------------------- - - named_rectangle:: - ~named_rectangle( - ) - { - disable_events(); - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - void named_rectangle:: - set_size ( - unsigned long width, - unsigned long height - ) - { - auto_mutex M(m); - rectangle old(rect); - const long x = rect.left(); - const long y = rect.top(); - rect.set_right(x+width-1); - rect.set_bottom(y+height-1); - - make_name_fit_in_rect(); - parent.invalidate_rectangle(rect+old); - } - -// ---------------------------------------------------------------------------------------- - - void named_rectangle:: - wrap_around ( - const rectangle& r - ) - { - auto_mutex M(m); - rectangle old(rect); - const unsigned long pad = name_height/2; - - rect = rectangle(r.left()-pad, r.top()-name_height*4/3, r.right()+pad, r.bottom()+pad); - - make_name_fit_in_rect(); - parent.invalidate_rectangle(rect+old); - } - -// ---------------------------------------------------------------------------------------- - - void named_rectangle:: - set_main_font ( - const shared_ptr_thread_safe& f - ) - { - auto_mutex M(m); - mfont = f; - mfont->compute_size(name_,name_width,name_height); - make_name_fit_in_rect(); - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - void named_rectangle:: - make_name_fit_in_rect ( - ) - { - // make sure the named rectangle is big enough to contain the name - const unsigned long wtemp = mfont->height() + name_width; - const unsigned long htemp = mfont->height() + name_height; - if (rect.width() < wtemp) - rect.set_right(rect.left() + wtemp - 1 ); - if (rect.height() < htemp) - rect.set_bottom(rect.bottom() + htemp - 1 ); - } - -// ---------------------------------------------------------------------------------------- - - void named_rectangle:: - set_name ( - const std::string& name - ) - { - set_name(convert_mbstring_to_wstring(name)); - } - - void named_rectangle:: - set_name ( - const std::wstring& name - ) - { - set_name(convert_wstring_to_utf32(name)); - } - - void named_rectangle:: - set_name ( - const dlib::ustring& name - ) - { - auto_mutex M(m); - name_ = name.c_str(); - mfont->compute_size(name_,name_width,name_height); - - make_name_fit_in_rect(); - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - const std::string named_rectangle:: - name ( - ) const - { - return convert_wstring_to_mbstring(wname()); - } - - const std::wstring named_rectangle:: - wname ( - ) const - { - return convert_utf32_to_wstring(uname()); - } - - const dlib::ustring named_rectangle:: - uname ( - ) const - { - auto_mutex M(m); - return dlib::ustring(name_.c_str()); - } - -// ---------------------------------------------------------------------------------------- - - void named_rectangle:: - draw ( - const canvas& c - ) const - { - rectangle area = rect.intersect(c); - if (area.is_empty()) - return; - - const unsigned long gap = mfont->height()/2; - rectangle strrect = rect; - strrect.set_left(rect.left() + gap); - - const unsigned long rtop = rect.top() + name_height/2; - - const rgb_pixel white(255,255,255); - const rgb_pixel gray(128,128,128); - - mfont->draw_string(c,strrect,name_); - draw_line(c,point(rect.left(), rtop), - point(rect.left()+gap/2, rtop), gray); - draw_line(c,point(rect.left(), rtop), - point(rect.left(), rect.bottom()-1), gray); - draw_line(c,point(rect.left(), rect.bottom()-1), - point(rect.right()-1, rect.bottom()-1), gray); - draw_line(c,point(rect.right()-1, rtop), - point(rect.right()-1, rect.bottom()-2), gray); - draw_line(c,point(strrect.left() + name_width + 2, rtop), - point(rect.right()-1, rtop), gray); - - draw_line(c,point(strrect.left() + name_width + 2, rtop+1), - point( rect.right()-2, rtop+1), white); - draw_line(c,point(rect.right(), rtop), - point(rect.right(), rect.bottom()), white); - draw_line(c,point(rect.left(), rect.bottom()), - point(rect.right(), rect.bottom()), white); - draw_line(c,point(rect.left()+1, rtop+1), - point(rect.left()+1, rect.bottom()-2), white); - draw_line(c,point(rect.left()+1, rtop+1), - point(rect.left()+gap/2, rtop+1), white); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // class mouse_tracker -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - mouse_tracker:: - mouse_tracker( - drawable_window& w - ) : - draggable(w), - offset(18), - nr(w), - x_label(w), - y_label(w), - click_x(-1), - click_y(-1) - { - set_draggable_area(rectangle(0,0,500,500)); - - - x_label.set_text("x: "); - y_label.set_text("y: "); - nr.set_name("mouse position"); - - - x_label.set_pos(offset,offset); - y_label.set_pos(x_label.get_rect().left(), x_label.get_rect().bottom()+3); - - nr.wrap_around(x_label.get_rect() + y_label.get_rect()); - rect = nr.get_rect(); - - set_z_order(2000000000); - x_label.set_z_order(2000000001); - y_label.set_z_order(2000000001); - nr.set_z_order(2000000001); - - enable_events(); - } - -// ---------------------------------------------------------------------------------------- - - mouse_tracker:: - ~mouse_tracker( - ) - { - disable_events(); - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - void mouse_tracker:: - set_main_font ( - const shared_ptr_thread_safe& f - ) - { - auto_mutex M(m); - nr.set_main_font(f); - x_label.set_main_font(f); - y_label.set_main_font(f); - mfont = f; - nr.wrap_around(x_label.get_rect() + y_label.get_rect()); - rect = nr.get_rect(); - } - -// ---------------------------------------------------------------------------------------- - - void mouse_tracker:: - set_pos ( - long x, - long y - ) - { - draggable::set_pos(x,y); - nr.set_pos(x,y); - x_label.set_pos(rect.left()+offset,rect.top()+offset); - y_label.set_pos(x_label.get_rect().left(), x_label.get_rect().bottom()+3); - } - -// ---------------------------------------------------------------------------------------- - - void mouse_tracker:: - show ( - ) - { - draggable::show(); - nr.show(); - x_label.show(); - y_label.show(); - } - -// ---------------------------------------------------------------------------------------- - - void mouse_tracker:: - hide ( - ) - { - draggable::hide(); - nr.hide(); - x_label.hide(); - y_label.hide(); - } - -// ---------------------------------------------------------------------------------------- - - void mouse_tracker:: - enable ( - ) - { - draggable::enable(); - nr.enable(); - x_label.enable(); - y_label.enable(); - } - -// ---------------------------------------------------------------------------------------- - - void mouse_tracker:: - disable ( - ) - { - draggable::disable(); - nr.disable(); - x_label.disable(); - y_label.disable(); - } - -// ---------------------------------------------------------------------------------------- - - void mouse_tracker:: - on_mouse_down ( - unsigned long btn, - unsigned long state, - long x, - long y, - bool double_clicked - ) - { - draggable::on_mouse_down(btn,state,x,y,double_clicked); - if ((state & base_window::SHIFT) && (btn == base_window::LEFT) && enabled && !hidden) - { - parent.invalidate_rectangle(rectangle(x,y,x,y)); - parent.invalidate_rectangle(rectangle(click_x,click_y,click_x,click_y)); - click_x = x; - click_y = y; - - y_label.set_text("y: 0"); - x_label.set_text("x: 0"); - } - } - -// ---------------------------------------------------------------------------------------- - - void mouse_tracker:: - on_mouse_move ( - unsigned long state, - long x, - long y - ) - { - if (!hidden && enabled) - { - parent.invalidate_rectangle(rect); - draggable::on_mouse_move(state,x,y); - - long dx = 0; - long dy = 0; - if (click_x != -1) - dx = click_x; - if (click_y != -1) - dy = click_y; - - sout.str(""); - sout << "y: " << y - dy; - y_label.set_text(sout.str()); - - sout.str(""); - sout << "x: " << x - dx; - x_label.set_text(sout.str()); - } - } - -// ---------------------------------------------------------------------------------------- - - void mouse_tracker:: - on_drag ( - ) - { - nr.set_pos(rect.left(),rect.top()); - x_label.set_pos(rect.left()+offset,rect.top()+offset); - y_label.set_pos(x_label.get_rect().left(), x_label.get_rect().bottom()+3); - - long x = 0; - long y = 0; - if (click_x != -1) - x = click_x; - if (click_y != -1) - y = click_y; - - sout.str(""); - sout << "y: " << lasty - y; - y_label.set_text(sout.str()); - - sout.str(""); - sout << "x: " << lastx - x; - x_label.set_text(sout.str()); - } - -// ---------------------------------------------------------------------------------------- - - void mouse_tracker:: - draw ( - const canvas& c - ) const - { - fill_rect(c, rect,rgb_pixel(212,208,200)); - draw_pixel(c, point(click_x,click_y),rgb_pixel(255,0,0)); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // class list_box -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - namespace list_box_helper{ - template - list_box:: - list_box( - drawable_window& w - ) : - scrollable_region(w,MOUSE_WHEEL|MOUSE_CLICK), - ms_enabled(false), - last_selected(0) - { - set_vertical_scroll_increment(mfont->height()); - set_horizontal_scroll_increment(mfont->height()); - - style.reset(new list_box_style_default()); - enable_events(); - } - -// ---------------------------------------------------------------------------------------- - - template - list_box:: - ~list_box( - ) - { - disable_events(); - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - template - void list_box:: - set_main_font ( - const shared_ptr_thread_safe& f - ) - { - auto_mutex M(m); - mfont = f; - // recompute the sizes of all the items - for (unsigned long i = 0; i < items.size(); ++i) - { - mfont->compute_size(items[i].name,items[i].width, items[i].height); - } - set_vertical_scroll_increment(mfont->height()); - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - template - bool list_box:: - is_selected ( - unsigned long index - ) const - { - auto_mutex M(m); - DLIB_ASSERT ( index < size() , - "\tbool list_box::is_selected(index)" - << "\n\tindex: " << index - << "\n\tsize(): " << size() ); - - return items[index].is_selected; - } - -// ---------------------------------------------------------------------------------------- - - template - void list_box:: - select ( - unsigned long index - ) - { - auto_mutex M(m); - DLIB_ASSERT ( index < size() , - "\tvoid list_box::select(index)" - << "\n\tindex: " << index - << "\n\tsize(): " << size() ); - - last_selected = index; - items[index].is_selected = true; - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - template - void list_box:: - unselect ( - unsigned long index - ) - { - auto_mutex M(m); - DLIB_ASSERT ( index < size() , - "\tvoid list_box::unselect(index)" - << "\n\tindex: " << index - << "\n\tsize(): " << size() ); - items[index].is_selected = false; - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - template - const S& list_box::operator [] ( - unsigned long index - ) const - { - auto_mutex M(m); - DLIB_ASSERT ( index < size() , - "\tconst std::string& list_box::operator[](index)" - << "\n\tindex: " << index - << "\n\tsize(): " << size() ); - return items[index].name; - } - -// ---------------------------------------------------------------------------------------- - - template - bool list_box:: - multiple_select_enabled ( - ) const - { - auto_mutex M(m); - return ms_enabled; - } - -// ---------------------------------------------------------------------------------------- - - template - void list_box:: - enable_multiple_select ( - ) - { - auto_mutex M(m); - ms_enabled = true; - } - -// ---------------------------------------------------------------------------------------- - - template - void list_box:: - disable_multiple_select ( - ) - { - auto_mutex M(m); - ms_enabled = false; - } - -// ---------------------------------------------------------------------------------------- - - template - bool list_box:: - at_start ( - ) const - { - auto_mutex M(m); - return items.at_start(); - } - -// ---------------------------------------------------------------------------------------- - - template - void list_box:: - reset ( - ) const - { - auto_mutex M(m); - items.reset(); - } - -// ---------------------------------------------------------------------------------------- - - template - bool list_box:: - current_element_valid ( - ) const - { - auto_mutex M(m); - return items.current_element_valid(); - } - -// ---------------------------------------------------------------------------------------- - - template - const S &list_box:: - element ( - ) const - { - auto_mutex M(m); - DLIB_ASSERT ( current_element_valid() , - "\tconst std::string& list_box::element()" - ); - return items.element().name; - } - -// ---------------------------------------------------------------------------------------- - - template - const S &list_box:: - element ( - ) - { - auto_mutex M(m); - DLIB_ASSERT ( current_element_valid() , - "\tconst std::string& list_box::element()" - ); - return items.element().name; - } - -// ---------------------------------------------------------------------------------------- - - template - bool list_box:: - move_next ( - ) const - { - auto_mutex M(m); - return items.move_next(); - } - -// ---------------------------------------------------------------------------------------- - - template - unsigned long list_box:: - size ( - ) const - { - auto_mutex M(m); - return items.size(); - } - -// ---------------------------------------------------------------------------------------- - - template - void list_box:: - draw ( - const canvas& c - ) const - { - scrollable_region::draw(c); - - rectangle area = display_rect().intersect(c); - if (area.is_empty()) - return; - - style->draw_list_box_background(c, display_rect(), enabled); - - long y = total_rect().top(); - for (unsigned long i = 0; i < items.size(); ++i) - { - if (y+(long)items[i].height <= area.top()) - { - y += items[i].height; - continue; - } - - rectangle r(total_rect().left(), y, display_rect().right(), y+items[i].height-1); - - style->draw_list_box_item(c,r, display_rect(), enabled, *mfont, items[i].name, items[i].is_selected); - - - y += items[i].height; - - if (y > area.bottom()) - break; - } - } - -// ---------------------------------------------------------------------------------------- - - template - void list_box:: - on_mouse_down ( - unsigned long btn, - unsigned long state, - long x, - long y, - bool is_double_click - ) - { - if (display_rect().contains(x,y) && btn == base_window::LEFT && enabled && !hidden ) - { - if ( ms_enabled == false || - ((!(state&base_window::CONTROL)) && !(state&base_window::SHIFT))) - { - items.reset(); - while (items.move_next()) - { - items.element().is_selected = false; - } - } - - y -= total_rect().top(); - long h = 0; - for (unsigned long i = 0; i < items.size(); ++i) - { - h += items[i].height; - if (h >= y) - { - if (ms_enabled) - { - if (state&base_window::CONTROL) - { - items[i].is_selected = !items[i].is_selected; - if (items[i].is_selected) - last_selected = i; - } - else if (state&base_window::SHIFT) - { - // we want to select everything between (and including) the - // current thing clicked and last_selected. - const unsigned long first = std::min(i,last_selected); - const unsigned long last = std::max(i,last_selected); - for (unsigned long j = first; j <= last; ++j) - items[j].is_selected = true; - } - else - { - items[i].is_selected = true; - last_selected = i; - if (is_double_click && event_handler.is_set()) - event_handler(i); - else if (single_click_event_handler.is_set()) - single_click_event_handler(i); - } - } - else - { - items[i].is_selected = true; - last_selected = i; - if (is_double_click && event_handler.is_set()) - event_handler(i); - else if (single_click_event_handler.is_set()) - single_click_event_handler(i); - } - - break; - } - } - - parent.invalidate_rectangle(rect); - } - } - -// ---------------------------------------------------------------------------------------- - - template - unsigned long list_box:: - get_selected ( - ) const - { - auto_mutex M(m); - DLIB_ASSERT ( multiple_select_enabled() == false, - "\tunsigned long list_box::get_selected()" - ); - for (unsigned long i = 0; i < items.size(); ++i) - { - if (items[i].is_selected) - return i; - } - return items.size(); - } -// ---------------------------------------------------------------------------------------- - - // making instance of template - template class list_box; - template class list_box; - template class list_box; - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // function message_box() -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - namespace message_box_helper - { - void box_win:: - initialize ( - ) - { - msg.set_pos(20,20); - msg.set_text(message); - rectangle msg_rect = msg.get_rect(); - btn_ok.set_name("OK"); - btn_ok.set_size(60,btn_ok.height()); - if (msg_rect.width() >= 60) - btn_ok.set_pos(msg_rect.width()/2+msg_rect.left()-btn_ok.width()/2,msg_rect.bottom()+15); - else - btn_ok.set_pos(20,msg_rect.bottom()+15); - btn_ok.set_click_handler(*this,&box_win::on_click); - - rectangle size = btn_ok.get_rect() + msg_rect; - set_size(size.right()+20,size.bottom()+20); - - - show(); - set_title(title); - } - - // ------------------------------------------------------------------------------------ - - box_win:: - box_win ( - const std::string& title_, - const std::string& message_ - ) : - drawable_window(false), - title(convert_mbstring_to_wstring(title_)), - message(convert_mbstring_to_wstring(message_)), - msg(*this), - btn_ok(*this) - { - initialize(); - } - - // ------------------------------------------------------------------------------------ - - box_win:: - box_win ( - const std::wstring& title_, - const std::wstring& message_ - ) : - drawable_window(false), - title(title_), - message(message_), - msg(*this), - btn_ok(*this) - { - initialize(); - } - - // ------------------------------------------------------------------------------------ - - box_win:: - box_win ( - const dlib::ustring& title_, - const dlib::ustring& message_ - ) : - drawable_window(false), - title(convert_utf32_to_wstring(title_)), - message(convert_utf32_to_wstring(message_)), - msg(*this), - btn_ok(*this) - { - initialize(); - } - - // ------------------------------------------------------------------------------------ - - box_win:: - ~box_win ( - ) - { - close_window(); - } - - // ------------------------------------------------------------------------------------ - - void box_win:: - deleter_thread ( - void* param - ) - { - // The point of this extra event_handler stuff is to allow the user - // to end the program from within the callback. So we want to destroy the - // window *before* we call their callback. - box_win& w = *static_cast(param); - w.close_window(); - any_function event_handler(w.event_handler); - delete &w; - if (event_handler.is_set()) - event_handler(); - } - - // ------------------------------------------------------------------------------------ - - void box_win:: - on_click ( - ) - { - hide(); - create_new_thread(&deleter_thread,this); - } - - // ------------------------------------------------------------------------------------ - - base_window::on_close_return_code box_win:: - on_window_close ( - ) - { - // The point of this extra event_handler stuff is to allow the user - // to end the program within the callback. So we want to destroy the - // window *before* we call their callback. - any_function event_handler_copy(event_handler); - delete this; - if (event_handler_copy.is_set()) - event_handler_copy(); - return CLOSE_WINDOW; - } - - // ------------------------------------------------------------------------------------ - // ------------------------------------------------------------------------------------ - // ------------------------------------------------------------------------------------ - - void blocking_box_win:: - initialize ( - ) - { - msg.set_pos(20,20); - msg.set_text(message); - rectangle msg_rect = msg.get_rect(); - btn_ok.set_name("OK"); - btn_ok.set_size(60,btn_ok.height()); - if (msg_rect.width() >= 60) - btn_ok.set_pos(msg_rect.width()/2+msg_rect.left()-btn_ok.width()/2,msg_rect.bottom()+15); - else - btn_ok.set_pos(20,msg_rect.bottom()+15); - btn_ok.set_click_handler(*this,&blocking_box_win::on_click); - - rectangle size = btn_ok.get_rect() + msg_rect; - set_size(size.right()+20,size.bottom()+20); - - - set_title(title); - show(); - } - - // ------------------------------------------------------------------------------------ - - blocking_box_win:: - blocking_box_win ( - const std::string& title_, - const std::string& message_ - ) : - drawable_window(false), - title(convert_mbstring_to_wstring(title_)), - message(convert_mbstring_to_wstring(message_)), - msg(*this), - btn_ok(*this) - { - initialize(); - } - - // ------------------------------------------------------------------------------------ - - blocking_box_win:: - blocking_box_win ( - const std::wstring& title_, - const std::wstring& message_ - ) : - drawable_window(false), - title(title_), - message(message_), - msg(*this), - btn_ok(*this) - { - initialize(); - } - - // ------------------------------------------------------------------------------------ - - blocking_box_win:: - blocking_box_win ( - const dlib::ustring& title_, - const dlib::ustring& message_ - ) : - drawable_window(false), - title(convert_utf32_to_wstring(title_)), - message(convert_utf32_to_wstring(message_)), - msg(*this), - btn_ok(*this) - { - initialize(); - } - - // ------------------------------------------------------------------------------------ - - blocking_box_win:: - ~blocking_box_win ( - ) - { - close_window(); - } - - // ------------------------------------------------------------------------------------ - - void blocking_box_win:: - on_click ( - ) - { - close_window(); - } - - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // function open_file_box() -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - namespace open_file_box_helper - { - box_win:: - box_win ( - const std::string& title, - bool has_text_field - ) : - lbl_dirs(*this), - lbl_files(*this), - lbl_file_name(*this), - lb_dirs(*this), - lb_files(*this), - btn_ok(*this), - btn_cancel(*this), - btn_root(*this), - tf_file_name(*this) - { - if (has_text_field == false) - { - tf_file_name.hide(); - lbl_file_name.hide(); - } - else - { - lbl_file_name.set_text("File: "); - } - - cur_dir = -1; - set_size(500,300); - - lbl_dirs.set_text("Directories:"); - lbl_files.set_text("Files:"); - btn_ok.set_name("Ok"); - btn_cancel.set_name("Cancel"); - btn_root.set_name("/"); - - btn_root.set_click_handler(*this,&box_win::on_root_click); - btn_cancel.set_click_handler(*this,&box_win::on_cancel_click); - btn_ok.set_click_handler(*this,&box_win::on_open_click); - lb_dirs.set_double_click_handler(*this,&box_win::on_dirs_click); - lb_files.set_click_handler(*this,&box_win::on_files_click); - lb_files.set_double_click_handler(*this,&box_win::on_files_double_click); - - - btn_root.set_pos(5,5); - - set_sizes(); - set_title(title); - - on_root_click(); - - // make it so that the file box starts out in our current working - // directory - std::string full_name(get_current_dir()); - - while (full_name.size() > 0) - { - std::string::size_type pos = full_name.find_first_of("\\/"); - std::string left(full_name.substr(0,pos)); - if (pos != std::string::npos) - full_name = full_name.substr(pos+1); - else - full_name.clear(); - - if (left.size() > 0) - enter_folder(left); - } - - - show(); - } - - // ------------------------------------------------------------------------------------ - - box_win:: - ~box_win ( - ) - { - close_window(); - } - - // ------------------------------------------------------------------------------------ - - void box_win:: - set_sizes( - ) - { - unsigned long width, height; - get_size(width,height); - - - if (lbl_file_name.is_hidden()) - { - lbl_dirs.set_pos(0,btn_root.bottom()+5); - lb_dirs.set_pos(0,lbl_dirs.bottom()); - lb_dirs.set_size(width/2,height-lb_dirs.top()-btn_cancel.height()-10); - - lbl_files.set_pos(lb_dirs.right(),btn_root.bottom()+5); - lb_files.set_pos(lb_dirs.right(),lbl_files.bottom()); - lb_files.set_size(width-lb_files.left(),height-lb_files.top()-btn_cancel.height()-10); - - btn_ok.set_pos(width - btn_ok.width()-25,lb_files.bottom()+5); - btn_cancel.set_pos(btn_ok.left() - btn_cancel.width()-5,lb_files.bottom()+5); - } - else - { - - lbl_dirs.set_pos(0,btn_root.bottom()+5); - lb_dirs.set_pos(0,lbl_dirs.bottom()); - lb_dirs.set_size(width/2,height-lb_dirs.top()-btn_cancel.height()-10-tf_file_name.height()); - - lbl_files.set_pos(lb_dirs.right(),btn_root.bottom()+5); - lb_files.set_pos(lb_dirs.right(),lbl_files.bottom()); - lb_files.set_size(width-lb_files.left(),height-lb_files.top()-btn_cancel.height()-10-tf_file_name.height()); - - lbl_file_name.set_pos(lb_files.left(), lb_files.bottom()+8); - tf_file_name.set_pos(lbl_file_name.right(), lb_files.bottom()+5); - tf_file_name.set_width(width-tf_file_name.left()-5); - - btn_ok.set_pos(width - btn_ok.width()-25,tf_file_name.bottom()+5); - btn_cancel.set_pos(btn_ok.left() - btn_cancel.width()-5,tf_file_name.bottom()+5); - } - - } - - // ------------------------------------------------------------------------------------ - - void box_win:: - on_window_resized ( - ) - { - set_sizes(); - } - - // ------------------------------------------------------------------------------------ - - void box_win:: - deleter_thread ( - ) - { - close_window(); - delete this; - } - - // ------------------------------------------------------------------------------------ - - void box_win:: - enter_folder ( - const std::string& folder_name - ) - { - if (btn_root.is_checked()) - btn_root.set_unchecked(); - if (cur_dir != -1) - sob[cur_dir]->set_unchecked(); - - - const std::string old_path = path; - const long old_cur_dir = cur_dir; - - scoped_ptr new_btn(new toggle_button(*this)); - new_btn->set_name(folder_name); - new_btn->set_click_handler(*this,&box_win::on_path_button_click); - - // remove any path buttons that won't be part of the path anymore - if (sob.size()) - { - while (sob.size() > (unsigned long)(cur_dir+1)) - { - scoped_ptr junk; - sob.remove(cur_dir+1,junk); - } - } - - if (sob.size()) - new_btn->set_pos(sob[sob.size()-1]->right()+5,sob[sob.size()-1]->top()); - else - new_btn->set_pos(btn_root.right()+5,btn_root.top()); - - cur_dir = sob.size(); - sob.add(sob.size(),new_btn); - - path += folder_name + directory::get_separator(); - if (set_dir(prefix + path) == false) - { - sob.remove(sob.size()-1,new_btn); - path = old_path; - cur_dir = old_cur_dir; - } - else - { - - sob[cur_dir]->set_checked(); - } - } - - // ------------------------------------------------------------------------------------ - - void box_win:: - on_dirs_click ( - unsigned long idx - ) - { - enter_folder(lb_dirs[idx]); - } - - // ------------------------------------------------------------------------------------ - - void box_win:: - on_files_click ( - unsigned long idx - ) - { - if (tf_file_name.is_hidden() == false) - { - tf_file_name.set_text(lb_files[idx]); - } - } - - // ------------------------------------------------------------------------------------ - - void box_win:: - on_files_double_click ( - unsigned long - ) - { - on_open_click(); - } - - // ------------------------------------------------------------------------------------ - - void box_win:: - on_cancel_click ( - ) - { - hide(); - create_new_thread(*this); - } - - // ------------------------------------------------------------------------------------ - - void box_win:: - on_open_click ( - ) - { - if (lb_files.get_selected() != lb_files.size() || tf_file_name.text().size() > 0) - { - if (event_handler.is_set()) - { - if (tf_file_name.is_hidden()) - event_handler(prefix + path + lb_files[lb_files.get_selected()]); - else if (tf_file_name.text().size() > 0) - event_handler(prefix + path + tf_file_name.text()); - } - hide(); - create_new_thread(*this); - } - } - - // ------------------------------------------------------------------------------------ - - void box_win:: - on_path_button_click ( - toggle_button& btn - ) - { - if (btn_root.is_checked()) - btn_root.set_unchecked(); - if (cur_dir != -1) - sob[cur_dir]->set_unchecked(); - std::string new_path; - - for (unsigned long i = 0; i < sob.size(); ++i) - { - new_path += sob[i]->name() + directory::get_separator(); - if (sob[i].get() == &btn) - { - cur_dir = i; - sob[i]->set_checked(); - break; - } - } - if (path != new_path) - { - path = new_path; - set_dir(prefix+path); - } - } - - // ------------------------------------------------------------------------------------ - - struct case_insensitive_compare - { - bool operator() ( - const std::string& a, - const std::string& b - ) const - { - std::string::size_type i, size; - size = std::min(a.size(),b.size()); - for (i = 0; i < size; ++i) - { - if (std::tolower(a[i]) < std::tolower(b[i])) - return true; - else if (std::tolower(a[i]) > std::tolower(b[i])) - return false; - } - if (a.size() < b.size()) - return true; - else - return false; - } - }; - - // ------------------------------------------------------------------------------------ - - bool box_win:: - set_dir ( - const std::string& dir - ) - { - try - { - directory d(dir); - queue::kernel_1a_c qod; - queue::kernel_1a_c qof; - queue::sort_1a_c qos; - d.get_dirs(qod); - d.get_files(qof); - - qod.reset(); - while (qod.move_next()) - { - std::string temp = qod.element().name(); - qos.enqueue(temp); - } - qos.sort(case_insensitive_compare()); - lb_dirs.load(qos); - qos.clear(); - - qof.reset(); - while (qof.move_next()) - { - std::string temp = qof.element().name(); - qos.enqueue(temp); - } - qos.sort(case_insensitive_compare()); - lb_files.load(qos); - return true; - } - catch (directory::listing_error& ) - { - return false; - } - catch (directory::dir_not_found&) - { - return false; - } - } - - // ------------------------------------------------------------------------------------ - - void box_win:: - on_root_click ( - ) - { - btn_root.set_checked(); - if (cur_dir != -1) - sob[cur_dir]->set_unchecked(); - - queue::kernel_1a_c qod, qod2; - queue::kernel_1a_c qof; - queue::sort_1a_c qos; - get_filesystem_roots(qod); - path.clear(); - cur_dir = -1; - if (qod.size() == 1) - { - qod.current().get_files(qof); - qod.current().get_dirs(qod2); - prefix = qod.current().full_name(); - - qod2.reset(); - while (qod2.move_next()) - { - std::string temp = qod2.element().name(); - qos.enqueue(temp); - } - qos.sort(case_insensitive_compare()); - lb_dirs.load(qos); - qos.clear(); - - qof.reset(); - while (qof.move_next()) - { - std::string temp = qof.element().name(); - qos.enqueue(temp); - } - qos.sort(case_insensitive_compare()); - lb_files.load(qos); - } - else - { - prefix.clear(); - qod.reset(); - while (qod.move_next()) - { - std::string temp = qod.element().full_name(); - temp = temp.substr(0,temp.size()-1); - qos.enqueue(temp); - } - qos.sort(case_insensitive_compare()); - lb_dirs.load(qos); - qos.clear(); - lb_files.load(qos); - } - } - - // ------------------------------------------------------------------------------------ - - base_window::on_close_return_code box_win:: - on_window_close ( - ) - { - delete this; - return CLOSE_WINDOW; - } - - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // class menu_bar -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - menu_bar:: - menu_bar( - drawable_window& w - ) : - drawable(w, 0xFFFF), // listen for all events - open_menu(0) - { - adjust_position(); - enable_events(); - } - -// ---------------------------------------------------------------------------------------- - - menu_bar:: - ~menu_bar() - { - disable_events(); - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - void menu_bar:: - set_main_font ( - const shared_ptr_thread_safe& f - ) - { - auto_mutex M(m); - mfont = f; - adjust_position(); - compute_menu_geometry(); - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - void menu_bar:: - set_number_of_menus ( - unsigned long num - ) - { - auto_mutex M(m); - menus.set_max_size(num); - menus.set_size(num); - open_menu = menus.size(); - compute_menu_geometry(); - - for (unsigned long i = 0; i < menus.size(); ++i) - { - menus[i].menu.set_on_hide_handler(*this,&menu_bar::on_popup_hide); - } - - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - unsigned long menu_bar:: - number_of_menus ( - ) const - { - auto_mutex M(m); - return menus.size(); - } - -// ---------------------------------------------------------------------------------------- - - void menu_bar:: - set_menu_name ( - unsigned long idx, - const std::string name, - char underline_ch - ) - { - set_menu_name(idx, convert_mbstring_to_wstring(name), underline_ch); - } - -// ---------------------------------------------------------------------------------------- - - void menu_bar:: - set_menu_name ( - unsigned long idx, - const std::wstring name, - char underline_ch - ) - { - set_menu_name(idx, convert_wstring_to_utf32(name), underline_ch); - } - -// ---------------------------------------------------------------------------------------- - - void menu_bar:: - set_menu_name ( - unsigned long idx, - const dlib::ustring name, - char underline_ch - ) - { - DLIB_ASSERT ( idx < number_of_menus() , - "\tvoid menu_bar::set_menu_name()" - << "\n\tidx: " << idx - << "\n\tnumber_of_menus(): " << number_of_menus() - ); - auto_mutex M(m); - menus[idx].name = name.c_str(); - menus[idx].underline_pos = name.find_first_of(underline_ch); - compute_menu_geometry(); - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - const std::string menu_bar:: - menu_name ( - unsigned long idx - ) const - { - return convert_wstring_to_mbstring(menu_wname(idx)); - } - -// ---------------------------------------------------------------------------------------- - - const std::wstring menu_bar:: - menu_wname ( - unsigned long idx - ) const - { - return convert_utf32_to_wstring(menu_uname(idx)); - } - -// ---------------------------------------------------------------------------------------- - - const dlib::ustring menu_bar:: - menu_uname ( - unsigned long idx - ) const - { - DLIB_ASSERT ( idx < number_of_menus() , - "\tstd::string menu_bar::menu_name()" - << "\n\tidx: " << idx - << "\n\tnumber_of_menus(): " << number_of_menus() - ); - auto_mutex M(m); - return menus[idx].name.c_str(); - } - -// ---------------------------------------------------------------------------------------- - - popup_menu& menu_bar:: - menu ( - unsigned long idx - ) - { - DLIB_ASSERT ( idx < number_of_menus() , - "\tpopup_menu& menu_bar::menu()" - << "\n\tidx: " << idx - << "\n\tnumber_of_menus(): " << number_of_menus() - ); - auto_mutex M(m); - return menus[idx].menu; - } - -// ---------------------------------------------------------------------------------------- - - const popup_menu& menu_bar:: - menu ( - unsigned long idx - ) const - { - DLIB_ASSERT ( idx < number_of_menus() , - "\tconst popup_menu& menu_bar::menu()" - << "\n\tidx: " << idx - << "\n\tnumber_of_menus(): " << number_of_menus() - ); - auto_mutex M(m); - return menus[idx].menu; - } - -// ---------------------------------------------------------------------------------------- - - void menu_bar:: - on_window_resized ( - ) - { - adjust_position(); - hide_menu(); - } - -// ---------------------------------------------------------------------------------------- - - void menu_bar:: - draw ( - const canvas& c - ) const - { - rectangle area(rect.intersect(c)); - if (area.is_empty()) - return; - - const unsigned char opacity = 40; - fill_rect_with_vertical_gradient(c, rect,rgb_alpha_pixel(255,255,255,opacity), - rgb_alpha_pixel(0,0,0,opacity)); - - // first draw the border between the menu and the rest of the window - draw_line(c, point(rect.left(),rect.bottom()-1), - point(rect.right(),rect.bottom()-1), 100); - draw_line(c, point(rect.left(),rect.bottom()), - point(rect.right(),rect.bottom()), 255); - - // now draw all the menu buttons - for (unsigned long i = 0; i < menus.size(); ++i) - { - mfont->draw_string(c,menus[i].rect, menus[i].name ); - if (menus[i].underline_p1 != menus[i].underline_p2) - draw_line(c, menus[i].underline_p1, menus[i].underline_p2); - - if (open_menu == i) - { - fill_rect_with_vertical_gradient(c, menus[i].bgrect,rgb_alpha_pixel(255,255,0,40), rgb_alpha_pixel(0,0,0,40)); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void menu_bar:: - on_window_moved ( - ) - { - hide_menu(); - } - -// ---------------------------------------------------------------------------------------- - - void menu_bar:: - on_focus_lost ( - ) - { - hide_menu(); - } - -// ---------------------------------------------------------------------------------------- - - void menu_bar:: - on_mouse_down ( - unsigned long btn, - unsigned long , - long x, - long y, - bool - ) - { - - if (rect.contains(x,y) == false || btn != (unsigned long)base_window::LEFT) - { - hide_menu(); - return; - } - - unsigned long old_menu = menus.size(); - - // if a menu is currently open then save its index - if (open_menu != menus.size()) - { - old_menu = open_menu; - hide_menu(); - } - - // figure out which menu should be open if any - for (unsigned long i = 0; i < menus.size(); ++i) - { - if (menus[i].bgrect.contains(x,y)) - { - if (old_menu != i) - show_menu(i); - - break; - } - } - - } - -// ---------------------------------------------------------------------------------------- - - void menu_bar:: - on_mouse_move ( - unsigned long , - long x, - long y - ) - { - // if the mouse is over the menu_bar and some menu is currently open - if (rect.contains(x,y) && open_menu != menus.size()) - { - // if the mouse is still in the same rectangle then don't do anything - if (menus[open_menu].bgrect.contains(x,y) == false) - { - // figure out which menu should be instead - for (unsigned long i = 0; i < menus.size(); ++i) - { - if (menus[i].bgrect.contains(x,y)) - { - show_menu(i); - break; - } - } - - } - } - } - -// ---------------------------------------------------------------------------------------- - - void menu_bar:: - on_keydown ( - unsigned long key, - bool is_printable, - unsigned long state - ) - { - if (state&base_window::KBD_MOD_ALT) - { - // check if the key matches any of our underlined keys - for (unsigned long i = 0; i < menus.size(); ++i) - { - // if we have found a matching key - if (is_printable && - menus[i].underline_pos != std::string::npos && - std::tolower(menus[i].name[menus[i].underline_pos]) == std::tolower(key)) - { - show_menu(i); - menus[open_menu].menu.select_first_item(); - return; - } - } - } - - if (open_menu != menus.size()) - { - unsigned long i = open_menu; - // if the submenu doesn't use this key for something then we will - if (menus[open_menu].menu.forwarded_on_keydown(key,is_printable,state) == false) - { - if (key == base_window::KEY_LEFT) - { - i = (i+menus.size()-1)%menus.size(); - show_menu(i); - menus[open_menu].menu.select_first_item(); - } - else if (key == base_window::KEY_RIGHT) - { - i = (i+1)%menus.size(); - show_menu(i); - menus[open_menu].menu.select_first_item(); - } - else if (key == base_window::KEY_ESC) - { - hide_menu(); - } - } - } - } - -// ---------------------------------------------------------------------------------------- - - void menu_bar:: - show_menu ( - unsigned long i - ) - { - rectangle temp; - - // menu already open so do nothing - if (i == open_menu) - return; - - // if a menu is currently open - if (open_menu != menus.size()) - { - menus[open_menu].menu.hide(); - temp = menus[open_menu].bgrect; - } - - // display the new menu - open_menu = i; - long wx, wy; - parent.get_pos(wx,wy); - wx += menus[i].bgrect.left(); - wy += menus[i].bgrect.bottom()+1; - menus[i].menu.set_pos(wx,wy); - menus[i].menu.show(); - parent.invalidate_rectangle(menus[i].bgrect+temp); - } - -// ---------------------------------------------------------------------------------------- - - void menu_bar:: - hide_menu ( - ) - { - // if a menu is currently open - if (open_menu != menus.size()) - { - menus[open_menu].menu.hide(); - parent.invalidate_rectangle(menus[open_menu].bgrect); - open_menu = menus.size(); - } - } - -// ---------------------------------------------------------------------------------------- - - void menu_bar:: - on_popup_hide ( - ) - { - // if a menu is currently open - if (open_menu != menus.size()) - { - parent.invalidate_rectangle(menus[open_menu].bgrect); - open_menu = menus.size(); - } - } - -// ---------------------------------------------------------------------------------------- - - void menu_bar:: - compute_menu_geometry ( - ) - { - long x = 7; - long bg_x = 0; - for (unsigned long i = 0; i < menus.size(); ++i) - { - // compute the locations of the text rectangles - menus[i].rect.set_top(5); - menus[i].rect.set_left(x); - menus[i].rect.set_bottom(rect.bottom()-2); - - unsigned long width, height; - mfont->compute_size(menus[i].name,width,height); - menus[i].rect = resize_rect_width(menus[i].rect, width); - x = menus[i].rect.right()+10; - - menus[i].bgrect.set_top(0); - menus[i].bgrect.set_left(bg_x); - menus[i].bgrect.set_bottom(rect.bottom()-2); - menus[i].bgrect.set_right(x-5); - bg_x = menus[i].bgrect.right()+1; - - if (menus[i].underline_pos != std::string::npos) - { - // now compute the location of the underline bar - rectangle r1 = mfont->compute_cursor_rect( - menus[i].rect, - menus[i].name, - menus[i].underline_pos); - - rectangle r2 = mfont->compute_cursor_rect( - menus[i].rect, - menus[i].name, - menus[i].underline_pos+1); - - menus[i].underline_p1.x() = r1.left()+1; - menus[i].underline_p2.x() = r2.left()-1; - menus[i].underline_p1.y() = r1.bottom()-mfont->height()+mfont->ascender()+2; - menus[i].underline_p2.y() = r2.bottom()-mfont->height()+mfont->ascender()+2; - } - else - { - // there is no underline in this case - menus[i].underline_p1 = menus[i].underline_p2; - } - - } - } - -// ---------------------------------------------------------------------------------------- - - void menu_bar:: - adjust_position ( - ) - { - unsigned long width, height; - rectangle old(rect); - parent.get_size(width,height); - rect.set_left(0); - rect.set_top(0); - rect = resize_rect(rect,width,mfont->height()+10); - parent.invalidate_rectangle(old+rect); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// class text_grid -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - text_grid:: - text_grid ( - drawable_window& w - ) : - scrollable_region(w, KEYBOARD_EVENTS | MOUSE_CLICK | FOCUS_EVENTS ), - has_focus(false), - cursor_timer(*this,&text_grid::timer_action), - border_color_(128,128,128) - { - - cursor_timer.set_delay_time(500); - set_vertical_scroll_increment(10); - set_horizontal_scroll_increment(10); - enable_events(); - } - -// ---------------------------------------------------------------------------------------- - - text_grid:: - ~text_grid ( - ) - { - // Disable all further events for this drawable object. We have to do this - // because we don't want draw() events coming to this object while or after - // it has been destructed. - disable_events(); - - // wait for the timer to stop doing its thing - cursor_timer.stop_and_wait(); - // Tell the parent window to redraw its area that previously contained this - // drawable object. - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - set_grid_size ( - unsigned long rows, - unsigned long cols - ) - { - auto_mutex M(m); - row_height.set_max_size(rows); - row_height.set_size(rows); - - col_width.set_max_size(cols); - col_width.set_size(cols); - - grid.set_size(rows,cols); - - for (unsigned long i = 0; i < row_height.size(); ++i) - row_height[i] = (mfont->height()*3)/2; - for (unsigned long i = 0; i < col_width.size(); ++i) - col_width[i] = mfont->height()*5; - - compute_total_rect(); - compute_bg_rects(); - } - -// ---------------------------------------------------------------------------------------- - - unsigned long text_grid:: - number_of_columns ( - ) const - { - auto_mutex M(m); - return grid.nc(); - } - -// ---------------------------------------------------------------------------------------- - - unsigned long text_grid:: - number_of_rows ( - ) const - { - auto_mutex M(m); - return grid.nr(); - } - -// ---------------------------------------------------------------------------------------- - - int text_grid:: - next_free_user_event_number ( - ) const - { - return scrollable_region::next_free_user_event_number()+1; - } - -// ---------------------------------------------------------------------------------------- - - rgb_pixel text_grid:: - border_color ( - ) const - { - auto_mutex M(m); - return border_color_; - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - set_border_color ( - rgb_pixel color - ) - { - auto_mutex M(m); - border_color_ = color; - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - const std::string text_grid:: - text ( - unsigned long row, - unsigned long col - ) const - { - return convert_wstring_to_mbstring(wtext(row, col)); - } - -// ---------------------------------------------------------------------------------------- - - const std::wstring text_grid:: - wtext ( - unsigned long row, - unsigned long col - ) const - { - return convert_utf32_to_wstring(utext(row, col)); - } - -// ---------------------------------------------------------------------------------------- - - const dlib::ustring text_grid:: - utext ( - unsigned long row, - unsigned long col - ) const - { - auto_mutex M(m); - DLIB_ASSERT ( row < number_of_rows() && col < number_of_columns(), - "\tconst std::string text_grid::text(row,col)" - << "\n\trow: " << row - << "\n\tcol: " << col - << "\n\tnumber_of_rows(): " << number_of_rows() - << "\n\tnumber_of_columns(): " << number_of_columns() - << "\n\tthis: " << this - ); - return grid[row][col].text.c_str(); - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - set_text ( - unsigned long row, - unsigned long col, - const std::string& str - ) - { - set_text(row, col, convert_mbstring_to_wstring(str)); - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - set_text ( - unsigned long row, - unsigned long col, - const std::wstring& str - ) - { - set_text(row, col, convert_wstring_to_utf32(str)); - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - set_text ( - unsigned long row, - unsigned long col, - const dlib::ustring& str - ) - { - auto_mutex M(m); - DLIB_ASSERT ( row < number_of_rows() && col < number_of_columns(), - "\tvoid text_grid::set_text(row,col)" - << "\n\trow: " << row - << "\n\tcol: " << col - << "\n\tnumber_of_rows(): " << number_of_rows() - << "\n\tnumber_of_columns(): " << number_of_columns() - << "\n\tthis: " << this - ); - grid[row][col].text = str.c_str(); - parent.invalidate_rectangle(get_text_rect(row,col)); - } - -// ---------------------------------------------------------------------------------------- - - const rgb_pixel text_grid:: - text_color ( - unsigned long row, - unsigned long col - ) const - { - auto_mutex M(m); - DLIB_ASSERT ( row < number_of_rows() && col < number_of_columns(), - "\tconst rgb_pixel text_grid::text_color(row,col)" - << "\n\trow: " << row - << "\n\tcol: " << col - << "\n\tnumber_of_rows(): " << number_of_rows() - << "\n\tnumber_of_columns(): " << number_of_columns() - << "\n\tthis: " << this - ); - return grid[row][col].text_color; - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - set_text_color ( - unsigned long row, - unsigned long col, - const rgb_pixel color - ) - { - auto_mutex M(m); - DLIB_ASSERT ( row < number_of_rows() && col < number_of_columns(), - "\tvoid text_grid::set_text_color(row,col,color)" - << "\n\trow: " << row - << "\n\tcol: " << col - << "\n\tnumber_of_rows(): " << number_of_rows() - << "\n\tnumber_of_columns(): " << number_of_columns() - << "\n\tthis: " << this - ); - grid[row][col].text_color = color; - parent.invalidate_rectangle(get_text_rect(row,col)); - } - -// ---------------------------------------------------------------------------------------- - - const rgb_pixel text_grid:: - background_color ( - unsigned long row, - unsigned long col - ) const - { - auto_mutex M(m); - DLIB_ASSERT ( row < number_of_rows() && col < number_of_columns(), - "\tconst rgb_pixel text_grid::background_color(row,col,color)" - << "\n\trow: " << row - << "\n\tcol: " << col - << "\n\tnumber_of_rows(): " << number_of_rows() - << "\n\tnumber_of_columns(): " << number_of_columns() - << "\n\tthis: " << this - ); - return grid[row][col].bg_color; - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - set_background_color ( - unsigned long row, - unsigned long col, - const rgb_pixel color - ) - { - auto_mutex M(m); - DLIB_ASSERT ( row < number_of_rows() && col < number_of_columns(), - "\tvoid text_grid::set_background_color(row,col,color)" - << "\n\trow: " << row - << "\n\tcol: " << col - << "\n\tnumber_of_rows(): " << number_of_rows() - << "\n\tnumber_of_columns(): " << number_of_columns() - << "\n\tthis: " << this - ); - grid[row][col].bg_color = color; - parent.invalidate_rectangle(get_bg_rect(row,col)); - } - -// ---------------------------------------------------------------------------------------- - - bool text_grid:: - is_editable ( - unsigned long row, - unsigned long col - ) const - { - auto_mutex M(m); - DLIB_ASSERT ( row < number_of_rows() && col < number_of_columns(), - "\tbool text_grid::is_editable(row,col)" - << "\n\trow: " << row - << "\n\tcol: " << col - << "\n\tnumber_of_rows(): " << number_of_rows() - << "\n\tnumber_of_columns(): " << number_of_columns() - << "\n\tthis: " << this - ); - return grid[row][col].is_editable; - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - set_editable ( - unsigned long row, - unsigned long col, - bool editable - ) - { - auto_mutex M(m); - DLIB_ASSERT ( row < number_of_rows() && col < number_of_columns(), - "\tvoid text_grid::set_editable(row,col,editable)" - << "\n\trow: " << row - << "\n\tcol: " << col - << "\n\tnumber_of_rows(): " << number_of_rows() - << "\n\tnumber_of_columns(): " << number_of_columns() - << "\n\teditable: " << editable - << "\n\tthis: " << this - ); - grid[row][col].is_editable = editable; - if (has_focus && active_row == static_cast(row) && active_col == static_cast(col)) - { - drop_input_focus(); - } - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - set_column_width ( - unsigned long col, - unsigned long width - ) - { - auto_mutex M(m); - DLIB_ASSERT ( col < number_of_columns(), - "\tvoid text_grid::set_column_width(col,width)" - << "\n\tcol: " << col - << "\n\tnumber_of_columns(): " << number_of_columns() - << "\n\twidth: " << width - << "\n\tthis: " << this - ); - col_width[col] = width; - compute_total_rect(); - compute_bg_rects(); - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - set_row_height ( - unsigned long row, - unsigned long height - ) - { - auto_mutex M(m); - DLIB_ASSERT ( row < number_of_rows() , - "\tvoid text_grid::set_row_height(row,height)" - << "\n\trow: " << row - << "\n\tnumber_of_rows(): " << number_of_rows() - << "\n\theight: " << height - << "\n\tthis: " << this - ); - row_height[row] = height; - compute_total_rect(); - compute_bg_rects(); - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - disable ( - ) - { - auto_mutex M(m); - scrollable_region::disable(); - drop_input_focus(); - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - hide ( - ) - { - auto_mutex M(m); - scrollable_region::hide(); - drop_input_focus(); - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - on_user_event ( - int num - ) - { - // ignore this user event if it isn't for us - if (num != scrollable_region::next_free_user_event_number()) - return; - - if (has_focus && !recent_cursor_move && enabled && !hidden) - { - show_cursor = !show_cursor; - parent.invalidate_rectangle(get_text_rect(active_row,active_col)); - } - recent_cursor_move = false; - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - timer_action ( - ) - { - parent.trigger_user_event(this,scrollable_region::next_free_user_event_number()); - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - compute_bg_rects ( - ) - { - // loop over each element in the grid and figure out what its rectangle should be - // with respect to the total_rect() - point p1, p2; - p1.y() = total_rect().top(); - for (long row = 0; row < grid.nr(); ++row) - { - p1.x() = total_rect().left(); - p2.y() = p1.y() + row_height[row]-1; - for (long col = 0; col < grid.nc(); ++col) - { - // if this is the last box in this row make it super wide so that it always - // goes to the end of the widget - if (col+1 == grid.nc()) - p2.x() = 1000000; - else - p2.x() = p1.x() + col_width[col]-1; - - // at this point p1 is the upper left corner of this box and p2 is the - // lower right corner of the box; - rectangle bg_rect(p1); - bg_rect += p2; - - grid[row][col].bg_rect = translate_rect(bg_rect, -total_rect().left(), -total_rect().top()); - - - p1.x() += 1 + col_width[col]; - } - p1.y() += 1 + row_height[row]; - } - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - compute_total_rect ( - ) - { - if (grid.size() == 0) - { - set_total_rect_size(0,0); - } - else - { - unsigned long width = col_width.size()-1; - unsigned long height = row_height.size()-1; - - for (unsigned long i = 0; i < col_width.size(); ++i) - width += col_width[i]; - for (unsigned long i = 0; i < row_height.size(); ++i) - height += row_height[i]; - - set_total_rect_size(width,height); - } - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - on_keydown ( - unsigned long key, - bool is_printable, - unsigned long state - ) - { - // ignore this event if we are disabled or hidden - if (!enabled || hidden) - return; - - if (has_focus) - { - if (is_printable) - { - // if the user hit the tab key then jump to the next box - if (key == '\t') - { - if (active_col+1 == grid.nc()) - { - if (active_row+1 == grid.nr()) - move_cursor(0,0,0); - else - move_cursor(active_row+1,0,0); - } - else - { - move_cursor(active_row,active_col+1,0); - } - } - if (key == '\n') - { - // ignore the enter key - } - else if (grid[active_row][active_col].is_editable) - { - // insert the key the user pressed into the string - grid[active_row][active_col].text.insert(cursor_pos,1,static_cast(key)); - move_cursor(active_row,active_col,cursor_pos+1); - - if (text_modified_handler.is_set()) - text_modified_handler(active_row,active_col); - } - } - else if ((state & base_window::KBD_MOD_CONTROL)) - { - if (key == base_window::KEY_LEFT) - move_cursor(active_row,active_col-1,0); - else if (key == base_window::KEY_RIGHT) - move_cursor(active_row,active_col+1,0); - else if (key == base_window::KEY_UP) - move_cursor(active_row-1,active_col,0); - else if (key == base_window::KEY_DOWN) - move_cursor(active_row+1,active_col,0); - else if (key == base_window::KEY_END) - move_cursor(active_row,active_col,grid[active_row][active_col].text.size()); - else if (key == base_window::KEY_HOME) - move_cursor(active_row,active_col,0); - } - else - { - if (key == base_window::KEY_LEFT) - move_cursor(active_row,active_col,cursor_pos-1); - else if (key == base_window::KEY_RIGHT) - move_cursor(active_row,active_col,cursor_pos+1); - else if (key == base_window::KEY_UP) - move_cursor(active_row-1,active_col,0); - else if (key == base_window::KEY_DOWN) - move_cursor(active_row+1,active_col,0); - else if (key == base_window::KEY_END) - move_cursor(active_row,active_col,grid[active_row][active_col].text.size()); - else if (key == base_window::KEY_HOME) - move_cursor(active_row,active_col,0); - else if (key == base_window::KEY_BACKSPACE) - { - if (cursor_pos > 0 && grid[active_row][active_col].is_editable) - { - grid[active_row][active_col].text.erase( - grid[active_row][active_col].text.begin()+cursor_pos-1, - grid[active_row][active_col].text.begin()+cursor_pos); - move_cursor(active_row,active_col,cursor_pos-1); - - if (text_modified_handler.is_set()) - text_modified_handler(active_row,active_col); - } - } - else if (key == base_window::KEY_DELETE) - { - if (cursor_pos < static_cast(grid[active_row][active_col].text.size()) && - grid[active_row][active_col].is_editable) - { - grid[active_row][active_col].text.erase( - grid[active_row][active_col].text.begin()+cursor_pos); - move_cursor(active_row,active_col,cursor_pos); - - if (text_modified_handler.is_set()) - text_modified_handler(active_row,active_col); - } - } - } - } // if (has_focus) - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - on_mouse_down ( - unsigned long btn, - unsigned long state, - long x, - long y, - bool is_double_click - ) - { - scrollable_region::on_mouse_down(btn, state, x, y, is_double_click); - if (display_rect().contains(x,y) && enabled && !hidden) - { - // figure out which box this click landed in - rectangle hit; - - // find which column we hit - unsigned long col = 0; - long box_x = total_rect().left(); - for (unsigned long i = 0; i < col_width.size(); ++i) - { - if (box_x <= x && (x < box_x+static_cast(col_width[i]) || (i+1 == col_width.size()))) - { - col = i; - hit.set_left(box_x); - hit.set_right(box_x+col_width[i]-1); - break; - } - else - { - box_x += col_width[i]+1; - } - } - - // find which row we hit - unsigned long row = 0; - long box_y = total_rect().top(); - for (unsigned long i = 0; i < row_height.size(); ++i) - { - if (box_y <= y && y < box_y+static_cast(row_height[i])) - { - row = i; - hit.set_top(box_y); - hit.set_bottom(box_y+row_height[i]-1); - break; - } - else - { - box_y += row_height[i]+1; - } - } - - // if we hit a box - if (hit.is_empty() == false) - { - move_cursor(row, - col, - mfont->compute_cursor_pos(get_text_rect(row,col), grid[row][col].text, x, y, grid[row][col].first) - ); - } - else - { - drop_input_focus(); - } - } - else - { - drop_input_focus(); - } - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - on_mouse_up ( - unsigned long btn, - unsigned long state, - long x, - long y - ) - { - scrollable_region::on_mouse_up(btn, state, x, y); - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - on_focus_lost ( - ) - { - drop_input_focus(); - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - draw ( - const canvas& c - ) const - { - scrollable_region::draw(c); - rectangle area = c.intersect(display_rect()); - if (area.is_empty() == true) - return; - - if (enabled) - fill_rect(c, area, 255); - - // don't do anything if the grid is empty - if (grid.size() == 0) - return; - - // draw all the vertical lines - point p1, p2; - p1.x() = p2.x() = total_rect().left(); - p1.y() = total_rect().top(); - p2.y() = total_rect().bottom(); - for (unsigned long i = 0; i < col_width.size()-1; ++i) - { - p1.x() += col_width[i]; - p2.x() += col_width[i]; - if (enabled) - draw_line(c,p1,p2,border_color_,area); - else - draw_line(c,p1,p2,128,area); - p1.x() += 1; - p2.x() += 1; - } - - // draw all the horizontal lines - p1.y() = p2.y() = total_rect().top(); - p1.x() = display_rect().left(); - p2.x() = display_rect().right(); - for (unsigned long i = 0; i < row_height.size(); ++i) - { - p1.y() += row_height[i]; - p2.y() += row_height[i]; - if (enabled) - draw_line(c,p1,p2,border_color_,area); - else - draw_line(c,p1,p2,128,area); - p1.y() += 1; - p2.y() += 1; - } - - // draw the backgrounds and text for each box - for (long row = 0; row < grid.nr(); ++row) - { - for (long col = 0; col < grid.nc(); ++col) - { - rectangle bg_rect(get_bg_rect(row,col)); - - rectangle text_rect(get_text_rect(row,col)); - - if (enabled) - { - fill_rect(c,bg_rect.intersect(area),grid[row][col].bg_color); - - mfont->draw_string(c, - text_rect, - grid[row][col].text, - grid[row][col].text_color, - grid[row][col].first, - std::string::npos, - area); - } - else - { - mfont->draw_string(c, - text_rect, - grid[row][col].text, - 128, - grid[row][col].first, - std::string::npos, - area); - } - - // if this box has input focus then draw it with a cursor - if (has_focus && active_col == col && active_row == row && show_cursor) - { - rectangle cursor_rect = mfont->compute_cursor_rect(text_rect, - grid[row][col].text, - cursor_pos, - grid[row][col].first); - draw_rectangle(c,cursor_rect,0,area); - } - - } - } - - - } - -// ---------------------------------------------------------------------------------------- - - rectangle text_grid:: - get_text_rect ( - unsigned long row, - unsigned long col - ) const - { - rectangle bg_rect(get_bg_rect(row,col)); - long padding = (bg_rect.height() - mfont->height())/2 + (bg_rect.height() - mfont->height())%2; - if (padding < 0) - padding = 0; - bg_rect.set_left(bg_rect.left()+padding); - bg_rect.set_top(bg_rect.top()+padding); - bg_rect.set_right(bg_rect.right()-padding); - bg_rect.set_bottom(bg_rect.bottom()-padding); - return bg_rect; - } - -// ---------------------------------------------------------------------------------------- - - rectangle text_grid:: - get_bg_rect ( - unsigned long row, - unsigned long col - ) const - { - return translate_rect(grid[row][col].bg_rect, total_rect().left(), total_rect().top()); - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - drop_input_focus ( - ) - { - if (has_focus) - { - parent.invalidate_rectangle(get_text_rect(active_row,active_col)); - has_focus = false; - show_cursor = false; - cursor_timer.stop(); - } - } - -// ---------------------------------------------------------------------------------------- - - void text_grid:: - move_cursor ( - long row, - long col, - long new_cursor_pos - ) - { - // don't do anything if the grid is empty - if (grid.size() == 0) - { - return; - } - - if (row < 0) - row = 0; - if (row >= grid.nr()) - row = grid.nr()-1; - if (col < 0) - col = 0; - if (col >= grid.nc()) - col = grid.nc()-1; - - if (new_cursor_pos < 0) - { - if (col == 0) - { - new_cursor_pos = 0; - } - else - { - --col; - new_cursor_pos = grid[row][col].text.size(); - } - } - - if (new_cursor_pos > static_cast(grid[row][col].text.size())) - { - if (col+1 == grid.nc()) - { - new_cursor_pos = grid[row][col].text.size(); - } - else - { - ++col; - new_cursor_pos = 0; - } - } - - // if some other box had the input focus then redraw it - if (has_focus && (active_row != row || active_col != col )) - { - parent.invalidate_rectangle(get_text_rect(active_row,active_col)); - } - - if (has_focus == false) - { - cursor_timer.start(); - } - - has_focus = true; - recent_cursor_move = true; - show_cursor = true; - active_row = row; - active_col = col; - cursor_pos = new_cursor_pos; - - // adjust the first character to draw so that the string is displayed well - rectangle text_rect(get_text_rect(active_row,active_col)); - rectangle cursor_rect = mfont->compute_cursor_rect(text_rect, - grid[row][col].text, - cursor_pos, - grid[row][col].first); - - // if the cursor rect is too far to the left of the string - if (cursor_pos < static_cast(grid[row][col].first)) - { - if (cursor_pos > 5) - { - grid[row][col].first = cursor_pos - 5; - } - else - { - grid[row][col].first = 0; - } - } - // if the cursor rect is too far to the right of the string - else if (cursor_rect.left() > text_rect.right()) - { - long distance = (cursor_rect.left() - text_rect.right()) + text_rect.width()/3; - // find the letter that is distance pixels from the start of the string - long sum = 0; - for (unsigned long i = grid[row][col].first; i < grid[row][col].text.size(); ++i) - { - sum += (*mfont)[grid[row][col].text[i]].width(); - if (sum >= distance) - { - grid[row][col].first = i; - break; - } - } - } - - scroll_to_rect(get_bg_rect(row,col)); - - // redraw our box - parent.invalidate_rectangle(text_rect); - - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // text_field object methods -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - rectangle text_box:: - get_text_rect ( - ) const - { - const unsigned long padding = style->get_padding(*mfont); - - rectangle text_rect; - text_rect.set_left(total_rect().left()+padding); - text_rect.set_top(total_rect().top()+padding); - text_rect.set_right(total_rect().right()-padding); - text_rect.set_bottom(total_rect().bottom()-padding); - return text_rect; - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - enable ( - ) - { - scrollable_region::enable(); - right_click_menu.enable(); - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - on_cut ( - ) - { - on_copy(); - on_delete_selected(); - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - on_copy ( - ) - { - if (highlight_start <= highlight_end) - { - put_on_clipboard(text_.substr(highlight_start, highlight_end-highlight_start+1)); - } - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - on_paste ( - ) - { - ustring temp_str; - get_from_clipboard(temp_str); - - - if (highlight_start <= highlight_end) - { - text_ = text_.substr(0,highlight_start) + temp_str + - text_.substr(highlight_end+1,text_.size()-highlight_end-1); - move_cursor(highlight_start+temp_str.size()); - highlight_start = 0; - highlight_end = -1; - parent.invalidate_rectangle(rect); - on_no_text_selected(); - - // send out the text modified event - if (text_modified_handler.is_set()) - text_modified_handler(); - } - else - { - text_ = text_.substr(0,cursor_pos) + temp_str + - text_.substr(cursor_pos,text_.size()-cursor_pos); - move_cursor(cursor_pos+temp_str.size()); - - // send out the text modified event - if (temp_str.size() != 0 && text_modified_handler.is_set()) - text_modified_handler(); - } - - adjust_total_rect(); - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - on_select_all ( - ) - { - move_cursor(static_cast(text_.size())); - highlight_start = 0; - highlight_end = static_cast(text_.size()-1); - if (highlight_start <= highlight_end) - on_text_is_selected(); - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - on_delete_selected ( - ) - { - if (highlight_start <= highlight_end) - { - text_ = text_.erase(highlight_start,highlight_end-highlight_start+1); - move_cursor(highlight_start); - highlight_start = 0; - highlight_end = -1; - - on_no_text_selected(); - // send out the text modified event - if (text_modified_handler.is_set()) - text_modified_handler(); - - adjust_total_rect(); - - parent.invalidate_rectangle(rect); - } - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - on_text_is_selected ( - ) - { - right_click_menu.menu().enable_menu_item(0); - right_click_menu.menu().enable_menu_item(1); - right_click_menu.menu().enable_menu_item(3); - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - on_no_text_selected ( - ) - { - right_click_menu.menu().disable_menu_item(0); - right_click_menu.menu().disable_menu_item(1); - right_click_menu.menu().disable_menu_item(3); - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - show ( - ) - { - scrollable_region::show(); - right_click_menu.show(); - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - disable ( - ) - { - auto_mutex M(m); - scrollable_region::disable(); - t.stop(); - has_focus = false; - cursor_visible = false; - right_click_menu.disable(); - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - hide ( - ) - { - auto_mutex M(m); - scrollable_region::hide(); - t.stop(); - has_focus = false; - cursor_visible = false; - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - adjust_total_rect ( - ) - { - const unsigned long padding = style->get_padding(*mfont); - unsigned long text_width; - unsigned long text_height; - - mfont->compute_size(text_, text_width, text_height); - - set_total_rect_size(text_width + padding*2, text_height + padding*2); - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - set_main_font ( - const shared_ptr_thread_safe& f - ) - { - auto_mutex M(m); - mfont = f; - adjust_total_rect(); - right_click_menu.set_rect(display_rect()); - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - draw ( - const canvas& c - ) const - { - scrollable_region::draw(c); - rectangle area = rect.intersect(c); - if (area.is_empty()) - return; - - const point origin(total_rect().left(), total_rect().top()); - - style->draw_text_box(c,display_rect(),get_text_rect(), enabled, *mfont, text_, - translate_rect(cursor_rect, origin), - text_color_, bg_color_, has_focus, cursor_visible, highlight_start, - highlight_end); - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - set_text ( - const std::string& text - ) - { - set_text(convert_mbstring_to_wstring(text)); - } - - void text_box:: - set_text ( - const std::wstring& text - ) - { - set_text(convert_wstring_to_utf32(text)); - } - - void text_box:: - set_text ( - const dlib::ustring& text - ) - { - auto_mutex M(m); - // do this to get rid of any reference counting that may be present in - // the std::string implementation. - text_ = text.c_str(); - - adjust_total_rect(); - move_cursor(0); - - highlight_start = 0; - highlight_end = -1; - } - -// ---------------------------------------------------------------------------------------- - - const std::string text_box:: - text ( - ) const - { - std::string temp = convert_wstring_to_mbstring(wtext()); - return temp; - } - - const std::wstring text_box:: - wtext ( - ) const - { - std::wstring temp = convert_utf32_to_wstring(utext()); - return temp; - } - - const dlib::ustring text_box:: - utext ( - ) const - { - auto_mutex M(m); - // do this to get rid of any reference counting that may be present in - // the dlib::ustring implementation. - dlib::ustring temp = text_.c_str(); - return temp; - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - set_size ( - unsigned long width, - unsigned long height - ) - { - auto_mutex M(m); - scrollable_region::set_size(width,height); - right_click_menu.set_rect(display_rect()); - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - set_pos ( - long x, - long y - ) - { - scrollable_region::set_pos(x,y); - right_click_menu.set_rect(get_text_rect()); - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - set_background_color ( - const rgb_pixel color - ) - { - auto_mutex M(m); - bg_color_ = color; - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - const rgb_pixel text_box:: - background_color ( - ) const - { - auto_mutex M(m); - return bg_color_; - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - set_text_color ( - const rgb_pixel color - ) - { - auto_mutex M(m); - text_color_ = color; - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - const rgb_pixel text_box:: - text_color ( - ) const - { - auto_mutex M(m); - return text_color_; - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - on_mouse_move ( - unsigned long state, - long x, - long y - ) - { - if (!enabled || hidden || !has_focus) - { - return; - } - - if (state & base_window::LEFT) - { - if (highlight_start <= highlight_end) - { - if (highlight_start == cursor_pos) - shift_pos = highlight_end + 1; - else - shift_pos = highlight_start; - } - - unsigned long new_pos = mfont->compute_cursor_pos(get_text_rect(),text_,x,y); - if (static_cast(new_pos) != cursor_pos) - { - move_cursor(new_pos); - parent.invalidate_rectangle(rect); - } - } - else if (shift_pos != -1) - { - shift_pos = -1; - } - - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - on_mouse_up ( - unsigned long btn, - unsigned long, - long , - long - ) - { - if (!enabled || hidden) - return; - - if (btn == base_window::LEFT) - shift_pos = -1; - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - on_mouse_down ( - unsigned long btn, - unsigned long state, - long x, - long y, - bool double_clicked - ) - { - using namespace std; - if (!enabled || hidden || btn != (unsigned long)base_window::LEFT) - return; - - if (display_rect().contains(x,y)) - { - has_focus = true; - cursor_visible = true; - parent.invalidate_rectangle(rect); - t.start(); - - - if (double_clicked) - { - // highlight the double clicked word - string::size_type first, last; - const ustring ustr = convert_utf8_to_utf32(std::string(" \t\n")); - first = text_.substr(0,cursor_pos).find_last_of(ustr.c_str()); - last = text_.find_first_of(ustr.c_str(),cursor_pos); - long f = static_cast(first); - long l = static_cast(last); - if (first == string::npos) - f = -1; - if (last == string::npos) - l = static_cast(text_.size()); - - ++f; - --l; - - move_cursor(l+1); - highlight_start = f; - highlight_end = l; - on_text_is_selected(); - } - else - { - if (state & base_window::SHIFT) - { - if (highlight_start <= highlight_end) - { - if (highlight_start == cursor_pos) - shift_pos = highlight_end + 1; - else - shift_pos = highlight_start; - } - else - { - shift_pos = cursor_pos; - } - } - - bool at_end = false; - if (cursor_pos == 0 || cursor_pos == static_cast(text_.size())) - at_end = true; - const long old_pos = cursor_pos; - - unsigned long new_pos = mfont->compute_cursor_pos(get_text_rect(),text_,x,y); - move_cursor(new_pos); - - shift_pos = cursor_pos; - - if (at_end && cursor_pos == old_pos) - { - highlight_start = 0; - highlight_end = -1; - on_no_text_selected(); - } - } - - } - else if (has_focus && rect.contains(x,y) == false) - { - t.stop(); - has_focus = false; - cursor_visible = false; - shift_pos = -1; - highlight_start = 0; - highlight_end = -1; - on_no_text_selected(); - - if (focus_lost_handler.is_set()) - focus_lost_handler(); - parent.invalidate_rectangle(rect); - } - else - { - has_focus = false; - } - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - on_keydown ( - unsigned long key, - bool is_printable, - unsigned long state - ) - { - // If the right click menu is up then we don't want to do anything with - // the keyboard ourselves. Let the popup menu use the keyboard for now. - if (right_click_menu.popup_menu_visible()) - return; - - if (has_focus && enabled && !hidden) - { - const ustring space_str = convert_utf8_to_utf32(std::string(" \t\n")); - const bool shift = (state&base_window::KBD_MOD_SHIFT) != 0; - const bool ctrl = (state&base_window::KBD_MOD_CONTROL) != 0; - - if (shift && is_printable == false) - { - if (shift_pos == -1) - { - if (highlight_start <= highlight_end) - { - if (highlight_start == cursor_pos) - shift_pos = highlight_end + 1; - else - shift_pos = highlight_start; - } - else - { - shift_pos = cursor_pos; - } - } - } - else - { - shift_pos = -1; - } - - if (key == base_window::KEY_LEFT) - { - if (cursor_pos != 0) - { - unsigned long new_pos; - if (ctrl) - { - // find the first non-whitespace to our left - std::string::size_type pos = text_.find_last_not_of(space_str.c_str(),cursor_pos); - if (pos != std::string::npos) - { - pos = text_.find_last_of(space_str.c_str(),pos); - if (pos != std::string::npos) - new_pos = static_cast(pos); - else - new_pos = 0; - } - else - { - new_pos = 0; - } - } - else - { - new_pos = cursor_pos-1; - } - - move_cursor(new_pos); - } - else if (shift_pos == -1) - { - highlight_start = 0; - highlight_end = -1; - on_no_text_selected(); - parent.invalidate_rectangle(rect); - } - - } - else if (key == base_window::KEY_RIGHT) - { - if (cursor_pos != static_cast(text_.size())) - { - unsigned long new_pos; - if (ctrl) - { - // find the first non-whitespace to our left - std::string::size_type pos = text_.find_first_not_of(space_str.c_str(),cursor_pos); - if (pos != std::string::npos) - { - pos = text_.find_first_of(space_str.c_str(),pos); - if (pos != std::string::npos) - new_pos = static_cast(pos+1); - else - new_pos = static_cast(text_.size()); - } - else - { - new_pos = static_cast(text_.size()); - } - } - else - { - new_pos = cursor_pos+1; - } - - move_cursor(new_pos); - } - else if (shift_pos == -1) - { - highlight_start = 0; - highlight_end = -1; - on_no_text_selected(); - parent.invalidate_rectangle(rect); - } - } - else if (key == base_window::KEY_UP) - { - if (ctrl) - { - move_cursor(0); - } - else - { - const point origin(total_rect().left(), total_rect().top()); - // move the cursor so the position that is just a few pixels above - // the current cursor_rect - move_cursor(mfont->compute_cursor_pos( - get_text_rect(), text_, cursor_rect.left()+origin.x(), - cursor_rect.top()+origin.y()-mfont->height()/2)); - - } - - if (shift_pos == -1) - { - highlight_start = 0; - highlight_end = -1; - on_no_text_selected(); - parent.invalidate_rectangle(rect); - } - } - else if (key == base_window::KEY_DOWN) - { - if (ctrl) - { - move_cursor(static_cast(text_.size())); - } - else - { - const point origin(total_rect().left(), total_rect().top()); - // move the cursor so the position that is just a few pixels above - // the current cursor_rect - move_cursor(mfont->compute_cursor_pos( - get_text_rect(), text_, cursor_rect.left()+origin.x(), - cursor_rect.bottom()+origin.y()+mfont->height()/2)); - } - - if (shift_pos == -1) - { - highlight_start = 0; - highlight_end = -1; - on_no_text_selected(); - parent.invalidate_rectangle(rect); - } - } - else if (is_printable) - { - if (ctrl) - { - if (key == 'a') - { - on_select_all(); - } - else if (key == 'c') - { - on_copy(); - } - else if (key == 'v') - { - on_paste(); - } - else if (key == 'x') - { - on_cut(); - } - } - else - { - if (highlight_start <= highlight_end) - { - text_ = text_.substr(0,highlight_start) + static_cast(key) + - text_.substr(highlight_end+1,text_.size()-highlight_end-1); - - adjust_total_rect(); - move_cursor(highlight_start+1); - highlight_start = 0; - highlight_end = -1; - on_no_text_selected(); - } - else - { - text_ = text_.substr(0,cursor_pos) + static_cast(key) + - text_.substr(cursor_pos,text_.size()-cursor_pos); - adjust_total_rect(); - move_cursor(cursor_pos+1); - } - - // send out the text modified event - if (text_modified_handler.is_set()) - text_modified_handler(); - - } - - if (key == '\n') - { - if (enter_key_handler.is_set()) - enter_key_handler(); - } - } - else if (key == base_window::KEY_BACKSPACE) - { - // if something is highlighted then delete that - if (highlight_start <= highlight_end) - { - on_delete_selected(); - } - else if (cursor_pos != 0) - { - text_ = text_.erase(cursor_pos-1,1); - adjust_total_rect(); - move_cursor(cursor_pos-1); - - // send out the text modified event - if (text_modified_handler.is_set()) - text_modified_handler(); - } - else - { - // do this just so it repaints itself right - move_cursor(cursor_pos); - } - - } - else if (key == base_window::KEY_DELETE) - { - // if something is highlighted then delete that - if (highlight_start <= highlight_end) - { - on_delete_selected(); - } - else if (cursor_pos != static_cast(text_.size())) - { - text_ = text_.erase(cursor_pos,1); - - adjust_total_rect(); - // send out the text modified event - if (text_modified_handler.is_set()) - text_modified_handler(); - } - else - { - // do this just so it repaints itself right - move_cursor(cursor_pos); - } - - } - else if (key == base_window::KEY_HOME) - { - if (ctrl) - { - move_cursor(0); - } - else if (cursor_pos != 0) - { - // find the start of the current line - ustring::size_type pos = text_.find_last_of('\n',cursor_pos-1); - if (pos == ustring::npos) - pos = 0; - else - pos += 1; - move_cursor(static_cast(pos)); - - } - - if (shift_pos == -1) - { - highlight_start = 0; - highlight_end = -1; - on_no_text_selected(); - parent.invalidate_rectangle(rect); - } - } - else if (key == base_window::KEY_END) - { - if (ctrl) - { - move_cursor(static_cast(text_.size())); - } - { - ustring::size_type pos = text_.find_first_of('\n',cursor_pos); - if (pos == ustring::npos) - pos = text_.size(); - - move_cursor(static_cast(pos)); - } - - if (shift_pos == -1) - { - highlight_start = 0; - highlight_end = -1; - on_no_text_selected(); - parent.invalidate_rectangle(rect); - } - } - else if (key == base_window::KEY_PAGE_DOWN || key == base_window::KEY_PAGE_UP) - { - long jump_size = display_rect().height() - - std::min(mfont->height()*3, display_rect().height()/5); - - // if we are supposed to page up then just jump in the other direction - if (key == base_window::KEY_PAGE_UP) - jump_size = -jump_size; - - scroll_to_rect(translate_rect(display_rect(), point(0, jump_size ))); - } - - cursor_visible = true; - recent_movement = true; - - } - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - on_string_put( - const std::wstring &str - ) - { - if (has_focus && enabled && !hidden) - { - ustring ustr = convert_wstring_to_utf32(str); - if (highlight_start <= highlight_end) - { - text_ = text_.substr(0,highlight_start) + ustr + - text_.substr(highlight_end+1,text_.size()-highlight_end-1); - - adjust_total_rect(); - move_cursor(highlight_start+ustr.size()); - highlight_start = 0; - highlight_end = -1; - on_no_text_selected(); - } - else - { - text_ = text_.substr(0,cursor_pos) + ustr + - text_.substr(cursor_pos,text_.size()-cursor_pos); - - adjust_total_rect(); - move_cursor(cursor_pos+ustr.size()); - } - - - // send out the text modified event - if (text_modified_handler.is_set()) - text_modified_handler(); - } - } - -// ---------------------------------------------------------------------------------------- - - void text_box:: - move_cursor ( - unsigned long pos - ) - { - using namespace std; - const long old_cursor_pos = cursor_pos; - - - - // figure out where the cursor is supposed to be - cursor_rect = mfont->compute_cursor_rect(get_text_rect(), text_, pos); - const point origin(total_rect().left(), total_rect().top()); - - - cursor_pos = pos; - - - const unsigned long padding = style->get_padding(*mfont); - - // find the delta between the cursor rect and the corner of the total rect - point delta = point(cursor_rect.left(), cursor_rect.top()) - point(total_rect().left(), total_rect().top()); - - // now scroll us so that we can see the current cursor - scroll_to_rect(centered_rect(cursor_rect, cursor_rect.width() + padding + 6, cursor_rect.height() + 1)); - - // adjust the cursor_rect so that it is relative to the total_rect - cursor_rect = translate_rect(cursor_rect, -origin); - - parent.set_im_pos(cursor_rect.left(), cursor_rect.top()); - - if (old_cursor_pos != cursor_pos) - { - if (shift_pos != -1) - { - highlight_start = std::min(shift_pos,cursor_pos); - highlight_end = std::max(shift_pos,cursor_pos)-1; - } - - if (highlight_start > highlight_end) - on_no_text_selected(); - else - on_text_is_selected(); - - recent_movement = true; - cursor_visible = true; - parent.invalidate_rectangle(display_rect()); - } - - if (shift_pos == -1) - { - highlight_start = 0; - highlight_end = -1; - } - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// image_display member functions -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - namespace impl - { - class image_display_functor - { - const std::string str; - const member_function_pointer mfp; - public: - image_display_functor ( - const std::string& str_, - const member_function_pointer& mfp_ - ) : str(str_), - mfp(mfp_) - {} - - void operator() ( - ) const { mfp(str); } - }; - } - - image_display:: - image_display( - drawable_window& w - ): - scrollable_region(w,KEYBOARD_EVENTS), - zoom_in_scale(1), - zoom_out_scale(1), - drawing_rect(true), - rect_is_selected(false), - selected_rect(0), - default_rect_color(255,0,0,255), - parts_menu(w), - part_width(15), // width part circles are drawn on the screen - overlay_editing_enabled(true), - highlight_timer(*this, &image_display::timer_event_unhighlight_rect), - highlighted_rect(std::numeric_limits::max()) - { - enable_mouse_drag(); - - highlight_timer.set_delay_time(250); - set_horizontal_scroll_increment(1); - set_vertical_scroll_increment(1); - set_horizontal_mouse_wheel_scroll_increment(30); - set_vertical_mouse_wheel_scroll_increment(30); - - parts_menu.disable(); - - - enable_events(); - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - on_part_add ( - const std::string& part_name - ) - { - if (!rect_is_selected) - return; - - const rectangle valid_area = get_rect_on_screen(selected_rect); - const point loc = nearest_point(valid_area,last_right_click_pos); - - // Transform loc from gui window space into the space used by the overlay - // rectangles (i.e. relative to the raw image) - const point origin(total_rect().tl_corner()); - point c1 = loc - origin; - if (zoom_in_scale != 1) - { - c1 = c1/(double)zoom_in_scale; - } - else if (zoom_out_scale != 1) - { - c1 = c1*(double)zoom_out_scale; - } - - overlay_rects[selected_rect].parts[part_name] = c1; - parent.invalidate_rectangle(rect); - - if (event_handler.is_set()) - event_handler(); - } - -// ---------------------------------------------------------------------------------------- - - image_display:: - ~image_display( - ) - { - highlight_timer.stop_and_wait(); - disable_events(); - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - rectangle image_display:: - get_image_display_rect ( - ) const - { - if (zoom_in_scale != 1) - { - return rectangle(0,0, img.nc()*zoom_in_scale-1, img.nr()*zoom_in_scale-1); - } - else if (zoom_out_scale != 1) - { - return rectangle(0,0, img.nc()/zoom_out_scale-1, img.nr()/zoom_out_scale-1); - } - else - { - return dlib::get_rect(img); - } - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - add_overlay ( - const overlay_rect& overlay - ) - { - auto_mutex M(m); - // push this new overlay into our overlay vector - overlay_rects.push_back(overlay); - - // make the parent window redraw us now that we changed the overlay - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - add_overlay ( - const overlay_line& overlay - ) - { - auto_mutex M(m); - - // push this new overlay into our overlay vector - overlay_lines.push_back(overlay); - - // make the parent window redraw us now that we changed the overlay - parent.invalidate_rectangle(get_rect_on_screen(rectangle(overlay.p1, overlay.p2))); - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - add_overlay ( - const overlay_circle& overlay - ) - { - auto_mutex M(m); - - // push this new overlay into our overlay vector - overlay_circles.push_back(overlay); - - // make the parent window redraw us now that we changed the overlay - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - add_overlay ( - const std::vector& overlay - ) - { - auto_mutex M(m); - - // push this new overlay into our overlay vector - overlay_rects.insert(overlay_rects.end(), overlay.begin(), overlay.end()); - - // make the parent window redraw us now that we changed the overlay - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - add_overlay ( - const std::vector& overlay - ) - { - auto_mutex M(m); - - // push this new overlay into our overlay vector - overlay_lines.insert(overlay_lines.end(), overlay.begin(), overlay.end()); - - // make the parent window redraw us now that we changed the overlay - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - add_overlay ( - const std::vector& overlay - ) - { - auto_mutex M(m); - - // push this new overlay into our overlay vector - overlay_circles.insert(overlay_circles.end(), overlay.begin(), overlay.end()); - - // make the parent window redraw us now that we changed the overlay - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - clear_overlay ( - ) - { - auto_mutex M(m); - overlay_rects.clear(); - overlay_lines.clear(); - overlay_circles.clear(); - parent.invalidate_rectangle(rect); - } - -// ---------------------------------------------------------------------------------------- - - rectangle image_display:: - get_rect_on_screen ( - rectangle orect - ) const - { - const point origin(total_rect().tl_corner()); - orect.left() = orect.left()*zoom_in_scale/zoom_out_scale; - orect.top() = orect.top()*zoom_in_scale/zoom_out_scale; - if (zoom_in_scale != 1) - { - // make it so the box surrounds the pixels when we zoom in. - orect.right() = (orect.right()+1)*zoom_in_scale/zoom_out_scale; - orect.bottom() = (orect.bottom()+1)*zoom_in_scale/zoom_out_scale; - } - else - { - orect.right() = orect.right()*zoom_in_scale/zoom_out_scale; - orect.bottom() = orect.bottom()*zoom_in_scale/zoom_out_scale; - } - - return translate_rect(orect, origin); - } - -// ---------------------------------------------------------------------------------------- - - rectangle image_display:: - get_rect_on_screen ( - unsigned long idx - ) const - { - return get_rect_on_screen(overlay_rects[idx].rect); - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - draw ( - const canvas& c - ) const - { - scrollable_region::draw(c); - - rectangle area = display_rect().intersect(c); - if (area.is_empty()) - return; - - const point origin(total_rect().tl_corner()); - - // draw the image on the screen - const rectangle img_area = total_rect().intersect(area); - for (long row = img_area.top(); row <= img_area.bottom(); ++row) - { - for (long col = img_area.left(); col <= img_area.right(); ++col) - { - assign_pixel(c[row-c.top()][col-c.left()], - img[(row-origin.y())*zoom_out_scale/zoom_in_scale][(col-origin.x())*zoom_out_scale/zoom_in_scale]); - } - } - - // now draw all the overlay rectangles - for (unsigned long i = 0; i < overlay_rects.size(); ++i) - { - const rectangle orect = get_rect_on_screen(i); - - if (rect_is_selected && selected_rect == i) - { - draw_rectangle(c, orect, invert_pixel(overlay_rects[i].color), area); - } - else if (highlighted_rect < overlay_rects.size() && highlighted_rect == i) - { - // Draw the rectangle wider and with a slightly different color that tapers - // out at the edges of the line. - hsi_pixel temp; - assign_pixel(temp, 0); - assign_pixel(temp, overlay_rects[i].color); - temp.s = 255; - temp.h = temp.h + 20; - if (temp.i < 245) - temp.i += 10; - rgb_pixel p; - assign_pixel(p, temp); - rgb_alpha_pixel po, po2; - assign_pixel(po, p); - po.alpha = 160; - po2 = po; - po2.alpha = 90; - draw_rectangle(c, grow_rect(orect,2), po2, area); - draw_rectangle(c, grow_rect(orect,1), po, area); - draw_rectangle(c, orect, p, area); - draw_rectangle(c, shrink_rect(orect,1), po, area); - draw_rectangle(c, shrink_rect(orect,2), po2, area); - } - else - { - draw_rectangle(c, orect, overlay_rects[i].color, area); - } - - if (overlay_rects[i].label.size() != 0) - { - // make a rectangle that is at the spot we want to draw our string - rectangle r(orect.br_corner(), c.br_corner()); - mfont->draw_string(c, r, overlay_rects[i].label, overlay_rects[i].color, 0, - std::string::npos, area); - } - - - // draw circles for each "part" in this overlay rectangle. - std::map::const_iterator itr; - for (itr = overlay_rects[i].parts.begin(); itr != overlay_rects[i].parts.end(); ++itr) - { - rectangle temp = centered_rect(get_rect_on_screen(centered_rect(itr->second,1,1)), part_width, part_width); - - if (rect_is_selected && selected_rect == i && - selected_part_name.size() != 0 && selected_part_name == itr->first) - { - draw_circle(c, center(temp), temp.width()/2, invert_pixel(overlay_rects[i].color), area); - } - else - { - draw_circle(c, center(temp), temp.width()/2, overlay_rects[i].color, area); - } - - // make a rectangle that is at the spot we want to draw our string - rectangle r((temp.br_corner() + temp.bl_corner())/2, - c.br_corner()); - mfont->draw_string(c, r, itr->first, overlay_rects[i].color, 0, - std::string::npos, area); - } - - if (overlay_rects[i].crossed_out) - { - if (rect_is_selected && selected_rect == i) - { - draw_line(c, orect.tl_corner(), orect.br_corner(),invert_pixel(overlay_rects[i].color), area); - draw_line(c, orect.bl_corner(), orect.tr_corner(),invert_pixel(overlay_rects[i].color), area); - } - else - { - draw_line(c, orect.tl_corner(), orect.br_corner(),overlay_rects[i].color, area); - draw_line(c, orect.bl_corner(), orect.tr_corner(),overlay_rects[i].color, area); - } - } - } - - // now draw all the overlay lines - for (unsigned long i = 0; i < overlay_lines.size(); ++i) - { - draw_line(c, - zoom_in_scale*overlay_lines[i].p1/zoom_out_scale + origin, - zoom_in_scale*overlay_lines[i].p2/zoom_out_scale + origin, - overlay_lines[i].color, area); - } - - // now draw all the overlay circles - for (unsigned long i = 0; i < overlay_circles.size(); ++i) - { - const point center = zoom_in_scale*overlay_circles[i].center/zoom_out_scale + origin; - const int radius = zoom_in_scale*overlay_circles[i].radius/zoom_out_scale; - draw_circle(c, - center, - radius, - overlay_circles[i].color, area); - - if (overlay_circles[i].label.size() != 0) - { - const point temp = center + point(0,radius); - - // make a rectangle that is at the spot we want to draw our string - rectangle r(temp, c.br_corner()); - mfont->draw_string(c, r, overlay_circles[i].label, overlay_circles[i].color, 0, - std::string::npos, area); - } - } - - if (drawing_rect) - draw_rectangle(c, rect_to_draw, invert_pixel(default_rect_color), area); - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - on_keydown ( - unsigned long key, - bool is_printable, - unsigned long state - ) - { - scrollable_region::on_keydown(key,is_printable, state); - - if (!is_printable && !hidden && enabled && rect_is_selected && - (key == base_window::KEY_BACKSPACE || key == base_window::KEY_DELETE)) - { - rect_is_selected = false; - parts_menu.disable(); - if (selected_part_name.size() == 0) - overlay_rects.erase(overlay_rects.begin() + selected_rect); - else - overlay_rects[selected_rect].parts.erase(selected_part_name); - parent.invalidate_rectangle(rect); - - if (event_handler.is_set()) - event_handler(); - } - - if (is_printable && !hidden && enabled && rect_is_selected && (key == 'i')) - { - overlay_rects[selected_rect].crossed_out = !overlay_rects[selected_rect].crossed_out; - parent.invalidate_rectangle(rect); - - if (event_handler.is_set()) - event_handler(); - } - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - add_labelable_part_name ( - const std::string& name - ) - { - auto_mutex lock(m); - if (part_names.insert(name).second) - { - member_function_pointer mfp; - mfp.set(*this,&image_display::on_part_add); - parts_menu.menu().add_menu_item(menu_item_text("Add " + name,impl::image_display_functor(name,mfp))); - } - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - clear_labelable_part_names ( - ) - { - auto_mutex lock(m); - part_names.clear(); - parts_menu.menu().clear(); - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - on_mouse_down ( - unsigned long btn, - unsigned long state, - long x, - long y, - bool is_double_click - ) - { - scrollable_region::on_mouse_down(btn, state, x, y, is_double_click); - - if (rect.contains(x,y) == false || hidden || !enabled) - return; - - if (image_clicked_handler.is_set()) - { - const point origin(total_rect().tl_corner()); - point p(x,y); - p -= origin; - if (zoom_in_scale != 1) - p = p/zoom_in_scale; - else if (zoom_out_scale != 1) - p = p*zoom_out_scale; - - if (dlib::get_rect(img).contains(p)) - image_clicked_handler(p, is_double_click, btn); - } - - if (!overlay_editing_enabled) - return; - - if (btn == base_window::RIGHT && rect_is_selected) - { - last_right_click_pos = point(x,y); - parts_menu.set_rect(get_rect_on_screen(selected_rect)); - return; - } - - if (btn == base_window::LEFT && (state&base_window::CONTROL) && !drawing_rect) - { - long best_dist = std::numeric_limits::max(); - long best_idx = 0; - // check if this click landed on any of the overlay rectangles - for (unsigned long i = 0; i < overlay_rects.size(); ++i) - { - const rectangle orect = get_rect_on_screen(i); - const long dist = distance_to_rect_edge(orect, point(x,y)); - - if (dist < best_dist) - { - best_dist = dist; - best_idx = i; - } - } - if (best_dist < 13) - { - overlay_rects[best_idx].label = default_rect_label; - highlighted_rect = best_idx; - highlight_timer.stop(); - highlight_timer.start(); - if (event_handler.is_set()) - event_handler(); - parent.invalidate_rectangle(rect); - } - return; - } - - - if (!is_double_click && btn == base_window::LEFT && (state&base_window::SHIFT)) - { - drawing_rect = true; - rect_anchor = point(x,y); - - if (rect_is_selected) - { - rect_is_selected = false; - parts_menu.disable(); - parent.invalidate_rectangle(rect); - } - } - else if (drawing_rect) - { - if (rect_is_selected) - { - rect_is_selected = false; - parts_menu.disable(); - } - - drawing_rect = false; - parent.invalidate_rectangle(rect); - } - else if (is_double_click) - { - const bool rect_was_selected = rect_is_selected; - rect_is_selected = false; - parts_menu.disable(); - - long best_dist = std::numeric_limits::max(); - long best_idx = 0; - std::string best_part; - - // check if this click landed on any of the overlay rectangles - for (unsigned long i = 0; i < overlay_rects.size(); ++i) - { - const rectangle orect = get_rect_on_screen(i); - - const long dist = distance_to_rect_edge(orect, point(x,y)); - - if (dist < best_dist) - { - best_dist = dist; - best_idx = i; - best_part.clear(); - } - - std::map::const_iterator itr; - for (itr = overlay_rects[i].parts.begin(); itr != overlay_rects[i].parts.end(); ++itr) - { - rectangle temp = centered_rect(get_rect_on_screen(centered_rect(itr->second,1,1)), part_width, part_width); - point c = center(temp); - - // distance from edge of part circle - const long dist = static_cast(std::abs(length(c - point(x,y)) + 0.5 - temp.width()/2)); - if (dist < best_dist) - { - best_idx = i; - best_dist = dist; - best_part = itr->first; - } - } - } - - - if (best_dist < 13) - { - rect_is_selected = true; - if (part_names.size() != 0) - parts_menu.enable(); - selected_rect = best_idx; - selected_part_name = best_part; - if (orect_selected_event_handler.is_set()) - orect_selected_event_handler(overlay_rects[best_idx]); - } - - if (rect_is_selected || rect_was_selected) - parent.invalidate_rectangle(rect); - } - else if (rect_is_selected) - { - rect_is_selected = false; - parts_menu.disable(); - parent.invalidate_rectangle(rect); - } - } - -// ---------------------------------------------------------------------------------------- - - std::vector image_display:: - get_overlay_rects ( - ) const - { - auto_mutex lock(m); - return overlay_rects; - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - set_default_overlay_rect_label ( - const std::string& label - ) - { - auto_mutex lock(m); - default_rect_label = label; - } - -// ---------------------------------------------------------------------------------------- - - std::string image_display:: - get_default_overlay_rect_label ( - ) const - { - auto_mutex lock(m); - return default_rect_label; - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - set_default_overlay_rect_color ( - const rgb_alpha_pixel& color - ) - { - auto_mutex lock(m); - default_rect_color = color; - } - -// ---------------------------------------------------------------------------------------- - - rgb_alpha_pixel image_display:: - get_default_overlay_rect_color ( - ) const - { - auto_mutex lock(m); - return default_rect_color; - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - on_mouse_up ( - unsigned long btn, - unsigned long state, - long x, - long y - ) - { - scrollable_region::on_mouse_up(btn,state,x,y); - - if (drawing_rect && btn == base_window::LEFT && (state&base_window::SHIFT) && - !hidden && enabled) - { - const point origin(total_rect().tl_corner()); - point c1 = point(x,y) - origin; - point c2 = rect_anchor - origin; - - if (zoom_in_scale != 1) - { - c1 = c1/(double)zoom_in_scale; - c2 = c2/(double)zoom_in_scale; - } - else if (zoom_out_scale != 1) - { - c1 = c1*(double)zoom_out_scale; - c2 = c2*(double)zoom_out_scale; - } - - rectangle new_rect(c1,c2); - if (zoom_in_scale != 1) - { - // When we are zoomed in we adjust the rectangles a little so they - // are drown surrounding the pixels inside the rect. This adjustment - // is necessary to make this code consistent with this goal. - new_rect.right() -= 1; - new_rect.bottom() -= 1; - } - - - if (new_rect.width() > 0 && new_rect.height() > 0) - { - add_overlay(overlay_rect(new_rect, default_rect_color, default_rect_label)); - - if (event_handler.is_set()) - event_handler(); - } - } - - if (drawing_rect) - { - drawing_rect = false; - parent.invalidate_rectangle(rect); - } - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - on_mouse_move ( - unsigned long state, - long x, - long y - ) - { - scrollable_region::on_mouse_move(state,x,y); - - if (drawing_rect) - { - if ((state&base_window::LEFT) && (state&base_window::SHIFT) && !hidden && enabled) - { - rectangle new_rect(point(x,y), rect_anchor); - parent.invalidate_rectangle(new_rect + rect_to_draw); - rect_to_draw = new_rect; - } - else - { - drawing_rect = false; - parent.invalidate_rectangle(rect); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - on_wheel_up ( - unsigned long state - ) - { - // disable mouse wheel if the user is drawing a rectangle - if (drawing_rect) - return; - - // if CONTROL is not being held down - if ((state & base_window::CONTROL) == 0) - { - scrollable_region::on_wheel_up(state); - return; - } - - if (rect.contains(lastx,lasty) == false || hidden || !enabled) - return; - - - if (zoom_in_scale < 100 && zoom_out_scale == 1) - { - const point mouse_loc(lastx, lasty); - // the pixel in img that the mouse is over - const point pix_loc = (mouse_loc - total_rect().tl_corner())/zoom_in_scale; - - zoom_in_scale = zoom_in_scale*10/9 + 1; - - set_total_rect_size(img.nc()*zoom_in_scale, img.nr()*zoom_in_scale); - - // make is to the pixel under the mouse doesn't move while we zoom - const point delta = total_rect().tl_corner() - (mouse_loc - pix_loc*zoom_in_scale); - scroll_to_rect(translate_rect(display_rect(), delta)); - } - else if (zoom_out_scale != 1) - { - const point mouse_loc(lastx, lasty); - // the pixel in img that the mouse is over - const point pix_loc = (mouse_loc - total_rect().tl_corner())*zoom_out_scale; - - zoom_out_scale = zoom_out_scale*9/10; - if (zoom_out_scale == 0) - zoom_out_scale = 1; - - set_total_rect_size(img.nc()/zoom_out_scale, img.nr()/zoom_out_scale); - - // make is to the pixel under the mouse doesn't move while we zoom - const point delta = total_rect().tl_corner() - (mouse_loc - pix_loc/zoom_out_scale); - scroll_to_rect(translate_rect(display_rect(), delta)); - } - } - -// ---------------------------------------------------------------------------------------- - - void image_display:: - on_wheel_down ( - unsigned long state - ) - { - // disable mouse wheel if the user is drawing a rectangle - if (drawing_rect) - return; - - // if CONTROL is not being held down - if ((state & base_window::CONTROL) == 0) - { - scrollable_region::on_wheel_down(state); - return; - } - - if (rect.contains(lastx,lasty) == false || hidden || !enabled) - return; - - - if (zoom_in_scale != 1) - { - const point mouse_loc(lastx, lasty); - // the pixel in img that the mouse is over - const point pix_loc = (mouse_loc - total_rect().tl_corner())/zoom_in_scale; - - zoom_in_scale = zoom_in_scale*9/10; - if (zoom_in_scale == 0) - zoom_in_scale = 1; - - set_total_rect_size(img.nc()*zoom_in_scale, img.nr()*zoom_in_scale); - - // make is to the pixel under the mouse doesn't move while we zoom - const point delta = total_rect().tl_corner() - (mouse_loc - pix_loc*zoom_in_scale); - scroll_to_rect(translate_rect(display_rect(), delta)); - } - else if (std::max(img.nr(), img.nc())/zoom_out_scale > 10) - { - const point mouse_loc(lastx, lasty); - // the pixel in img that the mouse is over - const point pix_loc = (mouse_loc - total_rect().tl_corner())*zoom_out_scale; - - zoom_out_scale = zoom_out_scale*10/9 + 1; - - set_total_rect_size(img.nc()/zoom_out_scale, img.nr()/zoom_out_scale); - - // make is to the pixel under the mouse doesn't move while we zoom - const point delta = total_rect().tl_corner() - (mouse_loc - pix_loc/zoom_out_scale); - scroll_to_rect(translate_rect(display_rect(), delta)); - } - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// image_window member functions -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - image_window:: - image_window( - ) : - gui_img(*this), - window_has_closed(false), - have_last_click(false), - mouse_btn(0), - clicked_signaler(this->wm), - tie_input_events(false) - { - - gui_img.set_image_clicked_handler(*this, &image_window::on_image_clicked); - gui_img.disable_overlay_editing(); - // show this window on the screen - show(); - } - -// ---------------------------------------------------------------------------------------- - - image_window:: - ~image_window( - ) - { - // You should always call close_window() in the destructor of window - // objects to ensure that no events will be sent to this window while - // it is being destructed. - close_window(); - } - -// ---------------------------------------------------------------------------------------- - - base_window::on_close_return_code image_window:: - on_window_close( - ) - { - window_has_closed = true; - clicked_signaler.broadcast(); - return base_window::CLOSE_WINDOW; - } - -// ---------------------------------------------------------------------------------------- - - bool image_window:: - get_next_keypress ( - unsigned long& key, - bool& is_printable, - unsigned long& state - ) - { - auto_mutex lock(wm); - while (have_last_keypress == false && !window_has_closed && - (have_last_click == false || !tie_input_events)) - { - clicked_signaler.wait(); - } - - if (window_has_closed) - return false; - - if (have_last_keypress) - { - // Mark that we are taking the key click so the next call to get_next_keypress() - // will have to wait for another click. - have_last_keypress = false; - key = next_key; - is_printable = next_is_printable; - state = next_state; - return true; - } - else - { - key = 0; - is_printable = true; - return false; - } - } - -// ---------------------------------------------------------------------------------------- - - void image_window:: - on_keydown ( - unsigned long key, - bool is_printable, - unsigned long state - ) - { - dlib::drawable_window::on_keydown(key,is_printable,state); - - have_last_keypress = true; - next_key = key; - next_is_printable = is_printable; - next_state = state; - clicked_signaler.signal(); - } - -// ---------------------------------------------------------------------------------------- - - void image_window:: - tie_events ( - ) - { - auto_mutex lock(wm); - tie_input_events = true; - } - -// ---------------------------------------------------------------------------------------- - - void image_window:: - untie_events ( - ) - { - auto_mutex lock(wm); - tie_input_events = false; - } - -// ---------------------------------------------------------------------------------------- - - bool image_window:: - events_tied ( - ) const - { - auto_mutex lock(wm); - return tie_input_events; - } - -// ---------------------------------------------------------------------------------------- - - bool image_window:: - get_next_double_click ( - point& p, - unsigned long& mouse_button - ) - { - p = point(-1,-1); - - auto_mutex lock(wm); - while (have_last_click == false && !window_has_closed && - (have_last_keypress==false || !tie_input_events)) - { - clicked_signaler.wait(); - } - - if (window_has_closed) - return false; - - if (have_last_click) - { - // Mark that we are taking the point click so the next call to - // get_next_double_click() will have to wait for another click. - have_last_click = false; - mouse_button = mouse_btn; - p = last_clicked_point; - return true; - } - else - { - return false; - } - } - -// ---------------------------------------------------------------------------------------- - - void image_window:: - on_image_clicked ( - const point& p, - bool is_double_click, - unsigned long btn - ) - { - if (is_double_click) - { - have_last_click = true; - last_clicked_point = p; - mouse_btn = btn; - clicked_signaler.signal(); - } - } - -// ---------------------------------------------------------------------------------------- - - void image_window:: - add_overlay ( - const overlay_rect& overlay - ) - { - gui_img.add_overlay(overlay); - } - -// ---------------------------------------------------------------------------------------- - - void image_window:: - add_overlay ( - const overlay_line& overlay - ) - { - gui_img.add_overlay(overlay); - } - -// ---------------------------------------------------------------------------------------- - - void image_window:: - add_overlay ( - const overlay_circle& overlay - ) - { - gui_img.add_overlay(overlay); - } - -// ---------------------------------------------------------------------------------------- - - void image_window:: - add_overlay ( - const std::vector& overlay - ) - { - gui_img.add_overlay(overlay); - } - -// ---------------------------------------------------------------------------------------- - - void image_window:: - add_overlay ( - const std::vector& overlay - ) - { - gui_img.add_overlay(overlay); - } - -// ---------------------------------------------------------------------------------------- - - void image_window:: - add_overlay ( - const std::vector& overlay - ) - { - gui_img.add_overlay(overlay); - } - -// ---------------------------------------------------------------------------------------- - - void image_window:: - clear_overlay ( - ) - { - gui_img.clear_overlay(); - } - -// ---------------------------------------------------------------------------------------- - - void image_window:: - on_window_resized( - ) - { - drawable_window::on_window_resized(); - unsigned long width, height; - get_size(width,height); - gui_img.set_size(width, height); - - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_WIDGETs_CPP_ - diff --git a/lib/3rdParty/dlib/include/dlib/gui_widgets/widgets.h b/lib/3rdParty/dlib/include/dlib/gui_widgets/widgets.h index bd29278a..049c4a47 100644 --- a/lib/3rdParty/dlib/include/dlib/gui_widgets/widgets.h +++ b/lib/3rdParty/dlib/include/dlib/gui_widgets/widgets.h @@ -4,13 +4,18 @@ #ifndef DLIB_WIDGETs_ #define DLIB_WIDGETs_ +#include +#include +#include +#include +#include +#include + #include "../algs.h" #include "widgets_abstract.h" #include "drawable.h" #include "../gui_core.h" #include "fonts.h" -#include -#include #include "../timer.h" #include "base_widgets.h" #include "../member_function_pointer.h" @@ -19,15 +24,12 @@ #include "../sequence.h" #include "../dir_nav.h" #include "../queue.h" -#include "../smart_pointers.h" #include "style.h" #include "../string.h" #include "../misc_api.h" -#include -#include #include "../any.h" -#include #include "../image_processing/full_object_detection.h" +#include "../geometry/line.h" #ifdef _MSC_VER // This #pragma directive is also located in the algs.h file but for whatever @@ -93,7 +95,7 @@ namespace dlib ) const; void set_main_font ( - const shared_ptr_thread_safe& f + const std::shared_ptr& f ); private: @@ -213,7 +215,7 @@ namespace dlib ); void set_main_font ( - const shared_ptr_thread_safe& f + const std::shared_ptr& f ); void set_pos ( @@ -291,7 +293,7 @@ namespace dlib any_function event_handler; any_function event_handler_self; - scoped_ptr style; + std::unique_ptr style; protected: @@ -435,6 +437,9 @@ namespace dlib void give_input_focus ( ); + bool has_input_focus ( + ) const; + void select_all_text ( ); @@ -475,7 +480,7 @@ namespace dlib ); void set_main_font ( - const shared_ptr_thread_safe& f + const std::shared_ptr& f ); int next_free_user_event_number ( @@ -651,7 +656,7 @@ namespace dlib any_function enter_key_handler; any_function focus_lost_handler; - scoped_ptr style; + std::unique_ptr style; timer t; @@ -863,7 +868,7 @@ namespace dlib ); void set_main_font ( - const shared_ptr_thread_safe& f + const std::shared_ptr& f ); int next_free_user_event_number ( @@ -1047,7 +1052,7 @@ namespace dlib any_function enter_key_handler; any_function focus_lost_handler; - scoped_ptr style; + std::unique_ptr style; timer t; @@ -1186,6 +1191,9 @@ namespace dlib unsigned long num ); + unsigned long selected_tab ( + ) const; + unsigned long number_of_tabs ( ) const; @@ -1259,7 +1267,7 @@ namespace dlib ); void set_main_font ( - const shared_ptr_thread_safe& f + const std::shared_ptr& f ); void fit_to_contents ( @@ -1378,7 +1386,7 @@ namespace dlib ); void set_main_font ( - const shared_ptr_thread_safe& f + const std::shared_ptr& f ); protected: @@ -1437,7 +1445,7 @@ namespace dlib ); void set_main_font ( - const shared_ptr_thread_safe& f + const std::shared_ptr& f ); protected: @@ -1785,14 +1793,14 @@ namespace dlib bool move_next ( ) const; - unsigned long size ( + size_t size ( ) const; unsigned long get_selected ( ) const; void set_main_font ( - const shared_ptr_thread_safe& f + const std::shared_ptr& f ); private: @@ -1824,7 +1832,7 @@ namespace dlib any_function single_click_event_handler; unsigned long last_selected; - scoped_ptr style; + std::unique_ptr style; // restricted functions list_box(list_box&); // copy constructor @@ -1923,7 +1931,7 @@ namespace dlib int cur_dir; any_function event_handler; - sequence >::kernel_2a_c sob; + sequence >::kernel_2a_c sob; }; } @@ -2038,7 +2046,7 @@ namespace dlib void set_pos(long,long){} void set_main_font ( - const shared_ptr_thread_safe& f + const std::shared_ptr& f ); void set_number_of_menus ( @@ -3231,6 +3239,16 @@ namespace dlib - else - parts_menu.is_enabled() == false - selected_part_name.size() == 0 + + - if (moving_overlay) then + - moving_rect == the index in overlay_rects that the move applies to. + - if (moving_what == MOVING_PART) then + - moving_part_name == the name of the part in + overlay_rects[moving_rect] that is being moved around with the + mouse. + - else + - moving_what will tell us which side of the rectangle in + overlay_rects[moving_rect] is being moved by the mouse. !*/ public: @@ -3575,17 +3593,276 @@ namespace dlib any_function image_clicked_handler; popup_menu_region parts_menu; point last_right_click_pos; - const int part_width; + const double part_width; std::set part_names; bool overlay_editing_enabled; timer highlight_timer; unsigned long highlighted_rect; + bool holding_shift_key; + + bool moving_overlay; + unsigned long moving_rect; + enum { + MOVING_RECT_LEFT, + MOVING_RECT_TOP, + MOVING_RECT_RIGHT, + MOVING_RECT_BOTTOM, + MOVING_PART + } moving_what; + std::string moving_part_name; // restricted functions image_display(image_display&); // copy constructor image_display& operator=(image_display&); // assignment operator }; +// ---------------------------------------------------------------------------------------- + + class perspective_display : public drawable, noncopyable + { + public: + + perspective_display( + drawable_window& w + ); + + ~perspective_display( + ); + + virtual void set_size ( + unsigned long width, + unsigned long height + ); + + struct overlay_line + { + overlay_line() { assign_pixel(color, 0);} + + overlay_line(const vector& p1_, const vector& p2_) + : p1(p1_), p2(p2_) { assign_pixel(color, 255); } + + template + overlay_line(const vector& p1_, const vector& p2_, pixel_type p) + : p1(p1_), p2(p2_) { assign_pixel(color, p); } + + vector p1; + vector p2; + rgb_pixel color; + }; + + struct overlay_dot + { + overlay_dot() { assign_pixel(color, 0);} + + overlay_dot(const vector& p_) + : p(p_) { assign_pixel(color, 255); } + + template + overlay_dot(const vector& p_, pixel_type color_) + : p(p_) { assign_pixel(color, color_); } + + vector p; + rgb_pixel color; + }; + + + void add_overlay ( + const std::vector& overlay + ); + + void add_overlay ( + const std::vector& overlay + ); + + void clear_overlay ( + ); + + template < + typename T + > + void set_dot_double_clicked_handler ( + T& object, + void (T::*event_handler_)(const vector&) + ) + { + auto_mutex M(m); + dot_clicked_event_handler = make_mfp(object,event_handler_); + } + + void set_dot_double_clicked_handler ( + const any_function&)>& event_handler_ + ); + + private: + + void draw ( + const canvas& c + ) const; + + void on_wheel_up ( + unsigned long state + ); + + void on_wheel_down ( + unsigned long state + ); + + void on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool is_double_click + ); + + void on_mouse_move ( + unsigned long state, + long x, + long y + ); + + static bool compare_second ( + const std::pair& a, + const std::pair& b + ) { return a.second < b.second; } + + + point last; + std::vector overlay_lines; + std::vector overlay_dots; + + camera_transform tform; + vector sum_pts; + vector max_pts; + any_function&)> dot_clicked_event_handler; + mutable array2d depth; + }; + +// ---------------------------------------------------------------------------------------- + + class perspective_window : public drawable_window, noncopyable + { + public: + + typedef perspective_display::overlay_line overlay_line; + typedef perspective_display::overlay_dot overlay_dot; + + perspective_window( + ) : disp(*this) + { + set_size(100,100); + on_window_resized(); + show(); + } + + perspective_window( + const std::vector >& point_cloud + ) : + disp(*this) + { + set_size(100,100); + on_window_resized(); + add_overlay(point_cloud); + show(); + } + + perspective_window( + const std::vector >& point_cloud, + const std::string& title + ) : + disp(*this) + { + set_size(100,100); + on_window_resized(); + add_overlay(point_cloud); + set_title(title); + show(); + } + + ~perspective_window( + ) + { + // You should always call close_window() in the destructor of window + // objects to ensure that no events will be sent to this window while + // it is being destructed. + close_window(); + } + + void add_overlay ( + const std::vector& overlay + ) + { + disp.add_overlay(overlay); + } + + void add_overlay ( + const std::vector& overlay + ) + { + disp.add_overlay(overlay); + } + + void clear_overlay ( + ) + { + disp.clear_overlay(); + } + + template + void add_overlay(const vector& p1, const vector& p2, pixel_type p) + { + add_overlay(std::vector(1,overlay_line(p1,p2,p))); + } + + void add_overlay(const std::vector >& d) + { + add_overlay(d, 255); + } + + template + void add_overlay(const std::vector >& d, pixel_type p) + { + std::vector temp; + temp.resize(d.size()); + for (unsigned long i = 0; i < temp.size(); ++i) + temp[i] = overlay_dot(d[i], p); + + add_overlay(temp); + } + + template < + typename T + > + void set_dot_double_clicked_handler ( + T& object, + void (T::*event_handler_)(const vector&) + ) + { + disp.set_dot_double_clicked_handler(object,event_handler_); + } + + void set_dot_double_clicked_handler ( + const any_function&)>& event_handler_ + ) + { + disp.set_dot_double_clicked_handler(event_handler_); + } + + private: + + void on_window_resized( + ) + { + drawable_window::on_window_resized(); + unsigned long width, height; + get_size(width,height); + disp.set_pos(0,0); + disp.set_size(width, height); + } + + perspective_display disp; + }; + // ---------------------------------------------------------------------------------------- class image_window : public drawable_window @@ -3679,6 +3956,9 @@ namespace dlib void add_overlay(const rectangle& r, pixel_type p) { add_overlay(image_display::overlay_rect(r,p)); } + void add_overlay(const rectangle& r) + { add_overlay(image_display::overlay_rect(r,rgb_pixel(255,0,0))); } + template void add_overlay(const rectangle& r, pixel_type p, const std::string& l) { add_overlay(image_display::overlay_rect(r,p,l)); } @@ -3694,6 +3974,9 @@ namespace dlib add_overlay(temp); } + void add_overlay(const std::vector& r) + { add_overlay(r, rgb_pixel(255,0,0)); } + void add_overlay( const full_object_detection& object, const std::vector& part_names @@ -3771,6 +4054,17 @@ namespace dlib const overlay_line& overlay ); + template + void add_overlay(const line& l, pixel_type p) + { + add_overlay(image_display::overlay_line(l.p1(),l.p2(),p)); + } + + void add_overlay(const line& l) + { + add_overlay(l, rgb_pixel(255,0,0)); + } + void add_overlay ( const overlay_circle& overlay ); diff --git a/lib/3rdParty/dlib/include/dlib/gui_widgets/widgets_abstract.h b/lib/3rdParty/dlib/include/dlib/gui_widgets/widgets_abstract.h index 98f247a4..210d5e08 100644 --- a/lib/3rdParty/dlib/include/dlib/gui_widgets/widgets_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/gui_widgets/widgets_abstract.h @@ -14,6 +14,7 @@ #include "../interfaces/enumerable.h" #include "style_abstract.h" #include "../image_processing/full_object_detection_abstract.h" +#include "../geometry/line_abstract.h" namespace dlib { @@ -533,10 +534,11 @@ namespace dlib { /*! INITIAL VALUE - text() == "" - width() == 10 - height() == a height appropriate for the font used. - The text color will be black. + - text() == "" + - width() == 10 + - height() == a height appropriate for the font used. The text color will + be black. + - has_input_focus() == false WHAT THIS OBJECT REPRESENTS This object represents a simple one line text input field. @@ -622,7 +624,16 @@ namespace dlib ); /*! ensures - - gives this text field input keyboard focus + - #has_input_focus() == true + !*/ + + bool has_input_focus ( + ); + /*! + ensures + - Returns true if this txt field has input keyboard focus. If this + is the case then it means that when the user types on the keyboard + the output will appear inside the text field. !*/ void select_all_text ( @@ -2338,10 +2349,17 @@ namespace dlib by double clicking on it and hitting delete or backspace. Finally, you can also add part labels (if they have been defined by calling add_labelable_part_name()) by selecting an overlay rectangle with the mouse and then right clicking - on the part. + on the part. If you want to move any rectangle or an object part then + shift+right click and drag it. Alternatively, if you haven't added any + part labels via add_labelable_part_name() you can add parts to a rectangle + by simply shift left clicking while it's selected. This will add parts + with integer names and the integer names begin with 0 and increase. This + feature is only activated if the rectangle has no parts or all the parts + are already integer names. - Finally, if you hold Ctrl and left click an overlay rectangle it will - change its label to get_default_overlay_rect_label(). + Finally, if you hold Ctrl and left click an overlay rectangle it will + change its label to get_default_overlay_rect_label() and color to + get_default_overlay_rect_color(). The image is drawn such that: - the pixel img[0][0] is the upper left corner of the image. @@ -2789,7 +2807,7 @@ namespace dlib > void set_image_clicked_handler ( T& object, - void (T::*event_handler)(const point& p, bool is_double_click) + void (T::*event_handler)(const point& p, bool is_double_click, unsigned long btn) ); /* requires @@ -2799,6 +2817,7 @@ namespace dlib anywhere on the image. When they do so this callback is called with the location of the image pixel which was clicked. The is_double_click bool will also tell you if it was a double click or single click. + - btn == the button that was released. (either base_window::LEFT, base_window::MIDDLE, or base_window::RIGHT) - any previous calls to this function are overridden by this new call. (i.e. you can only have one event handler associated with this event at a time) @@ -2807,7 +2826,7 @@ namespace dlib */ void set_image_clicked_handler ( - const any_function& event_handler + const any_function& event_handler ); /* ensures @@ -2815,6 +2834,7 @@ namespace dlib on the image. When they do so this callback is called with the location of the image pixel which was clicked. The is_double_click bool will also tell you if it was a double click or single click. + - btn == the button that was released. (either base_window::LEFT, base_window::MIDDLE, or base_window::RIGHT) - Any previous calls to this function are overridden by this new call. (i.e. you can only have one event handler associated with this event at a time) @@ -2917,7 +2937,7 @@ namespace dlib template void add_overlay( const rectangle& r, - pixel_type p + pixel_type p = rgb_pixel(255,0,0) ); /*! ensures @@ -2938,7 +2958,7 @@ namespace dlib template void add_overlay( const std::vector& r, - pixel_type p + pixel_type p = rgb_pixel(255,0,0) ); /*! ensures @@ -3000,6 +3020,16 @@ namespace dlib that it will be displayed. !*/ + template + void add_overlay( + const line& l, + pixel_type p + ); + /*! + ensures + - performs: add_overlay(overlay_line(l.p1(),l.p2(),p)); + !*/ + void add_overlay ( const overlay_circle& overlay ); @@ -3158,6 +3188,287 @@ namespace dlib image_window& operator= (image_window&); }; +// ---------------------------------------------------------------------------------------- + + class perspective_display : public drawable, noncopyable + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a tool for displaying 3D point clouds on a screen. You can + navigate the display with the mouse. Left click and drag rotates the + camera around the displayed data. Scrolling the mouse wheel zooms and + shift+left click (or just right click) and drag pans the view around. + !*/ + + public: + + perspective_display( + drawable_window& w + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + !*/ + + ~perspective_display( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + void set_size ( + unsigned long width, + unsigned long height + ); + /*! + ensures + - #width() == width + - #height() == height + - #top() == top() + - #left() == left() + - i.e. The location of the upper left corner of this widget stays the + same but its width and height are modified. + !*/ + + struct overlay_line + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a line that is drawn on the screen. Each line + is represented by its two end points (p1 and p2) as well as a color. + !*/ + + overlay_line() { assign_pixel(color, 0);} + + overlay_line(const vector& p1_, const vector& p2_) + : p1(p1_), p2(p2_) { assign_pixel(color, 255); } + + template + overlay_line(const vector& p1_, const vector& p2_, pixel_type p) + : p1(p1_), p2(p2_) { assign_pixel(color, p); } + + vector p1; + vector p2; + rgb_pixel color; + }; + + struct overlay_dot + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a dot that is drawn on the screen. Each dot is + represented by one point and a color. + !*/ + + overlay_dot() { assign_pixel(color, 0);} + + overlay_dot(const vector& p_) + : p(p_) { assign_pixel(color, 255); } + + template + overlay_dot(const vector& p_, pixel_type color_) + : p(p_) { assign_pixel(color, color_); } + + vector p; // The location of the dot + rgb_pixel color; + }; + + void add_overlay ( + const std::vector& overlay + ); + /*! + ensures + - Adds the given overlay lines into this object such that it will be + displayed. + !*/ + + void add_overlay ( + const std::vector& overlay + ); + /*! + ensures + - Adds the given overlay dots into this object such that it will be + displayed. + !*/ + + void clear_overlay ( + ); + /*! + ensures + - Removes all overlays from this object. The display will be empty. + !*/ + + template + void set_dot_double_clicked_handler ( + T& object, + void (T::*event_handler)(const vector&) + ); + /* + requires + - event_handler is a valid pointer to a member function in T + ensures + - The event_handler function is called on object when the user double + clicks on one of the overlay dots. The selected dot will be passed to + event_handler(). + - Any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + */ + + void set_dot_double_clicked_handler ( + const any_function&)>& event_handler + ); + /* + ensures + - The event_handler function is called when the user double clicks on one + of the overlay dots. The selected dot will be passed to event_handler(). + - Any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + */ + }; + +// ---------------------------------------------------------------------------------------- + + class perspective_window : public drawable_window, noncopyable + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a simple window that is just a container for a perspective_display. + It exists to make it easy to throw perspective_displays onto the screen + without having to put together your own drawable_window objects. + !*/ + public: + + typedef perspective_display::overlay_line overlay_line; + typedef perspective_display::overlay_dot overlay_dot; + + perspective_window( + ); + /*! + ensures + - The window is displayed on the screen and is 100x100 pixels in size. + !*/ + + perspective_window( + const std::vector >& point_cloud + ); + /*! + ensures + - The window is displayed on the screen and is 100x100 pixels in size. + - This window will have point_cloud added to it via add_overlay() and the + points will all be white. + !*/ + + perspective_window( + const std::vector >& point_cloud, + const std::string& title + ); + /*! + ensures + - The window is displayed on the screen and is 100x100 pixels in size. + - This window will have point_cloud added to it via add_overlay() and the + points will all be white. + - The title of the window will be set to the given title string. + !*/ + + ~perspective_window( + ); + /*! + ensures + - any resources associated with this object have been released + !*/ + + void add_overlay ( + const std::vector& overlay + ); + /*! + ensures + - Adds the given overlay lines into this object such that it will be + displayed. + !*/ + + void add_overlay ( + const std::vector& overlay + ); + /*! + ensures + - Adds the given overlay dots into this object such that it will be + displayed. + !*/ + + void clear_overlay ( + ); + /*! + ensures + - Removes all overlays from this object. The display will be empty. + !*/ + + void add_overlay( + const std::vector >& d + ); + /*! + ensures + - Adds the given dots into this object such that it will be + displayed. They will be colored white. + !*/ + + template + void add_overlay( + const std::vector >& d, + pixel_type p + ); + /*! + ensures + - Adds the given dots into this object such that it will be + displayed. They will be colored by pixel color p. + !*/ + + template + void add_overlay( + const vector& p1, + const vector& p2, + pixel_type color + ); + /*! + ensures + - Adds an overlay line going from p1 to p2 with the given color. + !*/ + + template < typename T > + void set_dot_double_clicked_handler ( + T& object, + void (T::*event_handler)(const vector&) + ); + /* + requires + - event_handler is a valid pointer to a member function in T + ensures + - The event_handler function is called on object when the user double + clicks on one of the overlay dots. The selected dot will be passed to + event_handler(). + - Any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + */ + + void set_dot_double_clicked_handler ( + const any_function&)>& event_handler + ); + /* + ensures + - The event_handler function is called when the user double clicks on one + of the overlay dots. The selected dot will be passed to event_handler(). + - Any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + */ + + }; + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/hash_map/hash_map_kernel_1.h b/lib/3rdParty/dlib/include/dlib/hash_map/hash_map_kernel_1.h index 7fbb2e6e..e8b1d6d7 100644 --- a/lib/3rdParty/dlib/include/dlib/hash_map/hash_map_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/hash_map/hash_map_kernel_1.h @@ -100,7 +100,7 @@ namespace dlib ); // functions from the enumerable interface - inline unsigned long size ( + inline size_t size ( ) const; inline bool at_start ( @@ -328,7 +328,7 @@ namespace dlib typename hash_table, typename mem_manager > - unsigned long hash_map_kernel_1:: + size_t hash_map_kernel_1:: size ( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/hash_map/hash_map_kernel_c.h b/lib/3rdParty/dlib/include/dlib/hash_map/hash_map_kernel_c.h index b643c5d4..4db93724 100644 --- a/lib/3rdParty/dlib/include/dlib/hash_map/hash_map_kernel_c.h +++ b/lib/3rdParty/dlib/include/dlib/hash_map/hash_map_kernel_c.h @@ -218,7 +218,7 @@ namespace dlib ) const { // make sure requires clause is not broken - DLIB_CASSERT( is_in_domain(d), + DLIB_CASSERT( this->is_in_domain(d), "\tconst range& hash_map::operator[]" << "\n\td must be in the domain of the hash_map" << "\n\tthis: " << this diff --git a/lib/3rdParty/dlib/include/dlib/hash_set/hash_set_kernel_1.h b/lib/3rdParty/dlib/include/dlib/hash_set/hash_set_kernel_1.h index 5c512404..c40770b9 100644 --- a/lib/3rdParty/dlib/include/dlib/hash_set/hash_set_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/hash_set/hash_set_kernel_1.h @@ -85,7 +85,7 @@ namespace dlib ); // functions from the enumerable interface - inline unsigned long size ( + inline size_t size ( ) const; inline bool at_start ( @@ -266,7 +266,7 @@ namespace dlib typename hash_table, typename mem_manager > - unsigned long hash_set_kernel_1:: + size_t hash_set_kernel_1:: size ( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/hash_table/hash_table_kernel_1.h b/lib/3rdParty/dlib/include/dlib/hash_table/hash_table_kernel_1.h index ce84c1ca..f06847a7 100644 --- a/lib/3rdParty/dlib/include/dlib/hash_table/hash_table_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/hash_table/hash_table_kernel_1.h @@ -145,7 +145,7 @@ namespace dlib ); // functions from the enumerable interface - inline unsigned long size ( + inline size_t size ( ) const; bool at_start ( @@ -336,7 +336,7 @@ namespace dlib typename mem_manager, typename compare > - unsigned long hash_table_kernel_1:: + size_t hash_table_kernel_1:: size( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/hash_table/hash_table_kernel_2.h b/lib/3rdParty/dlib/include/dlib/hash_table/hash_table_kernel_2.h index 52a4f423..58646413 100644 --- a/lib/3rdParty/dlib/include/dlib/hash_table/hash_table_kernel_2.h +++ b/lib/3rdParty/dlib/include/dlib/hash_table/hash_table_kernel_2.h @@ -116,7 +116,7 @@ namespace dlib ); // functions from the enumerable interface - inline unsigned long size ( + inline size_t size ( ) const; inline bool at_start ( @@ -266,7 +266,7 @@ namespace dlib typename mem_manager, typename compare > - unsigned long hash_table_kernel_2:: + size_t hash_table_kernel_2:: size( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/http_client/http_client.cpp b/lib/3rdParty/dlib/include/dlib/http_client/http_client.cpp deleted file mode 100644 index 7eb04bf5..00000000 --- a/lib/3rdParty/dlib/include/dlib/http_client/http_client.cpp +++ /dev/null @@ -1,740 +0,0 @@ - - -#include "../sockets.h" -#include "../string.h" -#include "../logger.h" -#include "../sockstreambuf.h" -#include "../timeout.h" -#include "http_client.h" -#include -#include -#include -#include -#include - -namespace dlib -{ - - typedef dlib::shared_ptr timeout_ptr; - - -#ifdef _MSC_VER -#define BR_CASECMP strnicmp -#else -#define BR_CASECMP strncasecmp -#endif -// Default timeout after 60 seconds -#define DEFAULT_TIMEOUT 60000 - -// ---------------------------------------------------------------------------------------- - - inline bool isXdigit( char c ) - { - return (c >= '0' && c <= '9') || - (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z'); - } - -// ---------------------------------------------------------------------------------------- - - std::string http_client::urldecode( const std::string& s ) - { - std::stringstream ss; - - for ( char const * p_read = s.c_str(), * p_end = (s.c_str() + s.size()); p_read < p_end; p_read++ ) - { - if ( p_read[0] == '%' && p_read+1 != p_end && p_read+2 != p_end && isXdigit(p_read[1]) && isXdigit(p_read[2]) ) - { - ss << static_cast((( (p_read[1] & 0xf) + ((p_read[1] >= 'A') ? 9 : 0) ) << 4 ) | ( (p_read[2] & 0xf) + ((p_read[2] >= 'A') ? 9 : 0) )); - p_read += 2; - } - else if ( p_read[0] == '+' ) - { - // Undo the encoding that replaces spaces with plus signs. - ss << ' '; - } - else - { - ss << p_read[0]; - } - } - - return ss.str(); - } - -// ---------------------------------------------------------------------------------------- - -//! \return modified string ``s'' with spaces trimmed from left - inline std::string& triml(std::string& s) - { - int pos(0); - for ( ; s[pos] == ' ' || s[pos] == '\t' || s[pos] == '\r' || s[pos] == '\n' ; ++pos ); - s.erase(0, pos); - return s; - } - -// ---------------------------------------------------------------------------------------- - -//! \return modified string ``s'' with spaces trimmed from right - inline std::string& trimr(std::string& s) - { - int pos(s.size()); - for ( ; pos && (s[pos-1] == ' ' || s[pos-1] == '\t' || s[pos-1] == '\r' || s[pos-1] == '\n') ; --pos ); - s.erase(pos, s.size()-pos); - return s; - } - -// ---------------------------------------------------------------------------------------- - -//! \return modified string ``s'' with spaces trimmed from edges - inline std::string& trim(std::string& s) - { - return triml(trimr(s)); - } - -// ---------------------------------------------------------------------------------------- - - http_client:: - http_client( - ) : - http_return(0), - timeout(DEFAULT_TIMEOUT), - OnDownload(0) - { - } - -// ---------------------------------------------------------------------------------------- - - std::string http_client::get_header(const std::string& header_name) const - { - stringmap::const_iterator ci = headers.find(header_name); - return ci != headers.end() ? ci->second : std::string(); - } - -// ---------------------------------------------------------------------------------------- - - void http_client::set_header(const std::string& header_name, long header_value) - { - char buf[21] = { 0 }; -#ifdef __WXMSW__ - ::ltoa(header_value, buf, 10); -#else - sprintf(buf, "%ld", header_value); -#endif - set_header(header_name, buf); - } - -// ---------------------------------------------------------------------------------------- - - void http_client::set_header(const std::string& header_name, const std::string& header_value) - { - headers[header_name] = header_value; - } - -// ---------------------------------------------------------------------------------------- - - bool http_client::is_header_set(const std::string& header_name) const - { - stringmap::const_iterator ci = headers.find(header_name); - return ci != headers.end() && !ci->second.empty(); - } - -// ---------------------------------------------------------------------------------------- - - void http_client::remove_header(const std::string& header_name) - { - headers.erase(header_name); - } - -// ---------------------------------------------------------------------------------------- - - void http_client::set_cookie(const std::string& cookie_name, long cookie_value) - { - char buf[21] = { 0 }; -#ifdef __WXMSW__ - ::ltoa(cookie_value, buf, 10); -#else - sprintf(buf, "%ld", cookie_value); -#endif - set_cookie(cookie_name, buf); - } - -// ---------------------------------------------------------------------------------------- - - void http_client::set_cookie(const std::string& cookie_name, const std::string& cookie_value) - { - cookies[cookie_name] = cookie_value; - } - -// ---------------------------------------------------------------------------------------- - - void http_client::remove_cookie(const std::string& cookie_name) - { - cookies.erase(cookie_name); - } - -// ---------------------------------------------------------------------------------------- - -// POST - const std::string& http_client::post_url (const std::string& url, const string_to_stringmap& postvars, const string_to_stringmap& filenames) - { - std::string CT; - std::string postBody = build_post(CT, postvars, filenames); - set_header("Content-Type", CT); - set_header("Content-Length", static_cast(postBody.size())); - - grab_url(url, "POST", postBody); - - return returned_body; - } - -// ---------------------------------------------------------------------------------------- - - const std::string& http_client::post_url (const std::string& url, const std::string& postbuffer) - { - if ( !is_header_set("Content-Type") ) // Maybe they just forgot it? - set_header("Content-Type", "application/x-www-form-urlencoded"); - - set_header("Content-Length", static_cast(postbuffer.size())); - - grab_url(url, "POST", postbuffer); - - return returned_body; - } - -// ---------------------------------------------------------------------------------------- - - std::string http_client::get_random_string( size_t length ) const - { - static bool has_seeded(false); - static std::string allowed_chars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"); - - if ( !has_seeded ) - { - has_seeded = true; - ::srand( static_cast(::time(NULL)) ); - } - - std::string retVal; retVal.reserve(length); - while ( retVal.size() < length ) - { - retVal += allowed_chars[(rand() % allowed_chars.size())]; - } - - return retVal; - } - -// ---------------------------------------------------------------------------------------- - -// static - std::string http_client::urlencode(const std::string& in, bool post_encode) - { - static std::string allowed_chars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"); - - std::stringstream ss; - ss << std::hex; - for (std::string::const_iterator ci = in.begin(); ci != in.end(); ++ci) - { - if ( allowed_chars.find(*ci) != std::string::npos ) - { - ss << *ci; - } - else if ( post_encode && *ci == ' ' ) - { - ss << '+'; - } - else - { - ss << '%' << std::setfill('0') << std::setw(2) << std::right << static_cast(*ci); - } - } - - return ss.str(); - } - -// ---------------------------------------------------------------------------------------- - - std::string http_client::get_basename( const std::string& filename ) const - { - std::string::size_type pos = filename.find_last_of("\\/"); - if ( pos == std::string::npos ) - return filename; - else - return filename.substr(pos+1); - } - -// ---------------------------------------------------------------------------------------- - - bool http_client::parse_url( - const std::string& url, - std::string& scheme, - std::string& user, - std::string& pass, - std::string& host, - short& port, - std::string& path - ) const - { - scheme.clear(); - user.clear(); - pass.clear(); - host.clear(); - path.clear(); - port = 0; - - // Find scheme - std::string::size_type pos_scheme = url.find("://"); - if ( pos_scheme == std::string::npos ) - { - pos_scheme = 0; - } - else - { - scheme = strtolower(url.substr(0, pos_scheme)); - pos_scheme += 3; - } - - std::string::size_type pos_path = url.find('/', pos_scheme); - if ( pos_path == std::string::npos ) - { - host = url.substr(pos_scheme); - } - else - { - host = url.substr(pos_scheme, pos_path - pos_scheme); - path = url.substr(pos_path); - } - - std::string::size_type pos_at = host.find('@'); - if ( pos_at != std::string::npos ) - { - std::string::size_type pos_dp = host.find(':'); - if ( pos_dp != std::string::npos && pos_dp < pos_at ) - { - user = host.substr(0, pos_dp); - pass = host.substr(pos_dp+1, pos_at-pos_dp-1); - } - else - { - user = host.substr(0, pos_at); - } - host = host.substr(pos_at+1); - } - - std::string::size_type pos_dp = host.find(':'); - if ( pos_dp != std::string::npos ) - { - port = dlib::string_cast(host.substr(pos_dp+1)); - host = host.substr(0, pos_dp); - } - - host = strtolower(host); - - if ( port == 0 ) - { - if ( scheme == "http" ) - port = 80; - else if ( scheme == "ftp" ) - port = 21; - else if ( scheme == "https" ) - port = 443; - } - - return !host.empty(); - } - -// ---------------------------------------------------------------------------------------- - - std::string http_client::strtolower(const std::string& in) const - { - std::string retVal = in; - - for (std::string::iterator ii = retVal.begin(); ii != retVal.end(); ++ii) - { - *ii = ::tolower(*ii); - } - - return retVal; - } - -// ---------------------------------------------------------------------------------------- - - std::string http_client::strtoupper(const std::string& in) const - { - std::string retVal = in; - - for (std::string::iterator ii = retVal.begin(); ii != retVal.end(); ++ii) - { - *ii = ::toupper(*ii); - } - - return retVal; - } - -// ---------------------------------------------------------------------------------------- - -// GET - const std::string& http_client::get_url(const std::string& url) - { - std::string CT = get_header("Content-Type"); - - // You do a GET with a POST header?? - if ( CT == "application/x-www-form-urlencoded" || CT == "multipart/form-data" ) - remove_header("Content-Type"); - - grab_url(url); - - return returned_body; - } - -// ---------------------------------------------------------------------------------------- - - std::string http_client::build_post(std::string& content_type, const string_to_stringmap& postvars, const string_to_stringmap& filenames_in) const - { - if ( postvars.empty() && filenames_in.empty() ) - return std::string(); - - string_to_stringmap filenames = filenames_in; - - // sanitize the files - if ( !filenames.empty() ) - { - string_to_stringmap::iterator var_names = filenames.begin(); - while (var_names != filenames.end()) - { - stringmap::iterator fnames = var_names->second.begin(); - - while( fnames != var_names->second.end() ) - { - FILE *fp = ::fopen(fnames->second.c_str(), "rb"); - if ( fp == NULL ) - { - stringmap::iterator old_one = fnames++; - var_names->second.erase(old_one); - } - else - { - fclose(fp); - ++fnames; - } - } - - if ( fnames->second.empty() ) - { - string_to_stringmap::iterator old_one = var_names++; - filenames.erase(old_one); - } - else - { - ++var_names; - } - } - } - - content_type = !filenames.empty() ? "multipart/form-data" : "application/x-www-form-urlencoded"; - std::stringstream postBody; - if ( !filenames.empty() ) - { - std::string mime_boundary = get_random_string(32); - - // First add the form vars - for (string_to_stringmap::const_iterator ci = postvars.begin(); ci != postvars.end(); ++ci) - { - for (stringmap::const_iterator si = ci->second.begin(); si != ci->second.end(); ++si) - { - postBody << "--" << mime_boundary << "\r\n" - "Content-Disposition: form-data; name=\"" << ci->first << "\"\r\n\r\n" - << si->second << "\r\n"; - } - } - - // Then add the files - for (string_to_stringmap::const_iterator ci = filenames.begin(); ci != filenames.end(); ++ci) - { - for (stringmap::const_iterator si = ci->second.begin(); si != ci->second.end(); ++si) - { - std::ifstream in(si->second.c_str()); - postBody << "--" << mime_boundary << "\r\n" - "Content-Disposition: form-data; name=\"" << ci->first << "\"; filename=\"" << get_basename(si->second) << "\"\r\n\r\n" - << in << "\r\n"; - } - } - - postBody << "--" << mime_boundary << "--\r\n"; - } - else - { - // No files... - for (string_to_stringmap::const_iterator ci = postvars.begin(); ci != postvars.end(); ++ci) - { - for (stringmap::const_iterator si = ci->second.begin(); si != ci->second.end(); ++si) - { - postBody << urlencode(ci->first) << '=' << urlencode(si->second) << '&'; - } - } - - // read the last '&' - char c; - postBody.read(&c, 1); - } - - return postBody.str(); - } - -// ---------------------------------------------------------------------------------------- - - bool http_client::grab_url(const std::string& url, const std::string& method, const std::string& post_body) - { - error_field.clear(); - returned_headers.clear(); - http_return = 0; - returned_body.clear(); - - std::string to_use_method = strtoupper(method); - - std::string scheme, user, pass, host, path; - short port; - if ( !parse_url(url, scheme, user, pass, host, port, path) ) - { - error_field = "Couldn't parse the URL!"; - return false; - } - - // Build request - std::stringstream ret; - ret << to_use_method << ' ' << path << " HTTP/1.0\r\n" - << "Host: " << host; - if (port != 80 && port != 443) ret << ':' << port; - ret << "\r\n"; - - bool content_length_said = false; - - set_header("Connection", "Close"); - for (stringmap::iterator ci = headers.begin(); ci != headers.end(); ++ci) - { - std::string head = strtolower(ci->first); - - if ( head == "content-length" ) - { - content_length_said = true; - } - - ret << ci->first << ':' << ' ' << ci->second << "\r\n"; - } - - if ( !content_length_said && to_use_method != "GET" ) - ret << "Content-Length: " << static_cast(post_body.size()) << "\r\n"; - - std::stringstream cookie_ss; - for (stringmap::iterator ci = cookies.begin(); ci != cookies.end(); ++ci) - { - std::string var = ci->first ; trim(var); - std::string val = ci->second; trim(val); - - if ( val.empty() || var.empty() ) - continue; - - if ( !cookie_ss.str().empty() ) - cookie_ss << ';' << ' '; - - cookie_ss << urlencode(var) << '=' << urlencode(val); - } - - if ( !cookie_ss.str().empty() ) - ret << "Cookie: " << cookie_ss.str() << "\r\n"; - - ret << "\r\n"; - ret << post_body; - - std::string request_build = ret.str(); - - std::stringstream ss; - { - dlib::connection * conn(0); - try - { - conn = dlib::connect(host, port); - } - catch (const dlib::socket_error& e) - { - error_field = e.what(); - return false; - } - - // Implement a timeout - timeout_ptr t; - if ( timeout > 0 ) - t.reset( new dlib::timeout(*conn, &dlib::connection::shutdown, timeout) ); - - // Write our request - conn->write(request_build.c_str(), static_cast(request_build.size())); - - t.reset(); - - // And read the response - char buf[512]; - long bytes_read(0), bytes_total(0); - bool read_headers(true); - - if ( timeout > 0 ) - t.reset( new dlib::timeout(*conn, &dlib::connection::shutdown, timeout) ); - - while ( (bytes_read = conn->read(buf, 512)) > 0 ) - { - ss.write(buf, bytes_read); - - // Incremental read headers - if ( read_headers ) - { - std::string body_with_headers = ss.str(); - std::string::size_type ctr(0); - - while ( true ) - { - std::string::size_type pos = body_with_headers.find("\r\n", ctr); - if ( pos == std::string::npos ) - { - // This is our last position of "\r\n" - ss.str(""); - ss.write( body_with_headers.substr(ctr).c_str(), body_with_headers.size() - ctr ); - break; - } - - std::string header = body_with_headers.substr(ctr, pos-ctr); - if ( header.empty() ) - { - // Ok, we're done reading the headers - read_headers = false; - // What follows now is the body - ss.str(""); - ss.write( body_with_headers.substr(pos + 2).c_str(), body_with_headers.size() - pos - 2 ); - break; - } - ctr = pos + 2; - - if ( returned_headers.empty() ) - { - if ( - header[0] == 'H' && - header[1] == 'T' && - header[2] == 'T' && - header[3] == 'P' && - header[4] == '/' && - (header[5] >= '0' && header[5] <= '9') && - header[6] == '.' && - (header[7] >= '0' && header[7] <= '9') && - header[8] == ' ' - ) - { - http_return = (header[9 ] - '0') * 100 + - (header[10] - '0') * 10 + - (header[11] - '0'); - continue; - } - } - - std::string::size_type pos_dp = header.find_first_of(':'); - std::string header_name, header_value; - if ( pos_dp == std::string::npos ) - { - // **TODO** what should I do here?? - header_name = header; - } - else - { - header_name = trim(header.substr(0, pos_dp)); - header_value = trim(header.substr(pos_dp+1)); - } - - returned_headers[ header_name ].push_back(header_value); - - if ( BR_CASECMP(header_name.c_str(), "Content-Length", 14) == 0 ) - { - bytes_total = atol( header_value.c_str() ); - } - else if ( BR_CASECMP(header_name.c_str(), "Set-Cookie", 10) == 0 ) - { - std::string::size_type cur_pos(0), pos_pk, pos_is; - std::string work, var, val; - for ( cur_pos = 0; cur_pos < header_value.size(); cur_pos++ ) - { - pos_pk = header_value.find(';', cur_pos); - work = trim( header_value.substr(cur_pos, pos_pk - cur_pos) ); - - pos_is = work.find('='); - if ( pos_is != std::string::npos ) - { // Hmmm? what in the else case? - var = trim( http_client::urldecode( work.substr(0, pos_is) ) ); - val = trim( http_client::urldecode( work.substr(pos_is + 1) ) ); - - if ( var != "expires" && var != "domain" && var != "path" ) - set_cookie( var, val ); - } - cur_pos = pos_pk == std::string::npos ? pos_pk - 1 : pos_pk; - } - } // Set-Cookie? - - } // while (true) - } // read_headers? - - // Call the OnDownload function if it's set - if ( OnDownload && !read_headers ) - { - if ( (*OnDownload)(static_cast(ss.tellp()), bytes_total, user_info) == false ) - { - t.reset(); - break; - } - } - - if ( bytes_total != 0 && static_cast(ss.tellp()) == bytes_total ) - { - t.reset(); - break; - } - - if ( timeout > 0 ) - t.reset( new dlib::timeout(*conn, &dlib::connection::shutdown, timeout) ); - } // while still data to read - - t.reset(); - - delete conn; - - - switch ( bytes_read ) - { - case dlib::TIMEOUT: error_field = "Timeout"; return false; break; - case dlib::WOULDBLOCK: error_field = "Would block"; return false; break; - case dlib::OTHER_ERROR: error_field = "Other error"; return false; break; - case dlib::SHUTDOWN: error_field = "Timeout"; return false; break; - case dlib::PORTINUSE: error_field = "Port in use"; return false; break; - } - } - - returned_body = ss.str(); - - return true; - } - -// ---------------------------------------------------------------------------------------- - - void http_client::clear() - { - headers.clear(); - cookies.clear(); - } - -// ---------------------------------------------------------------------------------------- - - void http_client::prepare_for_next_url( ) - { - remove_header("Content-Type"); - remove_header("Content-Length"); - } - -// ---------------------------------------------------------------------------------------- - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/image_io.h b/lib/3rdParty/dlib/include/dlib/image_io.h index 56ec6930..4fdc7988 100644 --- a/lib/3rdParty/dlib/include/dlib/image_io.h +++ b/lib/3rdParty/dlib/include/dlib/image_io.h @@ -1,5 +1,10 @@ // Copyright (C) 2006 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. + +#ifdef DLIB_ALL_SOURCE_END +#include "dlib_basic_cpp_build_tutorial.txt" +#endif + #ifndef DLIB_IMAGe_IO_ #define DLIB_IMAGe_IO_ @@ -9,6 +14,7 @@ #include "image_loader/load_image.h" #include "image_saver/image_saver.h" #include "image_saver/save_png.h" +#include "image_saver/save_jpeg.h" #endif // DLIB_IMAGe_IO_ diff --git a/lib/3rdParty/dlib/include/dlib/image_keypoint/binned_vector_feature_image.h b/lib/3rdParty/dlib/include/dlib/image_keypoint/binned_vector_feature_image.h index e749bd8a..019a1273 100644 --- a/lib/3rdParty/dlib/include/dlib/image_keypoint/binned_vector_feature_image.h +++ b/lib/3rdParty/dlib/include/dlib/image_keypoint/binned_vector_feature_image.h @@ -55,7 +55,7 @@ namespace dlib const image_type& img ); - inline unsigned long size ( + inline size_t size ( ) const; inline long nr ( @@ -280,7 +280,7 @@ namespace dlib typename feature_extractor, typename hash_function_type > - unsigned long binned_vector_feature_image:: + size_t binned_vector_feature_image:: size ( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/image_keypoint/binned_vector_feature_image_abstract.h b/lib/3rdParty/dlib/include/dlib/image_keypoint/binned_vector_feature_image_abstract.h index bcfb3e37..6bd6cdbb 100644 --- a/lib/3rdParty/dlib/include/dlib/image_keypoint/binned_vector_feature_image_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_keypoint/binned_vector_feature_image_abstract.h @@ -132,7 +132,7 @@ namespace dlib operator() as defined below. !*/ - unsigned long size ( + size_t size ( ) const; /*! ensures diff --git a/lib/3rdParty/dlib/include/dlib/image_keypoint/fine_hog_image.h b/lib/3rdParty/dlib/include/dlib/image_keypoint/fine_hog_image.h index 489b9d8d..a421ffe7 100644 --- a/lib/3rdParty/dlib/include/dlib/image_keypoint/fine_hog_image.h +++ b/lib/3rdParty/dlib/include/dlib/image_keypoint/fine_hog_image.h @@ -73,8 +73,8 @@ namespace dlib inline void unload( ) { clear(); } - inline unsigned long size ( - ) const { return static_cast(nr()*nc()); } + inline size_t size ( + ) const { return static_cast(nr()*nc()); } inline long nr ( ) const { return num_block_rows; } diff --git a/lib/3rdParty/dlib/include/dlib/image_keypoint/fine_hog_image_abstract.h b/lib/3rdParty/dlib/include/dlib/image_keypoint/fine_hog_image_abstract.h index 8a8eaaf1..50be85af 100644 --- a/lib/3rdParty/dlib/include/dlib/image_keypoint/fine_hog_image_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_keypoint/fine_hog_image_abstract.h @@ -132,7 +132,7 @@ namespace dlib Both sequence 1 and sequence 2 should have the same effect on H. !*/ - inline unsigned long size ( + inline size_t size ( ) const; /*! ensures diff --git a/lib/3rdParty/dlib/include/dlib/image_keypoint/hashed_feature_image.h b/lib/3rdParty/dlib/include/dlib/image_keypoint/hashed_feature_image.h index 2e61043a..80f42933 100644 --- a/lib/3rdParty/dlib/include/dlib/image_keypoint/hashed_feature_image.h +++ b/lib/3rdParty/dlib/include/dlib/image_keypoint/hashed_feature_image.h @@ -56,7 +56,7 @@ namespace dlib const image_type& img ); - inline unsigned long size ( + inline size_t size ( ) const; inline long nr ( @@ -325,7 +325,7 @@ namespace dlib typename feature_extractor, typename hash_function_type > - unsigned long hashed_feature_image:: + size_t hashed_feature_image:: size ( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/image_keypoint/hashed_feature_image_abstract.h b/lib/3rdParty/dlib/include/dlib/image_keypoint/hashed_feature_image_abstract.h index fae5678a..90c1348c 100644 --- a/lib/3rdParty/dlib/include/dlib/image_keypoint/hashed_feature_image_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_keypoint/hashed_feature_image_abstract.h @@ -125,7 +125,7 @@ namespace dlib operator() as defined below. !*/ - unsigned long size ( + size_t size ( ) const; /*! ensures diff --git a/lib/3rdParty/dlib/include/dlib/image_keypoint/hog.h b/lib/3rdParty/dlib/include/dlib/image_keypoint/hog.h index 3a45c2f2..823c25d6 100644 --- a/lib/3rdParty/dlib/include/dlib/image_keypoint/hog.h +++ b/lib/3rdParty/dlib/include/dlib/image_keypoint/hog.h @@ -89,8 +89,8 @@ namespace dlib inline void unload( ) { clear(); } - inline unsigned long size ( - ) const { return static_cast(nr()*nc()); } + inline size_t size ( + ) const { return static_cast(nr()*nc()); } inline long nr ( ) const { return num_block_rows; } diff --git a/lib/3rdParty/dlib/include/dlib/image_keypoint/hog_abstract.h b/lib/3rdParty/dlib/include/dlib/image_keypoint/hog_abstract.h index e287f49b..26c8cab6 100644 --- a/lib/3rdParty/dlib/include/dlib/image_keypoint/hog_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_keypoint/hog_abstract.h @@ -188,7 +188,7 @@ namespace dlib Both sequence 1 and sequence 2 should have the same effect on H. !*/ - inline unsigned long size ( + inline size_t size ( ) const; /*! ensures diff --git a/lib/3rdParty/dlib/include/dlib/image_keypoint/nearest_neighbor_feature_image.h b/lib/3rdParty/dlib/include/dlib/image_keypoint/nearest_neighbor_feature_image.h index 74f29f82..2ee45da2 100644 --- a/lib/3rdParty/dlib/include/dlib/image_keypoint/nearest_neighbor_feature_image.h +++ b/lib/3rdParty/dlib/include/dlib/image_keypoint/nearest_neighbor_feature_image.h @@ -53,7 +53,7 @@ namespace dlib const image_type& img ); - inline unsigned long size ( + inline size_t size ( ) const; inline long nr ( @@ -250,7 +250,7 @@ namespace dlib template < typename feature_extractor > - unsigned long nearest_neighbor_feature_image:: + size_t nearest_neighbor_feature_image:: size ( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/image_keypoint/nearest_neighbor_feature_image_abstract.h b/lib/3rdParty/dlib/include/dlib/image_keypoint/nearest_neighbor_feature_image_abstract.h index 2093151b..59d7cfeb 100644 --- a/lib/3rdParty/dlib/include/dlib/image_keypoint/nearest_neighbor_feature_image_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_keypoint/nearest_neighbor_feature_image_abstract.h @@ -102,7 +102,7 @@ namespace dlib operator() as defined below. !*/ - inline unsigned long size ( + inline size_t size ( ) const; /*! ensures diff --git a/lib/3rdParty/dlib/include/dlib/image_keypoint/poly_image.h b/lib/3rdParty/dlib/include/dlib/image_keypoint/poly_image.h index ef6a3935..8abb912f 100644 --- a/lib/3rdParty/dlib/include/dlib/image_keypoint/poly_image.h +++ b/lib/3rdParty/dlib/include/dlib/image_keypoint/poly_image.h @@ -193,7 +193,7 @@ namespace dlib num_cols = 0; } - inline unsigned long size ( + inline size_t size ( ) const { return static_cast(nr()*nc()); } inline long nr ( diff --git a/lib/3rdParty/dlib/include/dlib/image_keypoint/poly_image_abstract.h b/lib/3rdParty/dlib/include/dlib/image_keypoint/poly_image_abstract.h index 5e680848..2f17bb31 100644 --- a/lib/3rdParty/dlib/include/dlib/image_keypoint/poly_image_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_keypoint/poly_image_abstract.h @@ -197,7 +197,7 @@ namespace dlib Both sequence 1 and sequence 2 should have the same effect on H. !*/ - inline unsigned long size ( + inline size_t size ( ) const; /*! ensures diff --git a/lib/3rdParty/dlib/include/dlib/image_loader/image_loader.h b/lib/3rdParty/dlib/include/dlib/image_loader/image_loader.h index 4fa29dab..a5083dd4 100644 --- a/lib/3rdParty/dlib/include/dlib/image_loader/image_loader.h +++ b/lib/3rdParty/dlib/include/dlib/image_loader/image_loader.h @@ -44,7 +44,7 @@ namespace dlib unsigned long bfReserved; unsigned long biSize; unsigned long biWidth; - unsigned long biHeight; + long biHeight; unsigned short biBitCount; unsigned long biCompression; /* @@ -110,7 +110,11 @@ namespace dlib i += 4; a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3]; biHeight = a | (b<<8) | (c<<16) | (d<<24); - + + bool bottomUp = biHeight < 0; + if (bottomUp) + biHeight = 0 - biHeight; + i += 4+2; a = buf[i]; b = buf[i+1]; biBitCount = static_cast(a | (b<<8)); @@ -216,7 +220,7 @@ namespace dlib p.red = red[pixels[i]]; p.green = green[pixels[i]]; p.blue = blue[pixels[i]]; - assign_pixel(image[row][col+i],p); + assign_pixel(image[bottomUp ? biHeight - row - 1 : row][col+i],p); } } if (in.sgetn(reinterpret_cast(buf),padding) != padding) @@ -281,14 +285,14 @@ namespace dlib p.red = red[pixel1]; p.green = green[pixel1]; p.blue = blue[pixel1]; - assign_pixel(image[row][col], p); + assign_pixel(image[bottomUp ? biHeight - row - 1 : row][col], p); if (col+1 < biWidth) { p.red = red[pixel2]; p.green = green[pixel2]; p.blue = blue[pixel2]; - assign_pixel(image[row][col+1], p); + assign_pixel(image[bottomUp ? biHeight - row - 1 : row][col+1], p); } } if (in.sgetn(reinterpret_cast(buf),padding) != padding) @@ -359,7 +363,7 @@ namespace dlib p.red = red[buf[0]]; p.green = green[buf[0]]; p.blue = blue[buf[0]]; - assign_pixel(image[row][col],p); + assign_pixel(image[bottomUp ? biHeight - row - 1 : row][col],p); } if (in.sgetn(reinterpret_cast(buf),padding) != padding) throw image_load_error("bmp load error 9: file too short"); @@ -434,7 +438,7 @@ namespace dlib p.red = red[buf[0]]; p.green = green[buf[0]]; p.blue = blue[buf[0]]; - assign_pixel(image[row][col],p); + assign_pixel(image[bottomUp ? biHeight - row - 1 : row][col],p); ++col; } @@ -469,7 +473,7 @@ namespace dlib p.red = red[command]; p.green = green[command]; p.blue = blue[command]; - assign_pixel(image[row][col],p); + assign_pixel(image[bottomUp ? biHeight - row - 1 : row][col],p); ++col; } @@ -521,7 +525,7 @@ namespace dlib p.red = buf[2]; p.green = buf[1]; p.blue = buf[0]; - assign_pixel(image[row][col], p); + assign_pixel(image[bottomUp ? biHeight - row - 1 : row][col], p); } if (in.sgetn(reinterpret_cast(buf),padding) != padding) diff --git a/lib/3rdParty/dlib/include/dlib/image_loader/jpeg_loader.cpp b/lib/3rdParty/dlib/include/dlib/image_loader/jpeg_loader.cpp deleted file mode 100644 index e3aa998b..00000000 --- a/lib/3rdParty/dlib/include/dlib/image_loader/jpeg_loader.cpp +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (C) 2010 Davis E. King (davis@dlib.net), Nils Labugt -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_JPEG_LOADER_CPp_ -#define DLIB_JPEG_LOADER_CPp_ - -// only do anything with this file if DLIB_JPEG_SUPPORT is defined -#ifdef DLIB_JPEG_SUPPORT - -#include "../array2d.h" -#include "../pixel.h" -#include "../dir_nav.h" -#include "jpeg_loader.h" -#include -#include -#include -#include - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - jpeg_loader:: - jpeg_loader( const char* filename ) : height_( 0 ), width_( 0 ), output_components_(0) - { - read_image( filename ); - } - -// ---------------------------------------------------------------------------------------- - - jpeg_loader:: - jpeg_loader( const std::string& filename ) : height_( 0 ), width_( 0 ), output_components_(0) - { - read_image( filename.c_str() ); - } - -// ---------------------------------------------------------------------------------------- - - jpeg_loader:: - jpeg_loader( const dlib::file& f ) : height_( 0 ), width_( 0 ), output_components_(0) - { - read_image( f.full_name().c_str() ); - } - -// ---------------------------------------------------------------------------------------- - - bool jpeg_loader::is_gray() const - { - return (output_components_ == 1); - } - -// ---------------------------------------------------------------------------------------- - - bool jpeg_loader::is_rgb() const - { - return (output_components_ == 3); - } - -// ---------------------------------------------------------------------------------------- - - struct jpeg_loader_error_mgr - { - jpeg_error_mgr pub; /* "public" fields */ - jmp_buf setjmp_buffer; /* for return to caller */ - }; - - void jpeg_loader_error_exit (j_common_ptr cinfo) - { - /* cinfo->err really points to a jpeg_loader_error_mgr struct, so coerce pointer */ - jpeg_loader_error_mgr* myerr = (jpeg_loader_error_mgr*) cinfo->err; - - /* Return control to the setjmp point */ - longjmp(myerr->setjmp_buffer, 1); - } - -// ---------------------------------------------------------------------------------------- - - void jpeg_loader::read_image( const char* filename ) - { - if ( filename == NULL ) - { - throw image_load_error("jpeg_loader: invalid filename, it is NULL"); - } - FILE *fp = fopen( filename, "rb" ); - if ( !fp ) - { - throw image_load_error(std::string("jpeg_loader: unable to open file ") + filename); - } - - jpeg_decompress_struct cinfo; - jpeg_loader_error_mgr jerr; - - cinfo.err = jpeg_std_error(&jerr.pub); - - jerr.pub.error_exit = jpeg_loader_error_exit; - - /* Establish the setjmp return context for my_error_exit to use. */ - if (setjmp(jerr.setjmp_buffer)) - { - /* If we get here, the JPEG code has signaled an error. - * We need to clean up the JPEG object, close the input file, and return. - */ - jpeg_destroy_decompress(&cinfo); - fclose(fp); - throw image_load_error(std::string("jpeg_loader: error while reading ") + filename); - } - - - jpeg_create_decompress(&cinfo); - - jpeg_stdio_src(&cinfo, fp); - - jpeg_read_header(&cinfo, TRUE); - - jpeg_start_decompress(&cinfo); - - height_ = cinfo.output_height; - width_ = cinfo.output_width; - output_components_ = cinfo.output_components; - - if (output_components_ != 1 && - output_components_ != 3) - { - fclose( fp ); - jpeg_destroy_decompress(&cinfo); - std::ostringstream sout; - sout << "jpeg_loader: Unsupported number of colors (" << output_components_ << ") in file " << filename; - throw image_load_error(sout.str()); - } - - std::vector rows; - rows.resize(height_); - - // size the image buffer - data.resize(height_*width_*output_components_); - - // setup pointers to each row - for (unsigned long i = 0; i < rows.size(); ++i) - rows[i] = &data[i*width_*output_components_]; - - // read the data into the buffer - while (cinfo.output_scanline < cinfo.output_height) - { - jpeg_read_scanlines(&cinfo, &rows[cinfo.output_scanline], 100); - } - - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - - fclose( fp ); - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_JPEG_SUPPORT - -#endif // DLIB_JPEG_LOADER_CPp_ - - diff --git a/lib/3rdParty/dlib/include/dlib/image_loader/jpeg_loader.h b/lib/3rdParty/dlib/include/dlib/image_loader/jpeg_loader.h index 966cdc6e..097a461f 100644 --- a/lib/3rdParty/dlib/include/dlib/image_loader/jpeg_loader.h +++ b/lib/3rdParty/dlib/include/dlib/image_loader/jpeg_loader.h @@ -3,12 +3,13 @@ #ifndef DLIB_JPEG_IMPORT #define DLIB_JPEG_IMPORT +#include + #include "jpeg_loader_abstract.h" -#include "../smart_pointers.h" #include "image_loader.h" #include "../pixel.h" #include "../dir_nav.h" -#include +#include "../test_for_odr_violations.h" namespace dlib { @@ -23,6 +24,7 @@ namespace dlib bool is_gray() const; bool is_rgb() const; + bool is_rgba() const; template void get_image( T& t_) const @@ -37,7 +39,6 @@ namespace dlib COMPILE_TIME_ASSERT(sizeof(T) == 0); #endif image_view t(t_); - t.set_size( height_, width_ ); for ( unsigned n = 0; n < height_;n++ ) { @@ -49,6 +50,14 @@ namespace dlib unsigned char p = v[m]; assign_pixel( t[n][m], p ); } + else if ( is_rgba() ) { + rgb_alpha_pixel p; + p.red = v[m*4]; + p.green = v[m*4+1]; + p.blue = v[m*4+2]; + p.alpha = v[m*4+3]; + assign_pixel( t[n][m], p ); + } else // if ( is_rgb() ) { rgb_pixel p; diff --git a/lib/3rdParty/dlib/include/dlib/image_loader/load_image.h b/lib/3rdParty/dlib/include/dlib/image_loader/load_image.h index 2a735576..64ccea9f 100644 --- a/lib/3rdParty/dlib/include/dlib/image_loader/load_image.h +++ b/lib/3rdParty/dlib/include/dlib/image_loader/load_image.h @@ -9,6 +9,10 @@ #include "jpeg_loader.h" #include "image_loader.h" #include +#include +#ifdef DLIB_GIF_SUPPORT +#include +#endif namespace dlib { @@ -20,6 +24,7 @@ namespace dlib JPG, PNG, DNG, + GIF, UNKNOWN }; @@ -44,11 +49,22 @@ namespace dlib return BMP; else if(buffer[0]=='D' && buffer[1]=='N' && buffer[2] == 'G') return DNG; + else if(buffer[0]=='G' && buffer[1]=='I' && buffer[2] == 'F') + return GIF; return UNKNOWN; } }; +// ---------------------------------------------------------------------------------------- + +// handle the differences in API between libgif v5 and older. +#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5 +#define DLIB_GIFLIB_HANDLE_DIFF_VERSIONS ,0 +#else +#define DLIB_GIFLIB_HANDLE_DIFF_VERSIONS +#endif + template void load_image ( image_type& image, @@ -65,18 +81,145 @@ namespace dlib #endif #ifdef DLIB_JPEG_SUPPORT case image_file_type::JPG: load_jpeg(image, file_name); return; +#endif +#ifdef DLIB_GIF_SUPPORT + case image_file_type::GIF: + { + image_view img(image); + GifFileType* gif = DGifOpenFileName(file_name.c_str() DLIB_GIFLIB_HANDLE_DIFF_VERSIONS); + try + { + if (gif == 0) throw image_load_error("Couldn't open file " + file_name); + if (DGifSlurp(gif) != GIF_OK) + throw image_load_error("Error reading from " + file_name); + + if (gif->ImageCount != 1) throw image_load_error("Dlib only supports reading GIF files containing one image."); + if (gif->SavedImages == 0) throw image_load_error("Unsupported GIF format 1."); + + ColorMapObject* cmo=gif->SColorMap?gif->SColorMap:gif->SavedImages->ImageDesc.ColorMap; + + if (cmo==0) throw image_load_error("Unsupported GIF format 2."); + if (cmo->Colors == 0) throw image_load_error("Unsupported GIF format 3."); + if (gif->SavedImages->ImageDesc.Width != gif->SWidth) throw image_load_error("Unsupported GIF format 4."); + if (gif->SavedImages->ImageDesc.Height != gif->SHeight) throw image_load_error("Unsupported GIF format 5."); + if (gif->SavedImages->RasterBits == 0) throw image_load_error("Unsupported GIF format 6."); + if (gif->Image.Top != 0) throw image_load_error("Unsupported GIF format 7."); + if (gif->Image.Left != 0) throw image_load_error("Unsupported GIF format 8."); + + img.set_size(gif->SHeight, gif->SWidth); + unsigned char* raster = gif->SavedImages->RasterBits; + GifColorType* colormap = cmo->Colors; + if (gif->Image.Interlace) + { + const long interlaced_offset[] = { 0, 4, 2, 1 }; + const long interlaced_jumps[] = { 8, 8, 4, 2 }; + for (int i = 0; i < 4; ++i) + { + for (long r = interlaced_offset[i]; r < img.nr(); r += interlaced_jumps[i]) + { + for (long c = 0; c < img.nc(); ++c) + { + if (*raster >= cmo->ColorCount) + throw image_load_error("Invalid GIF color value"); + rgb_pixel p; + p.red = colormap[*raster].Red; + p.green = colormap[*raster].Green; + p.blue = colormap[*raster].Blue; + assign_pixel(img[r][c], p); + ++raster; + } + } + } + } + else + { + for (long r = 0; r < img.nr(); ++r) + { + for (long c = 0; c < img.nc(); ++c) + { + if (*raster >= cmo->ColorCount) + throw image_load_error("Invalid GIF color value"); + rgb_pixel p; + p.red = colormap[*raster].Red; + p.green = colormap[*raster].Green; + p.blue = colormap[*raster].Blue; + assign_pixel(img[r][c], p); + ++raster; + } + } + } + DGifCloseFile(gif DLIB_GIFLIB_HANDLE_DIFF_VERSIONS); + } + catch(...) + { + if (gif) + DGifCloseFile(gif DLIB_GIFLIB_HANDLE_DIFF_VERSIONS); + throw; + } + return; + } #endif default: ; } if (im_type == image_file_type::JPG) - throw image_load_error("DLIB_JPEG_SUPPORT not #defined: Unable to load image in file " + file_name); + { + std::ostringstream sout; + sout << "Unable to load image in file " + file_name + ".\n" + + "You must #define DLIB_JPEG_SUPPORT and link to libjpeg to read JPEG files.\n" + + "Do this by following the instructions at http://dlib.net/compile.html.\n\n"; +#ifdef _MSC_VER + sout << "Note that you must cause DLIB_JPEG_SUPPORT to be defined for your entire project.\n"; + sout << "So don't #define it in one file. Instead, add it to the C/C++->Preprocessor->Preprocessor Definitions\n"; + sout << "field in Visual Studio's Property Pages window so it takes effect for your entire application."; +#else + sout << "Note that you must cause DLIB_JPEG_SUPPORT to be defined for your entire project.\n"; + sout << "So don't #define it in one file. Instead, use a compiler switch like -DDLIB_JPEG_SUPPORT\n"; + sout << "so it takes effect for your entire application."; +#endif + throw image_load_error(sout.str()); + } else if (im_type == image_file_type::PNG) - throw image_load_error("DLIB_PNG_SUPPORT not #defined: Unable to load image in file " + file_name); + { + std::ostringstream sout; + sout << "Unable to load image in file " + file_name + ".\n" + + "You must #define DLIB_PNG_SUPPORT and link to libpng to read PNG files.\n" + + "Do this by following the instructions at http://dlib.net/compile.html.\n\n"; +#ifdef _MSC_VER + sout << "Note that you must cause DLIB_PNG_SUPPORT to be defined for your entire project.\n"; + sout << "So don't #define it in one file. Instead, add it to the C/C++->Preprocessor->Preprocessor Definitions\n"; + sout << "field in Visual Studio's Property Pages window so it takes effect for your entire application.\n"; +#else + sout << "Note that you must cause DLIB_PNG_SUPPORT to be defined for your entire project.\n"; + sout << "So don't #define it in one file. Instead, use a compiler switch like -DDLIB_PNG_SUPPORT\n"; + sout << "so it takes effect for your entire application."; +#endif + throw image_load_error(sout.str()); + } + else if (im_type == image_file_type::GIF) + { + std::ostringstream sout; + sout << "Unable to load image in file " + file_name + ".\n" + + "You must #define DLIB_GIF_SUPPORT and link to libgif to read GIF files.\n\n"; +#ifdef _MSC_VER + sout << "Note that you must cause DLIB_GIF_SUPPORT to be defined for your entire project.\n"; + sout << "So don't #define it in one file. Instead, add it to the C/C++->Preprocessor->Preprocessor Definitions\n"; + sout << "field in Visual Studio's Property Pages window so it takes effect for your entire application.\n"; +#else + sout << "Note that you must cause DLIB_GIF_SUPPORT to be defined for your entire project.\n"; + sout << "So don't #define it in one file. Instead, use a compiler switch like -DDLIB_GIF_SUPPORT\n"; + sout << "so it takes effect for your entire application."; +#endif + throw image_load_error(sout.str()); + } else + { throw image_load_error("Unknown image file format: Unable to load image in file " + file_name); + } } +// ---------------------------------------------------------------------------------------- + } #endif // DLIB_LOAd_IMAGE_Hh_ diff --git a/lib/3rdParty/dlib/include/dlib/image_loader/load_image_abstract.h b/lib/3rdParty/dlib/include/dlib/image_loader/load_image_abstract.h index 6bb03ac0..f357bb27 100644 --- a/lib/3rdParty/dlib/include/dlib/image_loader/load_image_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_loader/load_image_abstract.h @@ -3,8 +3,6 @@ #undef DLIB_LOAd_IMAGE_ABSTRACT_ #ifdef DLIB_LOAd_IMAGE_ABSTRACT_ -#include "load_image_abstract.h" -#include "../string.h" #include "../image_processing/generic_image.h" namespace dlib @@ -19,10 +17,13 @@ namespace dlib - image_type == an image object that implements the interface defined in dlib/image_processing/generic_image.h ensures - - This function looks at the file extensions and file headers to try and figure - out what kind of image format is inside the given file. It then calls one of - load_png(), load_jpeg(), load_bmp(), or load_dng() as appropriate and stores - the resulting image into #image. + - This function loads an image from disk, in the indicated file file_name, and + writes it to the indicated image object. + - It is capable of reading the PNG, JPEG, BMP, GIF, and DNG image formats. It + is always capable of reading BMP and DNG images. However, for PNG, JPEG, and + GIF you must #define DLIB_PNG_SUPPORT, DLIB_JPEG_SUPPORT, and + DLIB_GIF_SUPPORT respectively and link your program to libpng, libjpeg, and + libgif respectively. throws - image_load_error This exception is thrown if there is some error that prevents diff --git a/lib/3rdParty/dlib/include/dlib/image_loader/png_loader.cpp b/lib/3rdParty/dlib/include/dlib/image_loader/png_loader.cpp deleted file mode 100644 index 6d19beb2..00000000 --- a/lib/3rdParty/dlib/include/dlib/image_loader/png_loader.cpp +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (C) 2008 Davis E. King (davis@dlib.net), Nils Labugt -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_PNG_LOADER_CPp_ -#define DLIB_PNG_LOADER_CPp_ - -// only do anything with this file if DLIB_PNG_SUPPORT is defined -#ifdef DLIB_PNG_SUPPORT - -#include "../array2d.h" -#include "../pixel.h" -#include "../dir_nav.h" -#include "png_loader.h" -#include -#include "../string.h" -#include "../byte_orderer.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - struct LibpngData - { - png_bytep* row_pointers_; - png_structp png_ptr_; - png_infop info_ptr_; - png_infop end_info_; - }; - -// ---------------------------------------------------------------------------------------- - - png_loader:: - png_loader( const char* filename ) : height_( 0 ), width_( 0 ) - { - read_image( filename ); - } - -// ---------------------------------------------------------------------------------------- - - png_loader:: - png_loader( const std::string& filename ) : height_( 0 ), width_( 0 ) - { - read_image( filename.c_str() ); - } - -// ---------------------------------------------------------------------------------------- - - png_loader:: - png_loader( const dlib::file& f ) : height_( 0 ), width_( 0 ) - { - read_image( f.full_name().c_str() ); - } - -// ---------------------------------------------------------------------------------------- - - const unsigned char* png_loader::get_row( unsigned i ) const - { - return ld_->row_pointers_[i]; - } - -// ---------------------------------------------------------------------------------------- - - png_loader::~png_loader() - { - if ( ld_ && ld_->row_pointers_ != NULL ) - png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), &( ld_->end_info_ ) ); - } - -// ---------------------------------------------------------------------------------------- - - bool png_loader::is_gray() const - { - return ( color_type_ == PNG_COLOR_TYPE_GRAY ); - } - -// ---------------------------------------------------------------------------------------- - - bool png_loader::is_graya() const - { - return ( color_type_ == PNG_COLOR_TYPE_GRAY_ALPHA ); - } - -// ---------------------------------------------------------------------------------------- - - bool png_loader::is_rgb() const - { - return ( color_type_ == PNG_COLOR_TYPE_RGB ); - } - -// ---------------------------------------------------------------------------------------- - - bool png_loader::is_rgba() const - { - return ( color_type_ == PNG_COLOR_TYPE_RGB_ALPHA ); - } - -// ---------------------------------------------------------------------------------------- - - // Don't do anything when libpng calls us to tell us about an error. Just return to - // our own code and throw an exception (at the long jump target). - void png_loader_user_error_fn_silent(png_structp png_struct, png_const_charp ) - { - longjmp(png_jmpbuf(png_struct),1); - } - void png_loader_user_warning_fn_silent(png_structp , png_const_charp ) - { - } - - void png_loader::read_image( const char* filename ) - { - ld_.reset(new LibpngData); - if ( filename == NULL ) - { - throw image_load_error("png_loader: invalid filename, it is NULL"); - } - FILE *fp = fopen( filename, "rb" ); - if ( !fp ) - { - throw image_load_error(std::string("png_loader: unable to open file ") + filename); - } - png_byte sig[8]; - if (fread( sig, 1, 8, fp ) != 8) - { - fclose( fp ); - throw image_load_error(std::string("png_loader: error reading file ") + filename); - } - if ( png_sig_cmp( sig, 0, 8 ) != 0 ) - { - fclose( fp ); - throw image_load_error(std::string("png_loader: format error in file ") + filename); - } - ld_->png_ptr_ = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, &png_loader_user_error_fn_silent, &png_loader_user_warning_fn_silent ); - if ( ld_->png_ptr_ == NULL ) - { - fclose( fp ); - throw image_load_error(std::string("png_loader: parse error in file ") + filename); - } - ld_->info_ptr_ = png_create_info_struct( ld_->png_ptr_ ); - if ( ld_->info_ptr_ == NULL ) - { - fclose( fp ); - png_destroy_read_struct( &( ld_->png_ptr_ ), ( png_infopp )NULL, ( png_infopp )NULL ); - throw image_load_error(std::string("png_loader: parse error in file ") + filename); - } - ld_->end_info_ = png_create_info_struct( ld_->png_ptr_ ); - if ( ld_->end_info_ == NULL ) - { - fclose( fp ); - png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), ( png_infopp )NULL ); - throw image_load_error(std::string("png_loader: parse error in file ") + filename); - } - - if (setjmp(png_jmpbuf(ld_->png_ptr_))) - { - // If we get here, we had a problem writing the file - fclose(fp); - png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), &( ld_->end_info_ ) ); - throw image_load_error(std::string("png_loader: parse error in file ") + filename); - } - - png_set_palette_to_rgb(ld_->png_ptr_); - - png_init_io( ld_->png_ptr_, fp ); - png_set_sig_bytes( ld_->png_ptr_, 8 ); - // flags force one byte per channel output - byte_orderer bo; - int png_transforms = PNG_TRANSFORM_PACKING; - if (bo.host_is_little_endian()) - png_transforms |= PNG_TRANSFORM_SWAP_ENDIAN; - png_read_png( ld_->png_ptr_, ld_->info_ptr_, png_transforms, NULL ); - height_ = png_get_image_height( ld_->png_ptr_, ld_->info_ptr_ ); - width_ = png_get_image_width( ld_->png_ptr_, ld_->info_ptr_ ); - bit_depth_ = png_get_bit_depth( ld_->png_ptr_, ld_->info_ptr_ ); - color_type_ = png_get_color_type( ld_->png_ptr_, ld_-> info_ptr_ ); - - - if (color_type_ != PNG_COLOR_TYPE_GRAY && - color_type_ != PNG_COLOR_TYPE_RGB && - color_type_ != PNG_COLOR_TYPE_RGB_ALPHA && - color_type_ != PNG_COLOR_TYPE_GRAY_ALPHA) - { - fclose( fp ); - png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), &( ld_->end_info_ ) ); - throw image_load_error(std::string("png_loader: unsupported color type in file ") + filename); - } - - if (bit_depth_ != 8 && bit_depth_ != 16) - { - fclose( fp ); - png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), &( ld_->end_info_ ) ); - throw image_load_error("png_loader: unsupported bit depth of " + cast_to_string(bit_depth_) + " in file " + std::string(filename)); - } - - ld_->row_pointers_ = png_get_rows( ld_->png_ptr_, ld_->info_ptr_ ); - - fclose( fp ); - if ( ld_->row_pointers_ == NULL ) - { - png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), &( ld_->end_info_ ) ); - throw image_load_error(std::string("png_loader: parse error in file ") + filename); - } - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_PNG_SUPPORT - -#endif // DLIB_PNG_LOADER_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/image_loader/png_loader.h b/lib/3rdParty/dlib/include/dlib/image_loader/png_loader.h index 9067c33b..291d3fdd 100644 --- a/lib/3rdParty/dlib/include/dlib/image_loader/png_loader.h +++ b/lib/3rdParty/dlib/include/dlib/image_loader/png_loader.h @@ -3,11 +3,13 @@ #ifndef DLIB_PNG_IMPORT #define DLIB_PNG_IMPORT +#include + #include "png_loader_abstract.h" -#include "../smart_pointers.h" #include "image_loader.h" #include "../pixel.h" #include "../dir_nav.h" +#include "../test_for_odr_violations.h" namespace dlib { @@ -193,7 +195,7 @@ namespace dlib unsigned height_, width_; unsigned bit_depth_; int color_type_; - scoped_ptr ld_; + std::unique_ptr ld_; }; // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/image_processing.h b/lib/3rdParty/dlib/include/dlib/image_processing.h index 32316c12..a53f4a9d 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing.h @@ -1,5 +1,10 @@ // Copyright (C) 2011 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. + +#ifdef DLIB_ALL_SOURCE_END +#include "dlib_basic_cpp_build_tutorial.txt" +#endif + #ifndef DLIB_IMAGE_PROCESSInG_H_h_ #define DLIB_IMAGE_PROCESSInG_H_h_ @@ -15,6 +20,8 @@ #include "image_processing/remove_unobtainable_rectangles.h" #include "image_processing/scan_fhog_pyramid.h" #include "image_processing/shape_predictor.h" +#include "image_processing/shape_predictor_trainer.h" +#include "image_processing/correlation_tracker.h" #endif // DLIB_IMAGE_PROCESSInG_H_h_ diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/box_overlap_testing.h b/lib/3rdParty/dlib/include/dlib/image_processing/box_overlap_testing.h index 27eca301..32409d13 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/box_overlap_testing.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/box_overlap_testing.h @@ -10,27 +10,74 @@ namespace dlib { +// ---------------------------------------------------------------------------------------- + + inline double box_intersection_over_union ( + const drectangle& a, + const drectangle& b + ) + { + const double inner = a.intersect(b).area(); + if (inner == 0) + return 0; + const double outer = (a+b).area(); + return inner/outer; + } + +// ---------------------------------------------------------------------------------------- + + inline double box_intersection_over_union ( + const rectangle& a, + const rectangle& b + ) + { + return box_intersection_over_union(drectangle(a),drectangle(b)); + } + +// ---------------------------------------------------------------------------------------- + + inline double box_percent_covered ( + const drectangle& a, + const drectangle& b + ) + { + const double inner = a.intersect(b).area(); + if (inner == 0) + return 0; + return std::max(inner/a.area(), inner/b.area()); + } + +// ---------------------------------------------------------------------------------------- + + inline double box_percent_covered ( + const rectangle& a, + const rectangle& b + ) + { + return box_percent_covered(drectangle(a), drectangle(b)); + } + // ---------------------------------------------------------------------------------------- class test_box_overlap { public: test_box_overlap ( - ) : match_thresh(0.5), overlap_thresh(1.0) + ) : iou_thresh(0.5), percent_covered_thresh(1.0) {} explicit test_box_overlap ( - double match_thresh_, - double overlap_thresh_ = 1.0 - ) : match_thresh(match_thresh_), overlap_thresh(overlap_thresh_) + double iou_thresh_, + double percent_covered_thresh_ = 1.0 + ) : iou_thresh(iou_thresh_), percent_covered_thresh(percent_covered_thresh_) { // make sure requires clause is not broken - DLIB_ASSERT(0 <= match_thresh && match_thresh <= 1 && - 0 <= overlap_thresh && overlap_thresh <= 1, - "\t test_box_overlap::test_box_overlap(match_thresh, overlap_thresh)" + DLIB_ASSERT(0 <= iou_thresh && iou_thresh <= 1 && + 0 <= percent_covered_thresh && percent_covered_thresh <= 1, + "\t test_box_overlap::test_box_overlap(iou_thresh, percent_covered_thresh)" << "\n\t Invalid inputs were given to this function " - << "\n\t match_thresh: " << match_thresh - << "\n\t overlap_thresh: " << overlap_thresh + << "\n\t iou_thresh: " << iou_thresh + << "\n\t percent_covered_thresh: " << percent_covered_thresh << "\n\t this: " << this ); @@ -46,29 +93,29 @@ namespace dlib return false; const double outer = (a+b).area(); - if (inner/outer > match_thresh || - inner/a.area() > overlap_thresh || - inner/b.area() > overlap_thresh) + if (inner/outer > iou_thresh || + inner/a.area() > percent_covered_thresh || + inner/b.area() > percent_covered_thresh) return true; else return false; } - double get_overlap_thresh ( + double get_percent_covered_thresh ( ) const { - return overlap_thresh; + return percent_covered_thresh; } - double get_match_thresh ( + double get_iou_thresh ( ) const { - return match_thresh; + return iou_thresh; } - public: - double match_thresh; - double overlap_thresh; + private: + double iou_thresh; + double percent_covered_thresh; }; // ---------------------------------------------------------------------------------------- @@ -78,8 +125,8 @@ namespace dlib std::ostream& out ) { - serialize(item.get_match_thresh(), out); - serialize(item.get_overlap_thresh(), out); + serialize(item.get_iou_thresh(), out); + serialize(item.get_percent_covered_thresh(), out); } inline void deserialize ( @@ -87,10 +134,10 @@ namespace dlib std::istream& in ) { - double overlap_thresh, match_thresh; - deserialize(match_thresh, in); - deserialize(overlap_thresh, in); - item = test_box_overlap(match_thresh, overlap_thresh); + double percent_covered_thresh, iou_thresh; + deserialize(iou_thresh, in); + deserialize(percent_covered_thresh, in); + item = test_box_overlap(iou_thresh, percent_covered_thresh); } // ---------------------------------------------------------------------------------------- @@ -99,8 +146,8 @@ namespace dlib const std::vector >& rects ) { - double max_overlap = 0; - double max_match_score = 0; + double max_pcov = 0; + double max_iou_score = 0; for (unsigned long i = 0; i < rects.size(); ++i) { for (unsigned long j = 0; j < rects[i].size(); ++j) @@ -109,29 +156,29 @@ namespace dlib { const rectangle a = rects[i][j]; const rectangle b = rects[i][k]; - const double match_score = (a.intersect(b)).area()/(double)(a+b).area(); - const double overlap_a = (a.intersect(b)).area()/(double)(a).area(); - const double overlap_b = (a.intersect(b)).area()/(double)(b).area(); + const double iou_score = (a.intersect(b)).area()/(double)(a+b).area(); + const double pcov_a = (a.intersect(b)).area()/(double)(a).area(); + const double pcov_b = (a.intersect(b)).area()/(double)(b).area(); - if (match_score > max_match_score) - max_match_score = match_score; + if (iou_score > max_iou_score) + max_iou_score = iou_score; - if (overlap_a > max_overlap) - max_overlap = overlap_a; - if (overlap_b > max_overlap) - max_overlap = overlap_b; + if (pcov_a > max_pcov) + max_pcov = pcov_a; + if (pcov_b > max_pcov) + max_pcov = pcov_b; } } } // Relax these thresholds very slightly. We do this because on some systems the - // boxes that generated the max values erroneously trigger a box overlap match - // even though their overlap and match values are *equal* to the thresholds but not - // greater. That is, sometimes when double values get moved around they change + // boxes that generated the max values erroneously trigger a box overlap iou even + // though their percent covered and iou values are *equal* to the thresholds but + // not greater. That is, sometimes when double values get moved around they change // their values slightly, so this avoids the problems that can create. - max_match_score = std::min(1.0000001*max_match_score, 1.0); - max_overlap = std::min(1.0000001*max_overlap, 1.0); - return test_box_overlap(max_match_score, max_overlap); + max_iou_score = std::min(1.0000001*max_iou_score, 1.0); + max_pcov = std::min(1.0000001*max_pcov, 1.0); + return test_box_overlap(max_iou_score, max_pcov); } // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/box_overlap_testing_abstract.h b/lib/3rdParty/dlib/include/dlib/image_processing/box_overlap_testing_abstract.h index bcfa613b..1bb4a28a 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/box_overlap_testing_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/box_overlap_testing_abstract.h @@ -8,6 +8,58 @@ namespace dlib { +// ---------------------------------------------------------------------------------------- + + inline double box_intersection_over_union ( + const drectangle& a, + const drectangle& b + ); + /*! + ensures + - returns area of the intersection of a and b divided by (a+b).area(). If both + boxes are empty then returns 0. + !*/ + +// ---------------------------------------------------------------------------------------- + + inline double box_intersection_over_union ( + const rectangle& a, + const rectangle& b + ); + /*! + ensures + - returns area of the intersection of a and b divided by (a+b).area(). If both + boxes are empty then returns 0. + !*/ + +// ---------------------------------------------------------------------------------------- + + inline double box_percent_covered ( + const drectangle& a, + const drectangle& b + ); + /*! + ensures + - let OVERLAP = a.intersect(b).area() + - This function returns max(OVERLAP/a.area(), OVERLAP/b.area()) + e.g. If one box entirely contains another then this function returns 1, if + they don't overlap at all it returns 0. + !*/ + +// ---------------------------------------------------------------------------------------- + + inline double box_percent_covered ( + const rectangle& a, + const rectangle& b + ); + /*! + ensures + - let OVERLAP = a.intersect(b).area() + - This function returns max(OVERLAP/a.area(), OVERLAP/b.area()) + e.g. If one box entirely contains another then this function returns 1, if + they don't overlap at all it returns 0. + !*/ + // ---------------------------------------------------------------------------------------- class test_box_overlap @@ -28,21 +80,21 @@ namespace dlib ); /*! ensures - - #get_match_thresh() == 0.5 - - #get_overlap_thresh() == 1.0 + - #get_iou_thresh() == 0.5 + - #get_percent_covered_thresh() == 1.0 !*/ explicit test_box_overlap ( - double match_thresh, - double overlap_thresh = 1.0 + double iou_thresh, + double percent_covered_thresh = 1.0 ); /*! requires - - 0 <= match_thresh <= 1 - - 0 <= overlap_thresh <= 1 + - 0 <= iou_thresh <= 1 + - 0 <= percent_covered_thresh <= 1 ensures - - #get_match_thresh() == match_thresh - - #get_overlap_thresh() == overlap_thresh + - #get_iou_thresh() == iou_thresh + - #get_percent_covered_thresh() == percent_covered_thresh !*/ bool operator() ( @@ -52,31 +104,30 @@ namespace dlib /*! ensures - returns true if a and b overlap "enough". This is defined precisely below. - - if (a.intersect(b).area()/(a+b).area() > get_match_thresh() || - a.intersect(b).area()/a.area() > get_overlap_thresh() || - a.intersect(b).area()/b.area() > get_overlap_thresh() ) then + - if (a.intersect(b).area()/(a+b).area() > get_iou_thresh() || + a.intersect(b).area()/a.area() > get_percent_covered_thresh() || + a.intersect(b).area()/b.area() > get_percent_covered_thresh() ) then - returns true - else - returns false !*/ - double get_match_thresh ( + double get_iou_thresh ( ) const; /*! ensures - - returns the threshold used to determine if two rectangles match. - Note that the match score varies from 0 to 1 and only becomes 1 - when two rectangles are identical. - + - returns the threshold used to determine if two rectangle's intersection + over union value is big enough to be considered a match. Note that the + iou score varies from 0 to 1 and only becomes 1 when two rectangles are + identical. !*/ - double get_overlap_thresh ( + double get_percent_covered_thresh ( ) const; /*! ensures - returns the threshold used to determine if two rectangles overlap. This value is the percent of a rectangle's area covered by another rectangle. - !*/ }; @@ -110,7 +161,7 @@ namespace dlib that is consistent with the given set of sets of rectangles. - To be precise, this function finds and returns a test_box_overlap object TBO such that: - - TBO.get_match_thresh() and TBO.get_overlap_thresh() are as small + - TBO.get_iou_thresh() and TBO.get_percent_covered_thresh() are as small as possible such that the following conditions are satisfied. - for all valid i: - for all distinct rectangles A and B in rects[i]: diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/correlation_tracker.h b/lib/3rdParty/dlib/include/dlib/image_processing/correlation_tracker.h new file mode 100644 index 00000000..f005ddc7 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/image_processing/correlation_tracker.h @@ -0,0 +1,404 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CORRELATION_TrACKER_H_ +#define DLIB_CORRELATION_TrACKER_H_ + +#include "correlation_tracker_abstract.h" +#include "../geometry.h" +#include "../matrix.h" +#include "../array2d.h" +#include "../image_transforms/assign_image.h" +#include "../image_transforms/interpolation.h" + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class correlation_tracker + { + public: + + explicit correlation_tracker (unsigned long filter_size = 6, + unsigned long num_scale_levels = 5, + unsigned long scale_window_size = 23, + double regularizer_space = 0.001, + double nu_space = 0.025, + double regularizer_scale = 0.001, + double nu_scale = 0.025, + double scale_pyramid_alpha = 1.020 + ) + : filter_size(1 << filter_size), num_scale_levels(1 << num_scale_levels), + scale_window_size(scale_window_size), + regularizer_space(regularizer_space), nu_space(nu_space), + regularizer_scale(regularizer_scale), nu_scale(nu_scale), + scale_pyramid_alpha(scale_pyramid_alpha) + { + // Create the cosine mask used for space filtering. + mask = make_cosine_mask(); + + // Create the cosine mask used for the scale filtering. + scale_cos_mask.resize(get_num_scale_levels()); + const long max_level = get_num_scale_levels()/2; + for (unsigned long k = 0; k < get_num_scale_levels(); ++k) + { + double dist = std::abs((double)k-max_level)/max_level*pi/2; + dist = std::min(dist, pi/2); + scale_cos_mask[k] = std::cos(dist); + } + } + + template + void start_track ( + const image_type& img, + const drectangle& p + ) + { + DLIB_CASSERT(p.is_empty() == false, + "\t void correlation_tracker::start_track()" + << "\n\t You can't give an empty rectangle." + ); + + B.set_size(0,0); + + point_transform_affine tform = inv(make_chip(img, p, F)); + for (unsigned long i = 0; i < F.size(); ++i) + fft_inplace(F[i]); + make_target_location_image(tform(center(p)), G); + A.resize(F.size()); + for (unsigned long i = 0; i < F.size(); ++i) + { + A[i] = pointwise_multiply(G, F[i]); + B += squared(real(F[i]))+squared(imag(F[i])); + } + + position = p; + + // now do the scale space stuff + make_scale_space(img, Fs); + for (unsigned long i = 0; i < Fs.size(); ++i) + fft_inplace(Fs[i]); + make_scale_target_location_image(get_num_scale_levels()/2, Gs); + Bs.set_size(0); + As.resize(Fs.size()); + for (unsigned long i = 0; i < Fs.size(); ++i) + { + As[i] = pointwise_multiply(Gs, Fs[i]); + Bs += squared(real(Fs[i]))+squared(imag(Fs[i])); + } + } + + + unsigned long get_filter_size ( + ) const { return filter_size; } + + unsigned long get_num_scale_levels( + ) const { return num_scale_levels; } + + unsigned long get_scale_window_size ( + ) const { return scale_window_size; } + + double get_regularizer_space ( + ) const { return regularizer_space; } + inline double get_nu_space ( + ) const { return nu_space;} + + double get_regularizer_scale ( + ) const { return regularizer_scale; } + double get_nu_scale ( + ) const { return nu_scale;} + + drectangle get_position ( + ) const + { + return position; + } + + double get_scale_pyramid_alpha ( + ) const { return scale_pyramid_alpha; } + + + template + double update_noscale( + const image_type& img, + const drectangle& guess + ) + { + DLIB_CASSERT(get_position().is_empty() == false, + "\t double correlation_tracker::update()" + << "\n\t You must call start_track() first before calling update()." + ); + + + const point_transform_affine tform = make_chip(img, guess, F); + for (unsigned long i = 0; i < F.size(); ++i) + fft_inplace(F[i]); + + // use the current filter to predict the object's location + G = 0; + for (unsigned long i = 0; i < F.size(); ++i) + G += pointwise_multiply(F[i],conj(A[i])); + G = pointwise_multiply(G, reciprocal(B+get_regularizer_space())); + ifft_inplace(G); + const dlib::vector pp = max_point_interpolated(real(G)); + + + // Compute the peak to side lobe ratio. + const point p = pp; + running_stats rs; + const rectangle peak = centered_rect(p, 8,8); + for (long r = 0; r < G.nr(); ++r) + { + for (long c = 0; c < G.nc(); ++c) + { + if (!peak.contains(point(c,r))) + rs.add(G(r,c).real()); + } + } + const double psr = (G(p.y(),p.x()).real()-rs.mean())/rs.stddev(); + + // update the position of the object + position = translate_rect(guess, tform(pp)-center(guess)); + + // now update the position filters + make_target_location_image(pp, G); + B *= (1-get_nu_space()); + for (unsigned long i = 0; i < F.size(); ++i) + { + A[i] = get_nu_space()*pointwise_multiply(G, F[i]) + (1-get_nu_space())*A[i]; + B += get_nu_space()*(squared(real(F[i]))+squared(imag(F[i]))); + } + + return psr; + } + + template + double update ( + const image_type& img, + const drectangle& guess + ) + { + double psr = update_noscale(img, guess); + + // Now predict the scale change + make_scale_space(img, Fs); + for (unsigned long i = 0; i < Fs.size(); ++i) + fft_inplace(Fs[i]); + Gs = 0; + for (unsigned long i = 0; i < Fs.size(); ++i) + Gs += pointwise_multiply(Fs[i],conj(As[i])); + Gs = pointwise_multiply(Gs, reciprocal(Bs+get_regularizer_scale())); + ifft_inplace(Gs); + const double pos = max_point_interpolated(real(Gs)).y(); + + // update the rectangle's scale + position *= std::pow(get_scale_pyramid_alpha(), pos-(double)get_num_scale_levels()/2); + + + + // Now update the scale filters + make_scale_target_location_image(pos, Gs); + Bs *= (1-get_nu_scale()); + for (unsigned long i = 0; i < Fs.size(); ++i) + { + As[i] = get_nu_scale()*pointwise_multiply(Gs, Fs[i]) + (1-get_nu_scale())*As[i]; + Bs += get_nu_scale()*(squared(real(Fs[i]))+squared(imag(Fs[i]))); + } + + + return psr; + } + + template + double update_noscale ( + const image_type& img + ) + { + return update_noscale(img, get_position()); + } + + template + double update( + const image_type& img + ) + { + return update(img, get_position()); + } + + private: + + template + void make_scale_space( + const image_type& img, + std::vector,0,1> >& Fs + ) const + { + typedef typename image_traits::pixel_type pixel_type; + + // Make an image pyramid and put it into the chips array. + const long chip_size = get_scale_window_size(); + drectangle ppp = position*std::pow(get_scale_pyramid_alpha(), -(double)get_num_scale_levels()/2); + dlib::array > chips; + std::vector > from_points, to_points; + from_points.push_back(point(0,0)); + from_points.push_back(point(chip_size-1,0)); + from_points.push_back(point(chip_size-1,chip_size-1)); + for (unsigned long i = 0; i < get_num_scale_levels(); ++i) + { + array2d chip(chip_size,chip_size); + + // pull box into chip + to_points.clear(); + to_points.push_back(ppp.tl_corner()); + to_points.push_back(ppp.tr_corner()); + to_points.push_back(ppp.br_corner()); + transform_image(img,chip,interpolate_bilinear(),find_affine_transform(from_points, to_points)); + + chips.push_back(chip); + ppp *= get_scale_pyramid_alpha(); + } + + + // extract HOG for each chip + dlib::array > > hogs(chips.size()); + for (unsigned long i = 0; i < chips.size(); ++i) + { + extract_fhog_features(chips[i], hogs[i], 4); + hogs[i].resize(32); + assign_image(hogs[i][31], chips[i]); + assign_image(hogs[i][31], mat(hogs[i][31])/255.0); + } + + // Now copy the hog features into the Fs outputs and also apply the cosine + // windowing. + Fs.resize(hogs[0].size()*hogs[0][0].size()); + unsigned long i = 0; + for (long r = 0; r < hogs[0][0].nr(); ++r) + { + for (long c = 0; c < hogs[0][0].nc(); ++c) + { + for (unsigned long j = 0; j < hogs[0].size(); ++j) + { + Fs[i].set_size(hogs.size()); + for (unsigned long k = 0; k < hogs.size(); ++k) + { + Fs[i](k) = hogs[k][j][r][c]*scale_cos_mask[k]; + } + ++i; + } + } + } + } + + template + point_transform_affine make_chip ( + const image_type& img, + drectangle p, + std::vector > >& chip + ) const + { + typedef typename image_traits::pixel_type pixel_type; + array2d temp; + const double padding = 1.4; + const chip_details details(p*padding, chip_dims(get_filter_size(), get_filter_size())); + extract_image_chip(img, details, temp); + + + chip.resize(32); + dlib::array > hog; + extract_fhog_features(temp, hog, 1, 3,3 ); + for (unsigned long i = 0; i < hog.size(); ++i) + assign_image(chip[i], pointwise_multiply(matrix_cast(mat(hog[i])), mask)); + + assign_image(chip[31], temp); + assign_image(chip[31], pointwise_multiply(mat(chip[31]), mask)/255.0); + + return inv(get_mapping_to_chip(details)); + } + + void make_target_location_image ( + const dlib::vector& p, + matrix >& g + ) const + { + g.set_size(get_filter_size(), get_filter_size()); + g = 0; + rectangle area = centered_rect(p, 21,21).intersect(get_rect(g)); + for (long r = area.top(); r <= area.bottom(); ++r) + { + for (long c = area.left(); c <= area.right(); ++c) + { + double dist = length(point(c,r)-p); + g(r,c) = std::exp(-dist/3.0); + } + } + fft_inplace(g); + g = conj(g); + } + + + void make_scale_target_location_image ( + const double scale, + matrix,0,1>& g + ) const + { + g.set_size(get_num_scale_levels()); + for (long i = 0; i < g.size(); ++i) + { + double dist = std::pow((i-scale),2.0); + g(i) = std::exp(-dist/1.000); + } + fft_inplace(g); + g = conj(g); + } + + matrix make_cosine_mask ( + ) const + { + const long size = get_filter_size(); + matrix temp(size,size); + point cent = center(get_rect(temp)); + for (long r = 0; r < temp.nr(); ++r) + { + for (long c = 0; c < temp.nc(); ++c) + { + point delta = point(c,r)-cent; + double dist = length(delta)/(size/2.0)*(pi/2); + dist = std::min(dist*1.0, pi/2); + + temp(r,c) = std::cos(dist); + } + } + return temp; + } + + + std::vector > > A, F; + matrix B; + + std::vector,0,1> > As, Fs; + matrix Bs; + drectangle position; + + matrix mask; + std::vector scale_cos_mask; + + // G and Gs do not logically contribute to the state of this object. They are + // here just so we can void reallocating them over and over. + matrix > G; + matrix,0,1> Gs; + + unsigned long filter_size; + unsigned long num_scale_levels; + unsigned long scale_window_size; + double regularizer_space; + double nu_space; + double regularizer_scale; + double nu_scale; + double scale_pyramid_alpha; + }; +} + +#endif // DLIB_CORRELATION_TrACKER_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/correlation_tracker_abstract.h b/lib/3rdParty/dlib/include/dlib/image_processing/correlation_tracker_abstract.h new file mode 100644 index 00000000..5514f5e7 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/image_processing/correlation_tracker_abstract.h @@ -0,0 +1,162 @@ +// Copyright (C) 2015 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_CORRELATION_TrACKER_ABSTRACT_H_ +#ifdef DLIB_CORRELATION_TrACKER_ABSTRACT_H_ + +#include "../geometry/drectangle_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class correlation_tracker + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a tool for tracking moving objects in a video stream. You give it + the bounding box of an object in the first frame and it attempts to track the + object in the box from frame to frame. + + This tool is an implementation of the method described in the following paper: + Danelljan, Martin, et al. "Accurate scale estimation for robust visual + tracking." Proceedings of the British Machine Vision Conference BMVC. 2014. + !*/ + + public: + + explicit correlation_tracker (unsigned long filter_size = 6, + unsigned long num_scale_levels = 5, + unsigned long scale_window_size = 23, + double regularizer_space = 0.001, + double nu_space = 0.025, + double regularizer_scale = 0.001, + double nu_scale = 0.025, + double scale_pyramid_alpha = 1.020 + ); + /*! + requires + - p.is_empty() == false + ensures + - Initializes correlation_tracker. Higher value of filter_size and + num_scale_levels increases tracking precision but requires more CPU + for processing. Recommended values for filter_size = 5-7, + default = 6, for num_scale_levels = 4-6, default = 5 + - #get_position().is_empty() == true + !*/ + + template < + typename image_type + > + void start_track ( + const image_type& img, + const drectangle& p + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - p.is_empty() == false + ensures + - This object will start tracking the thing inside the bounding box in the + given image. That is, if you call update() with subsequent video frames + then it will try to keep track of the position of the object inside p. + - #get_position() == p + !*/ + + drectangle get_position ( + ) const; + /*! + ensures + - returns the predicted position of the object under track. + !*/ + + template < + typename image_type + > + double update_noscale ( + const image_type& img, + const drectangle& guess + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - get_position().is_empty() == false + (i.e. you must have started tracking by calling start_track()) + ensures + - When searching for the object in img, we search in the area around the + provided guess. This function only tracks object position without trying + to track the scale + - #get_position() == the new predicted location of the object in img. This + location will be a copy of guess that has been translated and NOT scaled + appropriately based on the content of img so that it, hopefully, bounds + the object in img. + - Returns the peak to side-lobe ratio. This is a number that measures how + confident the tracker is that the object is inside #get_position(). + Larger values indicate higher confidence. + !*/ + + template < + typename image_type + > + double update ( + const image_type& img, + const drectangle& guess + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - get_position().is_empty() == false + (i.e. you must have started tracking by calling start_track()) + ensures + - When searching for the object in img, we search in the area around the + provided guess. + - #get_position() == the new predicted location of the object in img. This + location will be a copy of guess that has been translated and scaled + appropriately based on the content of img so that it, hopefully, bounds + the object in img. + - Returns the peak to side-lobe ratio. This is a number that measures how + confident the tracker is that the object is inside #get_position(). + Larger values indicate higher confidence. + !*/ + + template < + typename image_type + > + double update_noscale ( + const image_type& img + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - get_position().is_empty() == false + (i.e. you must have started tracking by calling start_track()) + ensures + - performs: return update_noscale(img, get_position()) + !*/ + template < + typename image_type + > + double update ( + const image_type& img + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - get_position().is_empty() == false + (i.e. you must have started tracking by calling start_track()) + ensures + - performs: return update(img, get_position()) + !*/ + + }; +} + +#endif // DLIB_CORRELATION_TrACKER_ABSTRACT_H_ + + + diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/frontal_face_detector.h b/lib/3rdParty/dlib/include/dlib/image_processing/frontal_face_detector.h index 8680f31e..3f4b5976 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/frontal_face_detector.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/frontal_face_detector.h @@ -4,7 +4,8 @@ #define DLIB_FRONTAL_FACE_DETECTOr_Hh_ #include "frontal_face_detector_abstract.h" -#include "../image_processing.h" +#include "../image_processing/object_detector.h" +#include "../image_processing/scan_fhog_pyramid.h" #include #include "../compress_stream.h" #include "../base64.h" @@ -19,10 +20,6 @@ namespace dlib std::istringstream sin(get_serialized_frontal_faces()); frontal_face_detector detector; deserialize(detector, sin); - - // A corrected overlap threshold that leads to better precision face detection - detector.boxes_overlap.overlap_thresh = 0.3; - return detector; } diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/full_object_detection.h b/lib/3rdParty/dlib/include/dlib/image_processing/full_object_detection.h index 723a100d..1dfc99b2 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/full_object_detection.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/full_object_detection.h @@ -33,6 +33,7 @@ namespace dlib ) : rect(rect_) {} const rectangle& get_rect() const { return rect; } + rectangle& get_rect() { return rect; } unsigned long num_parts() const { return parts.size(); } const point& part( @@ -50,6 +51,21 @@ namespace dlib return parts[idx]; } + point& part( + unsigned long idx + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(idx < num_parts(), + "\t point full_object_detection::part()" + << "\n\t Invalid inputs were given to this function " + << "\n\t idx: " << idx + << "\n\t num_parts(): " << num_parts() + << "\n\t this: " << this + ); + return parts[idx]; + } + friend void serialize ( const full_object_detection& item, std::ostream& out @@ -75,6 +91,22 @@ namespace dlib deserialize(item.parts, in); } + bool operator==( + const full_object_detection& rhs + ) const + { + if (rect != rhs.rect) + return false; + if (parts.size() != rhs.parts.size()) + return false; + for (size_t i = 0; i < parts.size(); ++i) + { + if (parts[i] != rhs.parts[i]) + return false; + } + return true; + } + private: rectangle rect; std::vector parts; @@ -95,6 +127,62 @@ namespace dlib return true; } +// ---------------------------------------------------------------------------------------- + + struct mmod_rect + { + mmod_rect() = default; + mmod_rect(const rectangle& r) : rect(r) {} + mmod_rect(const rectangle& r, double score) : rect(r),detection_confidence(score) {} + mmod_rect(const rectangle& r, double score, const std::string& label) : rect(r),detection_confidence(score), label(label) {} + + rectangle rect; + double detection_confidence = 0; + bool ignore = false; + std::string label; + + operator rectangle() const { return rect; } + bool operator == (const mmod_rect& rhs) const + { + return rect == rhs.rect + && detection_confidence == rhs.detection_confidence + && ignore == rhs.ignore + && label == rhs.label; + } + }; + + inline mmod_rect ignored_mmod_rect(const rectangle& r) + { + mmod_rect temp(r); + temp.ignore = true; + return temp; + } + + inline void serialize(const mmod_rect& item, std::ostream& out) + { + int version = 2; + serialize(version, out); + serialize(item.rect, out); + serialize(item.detection_confidence, out); + serialize(item.ignore, out); + serialize(item.label, out); + } + + inline void deserialize(mmod_rect& item, std::istream& in) + { + int version = 0; + deserialize(version, in); + if (version != 1 && version != 2) + throw serialization_error("Unexpected version found while deserializing dlib::mmod_rect"); + deserialize(item.rect, in); + deserialize(item.detection_confidence, in); + deserialize(item.ignore, in); + if (version == 2) + deserialize(item.label, in); + else + item.label = ""; + } + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/full_object_detection_abstract.h b/lib/3rdParty/dlib/include/dlib/image_processing/full_object_detection_abstract.h index 799752b6..099ee01b 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/full_object_detection_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/full_object_detection_abstract.h @@ -64,6 +64,14 @@ namespace dlib this should be the bounding box for the object. !*/ + rectangle& get_rect( + ); + /*! + ensures + - returns the rectangle that indicates where this object is. In general, + this should be the bounding box for the object. + !*/ + unsigned long num_parts( ) const; /*! @@ -83,6 +91,27 @@ namespace dlib when the return value of part() is equal to OBJECT_PART_NOT_PRESENT. This is useful for modeling object parts that are not always observed. !*/ + + point& part( + unsigned long idx + ); + /*! + requires + - idx < num_parts() + ensures + - returns the location of the center of the idx-th part of this object. + Note that it is valid for a part to be "not present". This is indicated + when the return value of part() is equal to OBJECT_PART_NOT_PRESENT. + This is useful for modeling object parts that are not always observed. + !*/ + + bool operator==( + const full_object_detection& rhs + ) const; + /*! + ensures + - returns true if and only if *this and rhs have identical state. + !*/ }; // ---------------------------------------------------------------------------------------- @@ -116,6 +145,55 @@ namespace dlib obj.get_rect().contains(obj.part(i)) == true || obj.part(i) == OBJECT_PART_NOT_PRESENT !*/ +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + struct mmod_rect + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a simple struct that is used to give training data and receive detections + from the Max-Margin Object Detection loss layer loss_mmod_ object. + !*/ + + mmod_rect() = default; + mmod_rect(const rectangle& r) : rect(r) {} + mmod_rect(const rectangle& r, double score) : rect(r),detection_confidence(score) {} + mmod_rect(const rectangle& r, double score, const std::string& label) : rect(r),detection_confidence(score),label(label) {} + + rectangle rect; + double detection_confidence = 0; + bool ignore = false; + std::string label; + + operator rectangle() const { return rect; } + + bool operator == (const mmod_rect& rhs) const; + /*! + ensures + - returns true if and only if all the elements of this object compare equal + to the corresponding elements of rhs. + !*/ + }; + + mmod_rect ignored_mmod_rect( + const rectangle& r + ); + /*! + ensures + - returns a mmod_rect R such that: + - R.rect == r + - R.ignore == true + - R.detection_confidence == 0 + - R.label == "" + !*/ + + void serialize(const mmod_rect& item, std::ostream& out); + void deserialize(mmod_rect& item, std::istream& in); + /*! + provides serialization support + !*/ + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/generic_image.h b/lib/3rdParty/dlib/include/dlib/image_processing/generic_image.h index 36227736..ef3b2599 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/generic_image.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/generic_image.h @@ -4,6 +4,7 @@ #define DLIB_GeNERIC_IMAGE_Hh_ #include "../assert.h" +#include "../pixel.h" namespace dlib { @@ -128,6 +129,13 @@ namespace dlib image_traits::pixel_type !*/ + template + struct is_rgb_image { const static bool value = pixel_traits::pixel_type>::rgb; }; + + template + struct is_grayscale_image { const static bool value = pixel_traits::pixel_type>::grayscale; }; + + // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // UTILITIES TO MAKE ACCESSING IMAGE PIXELS SIMPLER diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/object_detector.h b/lib/3rdParty/dlib/include/dlib/image_processing/object_detector.h index 8807b1ca..9f78abd1 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/object_detector.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/object_detector.h @@ -189,7 +189,7 @@ namespace dlib std::istream& in ); - public: + private: bool overlaps_any_box ( const std::vector& rects, @@ -341,7 +341,7 @@ namespace dlib boxes_overlap(overlap_tester) { // make sure requires clause is not broken - DLIB_ASSERT(scanner_.get_num_detection_templates() > 0 && w_.size() > 0, + DLIB_CASSERT(scanner_.get_num_detection_templates() > 0 && w_.size() > 0, "\t object_detector::object_detector(scanner_,overlap_tester,w_)" << "\n\t Invalid inputs were given to this function " << "\n\t scanner_.get_num_detection_templates(): " << scanner_.get_num_detection_templates() @@ -349,10 +349,9 @@ namespace dlib << "\n\t this: " << this ); -#ifdef ENABLE_ASSERTS for (unsigned long i = 0; i < w_.size(); ++i) { - DLIB_ASSERT(w_[i].size() == scanner_.get_num_dimensions() + 1, + DLIB_CASSERT(w_[i].size() == scanner_.get_num_dimensions() + 1, "\t object_detector::object_detector(scanner_,overlap_tester,w_)" << "\n\t Invalid inputs were given to this function " << "\n\t scanner_.get_num_detection_templates(): " << scanner_.get_num_detection_templates() @@ -361,7 +360,6 @@ namespace dlib << "\n\t this: " << this ); } -#endif scanner.copy_configuration(scanner_); w.resize(w_.size()); @@ -382,7 +380,7 @@ namespace dlib const std::vector& detectors ) { - DLIB_ASSERT(detectors.size() != 0, + DLIB_CASSERT(detectors.size() != 0, "\t object_detector::object_detector(detectors)" << "\n\t Invalid inputs were given to this function " << "\n\t this: " << this diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/object_detector_abstract.h b/lib/3rdParty/dlib/include/dlib/image_processing/object_detector_abstract.h index fdeae283..9578d8b0 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/object_detector_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/object_detector_abstract.h @@ -185,7 +185,7 @@ namespace dlib ) const; /*! requires - - idx < num_detectors + - idx < num_detectors() ensures - returns the idx-th weight vector loaded into this object. All the weight vectors have the same dimension and logically each represents a different detector. diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/remove_unobtainable_rectangles.h b/lib/3rdParty/dlib/include/dlib/image_processing/remove_unobtainable_rectangles.h index b9fa46ae..95ab4f35 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/remove_unobtainable_rectangles.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/remove_unobtainable_rectangles.h @@ -156,10 +156,11 @@ namespace dlib template < typename image_array_type, - typename Pyramid_type + typename Pyramid_type, + typename Feature_extractor_type > std::vector > remove_unobtainable_rectangles ( - const structural_object_detection_trainer >& trainer, + const structural_object_detection_trainer >& trainer, const image_array_type& images, std::vector >& object_locations ) diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/remove_unobtainable_rectangles_abstract.h b/lib/3rdParty/dlib/include/dlib/image_processing/remove_unobtainable_rectangles_abstract.h index a3a41345..328326f1 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/remove_unobtainable_rectangles_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/remove_unobtainable_rectangles_abstract.h @@ -18,8 +18,7 @@ namespace dlib template < typename image_scanner_type, - typename image_array_type, - typename Pyramid_type + typename image_array_type > std::vector > remove_unobtainable_rectangles ( const structural_object_detection_trainer& trainer, diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/render_face_detections.h b/lib/3rdParty/dlib/include/dlib/image_processing/render_face_detections.h index 31405846..96ff8971 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/render_face_detections.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/render_face_detections.h @@ -18,46 +18,81 @@ namespace dlib std::vector lines; for (unsigned long i = 0; i < dets.size(); ++i) { - DLIB_CASSERT(dets[i].num_parts() == 68, + DLIB_CASSERT(dets[i].num_parts() == 68 || dets[i].num_parts() == 5, "\t std::vector render_face_detections()" - << "\n\t Invalid inputs were given to this function. " + << "\n\t You have to give either a 5 point or 68 point face landmarking output to this function. " << "\n\t dets["< render_face_detections ( + const full_object_detection& det, + const rgb_pixel color = rgb_pixel(0,255,0) + ) + { + std::vector dets; + dets.push_back(det); + return render_face_detections(dets, color); + } + +// ---------------------------------------------------------------------------------------- + } #endif // DLIB_RENDER_FACE_DeTECTIONS_H_ diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/render_face_detections_abstract.h b/lib/3rdParty/dlib/include/dlib/image_processing/render_face_detections_abstract.h index f8d61398..f609c8e8 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/render_face_detections_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/render_face_detections_abstract.h @@ -9,6 +9,8 @@ namespace dlib { +// ---------------------------------------------------------------------------------------- + inline std::vector render_face_detections ( const std::vector& dets, const rgb_pixel color = rgb_pixel(0,255,0) @@ -16,16 +18,40 @@ namespace dlib /*! requires - for all valid i: - - dets[i].num_parts() == 68 + - dets[i].num_parts() == 68 || dets[i].num_parts() == 5 ensures - Interprets the given objects as face detections with parts annotated using - the iBUG face landmark scheme. We then return a set of overlay lines that - will draw the objects onto the screen in a way that properly draws the - outline of the face features defined by the part locations. + either the iBUG face landmark scheme or a 5 point face annotation. We then + return a set of overlay lines that will draw the objects onto the screen in a + way that properly draws the outline of the face features defined by the part + locations. - returns a vector with dets.size() elements, each containing the lines necessary to render a face detection from dets. + - The 5 point face annotation scheme is assumed to be: + - det part 0 == left eye corner, outside part of eye. + - det part 1 == left eye corner, inside part of eye. + - det part 2 == right eye corner, outside part of eye. + - det part 3 == right eye corner, inside part of eye. + - det part 4 == immediately under the nose, right at the top of the philtrum. !*/ +// ---------------------------------------------------------------------------------------- + + inline std::vector render_face_detections ( + const full_object_detection& det, + const rgb_pixel color = rgb_pixel(0,255,0) + ); + /*! + requires + - det.num_parts() == 68 || det.num_parts() == 5 + ensures + - This function is identical to the above render_face_detections() routine + except that it takes just a single full_object_detection instead of a + std::vector of them. + !*/ + +// ---------------------------------------------------------------------------------------- + } #endif // DLIB_RENDER_FACE_DeTECTIONS_ABSTRACT_H_ diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/scan_fhog_pyramid.h b/lib/3rdParty/dlib/include/dlib/image_processing/scan_fhog_pyramid.h index 14222bb9..5ae0310a 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/scan_fhog_pyramid.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/scan_fhog_pyramid.h @@ -1,6 +1,5 @@ // Copyright (C) 2013 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. - #ifndef DLIB_SCAN_fHOG_PYRAMID_Hh_ #define DLIB_SCAN_fHOG_PYRAMID_Hh_ @@ -11,8 +10,6 @@ #include "../array2d.h" #include "object_detector.h" -#include - namespace dlib { @@ -463,87 +460,6 @@ namespace dlib } return area; } - - - template - rectangle apply_filters_to_fhog_parallel ( - const fhog_filterbank& w, - const array >& feats, - array2d& saliency_image - ) - { - const unsigned long num_separable_filters = w.num_separable_filters(); - rectangle area; - // use the separable filters if they would be faster than running the regular filters. - if (num_separable_filters > w.filters.size()*std::min(w.filters[0].nr(),w.filters[0].nc())/3.0) - { - area = spatially_filter_image(feats[0], saliency_image, w.filters[0]); - for (unsigned long i = 1; i < w.filters.size(); ++i) - { - // now we filter but the output adds to saliency_image rather than - // overwriting it. - spatially_filter_image(feats[i], saliency_image, w.filters[i], 1, false, true); - } - } - else - { - - // find the first filter to apply - unsigned long i = 0; - while (i < w.row_filters.size() && w.row_filters[i].size() == 0) - ++i; - - int start_filter = i; - - int num_filters = 0; - std::vector filters_before; - filters_before.push_back(0); - - // count the number of filters that will be used - for (; i < w.row_filters.size(); ++i) - { - num_filters += w.row_filters[i].size(); - filters_before.push_back(num_filters); - } - - array > saliency_images; - saliency_images.set_max_size(num_filters); - saliency_images.set_size(num_filters); - - i = start_filter; - - tbb::parallel_for((int)i, (int)w.row_filters.size(), [&](int k) - { - array2d saliency_tmp; - array2d scratch; - for (unsigned long j = 0; j < w.row_filters[k].size(); ++j) - { - area = float_spatially_filter_image_separable(feats[k], saliency_tmp, w.row_filters[k][j], w.col_filters[k][j], scratch, false); - swap(saliency_tmp, saliency_images[filters_before[k]-start_filter+j]); - } - }); - - saliency_image.clear(); - - saliency_image.set_size(feats[0].nr(), feats[0].nc()); - assign_all_pixels(saliency_image, 0); - - // TODO this could be optimised? - // Sum across the saliency images - for(unsigned int i = 0; i < saliency_images.size(); ++i) - { - for(int y = 0; y < saliency_image.nr(); ++y) - { - for(int x = 0; x < saliency_image.nc(); ++x) - { - saliency_image[y][x] += saliency_images[i][y][x]; - } - } - } - - } - return area; - } } // ---------------------------------------------------------------------------------------- @@ -696,73 +612,6 @@ namespace dlib } } } - - template < - typename pyramid_type, - typename image_type, - typename feature_extractor_type - > - void create_fhog_pyramid_parallel ( - const image_type& img, - const feature_extractor_type& fe, - array > >& feats, - int cell_size, - int filter_rows_padding, - int filter_cols_padding, - unsigned long min_pyramid_layer_width, - unsigned long min_pyramid_layer_height, - unsigned long max_pyramid_levels - ) - { - unsigned long levels = 0; - rectangle rect = get_rect(img); - - // figure out how many pyramid levels we should be using based on the image size - pyramid_type pyr; - do - { - rect = pyr.rect_down(rect); - ++levels; - } while (rect.width() >= min_pyramid_layer_width && rect.height() >= min_pyramid_layer_height && - levels < max_pyramid_levels); - - if (feats.max_size() < levels) - feats.set_max_size(levels); - feats.set_size(levels); - - typedef typename image_traits::pixel_type pixel_type; - - // First create the pyramids - array > image_pyramid; - image_pyramid.set_max_size(levels-1); - image_pyramid.set_size(levels-1); - - for(unsigned int pyr_level = 0; pyr_level < levels - 1; ++pyr_level) - { - array2d temp; - if(pyr_level == 0) - { - pyr(img, temp); - } - else - { - pyr(image_pyramid[pyr_level-1], temp); - } - swap(temp, image_pyramid[pyr_level]); - } - - tbb::parallel_for(0, (int)levels, [&](int pyr_level){ - if(pyr_level == 0) - { - fe(img, feats[pyr_level], cell_size,filter_rows_padding,filter_cols_padding); - } - else - { - fe(image_pyramid[pyr_level-1], feats[pyr_level], cell_size,filter_rows_padding,filter_cols_padding); - } - }); - } - } // ---------------------------------------------------------------------------------------- @@ -781,14 +630,9 @@ namespace dlib { unsigned long width, height; compute_fhog_window_size(width,height); - //impl::create_fhog_pyramid(img, fe, feats, cell_size, height, - // width, min_pyramid_layer_width, min_pyramid_layer_height, - // max_pyramid_levels); - - impl::create_fhog_pyramid_parallel(img, fe, feats, cell_size, height, + impl::create_fhog_pyramid(img, fe, feats, cell_size, height, width, min_pyramid_layer_width, min_pyramid_layer_height, max_pyramid_levels); - } // ---------------------------------------------------------------------------------------- @@ -962,66 +806,6 @@ namespace dlib std::sort(dets.rbegin(), dets.rend(), compare_pair_rect); } - template < - typename pyramid_type, - typename feature_extractor_type, - typename fhog_filterbank - > - void detect_from_fhog_pyramid_parallel ( - const array > >& feats, - const feature_extractor_type& fe, - const fhog_filterbank& w, - const double thresh, - const unsigned long det_box_height, - const unsigned long det_box_width, - const int cell_size, - const int filter_rows_padding, - const int filter_cols_padding, - std::vector >& dets - ) - { - dets.clear(); - - pyramid_type pyr; - - tbb::concurrent_vector> dets_conc; - - int num_features = feats.size(); - - tbb::parallel_for(0, num_features, [&](int l){ - - array2d saliency_image; - - //const rectangle area = apply_filters_to_fhog(w, feats[l], saliency_image); - - // TODO does not seem to help much? - const rectangle area = apply_filters_to_fhog_parallel(w, feats[l], saliency_image); - - // now search the saliency image for any detections - for (long r = area.top(); r <= area.bottom(); ++r) - { - for (long c = area.left(); c <= area.right(); ++c) - { - // if we found a detection - if (saliency_image[r][c] >= thresh) - { - rectangle rect = fe.feats_to_image(centered_rect(point(c,r),det_box_width,det_box_height), - cell_size, filter_rows_padding, filter_cols_padding); - rect = pyr.rect_up(rect, l); - dets_conc.push_back(std::make_pair(saliency_image[r][c], rect)); - } - } - } - }); - - for(size_t i = 0; i < dets_conc.size(); ++i) - { - dets.push_back(dets_conc[i]); - } - - std::sort(dets.rbegin(), dets.rend(), compare_pair_rect); - } - inline bool overlaps_any_box ( const test_box_overlap& tester, const std::vector& rects, @@ -1067,10 +851,7 @@ namespace dlib unsigned long width, height; compute_fhog_window_size(width,height); - //impl::detect_from_fhog_pyramid(feats, fe, w, thresh, - // height-2*padding, width-2*padding, cell_size, height, width, dets); - - impl::detect_from_fhog_pyramid_parallel(feats, fe, w, thresh, + impl::detect_from_fhog_pyramid(feats, fe, w, thresh, height-2*padding, width-2*padding, cell_size, height, width, dets); } @@ -1525,7 +1306,6 @@ namespace dlib // Do non-max suppression - dets.clear(); if (detectors.size() > 1) std::sort(dets_accum.rbegin(), dets_accum.rend()); for (unsigned long i = 0; i < dets_accum.size(); ++i) diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/scan_fhog_pyramid_abstract.h b/lib/3rdParty/dlib/include/dlib/image_processing/scan_fhog_pyramid_abstract.h index fa62e24f..d12a2b2b 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/scan_fhog_pyramid_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/scan_fhog_pyramid_abstract.h @@ -166,7 +166,7 @@ namespace dlib pretty much do whatever you want in terms of feature extraction so long as the following conditions are met: - #hog.size() == get_num_planes() - - Each image plane in of #hog has the same dimensions. + - Each image plane in #hog has the same dimensions. - for all valid i, r, and c: - #hog[i][r][c] == a feature value describing the image content centered at the following pixel location in img: @@ -604,7 +604,7 @@ namespace dlib ensures - This function allows you to determine the feature vector used for an object detection output from detect(). Note that this vector is - added to psi. Note also that you must use get_full_object_detection() to + added to psi. Note also that you can use get_full_object_detection() to convert a rectangle from detect() into the needed full_object_detection. - The dimensionality of the vector added to psi is get_num_dimensions(). This means that elements of psi after psi(get_num_dimensions()-1) are not modified. diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/scan_image.h b/lib/3rdParty/dlib/include/dlib/image_processing/scan_image.h index 1a9c46ed..71205c90 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/scan_image.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/scan_image.h @@ -11,6 +11,7 @@ #include "../rand.h" #include "../array2d.h" #include "../image_transforms/spatial_filtering.h" +#include "../image_transforms/thresholding.h" namespace dlib { @@ -235,6 +236,143 @@ namespace dlib } } +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + std::vector find_peaks ( + const image_type& img_, + const double non_max_suppression_radius, + const typename pixel_traits::pixel_type>::basic_pixel_type& thresh + ) + { + DLIB_CASSERT(non_max_suppression_radius >= 0); + const_image_view img(img_); + + using basic_pixel_type = typename pixel_traits::pixel_type>::basic_pixel_type; + + std::vector> peaks; + + for (long r = 1; r+1 < img.nr(); ++r) + { + for (long c = 1; c+1 < img.nc(); ++c) + { + auto val = img[r][c]; + if (val < thresh) + continue; + + if ( + val <= img[r-1][c] || + val <= img[r+1][c] || + val <= img[r][c+1] || + val <= img[r][c-1] || + val <= img[r-1][c-1] || + val <= img[r+1][c+1] || + val <= img[r-1][c+1] || + val <= img[r+1][c-1] + ) + { + continue; + } + + peaks.emplace_back(val,point(c,r)); + } + } + + + // now do non-max suppression of the peaks according to the supplied radius. + using pt = std::pair; + // First sort the peaks so the strongest peaks come first. We will greedily accept + // them and then do the normal peak sorting/non-max suppression thing. + std::sort(peaks.rbegin(), peaks.rend(), [](const pt& a, const pt&b ){ return a.first < b.first; }); + std::vector final_peaks; + const double radius_sqr = non_max_suppression_radius*non_max_suppression_radius; + + // If there are a lot of peaks then we will make a mask image and use that to do + // the non-max suppression since this is fast when peaks.size() is large. Otherwise we + // will do the simpler thing in the else block that doesn't require us to allocate a + // temporary mask image. + if (peaks.size() > 500 && radius_sqr != 0) + { + // hit will record which areas of the image have already been accounted for by some + // peak. So it is our mask image. + matrix hit(img.nr(), img.nc()); + // initially nothing has been hit. + hit = 0; + const unsigned long win_size = std::round(2*non_max_suppression_radius); + const rectangle area = get_rect(img); + for (auto& pp : peaks) + { + auto& p = pp.second; + if (!hit(p.y(),p.x())) + { + final_peaks.emplace_back(p); + + // mask out a circle around this new peak + rectangle win = centered_rect(p, win_size, win_size).intersect(area); + for (long r = win.top(); r <= win.bottom(); ++r) + { + for (long c = win.left(); c <= win.right(); ++c) + { + if (length_squared(point(c,r)-p) <= radius_sqr) + hit(r,c) = 1; + } + } + } + } + } + else + { + // if peaks.size() is relatively small then this is a faster way to do the non-max + // suppression. + for (auto& p : peaks) + { + bool hits_any_existing_peak = false; + // If the user set the radius to 0 then just copy the peaks to the output without + // checking anything. + if (radius_sqr != 0) + { + for (auto& v : final_peaks) + { + if (length_squared(p.second-v) <= radius_sqr) + { + hits_any_existing_peak = true; + break; + } + } + } + if (!hits_any_existing_peak) + { + final_peaks.emplace_back(p.second); + } + } + } + + return final_peaks; + } + + template < + typename image_type + > + std::vector find_peaks ( + const image_type& img + ) + { + return find_peaks(img, 0, partition_pixels(img)); + } + + template < + typename image_type + > + std::vector find_peaks ( + const image_type& img, + const double non_max_suppression_radius + ) + { + return find_peaks(img, non_max_suppression_radius, partition_pixels(img)); + } + // ---------------------------------------------------------------------------------------- template < diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/scan_image_abstract.h b/lib/3rdParty/dlib/include/dlib/image_processing/scan_image_abstract.h index fe2fc51a..6ff377fa 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/scan_image_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/scan_image_abstract.h @@ -132,6 +132,62 @@ namespace dlib - #dets == all the points which passed the threshold test. !*/ +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + std::vector find_peaks ( + const image_type& img, + const double non_max_suppression_radius, + const typename pixel_traits::pixel_type>::basic_pixel_type& thresh + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h. Moreover, these it must contain a + scalar pixel type (e.g. int rather than rgb_pixel) + - non_max_suppression_radius >= 0 + ensures + - Scans the given image and finds all pixels with values >= thresh that are + also local maximums within their 8-connected neighborhood of the image. Such + pixels are collected, sorted in decreasing order of their pixel values, and + then non-maximum suppression is applied to this list of points using the + given non_max_suppression_radius. The final list of peaks is then returned. + + Therefore, the returned list, V, will have these properties: + - V.size() == the number of peaks found in the image. + - When measured in image coordinates, no elements of V are within + non_max_suppression_radius distance of each other. That is, for all valid i!=j + it is true that length(V[i]-V[j]) > non_max_suppression_radius. + - For each element of V, that element has the maximum pixel value of all + pixels in the ball centered on that pixel with radius + non_max_suppression_radius. + !*/ + + template < + typename image_type + > + std::vector find_peaks ( + const image_type& img + ); + /*! + ensures + - performs: return find_peaks(img, 0, partition_pixels(img)) + !*/ + + template < + typename image_type + > + std::vector find_peaks ( + const image_type& img, + const double non_max_suppression_radius + ); + /*! + ensures + - performs: return find_peaks(img, non_max_suppression_radius, partition_pixels(img)) + !*/ + // ---------------------------------------------------------------------------------------- template < diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/scan_image_boxes.h b/lib/3rdParty/dlib/include/dlib/image_processing/scan_image_boxes.h index daf8e5b8..f4549565 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/scan_image_boxes.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/scan_image_boxes.h @@ -6,7 +6,6 @@ #include "scan_image_boxes_abstract.h" #include "../matrix.h" #include "../geometry.h" -#include "../image_processing.h" #include "../array2d.h" #include #include "../image_processing/full_object_detection.h" diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/scan_image_pyramid.h b/lib/3rdParty/dlib/include/dlib/image_processing/scan_image_pyramid.h index f0b9e081..455f1a64 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/scan_image_pyramid.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/scan_image_pyramid.h @@ -6,7 +6,7 @@ #include "scan_image_pyramid_abstract.h" #include "../matrix.h" #include "../geometry.h" -#include "../image_processing.h" +#include "scan_image.h" #include "../array2d.h" #include #include "full_object_detection.h" diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/shape_predictor.h b/lib/3rdParty/dlib/include/dlib/image_processing/shape_predictor.h index 98953920..05e9a60f 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/shape_predictor.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/shape_predictor.h @@ -9,7 +9,8 @@ #include "../matrix.h" #include "../geometry.h" #include "../pixel.h" -#include "../console_progress_indicator.h" +#include "../statistics.h" +#include namespace dlib { @@ -57,8 +58,11 @@ namespace dlib std::vector splits; std::vector > leaf_values; + unsigned long num_leaves() const { return leaf_values.size(); } + inline const matrix& operator()( - const std::vector& feature_pixel_values + const std::vector& feature_pixel_values, + unsigned long& i ) const /*! requires @@ -69,17 +73,19 @@ namespace dlib (i.e. there needs to be the right number of leaves given the number of splits in the tree) ensures - runs through the tree and returns the vector at the leaf we end up in. + - #i == the selected leaf node index. !*/ { - unsigned long i = 0; + i = 0; while (i < splits.size()) { - if (feature_pixel_values[splits[i].idx1] - feature_pixel_values[splits[i].idx2] > splits[i].thresh) + if ((float)feature_pixel_values[splits[i].idx1] - (float)feature_pixel_values[splits[i].idx2] > splits[i].thresh) i = left_child(i); else i = right_child(i); } - return leaf_values[i - splits.size()]; + i = i - splits.size(); + return leaf_values[i]; } friend void serialize (const regression_tree& item, std::ostream& out) @@ -205,7 +211,7 @@ namespace dlib from_points.push_back(rect.tl_corner()); to_points.push_back(point(0,0)); from_points.push_back(rect.tr_corner()); to_points.push_back(point(1,0)); from_points.push_back(rect.br_corner()); to_points.push_back(point(1,1)); - return find_similarity_transform(from_points, to_points); + return find_affine_transform(from_points, to_points); } // ------------------------------------------------------------------------------------ @@ -223,12 +229,12 @@ namespace dlib to_points.push_back(rect.tl_corner()); from_points.push_back(point(0,0)); to_points.push_back(rect.tr_corner()); from_points.push_back(point(1,0)); to_points.push_back(rect.br_corner()); from_points.push_back(point(1,1)); - return find_similarity_transform(from_points, to_points); + return find_affine_transform(from_points, to_points); } // ------------------------------------------------------------------------------------ - template + template void extract_feature_pixel_values ( const image_type& img_, const rectangle& rect, @@ -236,7 +242,7 @@ namespace dlib const matrix& reference_shape, const std::vector& reference_pixel_anchor_idx, const std::vector >& reference_pixel_deltas, - std::vector& feature_pixel_values + std::vector& feature_pixel_values ) /*! requires @@ -315,36 +321,37 @@ namespace dlib unsigned long num_parts ( ) const - /*! - ensures - - returns the number of points in the shape - !*/ { return initial_shape.size()/2; } + unsigned long num_features ( + ) const + { + unsigned long num = 0; + for (unsigned long iter = 0; iter < forests.size(); ++iter) + for (unsigned long i = 0; i < forests[iter].size(); ++i) + num += forests[iter][i].num_leaves(); + return num; + } + template full_object_detection operator()( const image_type& img, const rectangle& rect ) const - /*! - ensures - - runs the tree regressor on the detection rect inside img and returns a - full_object_detection DET such that: - - DET.get_rect() == rect - - DET.num_parts() == num_parts() - !*/ { using namespace impl; matrix current_shape = initial_shape; std::vector feature_pixel_values; for (unsigned long iter = 0; iter < forests.size(); ++iter) { - extract_feature_pixel_values(img, rect, current_shape, initial_shape, anchor_idx[iter], deltas[iter], feature_pixel_values); + extract_feature_pixel_values(img, rect, current_shape, initial_shape, + anchor_idx[iter], deltas[iter], feature_pixel_values); + unsigned long leaf_idx; // evaluate all the trees at this level of the cascade. for (unsigned long i = 0; i < forests[iter].size(); ++i) - current_shape += forests[iter][i](feature_pixel_values); + current_shape += forests[iter][i](feature_pixel_values, leaf_idx); } // convert the current_shape into a full_object_detection @@ -355,27 +362,45 @@ namespace dlib return full_object_detection(rect, parts); } - friend void serialize (const shape_predictor& item, std::ostream& out) + template + full_object_detection operator()( + const image_type& img, + const rectangle& rect, + std::vector >& feats + ) const { - int version = 1; - dlib::serialize(version, out); - dlib::serialize(item.initial_shape, out); - dlib::serialize(item.forests, out); - dlib::serialize(item.anchor_idx, out); - dlib::serialize(item.deltas, out); - } - friend void deserialize (shape_predictor& item, std::istream& in) - { - int version = 0; - dlib::deserialize(version, in); - if (version != 1) - throw serialization_error("Unexpected version found while deserializing dlib::shape_predictor."); - dlib::deserialize(item.initial_shape, in); - dlib::deserialize(item.forests, in); - dlib::deserialize(item.anchor_idx, in); - dlib::deserialize(item.deltas, in); + feats.clear(); + using namespace impl; + matrix current_shape = initial_shape; + std::vector feature_pixel_values; + unsigned long feat_offset = 0; + for (unsigned long iter = 0; iter < forests.size(); ++iter) + { + extract_feature_pixel_values(img, rect, current_shape, initial_shape, + anchor_idx[iter], deltas[iter], feature_pixel_values); + // evaluate all the trees at this level of the cascade. + for (unsigned long i = 0; i < forests[iter].size(); ++i) + { + unsigned long leaf_idx; + current_shape += forests[iter][i](feature_pixel_values, leaf_idx); + + feats.push_back(std::make_pair(feat_offset+leaf_idx, 1)); + feat_offset += forests[iter][i].num_leaves(); + } + } + + // convert the current_shape into a full_object_detection + const point_transform_affine tform_to_img = unnormalizing_tform(rect); + std::vector parts(current_shape.size()/2); + for (unsigned long i = 0; i < parts.size(); ++i) + parts[i] = tform_to_img(location(current_shape, i)); + return full_object_detection(rect, parts); } + friend void serialize (const shape_predictor& item, std::ostream& out); + + friend void deserialize (shape_predictor& item, std::istream& in); + private: matrix initial_shape; std::vector > forests; @@ -383,598 +408,27 @@ namespace dlib std::vector > > deltas; }; -// ---------------------------------------------------------------------------------------- - - class shape_predictor_trainer + inline void serialize (const shape_predictor& item, std::ostream& out) { - /*! - This thing really only works with unsigned char or rgb_pixel images (since we assume the threshold - should be in the range [-128,128]). - !*/ - public: - - shape_predictor_trainer ( - ) - { - _cascade_depth = 10; - _tree_depth = 4; - _num_trees_per_cascade_level = 500; - _nu = 0.1; - _oversampling_amount = 20; - _feature_pool_size = 400; - _lambda = 0.1; - _num_test_splits = 20; - _feature_pool_region_padding = 0; - _verbose = false; - } - - unsigned long get_cascade_depth ( - ) const { return _cascade_depth; } - - void set_cascade_depth ( - unsigned long depth - ) - { - DLIB_CASSERT(depth > 0, - "\t void shape_predictor_trainer::set_cascade_depth()" - << "\n\t Invalid inputs were given to this function. " - << "\n\t depth: " << depth - ); - - _cascade_depth = depth; - } - - unsigned long get_tree_depth ( - ) const { return _tree_depth; } - - void set_tree_depth ( - unsigned long depth - ) - { - DLIB_CASSERT(depth > 0, - "\t void shape_predictor_trainer::set_tree_depth()" - << "\n\t Invalid inputs were given to this function. " - << "\n\t depth: " << depth - ); - - _tree_depth = depth; - } - - unsigned long get_num_trees_per_cascade_level ( - ) const { return _num_trees_per_cascade_level; } - - void set_num_trees_per_cascade_level ( - unsigned long num - ) - { - DLIB_CASSERT( num > 0, - "\t void shape_predictor_trainer::set_num_trees_per_cascade_level()" - << "\n\t Invalid inputs were given to this function. " - << "\n\t num: " << num - ); - _num_trees_per_cascade_level = num; - } - - double get_nu ( - ) const { return _nu; } - void set_nu ( - double nu - ) - { - DLIB_CASSERT(nu > 0, - "\t void shape_predictor_trainer::set_nu()" - << "\n\t Invalid inputs were given to this function. " - << "\n\t nu: " << nu - ); - - _nu = nu; - } - - std::string get_random_seed ( - ) const { return rnd.get_seed(); } - void set_random_seed ( - const std::string& seed - ) { rnd.set_seed(seed); } - - unsigned long get_oversampling_amount ( - ) const { return _oversampling_amount; } - void set_oversampling_amount ( - unsigned long amount - ) - { - DLIB_CASSERT(amount > 0, - "\t void shape_predictor_trainer::set_oversampling_amount()" - << "\n\t Invalid inputs were given to this function. " - << "\n\t amount: " << amount - ); - - _oversampling_amount = amount; - } - - unsigned long get_feature_pool_size ( - ) const { return _feature_pool_size; } - void set_feature_pool_size ( - unsigned long size - ) - { - DLIB_CASSERT(size > 1, - "\t void shape_predictor_trainer::set_feature_pool_size()" - << "\n\t Invalid inputs were given to this function. " - << "\n\t size: " << size - ); - - _feature_pool_size = size; - } - - double get_lambda ( - ) const { return _lambda; } - void set_lambda ( - double lambda - ) - { - DLIB_CASSERT(lambda > 0, - "\t void shape_predictor_trainer::set_lambda()" - << "\n\t Invalid inputs were given to this function. " - << "\n\t lambda: " << lambda - ); - - _lambda = lambda; - } - - unsigned long get_num_test_splits ( - ) const { return _num_test_splits; } - void set_num_test_splits ( - unsigned long num - ) - { - DLIB_CASSERT(num > 0, - "\t void shape_predictor_trainer::set_num_test_splits()" - << "\n\t Invalid inputs were given to this function. " - << "\n\t num: " << num - ); - - _num_test_splits = num; - } - - - double get_feature_pool_region_padding ( - ) const { return _feature_pool_region_padding; } - void set_feature_pool_region_padding ( - double padding - ) - { - _feature_pool_region_padding = padding; - } - - void be_verbose ( - ) - { - _verbose = true; - } - - void be_quiet ( - ) - { - _verbose = false; - } - - template - shape_predictor train ( - const image_array& images, - const std::vector >& objects - ) const - { - using namespace impl; - DLIB_CASSERT(images.size() == objects.size() && images.size() > 0, - "\t shape_predictor shape_predictor_trainer::train()" - << "\n\t Invalid inputs were given to this function. " - << "\n\t images.size(): " << images.size() - << "\n\t objects.size(): " << objects.size() - ); - // make sure the objects agree on the number of parts and that there is at - // least one full_object_detection. - unsigned long num_parts = 0; - for (unsigned long i = 0; i < objects.size(); ++i) - { - for (unsigned long j = 0; j < objects[i].size(); ++j) - { - if (num_parts == 0) - { - num_parts = objects[i][j].num_parts(); - } - else - { - DLIB_CASSERT(objects[i][j].num_parts() == num_parts, - "\t shape_predictor shape_predictor_trainer::train()" - << "\n\t All the objects must agree on the number of parts. " - << "\n\t objects["< samples; - const matrix initial_shape = populate_training_sample_shapes(objects, samples); - const std::vector > > pixel_coordinates = randomly_sample_pixel_coordinates(initial_shape); - - unsigned long trees_fit_so_far = 0; - console_progress_indicator pbar(get_cascade_depth()*get_num_trees_per_cascade_level()); - if (_verbose) - std::cout << "Fitting trees..." << std::endl; - - std::vector > forests(get_cascade_depth()); - // Now start doing the actual training by filling in the forests - for (unsigned long cascade = 0; cascade < get_cascade_depth(); ++cascade) - { - // Each cascade uses a different set of pixels for its features. We compute - // their representations relative to the initial shape first. - std::vector anchor_idx; - std::vector > deltas; - create_shape_relative_encoding(initial_shape, pixel_coordinates[cascade], anchor_idx, deltas); - - // First compute the feature_pixel_values for each training sample at this - // level of the cascade. - for (unsigned long i = 0; i < samples.size(); ++i) - { - extract_feature_pixel_values(images[samples[i].image_idx], samples[i].rect, - samples[i].current_shape, initial_shape, anchor_idx, - deltas, samples[i].feature_pixel_values); - } - - // Now start building the trees at this cascade level. - for (unsigned long i = 0; i < get_num_trees_per_cascade_level(); ++i) - { - forests[cascade].push_back(make_regression_tree(samples, pixel_coordinates[cascade])); - - if (_verbose) - { - ++trees_fit_so_far; - pbar.print_status(trees_fit_so_far); - } - } - } - - if (_verbose) - std::cout << "Training complete " << std::endl; - - return shape_predictor(initial_shape, forests, pixel_coordinates); - } - - private: - - static matrix object_to_shape ( - const full_object_detection& obj - ) - { - matrix shape(obj.num_parts()*2); - const point_transform_affine tform_from_img = impl::normalizing_tform(obj.get_rect()); - for (unsigned long i = 0; i < obj.num_parts(); ++i) - { - vector p = tform_from_img(obj.part(i)); - shape(2*i) = p.x(); - shape(2*i+1) = p.y(); - } - return shape; - } - - struct training_sample - { - /*! - - CONVENTION - - feature_pixel_values.size() == get_feature_pool_size() - - feature_pixel_values[j] == the value of the j-th feature pool - pixel when you look it up relative to the shape in current_shape. - - - target_shape == The truth shape. Stays constant during the whole - training process. - - rect == the position of the object in the image_idx-th image. All shape - coordinates are coded relative to this rectangle. - !*/ - - unsigned long image_idx; - rectangle rect; - matrix target_shape; - - matrix current_shape; - std::vector feature_pixel_values; - - void swap(training_sample& item) - { - std::swap(image_idx, item.image_idx); - std::swap(rect, item.rect); - target_shape.swap(item.target_shape); - current_shape.swap(item.current_shape); - feature_pixel_values.swap(item.feature_pixel_values); - } - }; - - impl::regression_tree make_regression_tree ( - std::vector& samples, - const std::vector >& pixel_coordinates - ) const - { - using namespace impl; - std::deque > parts; - parts.push_back(std::make_pair((unsigned long)0, (unsigned long)samples.size())); - - impl::regression_tree tree; - - // walk the tree in breadth first order - const unsigned long num_split_nodes = static_cast(std::pow(2.0, (double)get_tree_depth())-1); - std::vector > sums(num_split_nodes*2+1); - for (unsigned long i = 0; i < samples.size(); ++i) - sums[0] += samples[i].target_shape - samples[i].current_shape; - - for (unsigned long i = 0; i < num_split_nodes; ++i) - { - std::pair range = parts.front(); - parts.pop_front(); - - const impl::split_feature split = generate_split(samples, range.first, - range.second, pixel_coordinates, sums[i], sums[left_child(i)], - sums[right_child(i)]); - tree.splits.push_back(split); - const unsigned long mid = partition_samples(split, samples, range.first, range.second); - - parts.push_back(std::make_pair(range.first, mid)); - parts.push_back(std::make_pair(mid, range.second)); - } - - // Now all the parts contain the ranges for the leaves so we can use them to - // compute the average leaf values. - tree.leaf_values.resize(parts.size()); - for (unsigned long i = 0; i < parts.size(); ++i) - { - if (parts[i].second != parts[i].first) - tree.leaf_values[i] = sums[num_split_nodes+i]*get_nu()/(parts[i].second - parts[i].first); - else - tree.leaf_values[i] = zeros_matrix(samples[0].target_shape); - - // now adjust the current shape based on these predictions - for (unsigned long j = parts[i].first; j < parts[i].second; ++j) - samples[j].current_shape += tree.leaf_values[i]; - } - - return tree; - } - - impl::split_feature randomly_generate_split_feature ( - const std::vector >& pixel_coordinates - ) const - { - const double lambda = get_lambda(); - impl::split_feature feat; - double accept_prob; - do - { - feat.idx1 = rnd.get_random_32bit_number()%get_feature_pool_size(); - feat.idx2 = rnd.get_random_32bit_number()%get_feature_pool_size(); - const double dist = length(pixel_coordinates[feat.idx1]-pixel_coordinates[feat.idx2]); - accept_prob = std::exp(-dist/lambda); - } - while(feat.idx1 == feat.idx2 || !(accept_prob > rnd.get_random_double())); - - feat.thresh = (rnd.get_random_double()*256 - 128)/2.0; - - return feat; - } - - impl::split_feature generate_split ( - const std::vector& samples, - unsigned long begin, - unsigned long end, - const std::vector >& pixel_coordinates, - const matrix& sum, - matrix& left_sum, - matrix& right_sum - ) const - { - // generate a bunch of random splits and test them and return the best one. - - const unsigned long num_test_splits = get_num_test_splits(); - - // sample the random features we test in this function - std::vector feats; - feats.reserve(num_test_splits); - for (unsigned long i = 0; i < num_test_splits; ++i) - feats.push_back(randomly_generate_split_feature(pixel_coordinates)); - - std::vector > left_sums(num_test_splits); - std::vector left_cnt(num_test_splits); - - // now compute the sums of vectors that go left for each feature - matrix temp; - for (unsigned long j = begin; j < end; ++j) - { - temp = samples[j].target_shape-samples[j].current_shape; - for (unsigned long i = 0; i < num_test_splits; ++i) - { - if (samples[j].feature_pixel_values[feats[i].idx1] - samples[j].feature_pixel_values[feats[i].idx2] > feats[i].thresh) - { - left_sums[i] += temp; - ++left_cnt[i]; - } - } - } - - // now figure out which feature is the best - double best_score = -1; - unsigned long best_feat = 0; - for (unsigned long i = 0; i < num_test_splits; ++i) - { - // check how well the feature splits the space. - double score = 0; - unsigned long right_cnt = end-begin-left_cnt[i]; - if (left_cnt[i] != 0 && right_cnt != 0) - { - temp = sum - left_sums[i]; - score = dot(left_sums[i],left_sums[i])/left_cnt[i] + dot(temp,temp)/right_cnt; - if (score > best_score) - { - best_score = score; - best_feat = i; - } - } - } - - left_sums[best_feat].swap(left_sum); - if (left_sum.size() != 0) - { - right_sum = sum - left_sum; - } - else - { - right_sum = sum; - left_sum = zeros_matrix(sum); - } - return feats[best_feat]; - } - - unsigned long partition_samples ( - const impl::split_feature& split, - std::vector& samples, - unsigned long begin, - unsigned long end - ) const - { - // splits samples based on split (sorta like in quick sort) and returns the mid - // point. make sure you return the mid in a way compatible with how we walk - // through the tree. - - unsigned long i = begin; - for (unsigned long j = begin; j < end; ++j) - { - if (samples[j].feature_pixel_values[split.idx1] - samples[j].feature_pixel_values[split.idx2] > split.thresh) - { - samples[i].swap(samples[j]); - ++i; - } - } - return i; - } - - - - matrix populate_training_sample_shapes( - const std::vector >& objects, - std::vector& samples - ) const - { - samples.clear(); - matrix mean_shape; - long count = 0; - // first fill out the target shapes - for (unsigned long i = 0; i < objects.size(); ++i) - { - for (unsigned long j = 0; j < objects[i].size(); ++j) - { - training_sample sample; - sample.image_idx = i; - sample.rect = objects[i][j].get_rect(); - sample.target_shape = object_to_shape(objects[i][j]); - for (unsigned long itr = 0; itr < get_oversampling_amount(); ++itr) - samples.push_back(sample); - mean_shape += sample.target_shape; - ++count; - } - } - - mean_shape /= count; - - // now go pick random initial shapes - for (unsigned long i = 0; i < samples.size(); ++i) - { - if ((i%get_oversampling_amount()) == 0) - { - // The mean shape is what we really use as an initial shape so always - // include it in the training set as an example starting shape. - samples[i].current_shape = mean_shape; - } - else - { - // Pick a random convex combination of two of the target shapes and use - // that as the initial shape for this sample. - const unsigned long rand_idx = rnd.get_random_32bit_number()%samples.size(); - const unsigned long rand_idx2 = rnd.get_random_32bit_number()%samples.size(); - const double alpha = rnd.get_random_double(); - samples[i].current_shape = alpha*samples[rand_idx].target_shape + (1-alpha)*samples[rand_idx2].target_shape; - } - } - - - return mean_shape; - } - - - void randomly_sample_pixel_coordinates ( - std::vector >& pixel_coordinates, - const double min_x, - const double min_y, - const double max_x, - const double max_y - ) const - /*! - ensures - - #pixel_coordinates.size() == get_feature_pool_size() - - for all valid i: - - pixel_coordinates[i] == a point in the box defined by the min/max x/y arguments. - !*/ - { - pixel_coordinates.resize(get_feature_pool_size()); - for (unsigned long i = 0; i < get_feature_pool_size(); ++i) - { - pixel_coordinates[i].x() = rnd.get_random_double()*(max_x-min_x) + min_x; - pixel_coordinates[i].y() = rnd.get_random_double()*(max_y-min_y) + min_y; - } - } - - std::vector > > randomly_sample_pixel_coordinates ( - const matrix& initial_shape - ) const - { - const double padding = get_feature_pool_region_padding(); - // Figure figure out the bounds on the object shapes. We will sample uniformly - // from this box. - matrix temp = reshape(initial_shape, initial_shape.size()/2, 2); - const double min_x = min(colm(temp,0))-padding; - const double min_y = min(colm(temp,1))-padding; - const double max_x = max(colm(temp,0))+padding; - const double max_y = max(colm(temp,1))+padding; - - std::vector > > pixel_coordinates; - pixel_coordinates.resize(get_cascade_depth()); - for (unsigned long i = 0; i < get_cascade_depth(); ++i) - randomly_sample_pixel_coordinates(pixel_coordinates[i], min_x, min_y, max_x, max_y); - return pixel_coordinates; - } - - - - mutable dlib::rand rnd; - - unsigned long _cascade_depth; - unsigned long _tree_depth; - unsigned long _num_trees_per_cascade_level; - double _nu; - unsigned long _oversampling_amount; - unsigned long _feature_pool_size; - double _lambda; - unsigned long _num_test_splits; - double _feature_pool_region_padding; - bool _verbose; - }; + int version = 1; + dlib::serialize(version, out); + dlib::serialize(item.initial_shape, out); + dlib::serialize(item.forests, out); + dlib::serialize(item.anchor_idx, out); + dlib::serialize(item.deltas, out); + } + + inline void deserialize (shape_predictor& item, std::istream& in) + { + int version = 0; + dlib::deserialize(version, in); + if (version != 1) + throw serialization_error("Unexpected version found while deserializing dlib::shape_predictor."); + dlib::deserialize(item.initial_shape, in); + dlib::deserialize(item.forests, in); + dlib::deserialize(item.anchor_idx, in); + dlib::deserialize(item.deltas, in); + } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- @@ -1036,8 +490,11 @@ namespace dlib for (unsigned long k = 0; k < det.num_parts(); ++k) { - double score = length(det.part(k) - objects[i][j].part(k))/scale; - rs.add(score); + if (objects[i][j].part(k) != OBJECT_PART_NOT_PRESENT) + { + double score = length(det.part(k) - objects[i][j].part(k))/scale; + rs.add(score); + } } } } diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/shape_predictor_abstract.h b/lib/3rdParty/dlib/include/dlib/image_processing/shape_predictor_abstract.h index c5cebc9b..718b4952 100644 --- a/lib/3rdParty/dlib/include/dlib/image_processing/shape_predictor_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_processing/shape_predictor_abstract.h @@ -25,9 +25,14 @@ namespace dlib and eyes, tip of the nose, and so forth. To create useful instantiations of this object you need to use the - shape_predictor_trainer object defined below to train a shape_predictor - using a set of training images, each annotated with shapes you want to - predict. + shape_predictor_trainer object defined in the + shape_predictor_trainer_abstract.h file to train a shape_predictor using a + set of training images, each annotated with shapes you want to predict. + + THREAD SAFETY + No synchronization is required when using this object. In particular, a + single instance of this object can be used from multiple threads at the + same time. !*/ public: @@ -37,6 +42,7 @@ namespace dlib /*! ensures - #num_parts() == 0 + - #num_features() == 0 !*/ unsigned long num_parts ( @@ -46,15 +52,27 @@ namespace dlib - returns the number of parts in the shapes predicted by this object. !*/ - template + unsigned long num_features ( + ) const; + /*! + ensures + - Returns the dimensionality of the feature vector output by operator(). + This number is the total number of trees in this object times the number + of leaves on each tree. + !*/ + + template full_object_detection operator()( const image_type& img, - const rectangle& rect + const rectangle& rect, + std::vector >& feats ) const; /*! requires - image_type == an image object that implements the interface defined in dlib/image_processing/generic_image.h + - T is some unsigned integral type (e.g. unsigned int). + - U is any scalar type capable of storing the value 1 (e.g. float). ensures - Runs the shape prediction algorithm on the part of the image contained in the given bounding rectangle. So it will try and fit the shape model to @@ -68,6 +86,29 @@ namespace dlib - for all valid i: - DET.part(i) == the location in img for the i-th part of the shape predicted by this object. + - #feats == a sparse vector that records which leaf each tree used to make + the shape prediction. Moreover, it is an indicator vector, Therefore, + for all valid i: + - #feats[i].second == 1 + Further, #feats is a vector from the space of num_features() dimensional + vectors. The output shape positions can be represented as the dot + product between #feats and a weight vector. Therefore, #feats encodes + all the information from img that was used to predict the returned shape + object. + !*/ + + template + full_object_detection operator()( + const image_type& img, + const rectangle& rect + ) const; + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + ensures + - Calling this function is equivalent to calling (*this)(img, rect, ignored) + where the 3d argument is discarded. !*/ }; @@ -78,296 +119,6 @@ namespace dlib provides serialization support !*/ -// ---------------------------------------------------------------------------------------- - - class shape_predictor_trainer - { - /*! - WHAT THIS OBJECT REPRESENTS - This object is a tool for training shape_predictors based on annotated training - images. Its implementation uses the algorithm described in: - One Millisecond Face Alignment with an Ensemble of Regression Trees - by Vahid Kazemi and Josephine Sullivan, CVPR 2014 - - !*/ - - public: - - shape_predictor_trainer ( - ); - /*! - ensures - - #get_cascade_depth() == 10 - - #get_tree_depth() == 4 - - #get_num_trees_per_cascade_level() == 500 - - #get_nu() == 0.1 - - #get_oversampling_amount() == 20 - - #get_feature_pool_size() == 400 - - #get_lambda() == 0.1 - - #get_num_test_splits() == 20 - - #get_feature_pool_region_padding() == 0 - - #get_random_seed() == "" - - This object will not be verbose - !*/ - - unsigned long get_cascade_depth ( - ) const; - /*! - ensures - - returns the number of cascades created when you train a model. This - means that the total number of trees in the learned model is equal to - get_cascade_depth()*get_num_trees_per_cascade_level(). - !*/ - - void set_cascade_depth ( - unsigned long depth - ); - /*! - requires - - depth > 0 - ensures - - #get_cascade_depth() == depth - !*/ - - unsigned long get_tree_depth ( - ) const; - /*! - ensures - - returns the depth of the trees used in the cascade. In particular, there - are pow(2,get_tree_depth()) leaves in each tree. - !*/ - - void set_tree_depth ( - unsigned long depth - ); - /*! - requires - - depth > 0 - ensures - - #get_tree_depth() == depth - !*/ - - unsigned long get_num_trees_per_cascade_level ( - ) const; - /*! - ensures - - returns the number of trees created for each cascade. This means that - the total number of trees in the learned model is equal to - get_cascade_depth()*get_num_trees_per_cascade_level(). - !*/ - - void set_num_trees_per_cascade_level ( - unsigned long num - ); - /*! - requires - - num > 0 - ensures - - #get_num_trees_per_cascade_level() == num - !*/ - - double get_nu ( - ) const; - /*! - ensures - - returns the regularization parameter. Larger values of this parameter - will cause the algorithm to fit the training data better but may also - cause overfitting. - !*/ - - void set_nu ( - double nu - ); - /*! - requires - - nu > 0 - ensures - - #get_nu() == nu - !*/ - - std::string get_random_seed ( - ) const; - /*! - ensures - - returns the random seed used by the internal random number generator. - Since this algorithm is a random forest style algorithm it relies on a - random number generator for generating the trees. So each setting of the - random seed will produce slightly different outputs. - !*/ - - void set_random_seed ( - const std::string& seed - ); - /*! - ensures - - #get_random_seed() == seed - !*/ - - unsigned long get_oversampling_amount ( - ) const; - /*! - ensures - - You give annotated images to this object as training examples. You - can effectively increase the amount of training data by adding in each - training example multiple times but with a randomly selected deformation - applied to it. That is what this parameter controls. That is, if you - supply N training samples to train() then the algorithm runs internally - with N*get_oversampling_amount() training samples. So the bigger this - parameter the better (excepting that larger values make training take - longer). In terms of the Kazemi paper, this parameter is the number of - randomly selected initial starting points sampled for each training - example. - !*/ - - void set_oversampling_amount ( - unsigned long amount - ); - /*! - requires - - amount > 0 - ensures - - #get_oversampling_amount() == amount - !*/ - - unsigned long get_feature_pool_size ( - ) const; - /*! - ensures - - At each level of the cascade we randomly sample get_feature_pool_size() - pixels from the image. These pixels are used to generate features for - the random trees. So in general larger settings of this parameter give - better accuracy but make the algorithm run slower. - !*/ - - void set_feature_pool_size ( - unsigned long size - ); - /*! - requires - - size > 1 - ensures - - #get_feature_pool_size() == size - !*/ - - double get_feature_pool_region_padding ( - ) const; - /*! - ensures - - When we randomly sample the pixels for the feature pool we do so in a box - fit around the provided training landmarks. By default, this box is the - tightest box that contains the landmarks (i.e. this is what happens when - get_feature_pool_region_padding()==0). However, you can expand or shrink - the size of the pixel sampling region by setting a different value of - get_feature_pool_region_padding(). - - To explain this precisely, for a padding of 0 we say that the pixels are - sampled from a box of size 1x1. The padding value is added to each side - of the box. So a padding of 0.5 would cause the algorithm to sample - pixels from a box that was 2x2, effectively multiplying the area pixels - are sampled from by 4. Similarly, setting the padding to -0.2 would - cause it to sample from a box 0.8x0.8 in size. - !*/ - - void set_feature_pool_region_padding ( - double padding - ); - /*! - ensures - - #get_feature_pool_region_padding() == padding - !*/ - - - double get_lambda ( - ) const; - /*! - ensures - - To decide how to split nodes in the regression trees the algorithm looks - at pairs of pixels in the image. These pixel pairs are sampled randomly - but with a preference for selecting pixels that are near each other. - get_lambda() controls this "nearness" preference. In particular, smaller - values of get_lambda() will make the algorithm prefer to select pixels - close together and larger values of get_lambda() will make it care less - about picking nearby pixel pairs. - - Note that this is the inverse of how it is defined in the Kazemi paper. - For this object, you should think of lambda as "the fraction of the - bounding box will we traverse to find a neighboring pixel". Nominally, - this is normalized between 0 and 1. So reasonable settings of lambda are - values in the range 0 < lambda < 1. - !*/ - - void set_lambda ( - double lambda - ); - /*! - requires - - lambda > 0 - ensures - - #get_lambda() == lambda - !*/ - - unsigned long get_num_test_splits ( - ) const; - /*! - ensures - - When generating the random trees we randomly sample get_num_test_splits() - possible split features at each node and pick the one that gives the best - split. Larger values of this parameter will usually give more accurate - outputs but take longer to train. - !*/ - - void set_num_test_splits ( - unsigned long num - ); - /*! - requires - - num > 0 - ensures - - #get_num_test_splits() == num - !*/ - - void be_verbose ( - ); - /*! - ensures - - This object will print status messages to standard out so that a - user can observe the progress of the algorithm. - !*/ - - void be_quiet ( - ); - /*! - ensures - - This object will not print anything to standard out - !*/ - - template - shape_predictor train ( - const image_array& images, - const std::vector >& objects - ) const; - /*! - requires - - image_array is a dlib::array of image objects where each image object - implements the interface defined in dlib/image_processing/generic_image.h - - images.size() == objects.size() - - images.size() > 0 - - for some i: objects[i].size() != 0 - (i.e. there has to be at least one full_object_detection in the training set) - - for all valid i,j,k,l: - - objects[i][j].num_parts() == objects[k][l].num_parts() - (i.e. all objects must agree on the number of parts) - - objects[i][j].num_parts() > 0 - ensures - - This object will try to learn to predict the locations of an object's parts - based on the object bounding box (i.e. full_object_detection::get_rect()) - and the image pixels in that box. That is, we will try to learn a - shape_predictor, SP, such that: - SP(images[i], objects[i][j].get_rect()) == objects[i][j] - This learned SP object is then returned. - !*/ - }; - // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- @@ -403,6 +154,8 @@ namespace dlib and compare the result with the truth part positions in objects[i][j]. We then return the average distance (measured in pixels) between a predicted part location and its true position. + - Note that any parts in objects that are set to OBJECT_PART_NOT_PRESENT are + simply ignored. - if (scales.size() != 0) then - Each time we compute the distance between a predicted part location and its true location in objects[i][j] we divide the distance by diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/shape_predictor_trainer.h b/lib/3rdParty/dlib/include/dlib/image_processing/shape_predictor_trainer.h new file mode 100644 index 00000000..3090998f --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/image_processing/shape_predictor_trainer.h @@ -0,0 +1,852 @@ +// Copyright (C) 2014 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SHAPE_PREDICToR_TRAINER_H_ +#define DLIB_SHAPE_PREDICToR_TRAINER_H_ + +#include "shape_predictor_trainer_abstract.h" +#include "shape_predictor.h" +#include "../console_progress_indicator.h" +#include "../threads.h" +#include "../data_io/image_dataset_metadata.h" +#include "box_overlap_testing.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class shape_predictor_trainer + { + /*! + This thing really only works with unsigned char or rgb_pixel images (since we assume the threshold + should be in the range [-128,128]). + !*/ + public: + + enum padding_mode_t + { + bounding_box_relative, + landmark_relative + }; + + shape_predictor_trainer ( + ) + { + _cascade_depth = 10; + _tree_depth = 4; + _num_trees_per_cascade_level = 500; + _nu = 0.1; + _oversampling_amount = 20; + _feature_pool_size = 400; + _lambda = 0.1; + _num_test_splits = 20; + _feature_pool_region_padding = 0; + _verbose = false; + _num_threads = 0; + _padding_mode = landmark_relative; + } + + unsigned long get_cascade_depth ( + ) const { return _cascade_depth; } + + void set_cascade_depth ( + unsigned long depth + ) + { + DLIB_CASSERT(depth > 0, + "\t void shape_predictor_trainer::set_cascade_depth()" + << "\n\t Invalid inputs were given to this function. " + << "\n\t depth: " << depth + ); + + _cascade_depth = depth; + } + + unsigned long get_tree_depth ( + ) const { return _tree_depth; } + + void set_tree_depth ( + unsigned long depth + ) + { + DLIB_CASSERT(depth > 0, + "\t void shape_predictor_trainer::set_tree_depth()" + << "\n\t Invalid inputs were given to this function. " + << "\n\t depth: " << depth + ); + + _tree_depth = depth; + } + + unsigned long get_num_trees_per_cascade_level ( + ) const { return _num_trees_per_cascade_level; } + + void set_num_trees_per_cascade_level ( + unsigned long num + ) + { + DLIB_CASSERT( num > 0, + "\t void shape_predictor_trainer::set_num_trees_per_cascade_level()" + << "\n\t Invalid inputs were given to this function. " + << "\n\t num: " << num + ); + _num_trees_per_cascade_level = num; + } + + double get_nu ( + ) const { return _nu; } + void set_nu ( + double nu + ) + { + DLIB_CASSERT(0 < nu && nu <= 1, + "\t void shape_predictor_trainer::set_nu()" + << "\n\t Invalid inputs were given to this function. " + << "\n\t nu: " << nu + ); + + _nu = nu; + } + + std::string get_random_seed ( + ) const { return rnd.get_seed(); } + void set_random_seed ( + const std::string& seed + ) { rnd.set_seed(seed); } + + unsigned long get_oversampling_amount ( + ) const { return _oversampling_amount; } + void set_oversampling_amount ( + unsigned long amount + ) + { + DLIB_CASSERT(amount > 0, + "\t void shape_predictor_trainer::set_oversampling_amount()" + << "\n\t Invalid inputs were given to this function. " + << "\n\t amount: " << amount + ); + + _oversampling_amount = amount; + } + + unsigned long get_feature_pool_size ( + ) const { return _feature_pool_size; } + void set_feature_pool_size ( + unsigned long size + ) + { + DLIB_CASSERT(size > 1, + "\t void shape_predictor_trainer::set_feature_pool_size()" + << "\n\t Invalid inputs were given to this function. " + << "\n\t size: " << size + ); + + _feature_pool_size = size; + } + + double get_lambda ( + ) const { return _lambda; } + void set_lambda ( + double lambda + ) + { + DLIB_CASSERT(lambda > 0, + "\t void shape_predictor_trainer::set_lambda()" + << "\n\t Invalid inputs were given to this function. " + << "\n\t lambda: " << lambda + ); + + _lambda = lambda; + } + + unsigned long get_num_test_splits ( + ) const { return _num_test_splits; } + void set_num_test_splits ( + unsigned long num + ) + { + DLIB_CASSERT(num > 0, + "\t void shape_predictor_trainer::set_num_test_splits()" + << "\n\t Invalid inputs were given to this function. " + << "\n\t num: " << num + ); + + _num_test_splits = num; + } + + void set_padding_mode ( + padding_mode_t mode + ) + { + _padding_mode = mode; + } + + padding_mode_t get_padding_mode ( + ) const { return _padding_mode; } + + double get_feature_pool_region_padding ( + ) const { return _feature_pool_region_padding; } + void set_feature_pool_region_padding ( + double padding + ) + { + DLIB_CASSERT(padding > -0.5, + "\t void shape_predictor_trainer::set_feature_pool_region_padding()" + << "\n\t Invalid inputs were given to this function. " + << "\n\t padding: " << padding + ); + + _feature_pool_region_padding = padding; + } + + void be_verbose ( + ) + { + _verbose = true; + } + + void be_quiet ( + ) + { + _verbose = false; + } + + unsigned long get_num_threads ( + ) const { return _num_threads; } + void set_num_threads ( + unsigned long num + ) + { + _num_threads = num; + } + + template + shape_predictor train ( + const image_array& images, + const std::vector >& objects + ) const + { + using namespace impl; + DLIB_CASSERT(images.size() == objects.size() && images.size() > 0, + "\t shape_predictor shape_predictor_trainer::train()" + << "\n\t Invalid inputs were given to this function. " + << "\n\t images.size(): " << images.size() + << "\n\t objects.size(): " << objects.size() + ); + // make sure the objects agree on the number of parts and that there is at + // least one full_object_detection. + unsigned long num_parts = 0; + std::vector part_present; + for (unsigned long i = 0; i < objects.size(); ++i) + { + for (unsigned long j = 0; j < objects[i].size(); ++j) + { + if (num_parts == 0) + { + num_parts = objects[i][j].num_parts(); + DLIB_CASSERT(objects[i][j].num_parts() != 0, + "\t shape_predictor shape_predictor_trainer::train()" + << "\n\t You can't give objects that don't have any parts to the trainer." + ); + part_present.resize(num_parts); + } + else + { + DLIB_CASSERT(objects[i][j].num_parts() == num_parts, + "\t shape_predictor shape_predictor_trainer::train()" + << "\n\t All the objects must agree on the number of parts. " + << "\n\t objects["< 1 ? _num_threads : 0); + + // determining the type of features used for this type of images + typedef typename std::remove_const::type>::type image_type; + typedef typename image_traits::pixel_type pixel_type; + typedef typename pixel_traits::basic_pixel_type feature_type; + + rnd.set_seed(get_random_seed()); + + std::vector> samples; + const matrix initial_shape = populate_training_sample_shapes(objects, samples); + const std::vector > > pixel_coordinates = randomly_sample_pixel_coordinates(initial_shape); + + unsigned long trees_fit_so_far = 0; + console_progress_indicator pbar(get_cascade_depth()*get_num_trees_per_cascade_level()); + if (_verbose) + std::cout << "Fitting trees..." << std::endl; + + std::vector > forests(get_cascade_depth()); + // Now start doing the actual training by filling in the forests + for (unsigned long cascade = 0; cascade < get_cascade_depth(); ++cascade) + { + // Each cascade uses a different set of pixels for its features. We compute + // their representations relative to the initial shape first. + std::vector anchor_idx; + std::vector > deltas; + create_shape_relative_encoding(initial_shape, pixel_coordinates[cascade], anchor_idx, deltas); + + // First compute the feature_pixel_values for each training sample at this + // level of the cascade. + parallel_for(tp, 0, samples.size(), [&](unsigned long i) + { + impl::extract_feature_pixel_values(images[samples[i].image_idx], samples[i].rect, + samples[i].current_shape, initial_shape, anchor_idx, + deltas, samples[i].feature_pixel_values); + }, 1); + + // Now start building the trees at this cascade level. + for (unsigned long i = 0; i < get_num_trees_per_cascade_level(); ++i) + { + forests[cascade].push_back(make_regression_tree(tp, samples, pixel_coordinates[cascade])); + + if (_verbose) + { + ++trees_fit_so_far; + pbar.print_status(trees_fit_so_far); + } + } + } + + if (_verbose) + std::cout << "Training complete " << std::endl; + + return shape_predictor(initial_shape, forests, pixel_coordinates); + } + + private: + + static void object_to_shape ( + const full_object_detection& obj, + matrix& shape, + matrix& present // a mask telling which elements of #shape are present. + ) + { + shape.set_size(obj.num_parts()*2); + present.set_size(obj.num_parts()*2); + const point_transform_affine tform_from_img = impl::normalizing_tform(obj.get_rect()); + for (unsigned long i = 0; i < obj.num_parts(); ++i) + { + if (obj.part(i) != OBJECT_PART_NOT_PRESENT) + { + vector p = tform_from_img(obj.part(i)); + shape(2*i) = p.x(); + shape(2*i+1) = p.y(); + present(2*i) = 1; + present(2*i+1) = 1; + + if (length(p) > 100) + { + std::cout << "Warning, one of your objects has parts that are way outside its bounding box! This is probably an error in your annotation." << std::endl; + } + } + else + { + shape(2*i) = 0; + shape(2*i+1) = 0; + present(2*i) = 0; + present(2*i+1) = 0; + } + } + } + + template + struct training_sample + { + /*! + + CONVENTION + - feature_pixel_values.size() == get_feature_pool_size() + - feature_pixel_values[j] == the value of the j-th feature pool + pixel when you look it up relative to the shape in current_shape. + + - target_shape == The truth shape. Stays constant during the whole + training process (except for the parts that are not present, those are + always equal to the current_shape values). + - present == 0/1 mask saying which parts of target_shape are present. + - rect == the position of the object in the image_idx-th image. All shape + coordinates are coded relative to this rectangle. + - diff_shape == temporary value for holding difference between current + shape and target shape + !*/ + + unsigned long image_idx; + rectangle rect; + matrix target_shape; + matrix present; + + matrix current_shape; + matrix diff_shape; + std::vector feature_pixel_values; + + void swap(training_sample& item) + { + std::swap(image_idx, item.image_idx); + std::swap(rect, item.rect); + target_shape.swap(item.target_shape); + present.swap(item.present); + current_shape.swap(item.current_shape); + diff_shape.swap(item.diff_shape); + feature_pixel_values.swap(item.feature_pixel_values); + } + }; + + template + impl::regression_tree make_regression_tree ( + thread_pool& tp, + std::vector>& samples, + const std::vector >& pixel_coordinates + ) const + { + using namespace impl; + std::deque > parts; + parts.push_back(std::make_pair(0, (unsigned long)samples.size())); + + impl::regression_tree tree; + + // walk the tree in breadth first order + const unsigned long num_split_nodes = static_cast(std::pow(2.0, (double)get_tree_depth())-1); + std::vector > sums(num_split_nodes*2+1); + if (tp.num_threads_in_pool() > 1) + { + // Here we need to calculate shape differences and store sum of differences into sums[0] + // to make it. I am splitting samples into blocks, each block will be processed by + // separate thread, and the sum of differences of each block is stored into separate + // place in block_sums + + const unsigned long num_workers = std::max(1UL, tp.num_threads_in_pool()); + const unsigned long num = samples.size(); + const unsigned long block_size = std::max(1UL, (num + num_workers - 1) / num_workers); + std::vector > block_sums(num_workers); + + parallel_for(tp, 0, num_workers, [&](unsigned long block) + { + const unsigned long block_begin = block * block_size; + const unsigned long block_end = std::min(num, block_begin + block_size); + for (unsigned long i = block_begin; i < block_end; ++i) + { + samples[i].diff_shape = samples[i].target_shape - samples[i].current_shape; + block_sums[block] += samples[i].diff_shape; + } + }, 1); + + // now calculate the total result from separate blocks + for (unsigned long i = 0; i < block_sums.size(); ++i) + sums[0] += block_sums[i]; + } + else + { + // synchronous implementation + for (unsigned long i = 0; i < samples.size(); ++i) + { + samples[i].diff_shape = samples[i].target_shape - samples[i].current_shape; + sums[0] += samples[i].diff_shape; + } + } + + for (unsigned long i = 0; i < num_split_nodes; ++i) + { + std::pair range = parts.front(); + parts.pop_front(); + + const impl::split_feature split = generate_split(tp, samples, range.first, + range.second, pixel_coordinates, sums[i], sums[left_child(i)], + sums[right_child(i)]); + tree.splits.push_back(split); + const unsigned long mid = partition_samples(split, samples, range.first, range.second); + + parts.push_back(std::make_pair(range.first, mid)); + parts.push_back(std::make_pair(mid, range.second)); + } + + // Now all the parts contain the ranges for the leaves so we can use them to + // compute the average leaf values. + matrix present_counts(samples[0].target_shape.size()); + tree.leaf_values.resize(parts.size()); + for (unsigned long i = 0; i < parts.size(); ++i) + { + // Get the present counts for each dimension so we can divide each + // dimension by the number of observations we have on it to find the mean + // displacement in each leaf. + present_counts = 0; + for (unsigned long j = parts[i].first; j < parts[i].second; ++j) + present_counts += samples[j].present; + present_counts = dlib::reciprocal(present_counts); + + if (parts[i].second != parts[i].first) + tree.leaf_values[i] = pointwise_multiply(present_counts,sums[num_split_nodes+i]*get_nu()); + else + tree.leaf_values[i] = zeros_matrix(samples[0].target_shape); + + // now adjust the current shape based on these predictions + parallel_for(tp, parts[i].first, parts[i].second, [&](unsigned long j) + { + samples[j].current_shape += tree.leaf_values[i]; + // For parts that aren't present in the training data, we just make + // sure that the target shape always matches and therefore gives zero + // error. So this makes the algorithm simply ignore non-present + // landmarks. + for (long k = 0; k < samples[j].present.size(); ++k) + { + // if this part is not present + if (samples[j].present(k) == 0) + samples[j].target_shape(k) = samples[j].current_shape(k); + } + }, 1); + } + + return tree; + } + + impl::split_feature randomly_generate_split_feature ( + const std::vector >& pixel_coordinates + ) const + { + const double lambda = get_lambda(); + impl::split_feature feat; + const size_t max_iters = get_feature_pool_size()*get_feature_pool_size(); + for (size_t i = 0; i < max_iters; ++i) + { + feat.idx1 = rnd.get_integer(get_feature_pool_size()); + feat.idx2 = rnd.get_integer(get_feature_pool_size()); + while (feat.idx1 == feat.idx2) + feat.idx2 = rnd.get_integer(get_feature_pool_size()); + const double dist = length(pixel_coordinates[feat.idx1]-pixel_coordinates[feat.idx2]); + const double accept_prob = std::exp(-dist/lambda); + if (accept_prob > rnd.get_random_double()) + break; + } + + feat.thresh = (rnd.get_random_double()*256 - 128)/2.0; + + return feat; + } + + template + impl::split_feature generate_split ( + thread_pool& tp, + const std::vector>& samples, + unsigned long begin, + unsigned long end, + const std::vector >& pixel_coordinates, + const matrix& sum, + matrix& left_sum, + matrix& right_sum + ) const + { + // generate a bunch of random splits and test them and return the best one. + + const unsigned long num_test_splits = get_num_test_splits(); + + // sample the random features we test in this function + std::vector feats; + feats.reserve(num_test_splits); + for (unsigned long i = 0; i < num_test_splits; ++i) + feats.push_back(randomly_generate_split_feature(pixel_coordinates)); + + std::vector > left_sums(num_test_splits); + std::vector left_cnt(num_test_splits); + + const unsigned long num_workers = std::max(1UL, tp.num_threads_in_pool()); + const unsigned long block_size = std::max(1UL, (num_test_splits + num_workers - 1) / num_workers); + + // now compute the sums of vectors that go left for each feature + parallel_for(tp, 0, num_workers, [&](unsigned long block) + { + const unsigned long block_begin = block * block_size; + const unsigned long block_end = std::min(block_begin + block_size, num_test_splits); + + for (unsigned long j = begin; j < end; ++j) + { + for (unsigned long i = block_begin; i < block_end; ++i) + { + if ((float)samples[j].feature_pixel_values[feats[i].idx1] - (float)samples[j].feature_pixel_values[feats[i].idx2] > feats[i].thresh) + { + left_sums[i] += samples[j].diff_shape; + ++left_cnt[i]; + } + } + } + + }, 1); + + // now figure out which feature is the best + double best_score = -1; + unsigned long best_feat = 0; + matrix temp; + for (unsigned long i = 0; i < num_test_splits; ++i) + { + // check how well the feature splits the space. + double score = 0; + unsigned long right_cnt = end-begin-left_cnt[i]; + if (left_cnt[i] != 0 && right_cnt != 0) + { + temp = sum - left_sums[i]; + score = dot(left_sums[i],left_sums[i])/left_cnt[i] + dot(temp,temp)/right_cnt; + if (score > best_score) + { + best_score = score; + best_feat = i; + } + } + } + + left_sums[best_feat].swap(left_sum); + if (left_sum.size() != 0) + { + right_sum = sum - left_sum; + } + else + { + right_sum = sum; + left_sum = zeros_matrix(sum); + } + return feats[best_feat]; + } + + template + unsigned long partition_samples ( + const impl::split_feature& split, + std::vector>& samples, + unsigned long begin, + unsigned long end + ) const + { + // splits samples based on split (sorta like in quick sort) and returns the mid + // point. make sure you return the mid in a way compatible with how we walk + // through the tree. + + unsigned long i = begin; + for (unsigned long j = begin; j < end; ++j) + { + if ((float)samples[j].feature_pixel_values[split.idx1] - (float)samples[j].feature_pixel_values[split.idx2] > split.thresh) + { + samples[i].swap(samples[j]); + ++i; + } + } + return i; + } + + + + template + matrix populate_training_sample_shapes( + const std::vector >& objects, + std::vector>& samples + ) const + { + samples.clear(); + matrix mean_shape; + matrix count; + // first fill out the target shapes + for (unsigned long i = 0; i < objects.size(); ++i) + { + for (unsigned long j = 0; j < objects[i].size(); ++j) + { + training_sample sample; + sample.image_idx = i; + sample.rect = objects[i][j].get_rect(); + object_to_shape(objects[i][j], sample.target_shape, sample.present); + for (unsigned long itr = 0; itr < get_oversampling_amount(); ++itr) + samples.push_back(sample); + mean_shape += sample.target_shape; + count += sample.present; + } + } + + mean_shape = pointwise_multiply(mean_shape,reciprocal(count)); + + // now go pick random initial shapes + for (unsigned long i = 0; i < samples.size(); ++i) + { + if ((i%get_oversampling_amount()) == 0) + { + // The mean shape is what we really use as an initial shape so always + // include it in the training set as an example starting shape. + samples[i].current_shape = mean_shape; + } + else + { + samples[i].current_shape.set_size(0); + + matrix hits(mean_shape.size()); + hits = 0; + + int iter = 0; + // Pick a few samples at random and randomly average them together to + // make the initial shape. Note that we make sure we get at least one + // observation (i.e. non-OBJECT_PART_NOT_PRESENT) on each part + // location. + while(min(hits) == 0 || iter < 2) + { + ++iter; + const unsigned long rand_idx = rnd.get_random_32bit_number()%samples.size(); + const double alpha = rnd.get_random_double()+0.1; + samples[i].current_shape += alpha*samples[rand_idx].target_shape; + hits += alpha*samples[rand_idx].present; + } + samples[i].current_shape = pointwise_multiply(samples[i].current_shape, reciprocal(hits)); + } + + } + for (unsigned long i = 0; i < samples.size(); ++i) + { + for (long k = 0; k < samples[i].present.size(); ++k) + { + // if this part is not present + if (samples[i].present(k) == 0) + samples[i].target_shape(k) = samples[i].current_shape(k); + } + } + + + return mean_shape; + } + + + void randomly_sample_pixel_coordinates ( + std::vector >& pixel_coordinates, + const double min_x, + const double min_y, + const double max_x, + const double max_y + ) const + /*! + ensures + - #pixel_coordinates.size() == get_feature_pool_size() + - for all valid i: + - pixel_coordinates[i] == a point in the box defined by the min/max x/y arguments. + !*/ + { + pixel_coordinates.resize(get_feature_pool_size()); + for (unsigned long i = 0; i < get_feature_pool_size(); ++i) + { + pixel_coordinates[i].x() = rnd.get_random_double()*(max_x-min_x) + min_x; + pixel_coordinates[i].y() = rnd.get_random_double()*(max_y-min_y) + min_y; + } + } + + std::vector > > randomly_sample_pixel_coordinates ( + const matrix& initial_shape + ) const + { + const double padding = get_feature_pool_region_padding(); + // Figure out the bounds on the object shapes. We will sample uniformly + // from this box. + matrix temp = reshape(initial_shape, initial_shape.size()/2, 2); + double min_x = min(colm(temp,0)); + double min_y = min(colm(temp,1)); + double max_x = max(colm(temp,0)); + double max_y = max(colm(temp,1)); + + if (get_padding_mode() == bounding_box_relative) + { + min_x = std::min(0.0, min_x); + min_y = std::min(0.0, min_y); + max_x = std::max(1.0, max_x); + max_y = std::max(1.0, max_y); + } + + min_x -= padding; + min_y -= padding; + max_x += padding; + max_y += padding; + + std::vector > > pixel_coordinates; + pixel_coordinates.resize(get_cascade_depth()); + for (unsigned long i = 0; i < get_cascade_depth(); ++i) + randomly_sample_pixel_coordinates(pixel_coordinates[i], min_x, min_y, max_x, max_y); + return pixel_coordinates; + } + + + + mutable dlib::rand rnd; + + unsigned long _cascade_depth; + unsigned long _tree_depth; + unsigned long _num_trees_per_cascade_level; + double _nu; + unsigned long _oversampling_amount; + unsigned long _feature_pool_size; + double _lambda; + unsigned long _num_test_splits; + double _feature_pool_region_padding; + bool _verbose; + unsigned long _num_threads; + padding_mode_t _padding_mode; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename some_type_of_rectangle + > + image_dataset_metadata::dataset make_bounding_box_regression_training_data ( + const image_dataset_metadata::dataset& truth, + const std::vector>& detections + ) + { + DLIB_CASSERT(truth.images.size() == detections.size(), + "truth.images.size(): "<< truth.images.size() << + "\tdetections.size(): "<< detections.size() + ); + image_dataset_metadata::dataset result = truth; + + for (size_t i = 0; i < truth.images.size(); ++i) + { + result.images[i].boxes.clear(); + for (auto truth_box : truth.images[i].boxes) + { + if (truth_box.ignore) + continue; + + // Find the detection that best matches the current truth_box. + auto det = max_scoring_element(detections[i], [&truth_box](const rectangle& r) { return box_intersection_over_union(r, truth_box.rect); }); + if (det.second > 0.5) + { + // Remove any existing parts and replace them with the truth_box corners. + truth_box.parts.clear(); + auto b = truth_box.rect; + truth_box.parts["left"] = (b.tl_corner()+b.bl_corner())/2; + truth_box.parts["right"] = (b.tr_corner()+b.br_corner())/2; + truth_box.parts["top"] = (b.tl_corner()+b.tr_corner())/2; + truth_box.parts["bottom"] = (b.bl_corner()+b.br_corner())/2; + truth_box.parts["middle"] = center(b); + + // Now replace the bounding truth_box with the detector's bounding truth_box. + truth_box.rect = det.first; + + result.images[i].boxes.push_back(truth_box); + } + } + } + return result; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SHAPE_PREDICToR_TRAINER_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/image_processing/shape_predictor_trainer_abstract.h b/lib/3rdParty/dlib/include/dlib/image_processing/shape_predictor_trainer_abstract.h new file mode 100644 index 00000000..278b9784 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/image_processing/shape_predictor_trainer_abstract.h @@ -0,0 +1,418 @@ +// Copyright (C) 2014 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SHAPE_PREDICToR_TRAINER_ABSTRACT_H_ +#ifdef DLIB_SHAPE_PREDICToR_TRAINER_ABSTRACT_H_ + +#include "shape_predictor_abstract.h" +#include "../data_io/image_dataset_metadata.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class shape_predictor_trainer + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a tool for training shape_predictors based on annotated training + images. Its implementation uses the algorithm described in: + One Millisecond Face Alignment with an Ensemble of Regression Trees + by Vahid Kazemi and Josephine Sullivan, CVPR 2014 + + !*/ + + public: + + shape_predictor_trainer ( + ); + /*! + ensures + - #get_cascade_depth() == 10 + - #get_tree_depth() == 4 + - #get_num_trees_per_cascade_level() == 500 + - #get_nu() == 0.1 + - #get_oversampling_amount() == 20 + - #get_feature_pool_size() == 400 + - #get_lambda() == 0.1 + - #get_num_test_splits() == 20 + - #get_feature_pool_region_padding() == 0 + - #get_random_seed() == "" + - #get_num_threads() == 0 + - #get_padding_mode() == landmark_relative + - This object will not be verbose + !*/ + + unsigned long get_cascade_depth ( + ) const; + /*! + ensures + - returns the number of cascades created when you train a model. This + means that the total number of trees in the learned model is equal to + get_cascade_depth()*get_num_trees_per_cascade_level(). + !*/ + + void set_cascade_depth ( + unsigned long depth + ); + /*! + requires + - depth > 0 + ensures + - #get_cascade_depth() == depth + !*/ + + unsigned long get_tree_depth ( + ) const; + /*! + ensures + - returns the depth of the trees used in the cascade. In particular, there + are pow(2,get_tree_depth()) leaves in each tree. + !*/ + + void set_tree_depth ( + unsigned long depth + ); + /*! + requires + - depth > 0 + ensures + - #get_tree_depth() == depth + !*/ + + unsigned long get_num_trees_per_cascade_level ( + ) const; + /*! + ensures + - returns the number of trees created for each cascade. This means that + the total number of trees in the learned model is equal to + get_cascade_depth()*get_num_trees_per_cascade_level(). + !*/ + + void set_num_trees_per_cascade_level ( + unsigned long num + ); + /*! + requires + - num > 0 + ensures + - #get_num_trees_per_cascade_level() == num + !*/ + + double get_nu ( + ) const; + /*! + ensures + - returns the regularization parameter. Larger values of this parameter + will cause the algorithm to fit the training data better but may also + cause overfitting. + !*/ + + void set_nu ( + double nu + ); + /*! + requires + - 0 < nu <= 1 + ensures + - #get_nu() == nu + !*/ + + std::string get_random_seed ( + ) const; + /*! + ensures + - returns the random seed used by the internal random number generator. + Since this algorithm is a random forest style algorithm it relies on a + random number generator for generating the trees. So each setting of the + random seed will produce slightly different outputs. + !*/ + + void set_random_seed ( + const std::string& seed + ); + /*! + ensures + - #get_random_seed() == seed + !*/ + + unsigned long get_oversampling_amount ( + ) const; + /*! + ensures + - You give annotated images to this object as training examples. You + can effectively increase the amount of training data by adding in each + training example multiple times but with a randomly selected deformation + applied to it. That is what this parameter controls. That is, if you + supply N training samples to train() then the algorithm runs internally + with N*get_oversampling_amount() training samples. So the bigger this + parameter the better (excepting that larger values make training take + longer). In terms of the Kazemi paper, this parameter is the number of + randomly selected initial starting points sampled for each training + example. + !*/ + + void set_oversampling_amount ( + unsigned long amount + ); + /*! + requires + - amount > 0 + ensures + - #get_oversampling_amount() == amount + !*/ + + unsigned long get_feature_pool_size ( + ) const; + /*! + ensures + - At each level of the cascade we randomly sample get_feature_pool_size() + pixels from the image. These pixels are used to generate features for + the random trees. So in general larger settings of this parameter give + better accuracy but make the algorithm run slower. + !*/ + + void set_feature_pool_size ( + unsigned long size + ); + /*! + requires + - size > 1 + ensures + - #get_feature_pool_size() == size + !*/ + + enum padding_mode_t + { + bounding_box_relative, + landmark_relative + }; + + padding_mode_t get_padding_mode ( + ) const; + /*! + ensures + - returns the current padding mode. See get_feature_pool_region_padding() + for a discussion of the modes. + !*/ + + void set_padding_mode ( + padding_mode_t mode + ); + /*! + ensures + - #get_padding_mode() == mode + !*/ + + double get_feature_pool_region_padding ( + ) const; + /*! + ensures + - This algorithm works by comparing the relative intensity of pairs of + pixels in the input image. To decide which pixels to look at, the + training algorithm randomly selects pixels from a box roughly centered + around the object of interest. We call this box the feature pool region + box. + + Each object of interest is defined by a full_object_detection, which + contains a bounding box and a list of landmarks. If + get_padding_mode()==landmark_relative then the feature pool region box is + the tightest box that contains the landmarks inside the + full_object_detection. In this mode the full_object_detection's bounding + box is ignored. Otherwise, if the padding mode is bounding_box_relative + then the feature pool region box is the tightest box that contains BOTH + the landmarks and the full_object_detection's bounding box. + + Additionally, you can adjust the size of the feature pool padding region + by setting get_feature_pool_region_padding() to some value. If + get_feature_pool_region_padding()==0 then the feature pool region box is + unmodified and defined exactly as stated above. However, you can expand + the size of the box by setting the padding > 0 or shrink it by setting it + to something < 0. + + To explain this precisely, for a padding of 0 we say that the pixels are + sampled from a box of size 1x1. The padding value is added to each side + of the box. So a padding of 0.5 would cause the algorithm to sample + pixels from a box that was 2x2, effectively multiplying the area pixels + are sampled from by 4. Similarly, setting the padding to -0.2 would + cause it to sample from a box 0.6x0.6 in size. + !*/ + + void set_feature_pool_region_padding ( + double padding + ); + /*! + requires + - padding > -0.5 + ensures + - #get_feature_pool_region_padding() == padding + !*/ + + double get_lambda ( + ) const; + /*! + ensures + - To decide how to split nodes in the regression trees the algorithm looks + at pairs of pixels in the image. These pixel pairs are sampled randomly + but with a preference for selecting pixels that are near each other. + get_lambda() controls this "nearness" preference. In particular, smaller + values of get_lambda() will make the algorithm prefer to select pixels + close together and larger values of get_lambda() will make it care less + about picking nearby pixel pairs. + + Note that this is the inverse of how it is defined in the Kazemi paper. + For this object, you should think of lambda as "the fraction of the + bounding box will we traverse to find a neighboring pixel". Nominally, + this is normalized between 0 and 1. So reasonable settings of lambda are + values in the range 0 < lambda < 1. + !*/ + + void set_lambda ( + double lambda + ); + /*! + requires + - lambda > 0 + ensures + - #get_lambda() == lambda + !*/ + + unsigned long get_num_test_splits ( + ) const; + /*! + ensures + - When generating the random trees we randomly sample get_num_test_splits() + possible split features at each node and pick the one that gives the best + split. Larger values of this parameter will usually give more accurate + outputs but take longer to train. + !*/ + + void set_num_test_splits ( + unsigned long num + ); + /*! + requires + - num > 0 + ensures + - #get_num_test_splits() == num + !*/ + + unsigned long get_num_threads ( + ) const; + /*! + ensures + - When running training process, it is possible to make some parts of it parallel + using CPU threads with #parallel_for() extension and creating #thread_pool internally + When get_num_threads() == 0, trainer will not create threads and all processing will + be done in the calling thread + !*/ + + void set_num_threads ( + unsigned long num + ); + /*! + requires + - num >= 0 + ensures + - #get_num_threads() == num + !*/ + + void be_verbose ( + ); + /*! + ensures + - This object will print status messages to standard out so that a + user can observe the progress of the algorithm. + !*/ + + void be_quiet ( + ); + /*! + ensures + - This object will not print anything to standard out + !*/ + + template + shape_predictor train ( + const image_array& images, + const std::vector >& objects + ) const; + /*! + requires + - image_array is a dlib::array of image objects where each image object + implements the interface defined in dlib/image_processing/generic_image.h + - images.size() == objects.size() + - images.size() > 0 + - for some i: objects[i].size() != 0 + (i.e. there has to be at least one full_object_detection in the training set) + - for all valid p, there must exist i and j such that: + objects[i][j].part(p) != OBJECT_PART_NOT_PRESENT. + (i.e. You can't define a part that is always set to OBJECT_PART_NOT_PRESENT.) + - for all valid i,j,k,l: + - objects[i][j].num_parts() == objects[k][l].num_parts() + (i.e. all objects must agree on the number of parts) + - objects[i][j].num_parts() > 0 + ensures + - This object will try to learn to predict the locations of an object's parts + based on the object bounding box (i.e. full_object_detection::get_rect()) + and the image pixels in that box. That is, we will try to learn a + shape_predictor, SP, such that: + SP(images[i], objects[i][j].get_rect()) == objects[i][j] + This learned SP object is then returned. + - Not all parts are required to be observed for all objects. So if you + have training instances with missing parts then set the part positions + equal to OBJECT_PART_NOT_PRESENT and this algorithm will basically ignore + those missing parts. + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename some_type_of_rectangle + > + image_dataset_metadata::dataset make_bounding_box_regression_training_data ( + const image_dataset_metadata::dataset& truth, + const std::vector>& detections + ); + /*! + requires + - truth.images.size() == detections.size() + - some_type_of_rectangle == rectangle, drectangle, mmod_rect, or any other type + that is convertible to a rectangle. + ensures + - Suppose you have an object detector that can roughly locate objects in an + image. This means your detector draws boxes around objects, but these are + *rough* boxes in the sense that they aren't positioned super accurately. For + instance, HOG based detectors usually have a stride of 8 pixels. So the + positional accuracy is going to be, at best, +/-8 pixels. + + If you want to get better positional accuracy one easy thing to do is train a + shape_predictor to give you the location of the object's box. The + make_bounding_box_regression_training_data() routine helps you do this by + creating an appropriate training dataset. It does this by taking the dataset + you used to train your detector (given by the truth object), and combining + that with the output of your detector on each image in the training dataset + (given by the detections object). In particular, it will create a new + annotated dataset where each object box is one of the rectangles from + detections and that object has 5 part annotations. These annotations + identify the sides and middle of the truth rectangle corresponding to the + detection rectangle. You can then take the returned dataset and train a + shape_predictor on it. The resulting shape_predictor can then be used to do + bounding box regression. + + As an aside, the reason we create 5 part annotations in this way is because + it gives the best shape_predictor when trained. If instead you used the 4 + corners it wouldn't work as well, due to tedious vagaries of the shape_predictor + training process. + + - We assume that detections[i] contains object detections corresponding to + the image truth.images[i]. + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SHAPE_PREDICToR_TRAINER_ABSTRACT_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/image_saver/image_saver.h b/lib/3rdParty/dlib/include/dlib/image_saver/image_saver.h index 43a2717a..cf4c3591 100644 --- a/lib/3rdParty/dlib/include/dlib/image_saver/image_saver.h +++ b/lib/3rdParty/dlib/include/dlib/image_saver/image_saver.h @@ -423,13 +423,6 @@ namespace dlib } }; - template - struct is_rgb_image - { - typedef typename image_traits::pixel_type pixel_type; - const static bool value = pixel_traits::rgb; - }; - template struct save_dng_helper >::type> { diff --git a/lib/3rdParty/dlib/include/dlib/image_saver/save_jpeg.h b/lib/3rdParty/dlib/include/dlib/image_saver/save_jpeg.h new file mode 100644 index 00000000..fb1808c4 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/image_saver/save_jpeg.h @@ -0,0 +1,82 @@ +// Copyright (C) 2014 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SAVE_JPEG_Hh_ +#define DLIB_SAVE_JPEG_Hh_ + +#include "save_jpeg_abstract.h" + +#include "../enable_if.h" +#include "../matrix.h" +#include "../array2d.h" +#include "../pixel.h" +#include "../image_processing/generic_image.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + void save_jpeg ( + const array2d& img, + const std::string& filename, + int quality = 75 + ); + +// ---------------------------------------------------------------------------------------- + + void save_jpeg ( + const array2d& img, + const std::string& filename, + int quality = 75 + ); + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + typename disable_if >::type save_jpeg( + const image_type& img, + const std::string& filename, + int quality = 75 + ) + { + // Convert any kind of grayscale image to an unsigned char image + if (pixel_traits::pixel_type>::grayscale) + { + array2d temp; + assign_image(temp, img); + save_jpeg(temp, filename, quality); + } + else + { + // This is some other kind of color image so just save it as an RGB image. + array2d temp; + assign_image(temp, img); + save_jpeg(temp, filename, quality); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + void save_jpeg( + const matrix_exp& img, + const std::string& file_name, + int quality = 75 + ) + { + array2d temp; + assign_image(temp, img); + save_jpeg(temp, file_name, quality); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SAVE_JPEG_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/image_saver/save_jpeg_abstract.h b/lib/3rdParty/dlib/include/dlib/image_saver/save_jpeg_abstract.h new file mode 100644 index 00000000..f441339b --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/image_saver/save_jpeg_abstract.h @@ -0,0 +1,52 @@ +// Copyright (C) 2014 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SAVE_JPEG_ABSTRACT_Hh_ +#ifdef DLIB_SAVE_JPEG_ABSTRACT_Hh_ + +#include "../image_processing/generic_image.h" +#include "../pixel.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void save_jpeg ( + const image_type& img, + const std::string& filename, + int quality = 75 + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h or a matrix expression + - image.size() != 0 + - 0 <= quality <= 100 + ensures + - writes the image to the file indicated by file_name in the JPEG format. + - image[0][0] will be in the upper left corner of the image. + - image[image.nr()-1][image.nc()-1] will be in the lower right corner of the + image. + - This routine can save images containing any type of pixel. However, + save_jpeg() can only natively store rgb_pixel and uint8 pixel types. All + other pixel types will be converted into one of these types as appropriate + before being saved to disk. + - The quality value determines how lossy the compression is. Larger quality + values result in larger output images but the images will look better. + throws + - image_save_error + This exception is thrown if there is an error that prevents us from saving + the image. + - std::bad_alloc + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SAVE_JPEG_ABSTRACT_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/image_saver/save_png.cpp b/lib/3rdParty/dlib/include/dlib/image_saver/save_png.cpp deleted file mode 100644 index 1c96b929..00000000 --- a/lib/3rdParty/dlib/include/dlib/image_saver/save_png.cpp +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_SAVE_PnG_CPPh_ -#define DLIB_SAVE_PnG_CPPh_ - -// only do anything with this file if DLIB_PNG_SUPPORT is defined -#ifdef DLIB_PNG_SUPPORT - -#include "save_png.h" -#include -#include -#include "../byte_orderer.h" - -namespace dlib -{ - // Don't do anything when libpng calls us to tell us about an error. Just return to - // our own code and throw an exception (at the long jump target). - void png_reader_user_error_fn_silent(png_structp png_struct, png_const_charp ) - { - longjmp(png_jmpbuf(png_struct),1); - } - void png_reader_user_warning_fn_silent(png_structp , png_const_charp ) - { - } - - namespace impl - { - void impl_save_png ( - const std::string& file_name, - std::vector& row_pointers, - const long width, - const png_type type, - const int bit_depth - ) - { - - FILE *fp; - png_structp png_ptr; - png_infop info_ptr; - - /* Open the file */ - fp = fopen(file_name.c_str(), "wb"); - if (fp == NULL) - throw image_save_error("Unable to open " + file_name + " for writing."); - - /* Create and initialize the png_struct with the desired error handler - * functions. If you want to use the default stderr and longjump method, - * you can supply NULL for the last three parameters. We also check that - * the library version is compatible with the one used at compile time, - * in case we are using dynamically linked libraries. REQUIRED. - */ - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, &png_reader_user_error_fn_silent, &png_reader_user_warning_fn_silent); - - if (png_ptr == NULL) - { - fclose(fp); - throw image_save_error("Error while writing PNG file " + file_name); - } - - /* Allocate/initialize the image information data. REQUIRED */ - info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) - { - fclose(fp); - png_destroy_write_struct(&png_ptr, NULL); - throw image_save_error("Error while writing PNG file " + file_name); - } - - /* Set error handling. REQUIRED if you aren't supplying your own - * error handling functions in the png_create_write_struct() call. - */ - if (setjmp(png_jmpbuf(png_ptr))) - { - /* If we get here, we had a problem writing the file */ - fclose(fp); - png_destroy_write_struct(&png_ptr, &info_ptr); - throw image_save_error("Error while writing PNG file " + file_name); - } - - int color_type = 0; - switch(type) - { - case png_type_rgb: color_type = PNG_COLOR_TYPE_RGB; break; - case png_type_rgb_alpha: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break; - case png_type_gray: color_type = PNG_COLOR_TYPE_GRAY; break; - default: - { - fclose(fp); - png_destroy_write_struct(&png_ptr, &info_ptr); - throw image_save_error("Invalid color type"); - } - } - - - /* Set up the output control if you are using standard C streams */ - png_init_io(png_ptr, fp); - - - int png_transforms = PNG_TRANSFORM_IDENTITY; - byte_orderer bo; - if (bo.host_is_little_endian()) - png_transforms |= PNG_TRANSFORM_SWAP_ENDIAN; - - const long height = row_pointers.size(); - - - png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - png_set_rows(png_ptr, info_ptr, &row_pointers[0]); - png_write_png(png_ptr, info_ptr, png_transforms, NULL); - - /* Clean up after the write, and free any memory allocated */ - png_destroy_write_struct(&png_ptr, &info_ptr); - - /* Close the file */ - fclose(fp); - } - } -} - -#endif // DLIB_PNG_SUPPORT - -#endif // DLIB_SAVE_PnG_CPPh_ - - diff --git a/lib/3rdParty/dlib/include/dlib/image_saver/save_png.h b/lib/3rdParty/dlib/include/dlib/image_saver/save_png.h index 5a1ddc12..cddf03ff 100644 --- a/lib/3rdParty/dlib/include/dlib/image_saver/save_png.h +++ b/lib/3rdParty/dlib/include/dlib/image_saver/save_png.h @@ -80,9 +80,9 @@ namespace dlib impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_rgb_alpha, 8); } - else if (pixel_traits::hsi || pixel_traits::rgb) + else if (pixel_traits::lab || pixel_traits::hsi || pixel_traits::rgb) { - // convert from HSI to RGB (Or potentially RGB pixels that aren't laid out as R G B) + // convert from Lab or HSI to RGB (Or potentially RGB pixels that aren't laid out as R G B) array2d temp_img; assign_image(temp_img, img_); for (unsigned long i = 0; i < row_pointers.size(); ++i) diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms.h b/lib/3rdParty/dlib/include/dlib/image_transforms.h index 966e7852..89b4e0db 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms.h @@ -1,5 +1,10 @@ // Copyright (C) 2006 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. + +#ifdef DLIB_ALL_SOURCE_END +#include "dlib_basic_cpp_build_tutorial.txt" +#endif + #ifndef DLIB_IMAGE_TRANSFORMs_ #define DLIB_IMAGE_TRANSFORMs_ @@ -12,11 +17,15 @@ #include "image_transforms/draw.h" #include "image_transforms/integral_image.h" #include "image_transforms/image_pyramid.h" +#include "image_transforms/hough_transform.h" #include "image_transforms/label_connected_blobs.h" #include "image_transforms/colormaps.h" #include "image_transforms/segment_image.h" #include "image_transforms/interpolation.h" #include "image_transforms/fhog.h" +#include "image_transforms/lbp.h" +#include "image_transforms/random_color_transform.h" +#include "image_transforms/random_cropper.h" #endif // DLIB_IMAGE_TRANSFORMs_ diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/assign_image.h b/lib/3rdParty/dlib/include/dlib/image_transforms/assign_image.h index 30f0751d..c69878ef 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/assign_image.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/assign_image.h @@ -337,7 +337,10 @@ namespace dlib { inside = inside.intersect(get_rect(img)); if (inside.is_empty()) + { + assign_all_pixels(img, 0); return; + } for (long r = 0; r < inside.top(); ++r) { diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/assign_image_abstract.h b/lib/3rdParty/dlib/include/dlib/image_transforms/assign_image_abstract.h index 5ba262ba..3fc4108e 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/assign_image_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/assign_image_abstract.h @@ -70,10 +70,10 @@ namespace dlib at the edge of the destination image's dynamic range. - Specifically, for all valid r and c: - scales get_pixel_intensity(src_img[r][c]) into the dynamic range - of the dest_img. This is done by computing the mean and standard - deviation of src_img. Call the mean M and the standard deviation - D. Then the scaling from src_img to dest_img is performed using - the following mapping: + of the dest_img. This is done using the mean and standard deviation + of src_img. Call the mean M and the standard deviation D. Then the + scaling from src_img to dest_img is performed using the following + mapping: let SRC_UPPER = min(M + thresh*D, max(mat(src_img))) let SRC_LOWER = max(M - thresh*D, min(mat(src_img))) let DEST_UPPER = pixel_traits::pixel_type>::max() diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/colormaps.h b/lib/3rdParty/dlib/include/dlib/image_transforms/colormaps.h index 67552bc1..813d1ff7 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/colormaps.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/colormaps.h @@ -63,6 +63,32 @@ namespace dlib return matrix_op(op(img)); } +// ---------------------------------------------------------------------------------------- + + inline rgb_pixel colormap_heat ( + double value, + double min_val, + double max_val + ) + { + // scale the gray value into the range [0, 1] + const double gray = put_in_range(0, 1, (value - min_val)/(max_val-min_val)); + rgb_pixel pix(0,0,0); + + pix.red = static_cast(std::min(gray/0.4,1.0)*255 + 0.5); + + if (gray > 0.4) + { + pix.green = static_cast(std::min((gray-0.4)/0.4,1.0)*255 + 0.5); + } + if (gray > 0.8) + { + pix.blue = static_cast(std::min((gray-0.8)/0.2,1.0)*255 + 0.5); + } + + return pix; + } + // ---------------------------------------------------------------------------------------- template @@ -89,22 +115,7 @@ namespace dlib const_ret_type apply (long r, long c ) const { - // scale the gray value into the range [0, 1] - const double gray = put_in_range(0, 1, (get_pixel_intensity(mat(img)(r,c)) - min_val)/(max_val-min_val)); - rgb_pixel pix(0,0,0); - - pix.red = static_cast(std::min(gray/0.4,1.0)*255 + 0.5); - - if (gray > 0.4) - { - pix.green = static_cast(std::min((gray-0.4)/0.4,1.0)*255 + 0.5); - } - if (gray > 0.8) - { - pix.blue = static_cast(std::min((gray-0.8)/0.2,1.0)*255 + 0.5); - } - - return pix; + return colormap_heat(get_pixel_intensity(mat(img)(r,c)), min_val, max_val); } long nr () const { return num_rows(img); } @@ -134,7 +145,58 @@ namespace dlib ) { typedef op_heatmap op; - return matrix_op(op(img,max(mat(img)),min(mat(img)))); + if (num_columns(img) * num_rows(img) != 0) + return matrix_op(op(img,max(mat(img)),min(mat(img)))); + else + return matrix_op(op(img,0,0)); + } + +// ---------------------------------------------------------------------------------------- + + inline rgb_pixel colormap_jet ( + double value, + double min_val, + double max_val + ) + { + // scale the gray value into the range [0, 8] + const double gray = 8*put_in_range(0, 1, (value - min_val)/(max_val-min_val)); + rgb_pixel pix; + // s is the slope of color change + const double s = 1.0/2.0; + + if (gray <= 1) + { + pix.red = 0; + pix.green = 0; + pix.blue = static_cast((gray+1)*s*255 + 0.5); + } + else if (gray <= 3) + { + pix.red = 0; + pix.green = static_cast((gray-1)*s*255 + 0.5); + pix.blue = 255; + } + else if (gray <= 5) + { + pix.red = static_cast((gray-3)*s*255 + 0.5); + pix.green = 255; + pix.blue = static_cast((5-gray)*s*255 + 0.5); + } + else if (gray <= 7) + { + pix.red = 255; + pix.green = static_cast((7-gray)*s*255 + 0.5); + pix.blue = 0; + } + else + { + pix.red = static_cast((9-gray)*s*255 + 0.5); + pix.green = 0; + pix.blue = 0; + } + + return pix; } // ---------------------------------------------------------------------------------------- @@ -163,44 +225,7 @@ namespace dlib const_ret_type apply (long r, long c ) const { - // scale the gray value into the range [0, 8] - const double gray = 8*put_in_range(0, 1, (get_pixel_intensity(mat(img)(r,c)) - min_val)/(max_val-min_val)); - rgb_pixel pix; - // s is the slope of color change - const double s = 1.0/2.0; - - if (gray <= 1) - { - pix.red = 0; - pix.green = 0; - pix.blue = static_cast((gray+1)*s*255 + 0.5); - } - else if (gray <= 3) - { - pix.red = 0; - pix.green = static_cast((gray-1)*s*255 + 0.5); - pix.blue = 255; - } - else if (gray <= 5) - { - pix.red = static_cast((gray-3)*s*255 + 0.5); - pix.green = 255; - pix.blue = static_cast((5-gray)*s*255 + 0.5); - } - else if (gray <= 7) - { - pix.red = 255; - pix.green = static_cast((7-gray)*s*255 + 0.5); - pix.blue = 0; - } - else - { - pix.red = static_cast((9-gray)*s*255 + 0.5); - pix.green = 0; - pix.blue = 0; - } - - return pix; + return colormap_jet(get_pixel_intensity(mat(img)(r,c)), min_val, max_val); } long nr () const { return num_rows(img); } @@ -230,7 +255,10 @@ namespace dlib ) { typedef op_jet op; - return matrix_op(op(img,max(mat(img)),min(mat(img)))); + if (num_columns(img) * num_rows(img) != 0) + return matrix_op(op(img,max(mat(img)),min(mat(img)))); + else + return matrix_op(op(img,0,0)); } // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/colormaps_abstract.h b/lib/3rdParty/dlib/include/dlib/image_transforms/colormaps_abstract.h index f4762487..41a7784b 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/colormaps_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/colormaps_abstract.h @@ -37,6 +37,20 @@ namespace dlib // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- + rgb_pixel colormap_heat ( + double value, + double min_val, + double max_val + ); + /*! + requires + - min_val <= max_val + ensures + - Maps value to a color. In particular, we use a heatmap color scheme where + values <= min_val are black and larger values become more red, then yellow, + and then white as they approach max_val. + !*/ + template < typename image_type > @@ -51,11 +65,9 @@ namespace dlib dlib/image_processing/generic_image.h, or something convertible to a matrix via mat(). ensures - - Interprets img as a grayscale image and returns a new matrix - which represents a colored version of img. In particular, the - colors will depict img using a heatmap where pixels with a - value <= min_val are black and larger pixel values become - more red, then yellow, and then white as they approach max_val. + - Interprets img as a grayscale image and returns a new matrix which represents + a colored version of img. In particular, the colormap is defined by + out_color = colormap_heat(grayscale_pixel_value, min_val, max_val). - The returned matrix will have the same dimensions as img. !*/ @@ -79,6 +91,20 @@ namespace dlib // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- + rgb_pixel colormap_jet ( + double value, + double min_val, + double max_val + ); + /*! + requires + - min_val <= max_val + ensures + - Maps value to a color. In particular, we use a jet color scheme where + values <= min_val are dark blue and larger values become light blue, then + yellow, and then finally red as they approach max_val. + !*/ + template < typename image_type > @@ -94,10 +120,8 @@ namespace dlib via mat(). ensures - Interprets img as a grayscale image and returns a new matrix which represents - a colored version of img. In particular, the colors will depict img using a - jet color scheme where pixels with a value <= min_val are dark blue and - larger pixel values become light blue, then yellow, and then finally red as - they approach max_Val. + a colored version of img. In particular, the colormap is defined by + out_color = colormap_jet(grayscale_pixel_value, min_val, max_val). - The returned matrix will have the same dimensions as img. !*/ diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/draw.h b/lib/3rdParty/dlib/include/dlib/image_transforms/draw.h index c38db500..66737b21 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/draw.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/draw.h @@ -215,7 +215,7 @@ namespace dlib unsigned int thickness ) { - for (int i = 0; i < thickness; ++i) + for (unsigned int i = 0; i < thickness; ++i) { if ((i%2)==0) draw_rectangle(c,shrink_rect(rect,(i+1)/2),val); @@ -293,6 +293,98 @@ namespace dlib return temp; } +// ---------------------------------------------------------------------------------------- + + template < + typename image_type, + typename pixel_type + > + void draw_solid_circle ( + image_type& img_, + const dpoint& center_point, + double radius, + const pixel_type& pixel + ) + { + image_view img(img_); + using std::sqrt; + const rectangle valid_area(get_rect(img)); + const double x = center_point.x(); + const double y = center_point.y(); + const point cp(center_point); + if (radius > 1) + { + long first_x = static_cast(x - radius + 0.5); + long last_x = static_cast(x + radius + 0.5); + const double rs = radius*radius; + + // ensure that we only loop over the part of the x dimension that this + // image contains. + if (first_x < valid_area.left()) + first_x = valid_area.left(); + if (last_x > valid_area.right()) + last_x = valid_area.right(); + + long top, bottom; + + top = static_cast(sqrt(std::max(rs - (first_x-x-0.5)*(first_x-x-0.5),0.0))+0.5); + top += y; + long last = top; + + // draw the left half of the circle + long middle = std::min(cp.x()-1,last_x); + for (long i = first_x; i <= middle; ++i) + { + double a = i - x + 0.5; + // find the top of the arc + top = static_cast(sqrt(std::max(rs - a*a,0.0))+0.5); + top += y; + long temp = top; + + while(top >= last) + { + bottom = y - top + y; + draw_line(img_, point(i,top),point(i,bottom),pixel); + --top; + } + + last = temp; + } + + middle = std::max(cp.x(),first_x); + top = static_cast(sqrt(std::max(rs - (last_x-x+0.5)*(last_x-x+0.5),0.0))+0.5); + top += y; + last = top; + // draw the right half of the circle + for (long i = last_x; i >= middle; --i) + { + double a = i - x - 0.5; + // find the top of the arc + top = static_cast(sqrt(std::max(rs - a*a,0.0))+0.5); + top += y; + long temp = top; + + while(top >= last) + { + bottom = y - top + y; + draw_line(img_, point(i,top),point(i,bottom),pixel); + --top; + } + + last = temp; + } + } + else if (valid_area.contains(cp)) + { + // For circles smaller than a pixel we will just alpha blend them in proportion + // to how small they are. + rgb_alpha_pixel temp; + assign_pixel(temp, pixel); + temp.alpha = static_cast(255*radius + 0.5); + assign_pixel(img[cp.y()][cp.x()], temp); + } + } + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/draw_abstract.h b/lib/3rdParty/dlib/include/dlib/image_transforms/draw_abstract.h index 27a0aec6..6631f8d8 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/draw_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/draw_abstract.h @@ -79,6 +79,29 @@ namespace dlib - The drawn rectangle will have edges that are thickness pixels wide. !*/ +// ---------------------------------------------------------------------------------------- + + template < + typename image_type, + typename pixel_type + > + void draw_solid_circle ( + image_type& img, + const dpoint& center_point, + double radius, + const pixel_type& pixel + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - pixel_traits is defined + ensures + - Draws a fully filled in circle onto image that is centered at center_point + and has the given radius. The circle will be filled by assigning the given + pixel value to each element of the circle. + !*/ + // ---------------------------------------------------------------------------------------- template < diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/edge_detector.h b/lib/3rdParty/dlib/include/dlib/image_transforms/edge_detector.h index 2fa898fe..67f50117 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/edge_detector.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/edge_detector.h @@ -6,6 +6,9 @@ #include "edge_detector_abstract.h" #include "../pixel.h" #include "../array2d.h" +#include "../geometry.h" +#include +#include "../image_keypoint/build_separable_poly_filters.h" namespace dlib { @@ -292,6 +295,439 @@ namespace dlib } } +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void normalize_image_gradients ( + image_type& img1_, + image_type& img2_ + ) + { + image_view img1(img1_); + image_view img2(img2_); + + using pixel_type = typename image_traits::pixel_type; + static_assert(std::is_same::value || + std::is_same::value || + std::is_same::value, + "normalize_image_gradients() requires the input images to use floating point pixel types."); + + DLIB_CASSERT(img1.nr() == img2.nr()); + DLIB_CASSERT(img1.nc() == img2.nc()); + + // normalize all the gradients + for (long r = 0; r < img1.nr(); ++r) + { + for (long c = 0; c < img1.nc(); ++c) + { + if (img1[r][c] != 0 || img2[r][c] != 0) + { + double len = std::sqrt(img1[r][c]*img1[r][c] + img2[r][c]*img2[r][c]); + img1[r][c] /= len; + img2[r][c] /= len; + } + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + std::vector remove_incoherent_edge_pixels ( + const std::vector& line, + const image_type& horz_gradient_, + const image_type& vert_gradient_, + double angle_threshold + ) + { + const_image_view horz_gradient(horz_gradient_); + const_image_view vert_gradient(vert_gradient_); + + DLIB_CASSERT(horz_gradient.nr() == vert_gradient.nr()); + DLIB_CASSERT(horz_gradient.nc() == vert_gradient.nc()); + DLIB_CASSERT(angle_threshold >= 0); +#ifdef ENABLE_ASSERTS + for (auto& p : line) + DLIB_ASSERT(get_rect(horz_gradient).contains(p), "All line points must be inside the given images."); +#endif + + // We make sure that each vector is within this threshold of the mean vector. So + // to make sure they are pairwise within the user supplied angel threshold we need + // to divide by 2 before we proceed. + angle_threshold /= 2; + + const double dotthresh = std::cos(angle_threshold*pi/180); + // find the average gradient on this line + dpoint avg; + for (auto p : line) + avg += dpoint(horz_gradient[p.y()][p.x()], vert_gradient[p.y()][p.x()]); + dpoint ref = avg.normalize(); + + // now iterate a few times and find the most common average gradient. + for (int i = 0; i < 10; ++i) + { + avg = dpoint(); + for (auto p : line) + { + const dpoint v(horz_gradient[p.y()][p.x()], vert_gradient[p.y()][p.x()]); + const double dp = ref.dot(v); + if (dp > dotthresh) + avg += v; + else if (-dp > dotthresh) + avg -= v; + } + ref = avg.normalize(); + } + + // now remove all the points that deviate from the average gradient too much. + std::vector newpixels; + for (auto p : line) + { + dpoint v(horz_gradient[p.y()][p.x()], vert_gradient[p.y()][p.x()]); + if (std::abs(ref.dot(v)) > dotthresh) + newpixels.push_back(p); + } + return newpixels; + } + + template < + typename image_type + > + std::vector> remove_incoherent_edge_pixels ( + const std::vector>& line_pixels, + const image_type& horz_gradient_, + const image_type& vert_gradient_, + const double angle_threshold + ) + { + std::vector> temp; + temp.reserve(line_pixels.size()); + for (auto& line : line_pixels) + temp.emplace_back(remove_incoherent_edge_pixels(line, horz_gradient_, vert_gradient_, angle_threshold)); + return temp; + } + +// ---------------------------------------------------------------------------------------- + + class image_gradients + { + + public: + + image_gradients ( + ) : image_gradients(1) {} + + image_gradients ( + long scale + ) : the_scale(scale) + { + DLIB_CASSERT(scale >= 1); + + scale = 2*scale+1; + + auto dfilters = build_separable_poly_filters(2,scale); + DLIB_CASSERT(dfilters[1].size() == 1); + DLIB_CASSERT(dfilters[2].size() == 1); + DLIB_CASSERT(dfilters[3].size() == 1); + DLIB_CASSERT(dfilters[4].size() == 1); + DLIB_CASSERT(dfilters[5].size() == 1); + + filter_x.first = matrix_cast(dfilters[1][0].first); + filter_x.second = matrix_cast(dfilters[1][0].second); + + filter_y.first = matrix_cast(dfilters[2][0].first); + filter_y.second = matrix_cast(dfilters[2][0].second); + + // We multiply by 2 so that the filter gives the gradient rather than the x^2 + // polynomial coefficient. + filter_xx.first = 2*matrix_cast(dfilters[3][0].first); + filter_xx.second = matrix_cast(dfilters[3][0].second); + + filter_xy.first = matrix_cast(dfilters[4][0].first); + filter_xy.second = matrix_cast(dfilters[4][0].second); + + // We multiply by 2 so that the filter gives the gradient rather than the y^2 + // polynomial coefficient. + filter_yy.first = 2*matrix_cast(dfilters[5][0].first); + filter_yy.second = matrix_cast(dfilters[5][0].second); + } + + + long get_scale() const { return the_scale; } + + template < + typename in_image_type, + typename out_image_type + > + rectangle gradient_x( + const in_image_type& img, + out_image_type& out + ) const + { + return spatially_filter_image_separable(img, out, filter_x.second, filter_x.first); + } + + template < + typename in_image_type, + typename out_image_type + > + rectangle gradient_y( + const in_image_type& img, + out_image_type& out + ) const + { + return spatially_filter_image_separable(img, out, filter_y.second, filter_y.first); + } + + + template < + typename in_image_type, + typename out_image_type + > + rectangle gradient_xx( + const in_image_type& img, + out_image_type& out + ) const + { + return spatially_filter_image_separable(img, out, filter_xx.second, filter_xx.first); + } + + template < + typename in_image_type, + typename out_image_type + > + rectangle gradient_xy( + const in_image_type& img, + out_image_type& out + ) const + { + return spatially_filter_image_separable(img, out, filter_xy.second, filter_xy.first); + } + + template < + typename in_image_type, + typename out_image_type + > + rectangle gradient_yy( + const in_image_type& img, + out_image_type& out + ) const + { + return spatially_filter_image_separable(img, out, filter_yy.second, filter_yy.first); + } + + matrix get_x_filter() const { return filter_x.first*trans(filter_x.second); } + matrix get_y_filter() const { return filter_y.first*trans(filter_y.second); } + matrix get_xx_filter() const { return filter_xx.first*trans(filter_xx.second); } + matrix get_xy_filter() const { return filter_xy.first*trans(filter_xy.second); } + matrix get_yy_filter() const { return filter_yy.first*trans(filter_yy.second); } + + private: + std::pair,matrix> filter_x; + std::pair,matrix> filter_y; + std::pair,matrix> filter_xx; + std::pair,matrix> filter_xy; + std::pair,matrix> filter_yy; + + long the_scale; + }; + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template < + typename in_image_type, + typename out_image_type + > + void find_lines( + const in_image_type& xx_, + const in_image_type& xy_, + const in_image_type& yy_, + out_image_type& horz_, + out_image_type& vert_, + double positive_if_should_find_dark_lines + ) + { + typedef typename image_traits::pixel_type out_pixel_type; + static_assert(std::is_same::value || std::is_same::value, + "Output images must contain either float or double valued pixels"); + + const_image_view xx(xx_); + const_image_view xy(xy_); + const_image_view yy(yy_); + + DLIB_CASSERT(xx.nr() == xy.nr()); + DLIB_CASSERT(xx.nr() == yy.nr()); + DLIB_CASSERT(xx.nc() == xy.nc()); + DLIB_CASSERT(xx.nc() == yy.nc()); + + + image_view x(horz_); + image_view y(vert_); + + x.set_size(xx.nr(), xx.nc()); + y.set_size(xx.nr(), xx.nc()); + + + // store the max eigenvalue into xy and then the associated eigen vector into [xx,yy] + for (long r = 0; r < xx.nr(); ++r) + { + for (long c = 0; c < xx.nc(); ++c) + { + // negate to that lambda will be the *minimum* eigenvalue + double w1 = positive_if_should_find_dark_lines*xx[r][c]/2.0; + double w2 = positive_if_should_find_dark_lines*yy[r][c]/2.0; + double w3 = positive_if_should_find_dark_lines*xy[r][c]; + + + auto lambda = w1 + w2 + std::sqrt((w1-w2)*(w1-w2) + w3*w3); + if (lambda < 0) + lambda = 0; + + if (2*w1!=lambda) + { + x[r][c] = -w3/(2*w1-lambda); + y[r][c] = 1; + + double norm = std::sqrt(x[r][c]*x[r][c] + y[r][c]*y[r][c]); + x[r][c] *= lambda/norm; + y[r][c] *= lambda/norm; + } + else + { + x[r][c] = lambda; + y[r][c] = 0; + } + } + } + } + } + + template < + typename in_image_type, + typename out_image_type + > + void find_bright_lines( + const in_image_type& xx, + const in_image_type& xy, + const in_image_type& yy, + out_image_type& horz, + out_image_type& vert + ) + { + impl::find_lines(xx,xy,yy,horz,vert,-1); + } + + template < + typename in_image_type, + typename out_image_type + > + void find_dark_lines( + const in_image_type& xx, + const in_image_type& xy, + const in_image_type& yy, + out_image_type& horz, + out_image_type& vert + ) + { + impl::find_lines(xx,xy,yy,horz,vert,+1); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void find_bright_keypoints( + const in_image_type& xx_, + const in_image_type& xy_, + const in_image_type& yy_, + out_image_type& saliency_ + ) + { + typedef typename image_traits::pixel_type out_pixel_type; + static_assert(std::is_same::value || std::is_same::value, + "Output images must contain either float or double valued pixels"); + + const_image_view xx(xx_); + const_image_view xy(xy_); + const_image_view yy(yy_); + + DLIB_CASSERT(xx.nr() == xy.nr()); + DLIB_CASSERT(xx.nr() == yy.nr()); + DLIB_CASSERT(xx.nc() == xy.nc()); + DLIB_CASSERT(xx.nc() == yy.nc()); + + + image_view saliency(saliency_); + saliency.set_size(xx.nr(), xx.nc()); + + + for (long r = 0; r < xx.nr(); ++r) + { + for (long c = 0; c < xx.nc(); ++c) + { + matrix tmp; + tmp = xx[r][c], xy[r][c], + xy[r][c], yy[r][c]; + + matrix e = real_eigenvalues(tmp); + saliency[r][c] = prod(upperbound(e,0)); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void find_dark_keypoints( + const in_image_type& xx_, + const in_image_type& xy_, + const in_image_type& yy_, + out_image_type& saliency_ + ) + { + typedef typename image_traits::pixel_type out_pixel_type; + static_assert(std::is_same::value || std::is_same::value, + "Output images must contain either float or double valued pixels"); + + const_image_view xx(xx_); + const_image_view xy(xy_); + const_image_view yy(yy_); + + DLIB_CASSERT(xx.nr() == xy.nr()); + DLIB_CASSERT(xx.nr() == yy.nr()); + DLIB_CASSERT(xx.nc() == xy.nc()); + DLIB_CASSERT(xx.nc() == yy.nc()); + + + image_view saliency(saliency_); + saliency.set_size(xx.nr(), xx.nc()); + + + for (long r = 0; r < xx.nr(); ++r) + { + for (long c = 0; c < xx.nc(); ++c) + { + matrix tmp; + tmp = xx[r][c], xy[r][c], + xy[r][c], yy[r][c]; + + matrix e = real_eigenvalues(tmp); + saliency[r][c] = prod(lowerbound(e,0)); + } + } + } + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/edge_detector_abstract.h b/lib/3rdParty/dlib/include/dlib/image_transforms/edge_detector_abstract.h index 42c99166..05b4acac 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/edge_detector_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/edge_detector_abstract.h @@ -5,6 +5,8 @@ #include "../pixel.h" #include "../image_processing/generic_image.h" +#include "../geometry.h" +#include namespace dlib { @@ -103,6 +105,446 @@ namespace dlib - performs assign_pixel(#out_img[r][c], 0) !*/ +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void normalize_image_gradients ( + image_type& img1, + image_type& img2 + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - image_type contains float, double, or long double pixels. + - img1.nr() == img2.nr() + - img1.nc() == img2.nc() + ensures + - #out_img.nr() = img1.nr() + - #out_img.nc() = img1.nc() + - This function assumes img1 and img2 are the two gradient images produced by a + function like sobel_edge_detector(). It then unit normalizes the gradient + vectors. That is, for all valid r and c, this function ensures that: + - img1[r][c]*img1[r][c] + img2[r][c]*img2[r][c] == 1 + unless both img1[r][c] and img2[r][c] were 0 initially, then they stay zero. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + std::vector remove_incoherent_edge_pixels ( + const std::vector& line, + const image_type& horz_gradient, + const image_type& vert_gradient, + const double angle_threshold + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - image_type contains float, double, or long double pixels. + - horz_gradient.nr() == vert_gradient.nr() + - horz_gradient.nc() == vert_gradient.nc() + - horz_gradient and vert_gradient represent unit normalized vectors. That is, + you should have called normalize_image_gradients(horz_gradient,vert_gradient) + or otherwise caused all the gradients to have unit norm. + - for all valid i: + get_rect(horz_gradient).contains(line[i]) + ensures + - This routine looks at all the points in the given line and discards the ones that + have outlying gradient directions. To be specific, this routine returns a set + of points PTS such that: + - for all valid i,j: + - The difference in angle between the gradients for PTS[i] and PTS[j] is + less than angle_threshold degrees. + - PTS.size() <= line.size() + - PTS is just line with some elements removed. + !*/ + + template < + typename image_type + > + std::vector> remove_incoherent_edge_pixels ( + const std::vector>& lines, + const image_type& horz_gradient, + const image_type& vert_gradient, + const double angle_threshold + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - image_type contains float, double, or long double pixels. + - horz_gradient.nr() == vert_gradient.nr() + - horz_gradient.nc() == vert_gradient.nc() + - horz_gradient and vert_gradient represent unit normalized vectors. That is, + you should have called normalize_image_gradients(horz_gradient,vert_gradient) + or otherwise caused all the gradients to have unit norm. + - for all valid i,j: + get_rect(horz_gradient).contains(lines[i][j]) + ensures + - Returns a vector LINES where: + - LINES.size() == lines.size() + - LINES[i] == remove_incoherent_edge_pixels(lines[i], horz_gradient, vert_gradient, angle_threshold) + !*/ + +// ---------------------------------------------------------------------------------------- + + class image_gradients + { + /*! + WHAT THIS OBJECT REPRESENTS + This class is a tool for computing first and second derivatives of an + image. It does this by fitting a quadratic surface around each pixel and + then computing the gradients of that quadratic surface. For the details + see the paper: + Quadratic models for curved line detection in SAR CCD by Davis E. King + and Rhonda D. Phillips + + This technique gives very accurate gradient estimates and is also very fast + since the entire gradient estimation procedure, for each type of gradient, + is accomplished by cross-correlating the image with a single separable + filter. This means you can compute gradients at very large scales (e.g. by + fitting the quadratic to a large window, like a 99x99 window) and it still + runs very quickly. + !*/ + + public: + + image_gradients ( + ); + /*! + ensures + - #get_scale() == 1 + !*/ + + image_gradients ( + long scale + ); + /*! + requires + - scale >= 1 + ensures + - #get_scale() == scale + !*/ + + long get_scale( + ) const; + /*! + ensures + - When we estimate a gradient we do so by fitting a quadratic filter so a + window of size get_scale()*2+1 centered on each pixel. Therefore, the + scale parameter controls the size of gradients we will find. For + example, a very large scale will cause the gradient_xx() to be + insensitive to high frequency noise in the image while smaller scales + would be more sensitive to such fluctuations in the image. + !*/ + + template < + typename in_image_type, + typename out_image_type + > + rectangle gradient_x( + const in_image_type& img, + out_image_type& out + ) const; + /*! + requires + - in_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - out_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - img and out do not contain pixels with an alpha channel. That is, + pixel_traits::has_alpha is false for the pixels in these objects. + - is_same_object(img, out) == false + - out_image_type must use signed grayscale pixels + ensures + - Let VALID_AREA = shrink_rect(get_rect(img),get_scale()). + - Computes the 1st order gradient of img in the x direction at each + location in VALID_AREA. The gradients are stored in out. All pixels in + #out that are outside VALID_AREA are set to 0. + - #num_rows(out) == num_rows(img) + - #num_columns(out) == num_columns(img) + - While not a requirement, it is a good idea if the output image contains + float or double pixels. If get_scale() is small then this is less of an + issue, but at large scales the gradient can easily be a small number + which is not well represented by integer pixel type such as short. Also, + if you use float pixels in the input and output images then this routine + will use SIMD instructions and is particularly fast. + - returns VALID_AREA. That is, returns the part of the output image which + contains actual valid gradient values. + !*/ + + template < + typename in_image_type, + typename out_image_type + > + rectangle gradient_y( + const in_image_type& img, + out_image_type& out + ) const; + /*! + This routine is identical to gradient_x() (defined above) except that it + computes the 1st order y gradient. + !*/ + + template < + typename in_image_type, + typename out_image_type + > + rectangle gradient_xx( + const in_image_type& img, + out_image_type& out + ) const; + /*! + This routine is identical to gradient_x() (defined above) except that it + computes the 2nd order x gradient. + !*/ + + template < + typename in_image_type, + typename out_image_type + > + rectangle gradient_xy( + const in_image_type& img, + out_image_type& out + ) const; + /*! + This routine is identical to gradient_x() (defined above) except that it + computes the partial derivative with respect to x and y. + !*/ + + template < + typename in_image_type, + typename out_image_type + > + rectangle gradient_yy( + const in_image_type& img, + out_image_type& out + ) const; + /*! + This routine is identical to gradient_x() (defined above) except that it + computes the 2nd order y gradient. + !*/ + + matrix get_x_filter( + ) const; + /*! + ensures + - Returns the filter used by gradient_x() to compute the image gradient. + That is, the output of gradient_x() is found by cross correlating the + filter get_x_filter() with the image. + - The returned filter has get_scale()*2+1 rows and columns. + !*/ + + matrix get_y_filter( + ) const; + /*! + ensures + - Returns the filter used by gradient_y() to compute the image gradient. + That is, the output of gradient_y() is found by cross correlating the + filter get_y_filter() with the image. + - The returned filter has get_scale()*2+1 rows and columns. + !*/ + + matrix get_xx_filter( + ) const; + /*! + ensures + - Returns the filter used by gradient_xx() to compute the image gradient. + That is, the output of gradient_xx() is found by cross correlating the + filter get_xx_filter() with the image. + - The returned filter has get_scale()*2+1 rows and columns. + !*/ + + + matrix get_xy_filter( + ) const; + /*! + ensures + - Returns the filter used by gradient_xy() to compute the image gradient. + That is, the output of gradient_xy() is found by cross correlating the + filter get_xy_filter() with the image. + - The returned filter has get_scale()*2+1 rows and columns. + !*/ + + + matrix get_yy_filter( + ) const; + /*! + ensures + - Returns the filter used by gradient_yy() to compute the image gradient. + That is, the output of gradient_yy() is found by cross correlating the + filter get_yy_filter() with the image. + - The returned filter has get_scale()*2+1 rows and columns. + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void find_bright_lines( + const in_image_type& xx, + const in_image_type& xy, + const in_image_type& yy, + out_image_type& horz, + out_image_type& vert + ); + /*! + requires + - in_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - out_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - All images are grayscale and the horz and vert images must contain float or + double pixel types. + - num_rows(xx) == num_rows(xy) == num_rows(yy) + - num_columns(xx) == num_columns(xy) == num_columns(yy) + ensures + - This routine is similar to sobel_edge_detector(), except instead of finding + an edge it finds a bright/white line. For example, the border between a + black piece of paper and a white table is an edge, but a curve drawn with a + pencil on a piece of paper makes a line. Therefore, the output of this + routine is a vector field encoded in the horz and vert images. The vector + obtains a large magnitude when centered on a bright line in an image and the + direction of the vector is perpendicular to the line. To be very precise, + each vector points in the direction of greatest change in second derivative + and the magnitude of the vector encodes the derivative magnitude in that + direction. Moreover, if the second derivative is positive then the output + vector is zero. This zeroing if positive gradients causes the output to be + sensitive only to bright lines surrounded by darker pixels. + - We assume that xx, xy, and yy are the 3 second order gradients of the image + in question. You can obtain these gradients using the image_gradients class. + - The output images will have the same sizes as the input images, that is: + - #num_rows(horz) == #num_rows(vert) == num_rows(xx) + - #num_columns(horz) == #num_columns(vert) == num_columns(xx) + !*/ + + template < + typename in_image_type, + typename out_image_type + > + void find_dark_lines( + const in_image_type& xx, + const in_image_type& xy, + const in_image_type& yy, + out_image_type& horz, + out_image_type& vert + ); + /*! + requires + - in_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - out_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - All images are grayscale and the horz and vert images must contain float or + double pixel types. + - num_rows(xx) == num_rows(xy) == num_rows(yy) + - num_columns(xx) == num_columns(xy) == num_columns(yy) + ensures + - This routine is similar to sobel_edge_detector(), except instead of finding + an edge it finds a dark/black line. For example, the border between a + black piece of paper and a white table is an edge, but a curve drawn with a + pencil on a piece of paper makes a line. Therefore, the output of this + routine is a vector field encoded in the horz and vert images. The vector + obtains a large magnitude when centered on a dark line in an image and the + direction of the vector is perpendicular to the line. To be very precise, + each vector points in the direction of greatest change in second derivative + and the magnitude of the vector encodes the derivative magnitude in that + direction. Moreover, if the second derivative is negative then the output + vector is zero. This zeroing if negative gradients causes the output to be + sensitive only to dark lines surrounded by light pixels. + - We assume that xx, xy, and yy are the 3 second order gradients of the image + in question. You can obtain these gradients using the image_gradients class. + - The output images will have the same sizes as the input images, that is: + - #num_rows(horz) == #num_rows(vert) == num_rows(xx) + - #num_columns(horz) == #num_columns(vert) == num_columns(xx) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void find_bright_keypoints( + const in_image_type& xx, + const in_image_type& xy, + const in_image_type& yy, + out_image_type& saliency + ); + /*! + requires + - in_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - out_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - All images are grayscale and the saliency image must contain float or double + pixel types. + - num_rows(xx) == num_rows(xy) == num_rows(yy) + - num_columns(xx) == num_columns(xy) == num_columns(yy) + ensures + - This routine finds bright "keypoints" in an image. In general, these are + bright/white localized blobs. It does this by computing the determinant of + the image Hessian at each location and storing this value into the output + saliency image if both eigenvalues of the Hessian are negative. If either + eigenvalue is positive then the saliency for that pixel is 0. I.e. + - for all valid r,c: + - #saliency[r][c] == a number >= 0 and larger values indicate the + presence of a keypoint at this pixel location. + - We assume that xx, xy, and yy are the 3 second order gradients of the image + in question. You can obtain these gradients using the image_gradients class. + - The output image will have the same size as the input images, that is: + - #num_rows(saliency) == num_rows(xx) + - #num_columns(saliency) == num_columns(xx) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void find_dark_keypoints( + const in_image_type& xx, + const in_image_type& xy, + const in_image_type& yy, + out_image_type& saliency + ); + /*! + requires + - in_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - out_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - All images are grayscale and the saliency image must contain float or double + pixel types. + - num_rows(xx) == num_rows(xy) == num_rows(yy) + - num_columns(xx) == num_columns(xy) == num_columns(yy) + ensures + - This routine finds dark "keypoints" in an image. In general, these are dark + localized blobs. It does this by computing the determinant of the image + Hessian at each location and storing this value into the output saliency + image if both eigenvalues of the Hessian are positive. If either eigenvalue + is negative then the saliency for that pixel is 0. I.e. + - for all valid r,c: + - #saliency[r][c] == a number >= 0 and larger values indicate the + presence of a keypoint at this pixel location. + - We assume that xx, xy, and yy are the 3 second order gradients of the image + in question. You can obtain these gradients using the image_gradients class. + - The output image will have the same size as the input images, that is: + - #num_rows(saliency) == num_rows(xx) + - #num_columns(saliency) == num_columns(xx) + !*/ + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/equalize_histogram.h b/lib/3rdParty/dlib/include/dlib/image_transforms/equalize_histogram.h index dd048759..5bc797b3 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/equalize_histogram.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/equalize_histogram.h @@ -14,6 +14,45 @@ namespace dlib // --------------------------------------------------------------------------------------- + template < + typename in_image_type, + long R, + long C, + typename MM + > + void get_histogram ( + const in_image_type& in_img_, + matrix& hist, + size_t hist_size + ) + { + typedef typename image_traits::pixel_type pixel_type; + COMPILE_TIME_ASSERT( pixel_traits::is_unsigned == true ); + + // make sure hist is the right size + if (R == 1) + hist.set_size(1,hist_size); + else + hist.set_size(hist_size,1); + + + set_all_elements(hist,0); + + const_image_view in_img(in_img_); + // compute the histogram + for (long r = 0; r < in_img.nr(); ++r) + { + for (long c = 0; c < in_img.nc(); ++c) + { + auto p = get_pixel_intensity(in_img[r][c]); + if (p < hist_size) + ++hist(p); + } + } + } + +// ---------------------------------------------------------------------------------------- + template < typename in_image_type, long R, diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/equalize_histogram_abstract.h b/lib/3rdParty/dlib/include/dlib/image_transforms/equalize_histogram_abstract.h index 2592aef1..68401f76 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/equalize_histogram_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/equalize_histogram_abstract.h @@ -70,7 +70,7 @@ namespace dlib - Let pixel_type denote the type of pixel in in_img, then we must have: - pixel_traits::is_unsigned == true - pixel_traits::max() <= 65535 - - hist must be capable of representing a column vector of length + - hist must be capable of representing a column or row vector of length pixel_traits::max(). I.e. if R and C are nonzero then they must be values that don't conflict with the previous sentence. ensures @@ -82,6 +82,37 @@ namespace dlib in in_img !*/ +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + long R, + long C, + typename MM + > + void get_histogram ( + const in_image_type& in_img, + matrix& hist, + size_t hist_size + ); + /*! + requires + - in_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - Let pixel_type denote the type of pixel in in_img, then we must have: + - pixel_traits::is_unsigned == true + - hist must be capable of representing a column or row vector of length + hist_size. I.e. if R and C are nonzero then they must be values that don't + conflict with the previous sentence. + ensures + - #hist.size() == hist_size + - #hist.nc() == 1 || #hist.nr() == 1 (i.e. hist is either a row or column vector) + - #hist == the histogram for in_img, except pixel values >= hist_size are + ignored. I.e. it is the case that for all valid i: + - hist(i) == the number of times a pixel with intensity i appears + in in_img + !*/ + // --------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/fhog.h b/lib/3rdParty/dlib/include/dlib/image_transforms/fhog.h index 49190c51..d99973ad 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/fhog.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/fhog.h @@ -11,8 +11,7 @@ #include "assign_image.h" #include "draw.h" #include "interpolation.h" -#include "../simd/simd4i.h" -#include "../simd/simd4f.h" +#include "../simd.h" namespace dlib { @@ -21,16 +20,16 @@ namespace dlib namespace impl_fhog { - template + template inline typename dlib::enable_if_c::rgb>::type get_gradient ( const int r, const int c, const image_type& img, - matrix& grad, - double& len + matrix& grad, + T& len ) { - matrix grad2, grad3; + matrix grad2, grad3; // get the red gradient grad(0) = (int)img[r][c+1].red-(int)img[r][c-1].red; grad(1) = (int)img[r+1][c].red-(int)img[r-1][c].red; @@ -39,12 +38,12 @@ namespace dlib // get the green gradient grad2(0) = (int)img[r][c+1].green-(int)img[r][c-1].green; grad2(1) = (int)img[r+1][c].green-(int)img[r-1][c].green; - double v2 = length_squared(grad2); + T v2 = length_squared(grad2); // get the blue gradient grad3(0) = (int)img[r][c+1].blue-(int)img[r][c-1].blue; grad3(1) = (int)img[r+1][c].blue-(int)img[r-1][c].blue; - double v3 = length_squared(grad3); + T v3 = length_squared(grad3); // pick color with strongest gradient if (v2 > len) @@ -142,15 +141,148 @@ namespace dlib len = select(cmp,tlen,blen); } - // ------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ template + inline typename dlib::enable_if_c::rgb>::type get_gradient( + const int r, + const int c, + const image_type& img, + simd8f& grad_x, + simd8f& grad_y, + simd8f& len + ) + { + simd8i rleft((int)img[r][c - 1].red, + (int)img[r][c].red, + (int)img[r][c + 1].red, + (int)img[r][c + 2].red, + (int)img[r][c + 3].red, + (int)img[r][c + 4].red, + (int)img[r][c + 5].red, + (int)img[r][c + 6].red); + simd8i rright((int)img[r][c + 1].red, + (int)img[r][c + 2].red, + (int)img[r][c + 3].red, + (int)img[r][c + 4].red, + (int)img[r][c + 5].red, + (int)img[r][c + 6].red, + (int)img[r][c + 7].red, + (int)img[r][c + 8].red); + simd8i rtop((int)img[r - 1][c].red, + (int)img[r - 1][c + 1].red, + (int)img[r - 1][c + 2].red, + (int)img[r - 1][c + 3].red, + (int)img[r - 1][c + 4].red, + (int)img[r - 1][c + 5].red, + (int)img[r - 1][c + 6].red, + (int)img[r - 1][c + 7].red); + simd8i rbottom((int)img[r + 1][c].red, + (int)img[r + 1][c + 1].red, + (int)img[r + 1][c + 2].red, + (int)img[r + 1][c + 3].red, + (int)img[r + 1][c + 4].red, + (int)img[r + 1][c + 5].red, + (int)img[r + 1][c + 6].red, + (int)img[r + 1][c + 7].red); + + simd8i gleft((int)img[r][c - 1].green, + (int)img[r][c].green, + (int)img[r][c + 1].green, + (int)img[r][c + 2].green, + (int)img[r][c + 3].green, + (int)img[r][c + 4].green, + (int)img[r][c + 5].green, + (int)img[r][c + 6].green); + simd8i gright((int)img[r][c + 1].green, + (int)img[r][c + 2].green, + (int)img[r][c + 3].green, + (int)img[r][c + 4].green, + (int)img[r][c + 5].green, + (int)img[r][c + 6].green, + (int)img[r][c + 7].green, + (int)img[r][c + 8].green); + simd8i gtop((int)img[r - 1][c].green, + (int)img[r - 1][c + 1].green, + (int)img[r - 1][c + 2].green, + (int)img[r - 1][c + 3].green, + (int)img[r - 1][c + 4].green, + (int)img[r - 1][c + 5].green, + (int)img[r - 1][c + 6].green, + (int)img[r - 1][c + 7].green); + simd8i gbottom((int)img[r + 1][c].green, + (int)img[r + 1][c + 1].green, + (int)img[r + 1][c + 2].green, + (int)img[r + 1][c + 3].green, + (int)img[r + 1][c + 4].green, + (int)img[r + 1][c + 5].green, + (int)img[r + 1][c + 6].green, + (int)img[r + 1][c + 7].green); + + simd8i bleft((int)img[r][c - 1].blue, + (int)img[r][c].blue, + (int)img[r][c + 1].blue, + (int)img[r][c + 2].blue, + (int)img[r][c + 3].blue, + (int)img[r][c + 4].blue, + (int)img[r][c + 5].blue, + (int)img[r][c + 6].blue); + simd8i bright((int)img[r][c + 1].blue, + (int)img[r][c + 2].blue, + (int)img[r][c + 3].blue, + (int)img[r][c + 4].blue, + (int)img[r][c + 5].blue, + (int)img[r][c + 6].blue, + (int)img[r][c + 7].blue, + (int)img[r][c + 8].blue); + simd8i btop((int)img[r - 1][c].blue, + (int)img[r - 1][c + 1].blue, + (int)img[r - 1][c + 2].blue, + (int)img[r - 1][c + 3].blue, + (int)img[r - 1][c + 4].blue, + (int)img[r - 1][c + 5].blue, + (int)img[r - 1][c + 6].blue, + (int)img[r - 1][c + 7].blue); + simd8i bbottom((int)img[r + 1][c].blue, + (int)img[r + 1][c + 1].blue, + (int)img[r + 1][c + 2].blue, + (int)img[r + 1][c + 3].blue, + (int)img[r + 1][c + 4].blue, + (int)img[r + 1][c + 5].blue, + (int)img[r + 1][c + 6].blue, + (int)img[r + 1][c + 7].blue); + + simd8i grad_x_red = rright - rleft; + simd8i grad_y_red = rbottom - rtop; + simd8i grad_x_green = gright - gleft; + simd8i grad_y_green = gbottom - gtop; + simd8i grad_x_blue = bright - bleft; + simd8i grad_y_blue = bbottom - btop; + + simd8i rlen = grad_x_red*grad_x_red + grad_y_red*grad_y_red; + simd8i glen = grad_x_green*grad_x_green + grad_y_green*grad_y_green; + simd8i blen = grad_x_blue*grad_x_blue + grad_y_blue*grad_y_blue; + + simd8i cmp = rlen > glen; + simd8i tgrad_x = select(cmp, grad_x_red, grad_x_green); + simd8i tgrad_y = select(cmp, grad_y_red, grad_y_green); + simd8i tlen = select(cmp, rlen, glen); + + cmp = tlen > blen; + grad_x = select(cmp, tgrad_x, grad_x_blue); + grad_y = select(cmp, tgrad_y, grad_y_blue); + len = select(cmp, tlen, blen); + } + + // ------------------------------------------------------------------------------------ + + template inline typename dlib::disable_if_c::rgb>::type get_gradient ( const int r, const int c, const image_type& img, - matrix& grad, - double& len + matrix& grad, + T& len ) { grad(0) = (int)get_pixel_intensity(img[r][c+1])-(int)get_pixel_intensity(img[r][c-1]); @@ -192,7 +324,59 @@ namespace dlib len = (grad_x*grad_x + grad_y*grad_y); } - // ------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ + + template + inline typename dlib::disable_if_c::rgb>::type get_gradient( + int r, + int c, + const image_type& img, + simd8f& grad_x, + simd8f& grad_y, + simd8f& len + ) + { + simd8i left((int)get_pixel_intensity(img[r][c - 1]), + (int)get_pixel_intensity(img[r][c]), + (int)get_pixel_intensity(img[r][c + 1]), + (int)get_pixel_intensity(img[r][c + 2]), + (int)get_pixel_intensity(img[r][c + 3]), + (int)get_pixel_intensity(img[r][c + 4]), + (int)get_pixel_intensity(img[r][c + 5]), + (int)get_pixel_intensity(img[r][c + 6])); + simd8i right((int)get_pixel_intensity(img[r][c + 1]), + (int)get_pixel_intensity(img[r][c + 2]), + (int)get_pixel_intensity(img[r][c + 3]), + (int)get_pixel_intensity(img[r][c + 4]), + (int)get_pixel_intensity(img[r][c + 5]), + (int)get_pixel_intensity(img[r][c + 6]), + (int)get_pixel_intensity(img[r][c + 7]), + (int)get_pixel_intensity(img[r][c + 8])); + + simd8i top((int)get_pixel_intensity(img[r - 1][c]), + (int)get_pixel_intensity(img[r - 1][c + 1]), + (int)get_pixel_intensity(img[r - 1][c + 2]), + (int)get_pixel_intensity(img[r - 1][c + 3]), + (int)get_pixel_intensity(img[r - 1][c + 4]), + (int)get_pixel_intensity(img[r - 1][c + 5]), + (int)get_pixel_intensity(img[r - 1][c + 6]), + (int)get_pixel_intensity(img[r - 1][c + 7])); + simd8i bottom((int)get_pixel_intensity(img[r + 1][c]), + (int)get_pixel_intensity(img[r + 1][c + 1]), + (int)get_pixel_intensity(img[r + 1][c + 2]), + (int)get_pixel_intensity(img[r + 1][c + 3]), + (int)get_pixel_intensity(img[r + 1][c + 4]), + (int)get_pixel_intensity(img[r + 1][c + 5]), + (int)get_pixel_intensity(img[r + 1][c + 6]), + (int)get_pixel_intensity(img[r + 1][c + 7])); + + grad_x = right - left; + grad_y = bottom - top; + + len = (grad_x*grad_x + grad_y*grad_y); + } + + // ------------------------------------------------------------------------------------ template inline void set_hog ( @@ -200,7 +384,7 @@ namespace dlib int o, int x, int y, - const double& value + const float& value ) { hog[o][y][x] = value; @@ -229,6 +413,24 @@ namespace dlib } } + template + void init_hog_zero_everything ( + dlib::array,mm2>& hog, + int hog_nr, + int hog_nc, + int filter_rows_padding, + int filter_cols_padding + ) + { + const int num_hog_bands = 27+4; + hog.resize(num_hog_bands); + for (int i = 0; i < num_hog_bands; ++i) + { + hog[i].set_size(hog_nr+filter_rows_padding-1, hog_nc+filter_cols_padding-1); + assign_all_pixels(hog[i], 0); + } + } + // ------------------------------------------------------------------------------------ template @@ -237,7 +439,7 @@ namespace dlib int o, int x, int y, - const double& value + const float& value ) { hog[y][x](o) = value; @@ -268,6 +470,229 @@ namespace dlib } } + template + void init_hog_zero_everything ( + array2d,mm>& hog, + int hog_nr, + int hog_nc, + int filter_rows_padding, + int filter_cols_padding + ) + { + hog.set_size(hog_nr+filter_rows_padding-1, hog_nc+filter_cols_padding-1); + + for (long r = 0; r < hog.nr(); ++r) + { + for (long c = 0; c < hog.nc(); ++c) + { + set_all_elements(hog[r][c], 0); + } + } + } + + // ------------------------------------------------------------------------------------ + + template < + typename image_type, + typename out_type + > + void impl_extract_fhog_features_cell_size_1( + const image_type& img_, + out_type& hog, + int filter_rows_padding, + int filter_cols_padding + ) + { + const_image_view img(img_); + // make sure requires clause is not broken + DLIB_ASSERT( filter_rows_padding > 0 && + filter_cols_padding > 0 , + "\t void extract_fhog_features()" + << "\n\t Invalid inputs were given to this function. " + << "\n\t filter_rows_padding: " << filter_rows_padding + << "\n\t filter_cols_padding: " << filter_cols_padding + ); + + /* + This function is an optimized version of impl_extract_fhog_features() for + the case where cell_size == 1. + */ + + + // unit vectors used to compute gradient orientation + matrix directions[9]; + directions[0] = 1.0000, 0.0000; + directions[1] = 0.9397, 0.3420; + directions[2] = 0.7660, 0.6428; + directions[3] = 0.500, 0.8660; + directions[4] = 0.1736, 0.9848; + directions[5] = -0.1736, 0.9848; + directions[6] = -0.5000, 0.8660; + directions[7] = -0.7660, 0.6428; + directions[8] = -0.9397, 0.3420; + + + + if (img.nr() <= 2 || img.nc() <= 2) + { + hog.clear(); + return; + } + + array2d angle(img.nr(), img.nc()); + + array2d norm(img.nr(), img.nc()); + zero_border_pixels(norm,1,1); + + // memory for HOG features + const long hog_nr = img.nr()-2; + const long hog_nc = img.nc()-2; + + const int padding_rows_offset = (filter_rows_padding-1)/2; + const int padding_cols_offset = (filter_cols_padding-1)/2; + init_hog_zero_everything(hog, hog_nr, hog_nc, filter_rows_padding, filter_cols_padding); + + + const int visible_nr = img.nr()-1; + const int visible_nc = img.nc()-1; + + // First populate the gradient histograms + for (int y = 1; y < visible_nr; y++) + { + int x; + for (x = 1; x < visible_nc - 7; x += 8) + { + // v will be the length of the gradient vectors. + simd8f grad_x, grad_y, v; + get_gradient(y, x, img, grad_x, grad_y, v); + + float _vv[8]; + v.store(_vv); + + // Now snap the gradient to one of 18 orientations + simd8f best_dot = 0; + simd8f best_o = 0; + for (int o = 0; o < 9; o++) + { + simd8f dot = grad_x*directions[o](0) + grad_y*directions[o](1); + simd8f_bool cmp = dot>best_dot; + best_dot = select(cmp, dot, best_dot); + dot *= -1; + best_o = select(cmp, o, best_o); + + cmp = dot > best_dot; + best_dot = select(cmp, dot, best_dot); + best_o = select(cmp, o + 9, best_o); + } + + int32 _best_o[8]; simd8i(best_o).store(_best_o); + + norm[y][x + 0] = _vv[0]; + norm[y][x + 1] = _vv[1]; + norm[y][x + 2] = _vv[2]; + norm[y][x + 3] = _vv[3]; + norm[y][x + 4] = _vv[4]; + norm[y][x + 5] = _vv[5]; + norm[y][x + 6] = _vv[6]; + norm[y][x + 7] = _vv[7]; + + angle[y][x + 0] = _best_o[0]; + angle[y][x + 1] = _best_o[1]; + angle[y][x + 2] = _best_o[2]; + angle[y][x + 3] = _best_o[3]; + angle[y][x + 4] = _best_o[4]; + angle[y][x + 5] = _best_o[5]; + angle[y][x + 6] = _best_o[6]; + angle[y][x + 7] = _best_o[7]; + } + // Now process the right columns that don't fit into simd registers. + for (; x < visible_nc; x++) + { + matrix grad; + float v; + get_gradient(y,x,img,grad,v); + + // snap to one of 18 orientations + float best_dot = 0; + int best_o = 0; + for (int o = 0; o < 9; o++) + { + const float dot = dlib::dot(directions[o], grad); + if (dot > best_dot) + { + best_dot = dot; + best_o = o; + } + else if (-dot > best_dot) + { + best_dot = -dot; + best_o = o+9; + } + } + + norm[y][x] = v; + angle[y][x] = best_o; + } + } + + const float eps = 0.0001; + // compute features + for (int y = 0; y < hog_nr; y++) + { + const int yy = y+padding_rows_offset; + for (int x = 0; x < hog_nc; x++) + { + const simd4f z1(norm[y+1][x+1], + norm[y][x+1], + norm[y+1][x], + norm[y][x]); + + const simd4f z2(norm[y+1][x+2], + norm[y][x+2], + norm[y+1][x+1], + norm[y][x+1]); + + const simd4f z3(norm[y+2][x+1], + norm[y+1][x+1], + norm[y+2][x], + norm[y+1][x]); + + const simd4f z4(norm[y+2][x+2], + norm[y+1][x+2], + norm[y+2][x+1], + norm[y+1][x+1]); + + const simd4f temp0 = std::sqrt(norm[y+1][x+1]); + const simd4f nn = 0.2*sqrt(z1+z2+z3+z4+eps); + const simd4f n = 0.1/nn; + + simd4f t = 0; + + const int xx = x+padding_cols_offset; + + simd4f h0 = min(temp0,nn)*n; + const float vv = sum(h0); + set_hog(hog,angle[y+1][x+1],xx,yy, vv); + t += h0; + + t *= 2*0.2357; + + // contrast-insensitive features + set_hog(hog,angle[y+1][x+1]%9+18,xx,yy, vv); + + + float temp[4]; + t.store(temp); + + // texture features + set_hog(hog,27,xx,yy, temp[0]); + set_hog(hog,28,xx,yy, temp[1]); + set_hog(hog,29,xx,yy, temp[2]); + set_hog(hog,30,xx,yy, temp[3]); + } + } + } + // ------------------------------------------------------------------------------------ template < @@ -331,8 +756,14 @@ namespace dlib WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + if (cell_size == 1) + { + impl_extract_fhog_features_cell_size_1(img_,hog,filter_rows_padding,filter_cols_padding); + return; + } + // unit vectors used to compute gradient orientation - matrix directions[9]; + matrix directions[9]; directions[0] = 1.0000, 0.0000; directions[1] = 0.9397, 0.3420; directions[2] = 0.7660, 0.6428; @@ -346,8 +777,8 @@ namespace dlib // First we allocate memory for caching orientation histograms & their norms. - const int cells_nr = (int)((double)img.nr()/(double)cell_size + 0.5); - const int cells_nc = (int)((double)img.nc()/(double)cell_size + 0.5); + const int cells_nr = (int)((float)img.nr()/(float)cell_size + 0.5); + const int cells_nc = (int)((float)img.nc()/(float)cell_size + 0.5); if (cells_nr == 0 || cells_nc == 0) { @@ -389,44 +820,42 @@ namespace dlib // First populate the gradient histograms for (int y = 1; y < visible_nr; y++) { - const double yp = ((double)y+0.5)/(double)cell_size - 0.5; + const float yp = ((float)y+0.5)/(float)cell_size - 0.5; const int iyp = (int)std::floor(yp); - const double vy0 = yp-iyp; - const double vy1 = 1.0-vy0; + const float vy0 = yp - iyp; + const float vy1 = 1.0 - vy0; int x; - for (x = 1; x < visible_nc-3; x+=4) + for (x = 1; x < visible_nc - 7; x += 8) { - simd4f xx(x,x+1,x+2,x+3); + simd8f xx(x, x + 1, x + 2, x + 3, x + 4, x + 5, x + 6, x + 7); // v will be the length of the gradient vectors. - simd4f grad_x, grad_y, v; - get_gradient(y,x,img,grad_x,grad_y,v); + simd8f grad_x, grad_y, v; + get_gradient(y, x, img, grad_x, grad_y, v); // We will use bilinear interpolation to add into the histogram bins. // So first we precompute the values needed to determine how much each // pixel votes into each bin. - simd4f xp = (xx+0.5)/(float)cell_size + 0.5; - simd4i ixp = simd4i(xp); - simd4f vx0 = xp-ixp; - simd4f vx1 = 1.0f-vx0; + simd8f xp = (xx + 0.5) / (float)cell_size + 0.5; + simd8i ixp = simd8i(xp); + simd8f vx0 = xp - ixp; + simd8f vx1 = 1.0f - vx0; v = sqrt(v); - // TODO this should/cood be optimised - // Now snap the gradient to one of 18 orientations - simd4f best_dot = 0; - simd4f best_o = 0; - for (int o = 0; o < 9; o++) + simd8f best_dot = 0; + simd8f best_o = 0; + for (int o = 0; o < 9; o++) { - simd4f dot = grad_x*directions[o](0) + grad_y*directions[o](1); - simd4f_bool cmp = dot>best_dot; - best_dot = select(cmp,dot,best_dot); + simd8f dot = grad_x*directions[o](0) + grad_y*directions[o](1); + simd8f_bool cmp = dot>best_dot; + best_dot = select(cmp, dot, best_dot); dot *= -1; - best_o = select(cmp,o,best_o); + best_o = select(cmp, o, best_o); - cmp = dot>best_dot; - best_dot = select(cmp,dot,best_dot); - best_o = select(cmp,o+9,best_o); + cmp = dot > best_dot; + best_dot = select(cmp, dot, best_dot); + best_o = select(cmp, o + 9, best_o); } @@ -435,51 +864,71 @@ namespace dlib vx1 *= v; vx0 *= v; // The amounts for each bin - simd4f v11 = vy1*vx1; - simd4f v01 = vy0*vx1; - simd4f v10 = vy1*vx0; - simd4f v00 = vy0*vx0; + simd8f v11 = vy1*vx1; + simd8f v01 = vy0*vx1; + simd8f v10 = vy1*vx0; + simd8f v00 = vy0*vx0; - int32 _best_o[4]; simd4i(best_o).store(_best_o); - int32 _ixp[4]; ixp.store(_ixp); - float _v11[4]; v11.store(_v11); - float _v01[4]; v01.store(_v01); - float _v10[4]; v10.store(_v10); - float _v00[4]; v00.store(_v00); + int32 _best_o[8]; simd8i(best_o).store(_best_o); + int32 _ixp[8]; ixp.store(_ixp); + float _v11[8]; v11.store(_v11); + float _v01[8]; v01.store(_v01); + float _v10[8]; v10.store(_v10); + float _v00[8]; v00.store(_v00); - hist[iyp+1] [_ixp[0] ](_best_o[0]) += _v11[0]; - hist[iyp+1+1][_ixp[0] ](_best_o[0]) += _v01[0]; - hist[iyp+1] [_ixp[0]+1](_best_o[0]) += _v10[0]; - hist[iyp+1+1][_ixp[0]+1](_best_o[0]) += _v00[0]; + hist[iyp + 1][_ixp[0]](_best_o[0]) += _v11[0]; + hist[iyp + 1 + 1][_ixp[0]](_best_o[0]) += _v01[0]; + hist[iyp + 1][_ixp[0] + 1](_best_o[0]) += _v10[0]; + hist[iyp + 1 + 1][_ixp[0] + 1](_best_o[0]) += _v00[0]; - hist[iyp+1] [_ixp[1] ](_best_o[1]) += _v11[1]; - hist[iyp+1+1][_ixp[1] ](_best_o[1]) += _v01[1]; - hist[iyp+1] [_ixp[1]+1](_best_o[1]) += _v10[1]; - hist[iyp+1+1][_ixp[1]+1](_best_o[1]) += _v00[1]; + hist[iyp + 1][_ixp[1]](_best_o[1]) += _v11[1]; + hist[iyp + 1 + 1][_ixp[1]](_best_o[1]) += _v01[1]; + hist[iyp + 1][_ixp[1] + 1](_best_o[1]) += _v10[1]; + hist[iyp + 1 + 1][_ixp[1] + 1](_best_o[1]) += _v00[1]; - hist[iyp+1] [_ixp[2] ](_best_o[2]) += _v11[2]; - hist[iyp+1+1][_ixp[2] ](_best_o[2]) += _v01[2]; - hist[iyp+1] [_ixp[2]+1](_best_o[2]) += _v10[2]; - hist[iyp+1+1][_ixp[2]+1](_best_o[2]) += _v00[2]; + hist[iyp + 1][_ixp[2]](_best_o[2]) += _v11[2]; + hist[iyp + 1 + 1][_ixp[2]](_best_o[2]) += _v01[2]; + hist[iyp + 1][_ixp[2] + 1](_best_o[2]) += _v10[2]; + hist[iyp + 1 + 1][_ixp[2] + 1](_best_o[2]) += _v00[2]; - hist[iyp+1] [_ixp[3] ](_best_o[3]) += _v11[3]; - hist[iyp+1+1][_ixp[3] ](_best_o[3]) += _v01[3]; - hist[iyp+1] [_ixp[3]+1](_best_o[3]) += _v10[3]; - hist[iyp+1+1][_ixp[3]+1](_best_o[3]) += _v00[3]; + hist[iyp + 1][_ixp[3]](_best_o[3]) += _v11[3]; + hist[iyp + 1 + 1][_ixp[3]](_best_o[3]) += _v01[3]; + hist[iyp + 1][_ixp[3] + 1](_best_o[3]) += _v10[3]; + hist[iyp + 1 + 1][_ixp[3] + 1](_best_o[3]) += _v00[3]; + + hist[iyp + 1][_ixp[4]](_best_o[4]) += _v11[4]; + hist[iyp + 1 + 1][_ixp[4]](_best_o[4]) += _v01[4]; + hist[iyp + 1][_ixp[4] + 1](_best_o[4]) += _v10[4]; + hist[iyp + 1 + 1][_ixp[4] + 1](_best_o[4]) += _v00[4]; + + hist[iyp + 1][_ixp[5]](_best_o[5]) += _v11[5]; + hist[iyp + 1 + 1][_ixp[5]](_best_o[5]) += _v01[5]; + hist[iyp + 1][_ixp[5] + 1](_best_o[5]) += _v10[5]; + hist[iyp + 1 + 1][_ixp[5] + 1](_best_o[5]) += _v00[5]; + + hist[iyp + 1][_ixp[6]](_best_o[6]) += _v11[6]; + hist[iyp + 1 + 1][_ixp[6]](_best_o[6]) += _v01[6]; + hist[iyp + 1][_ixp[6] + 1](_best_o[6]) += _v10[6]; + hist[iyp + 1 + 1][_ixp[6] + 1](_best_o[6]) += _v00[6]; + + hist[iyp + 1][_ixp[7]](_best_o[7]) += _v11[7]; + hist[iyp + 1 + 1][_ixp[7]](_best_o[7]) += _v01[7]; + hist[iyp + 1][_ixp[7] + 1](_best_o[7]) += _v10[7]; + hist[iyp + 1 + 1][_ixp[7] + 1](_best_o[7]) += _v00[7]; } // Now process the right columns that don't fit into simd registers. for (; x < visible_nc; x++) { - matrix grad; - double v; + matrix grad; + float v; get_gradient(y,x,img,grad,v); // snap to one of 18 orientations - double best_dot = 0; + float best_dot = 0; int best_o = 0; for (int o = 0; o < 9; o++) { - const double dot = dlib::dot(directions[o], grad); + const float dot = dlib::dot(directions[o], grad); if (dot > best_dot) { best_dot = dot; @@ -494,10 +943,10 @@ namespace dlib v = std::sqrt(v); // add to 4 histograms around pixel using bilinear interpolation - const double xp = ((double)x+0.5)/(double)cell_size - 0.5; + const float xp = ((double)x + 0.5) / (double)cell_size - 0.5; const int ixp = (int)std::floor(xp); - const double vx0 = xp-ixp; - const double vx1 = 1.0-vx0; + const float vx0 = xp - ixp; + const float vx1 = 1.0 - vx0; hist[iyp+1][ixp+1](best_o) += vy1*vx1*v; hist[iyp+1+1][ixp+1](best_o) += vy0*vx1*v; @@ -518,7 +967,7 @@ namespace dlib } } - const double eps = 0.0001; + const float eps = 0.0001; // compute features for (int y = 0; y < hog_nr; y++) { @@ -699,7 +1148,7 @@ namespace dlib int filter_cols_padding = 1 ) { - matrix feats; + matrix feats; extract_fhog_features(img, feats, cell_size, filter_rows_padding, filter_cols_padding); return feats; } @@ -820,7 +1269,8 @@ namespace dlib > matrix draw_fhog( const dlib::array,mm2>& hog, - const long cell_draw_size = 15 + const long cell_draw_size = 15, + const float min_response_threshold = 0.0 ) { // make sure requires clause is not broken @@ -846,7 +1296,7 @@ namespace dlib const float val = hog[d][r/cell_draw_size][c/cell_draw_size] + hog[d+mbars.size()][r/cell_draw_size][c/cell_draw_size] + hog[d+mbars.size()*2][r/cell_draw_size][c/cell_draw_size]; - if (val > 0) + if (val > min_response_threshold) { set_subm(himg, r, c, cell_draw_size, cell_draw_size) += val*mbars[d%mbars.size()]; } @@ -854,7 +1304,7 @@ namespace dlib } } - const double thresh = mean(himg) + 4*stddev(himg); + const float thresh = mean(himg) + 4 * stddev(himg); if (thresh != 0) return matrix_cast(upperbound(round(himg*255/thresh),255)); else @@ -868,7 +1318,8 @@ namespace dlib > matrix draw_fhog ( const std::vector >& hog, - const long cell_draw_size = 15 + const long cell_draw_size = 15, + const float min_response_threshold = 0.0 ) { // make sure requires clause is not broken @@ -893,7 +1344,7 @@ namespace dlib } } } - return draw_fhog(temp,cell_draw_size); + return draw_fhog(temp,cell_draw_size, min_response_threshold); } // ---------------------------------------------------------------------------------------- @@ -904,7 +1355,8 @@ namespace dlib > matrix draw_fhog( const array2d,mm>& hog, - const long cell_draw_size = 15 + const long cell_draw_size = 15, + const float min_response_threshold = 0.0 ) { // make sure requires clause is not broken @@ -929,7 +1381,7 @@ namespace dlib const float val = hog[r/cell_draw_size][c/cell_draw_size](d) + hog[r/cell_draw_size][c/cell_draw_size](d+mbars.size()) + hog[r/cell_draw_size][c/cell_draw_size](d+mbars.size()*2); - if (val > 0) + if (val > min_response_threshold) { set_subm(himg, r, c, cell_draw_size, cell_draw_size) += val*mbars[d%mbars.size()]; } @@ -937,7 +1389,7 @@ namespace dlib } } - const double thresh = mean(himg) + 4*stddev(himg); + const float thresh = mean(himg) + 4 * stddev(himg); if (thresh != 0) return matrix_cast(upperbound(round(himg*255/thresh),255)); else diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/fhog_abstract.h b/lib/3rdParty/dlib/include/dlib/image_transforms/fhog_abstract.h index ff629d71..f66c5d55 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/fhog_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/fhog_abstract.h @@ -271,7 +271,8 @@ namespace dlib > matrix draw_fhog( const dlib::array,mm2>& hog, - const long cell_draw_size = 15 + const long cell_draw_size = 15, + const float min_response_threshold = 0.0 ); /*! requires @@ -285,6 +286,8 @@ namespace dlib then returned. - The size of the cells in the output image will be rendered as cell_draw_size pixels wide and tall. + - HOG cells with a response value less than min_response_threshold are not + drawn. !*/ // ---------------------------------------------------------------------------------------- @@ -294,7 +297,8 @@ namespace dlib > matrix draw_fhog ( const std::vector >& hog, - const long cell_draw_size = 15 + const long cell_draw_size = 15, + const float min_response_threshold = 0.0 ); /*! requires @@ -303,6 +307,8 @@ namespace dlib ensures - This function just converts the given hog object into an array> and passes it to the above draw_fhog() routine and returns the results. + - HOG cells with a response value less than min_response_threshold are not + drawn. !*/ // ---------------------------------------------------------------------------------------- @@ -313,7 +319,8 @@ namespace dlib > matrix draw_fhog( const array2d,mm>& hog, - const long cell_draw_size = 15 + const long cell_draw_size = 15, + const float min_response_threshold = 0.0 ); /*! requires @@ -326,6 +333,8 @@ namespace dlib then returned. - The size of the cells in the output image will be rendered as cell_draw_size pixels wide and tall. + - HOG cells with a response value less than min_response_threshold are not + drawn. !*/ // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/hough_transform.h b/lib/3rdParty/dlib/include/dlib/image_transforms/hough_transform.h new file mode 100644 index 00000000..62edc27c --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/hough_transform.h @@ -0,0 +1,586 @@ +// Copyright (C) 2014 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_HOUGH_tRANSFORM_Hh_ +#define DLIB_HOUGH_tRANSFORM_Hh_ + +#include "hough_transform_abstract.h" +#include "../image_processing/generic_image.h" +#include "../geometry.h" +#include "../algs.h" +#include "assign_image.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class hough_transform + { + + public: + explicit hough_transform ( + unsigned long size_ + ) : _size(size_) + { + DLIB_CASSERT(size_ > 0, + "\t hough_transform::hough_transform(size_)" + << "\n\t Invalid arguments given to this function." + ); + + even_size = _size - (_size%2); + + const point cent = center(rectangle(0,0,size_-1,size_-1)); + xcos_theta.set_size(size_, size_); + ysin_theta.set_size(size_, size_); + + std::vector cos_theta(size_), sin_theta(size_); + const double scale = 1<<16; + for (unsigned long t = 0; t < size_; ++t) + { + double theta = t*pi/even_size; + + cos_theta[t] = scale*std::cos(theta)/sqrt_2; + sin_theta[t] = scale*std::sin(theta)/sqrt_2; + } + const double offset = scale*even_size/4.0 + 0.5; + + for (unsigned long c = 0; c < size_; ++c) + { + const long x = c - cent.x(); + for (unsigned long t = 0; t < size_; ++t) + xcos_theta(c,t) = static_cast(x*cos_theta[t] + offset); + } + for (unsigned long r = 0; r < size_; ++r) + { + const long y = r - cent.y(); + for (unsigned long t = 0; t < size_; ++t) + ysin_theta(r,t) = static_cast(y*sin_theta[t] + offset); + } + } + + inline unsigned long size( + ) const { return _size; } + + long nr( + ) const { return _size; } + + long nc( + ) const { return _size; } + + std::pair get_line ( + const point& p + ) const + { + DLIB_ASSERT(rectangle(0,0,size()-1,size()-1).contains(p) == true, + "\t pair hough_transform::get_line(point)" + << "\n\t Invalid arguments given to this function." + << "\n\t p: " << p + << "\n\t size(): " << size() + ); + + // First we compute the radius measured in pixels from the center and the theta + // angle in radians. + double theta, radius; + get_line_properties(p, theta, radius); + theta *= pi/180; + + // now make a line segment on the line. + const rectangle box = get_rect(*this); + const dpoint cent = center(box); + dpoint v1 = cent + dpoint(size()+1000,0) + dpoint(0,radius); + dpoint v2 = cent - dpoint(size()+1000,0) + dpoint(0,radius); + point p1 = rotate_point(cent, v1, theta); + point p2 = rotate_point(cent, v2, theta); + + clip_line_to_rectangle(box, p1, p2); + + return std::make_pair(p1,p2); + } + + double get_line_angle_in_degrees ( + const point& p + ) const + { + double angle, radius; + get_line_properties(p, angle, radius); + return angle; + } + + void get_line_properties ( + const point& p, + double& angle_in_degrees, + double& radius + ) const + { + const dpoint cent = center(get_rect(*this)); + double theta = p.x()-cent.x(); + radius = p.y()-cent.y(); + angle_in_degrees = 180*theta/even_size; + radius = radius*sqrt_2 + 0.5; + } + + template < + typename image_type + > + point get_best_hough_point ( + const point& p, + const image_type& himg_ + ) + { + const const_image_view himg(himg_); + + DLIB_ASSERT(himg.nr() == size() && himg.nc() == size() && + rectangle(0,0,size()-1,size()-1).contains(p) == true, + "\t point hough_transform::get_best_hough_point()" + << "\n\t Invalid arguments given to this function." + << "\n\t himg.nr(): " << himg.nr() + << "\n\t himg.nc(): " << himg.nc() + << "\n\t size(): " << size() + << "\n\t p: " << p + ); + + + typedef typename image_traits::pixel_type pixel_type; + COMPILE_TIME_ASSERT(pixel_traits::grayscale == true); + pixel_type best_val = std::numeric_limits::min(); + point best_point; + + + const long max_n8 = (himg.nc()/8)*8; + const long max_n4 = (himg.nc()/4)*4; + const long r = p.y(); + const long c = p.x(); + + const int32* ysin = &ysin_theta(r,0); + const int32* xcos = &xcos_theta(c,0); + long t = 0; + while(t < max_n8) + { + long rr0 = (*xcos++ + *ysin++)>>16; + long rr1 = (*xcos++ + *ysin++)>>16; + long rr2 = (*xcos++ + *ysin++)>>16; + long rr3 = (*xcos++ + *ysin++)>>16; + long rr4 = (*xcos++ + *ysin++)>>16; + long rr5 = (*xcos++ + *ysin++)>>16; + long rr6 = (*xcos++ + *ysin++)>>16; + long rr7 = (*xcos++ + *ysin++)>>16; + + if (himg[rr0][t++] > best_val) + { + best_val = himg[rr0][t-1]; + best_point.x() = t-1; + best_point.y() = rr0; + } + if (himg[rr1][t++] > best_val) + { + best_val = himg[rr1][t-1]; + best_point.x() = t-1; + best_point.y() = rr1; + } + if (himg[rr2][t++] > best_val) + { + best_val = himg[rr2][t-1]; + best_point.x() = t-1; + best_point.y() = rr2; + } + if (himg[rr3][t++] > best_val) + { + best_val = himg[rr3][t-1]; + best_point.x() = t-1; + best_point.y() = rr3; + } + if (himg[rr4][t++] > best_val) + { + best_val = himg[rr4][t-1]; + best_point.x() = t-1; + best_point.y() = rr4; + } + if (himg[rr5][t++] > best_val) + { + best_val = himg[rr5][t-1]; + best_point.x() = t-1; + best_point.y() = rr5; + } + if (himg[rr6][t++] > best_val) + { + best_val = himg[rr6][t-1]; + best_point.x() = t-1; + best_point.y() = rr6; + } + if (himg[rr7][t++] > best_val) + { + best_val = himg[rr7][t-1]; + best_point.x() = t-1; + best_point.y() = rr7; + } + } + while(t < max_n4) + { + long rr0 = (*xcos++ + *ysin++)>>16; + long rr1 = (*xcos++ + *ysin++)>>16; + long rr2 = (*xcos++ + *ysin++)>>16; + long rr3 = (*xcos++ + *ysin++)>>16; + if (himg[rr0][t++] > best_val) + { + best_val = himg[rr0][t-1]; + best_point.x() = t-1; + best_point.y() = rr0; + } + if (himg[rr1][t++] > best_val) + { + best_val = himg[rr1][t-1]; + best_point.x() = t-1; + best_point.y() = rr1; + } + if (himg[rr2][t++] > best_val) + { + best_val = himg[rr2][t-1]; + best_point.x() = t-1; + best_point.y() = rr2; + } + if (himg[rr3][t++] > best_val) + { + best_val = himg[rr3][t-1]; + best_point.x() = t-1; + best_point.y() = rr3; + } + } + while(t < himg.nc()) + { + long rr0 = (*xcos++ + *ysin++)>>16; + if (himg[rr0][t++] > best_val) + { + best_val = himg[rr0][t-1]; + best_point.x() = t-1; + best_point.y() = rr0; + } + } + + return best_point; + } + + template < + typename in_image_type, + typename out_image_type + > + void operator() ( + const in_image_type& img_, + const rectangle& box, + out_image_type& himg_ + ) const + { + typedef typename image_traits::pixel_type in_pixel_type; + typedef typename image_traits::pixel_type out_pixel_type; + + DLIB_CASSERT(box.width() == size() && box.height() == size(), + "\t void hough_transform::operator()" + << "\n\t Invalid arguments given to this function." + << "\n\t box.width(): " << box.width() + << "\n\t box.height(): " << box.height() + << "\n\t size(): " << size() + ); + + COMPILE_TIME_ASSERT(pixel_traits::grayscale == true); + COMPILE_TIME_ASSERT(pixel_traits::grayscale == true); + + const_image_view img(img_); + image_view himg(himg_); + + himg.set_size(size(), size()); + assign_all_pixels(himg, 0); + + auto record_hit = [&](const point& hough_point, const point& /*img_point*/, const in_pixel_type& val) + { + himg[hough_point.y()][hough_point.x()] += val; + }; + perform_generic_hough_transform(img_, box, record_hit); + } + + template < + typename in_image_type, + typename out_image_type + > + void operator() ( + const in_image_type& img_, + out_image_type& himg_ + ) const + { + rectangle box(0,0, num_columns(img_)-1, num_rows(img_)-1); + (*this)(img_, box, himg_); + } + + template < + typename in_image_type + > + std::vector> find_pixels_voting_for_lines ( + const in_image_type& img, + const rectangle& box, + const std::vector& hough_points, + const unsigned long angle_window_size = 1, + const unsigned long radius_window_size = 1 + ) const + { + + typedef typename image_traits::pixel_type in_pixel_type; + + DLIB_CASSERT(angle_window_size >= 1); + DLIB_CASSERT(radius_window_size >= 1); + DLIB_CASSERT(box.width() == size() && box.height() == size(), + "\t std::vector> hough_transform::find_pixels_voting_for_lines()" + << "\n\t Invalid arguments given to this function." + << "\n\t box.width(): " << box.width() + << "\n\t box.height(): " << box.height() + << "\n\t size(): " << size() + ); +#ifdef ENABLE_ASSERTS + for (auto& p : hough_points) + DLIB_CASSERT(get_rect(*this).contains(p), + "You gave a hough_points that isn't actually in the Hough space of this object." + << "\n\t get_rect(*this): "<< get_rect(*this) + << "\n\t p: "<< p + ); +#endif + + std::vector> constituent_points(hough_points.size()); + + // make a map that lets us look up in constant time if a hough point is in the + // constituent_points output and if so where. + matrix hmap(size(),size()); + hmap = hough_points.size(); + for (size_t i = 0; i < hough_points.size(); ++i) + { + rectangle area = centered_rect(hough_points[i],angle_window_size,radius_window_size).intersect(get_rect(hmap)); + for (long r = area.top(); r <= area.bottom(); ++r) + { + for (long c = area.left(); c <= area.right(); ++c) + { + hmap(r,c) = i; + } + } + } + + // record that this image point voted for this Hough point + auto record_hit = [&](const point& hough_point, const point& img_point, in_pixel_type) + { + auto idx = hmap(hough_point.y(), hough_point.x()); + if (idx < constituent_points.size()) + constituent_points[idx].push_back(img_point); + }; + + perform_generic_hough_transform(img, box, record_hit); + + return constituent_points; + } + + template < + typename in_image_type + > + std::vector> find_pixels_voting_for_lines ( + const in_image_type& img, + const std::vector& hough_points, + const unsigned long angle_window_size = 1, + const unsigned long radius_window_size = 1 + ) const + { + rectangle box(0,0, num_columns(img)-1, num_rows(img)-1); + return find_pixels_voting_for_lines(img, box, hough_points, angle_window_size, radius_window_size); + } + + template < + typename image_type, + typename thresh_type + > + std::vector find_strong_hough_points( + const image_type& himg_, + const thresh_type hough_count_threshold, + const double angle_nms_thresh, + const double radius_nms_thresh + ) + { + const_image_view himg(himg_); + + DLIB_CASSERT(himg.nr() == size()); + DLIB_CASSERT(himg.nc() == size()); + DLIB_CASSERT(angle_nms_thresh >= 0) + DLIB_CASSERT(radius_nms_thresh >= 0) + + std::vector> initial_lines; + for (long r = 0; r < himg.nr(); ++r) + { + for (long c = 0; c < himg.nc(); ++c) + { + if (himg[r][c] >= hough_count_threshold) + initial_lines.emplace_back(himg[r][c], point(c,r)); + } + } + + + std::vector final_lines; + std::vector> final_angle_and_radius; + + // Now do non-max suppression. First, sort the initial_lines so the best lines come first. + std::sort(initial_lines.rbegin(), initial_lines.rend(), + [](const std::pair& a, const std::pair& b){ return a.first + void perform_generic_hough_transform ( + const in_image_type& img_, + const rectangle& box, + record_hit_function_type record_hit + ) const + { + + typedef typename image_traits::pixel_type in_pixel_type; + + DLIB_ASSERT(box.width() == size() && box.height() == size(), + "\t void hough_transform::perform_generic_hough_transform()" + << "\n\t Invalid arguments given to this function." + << "\n\t box.width(): " << box.width() + << "\n\t box.height(): " << box.height() + << "\n\t size(): " << size() + ); + + COMPILE_TIME_ASSERT(pixel_traits::grayscale == true); + + + const_image_view img(img_); + + + const rectangle area = box.intersect(get_rect(img)); + + const long max_n8 = (size()/8)*8; + const long max_n4 = (size()/4)*4; + for (long r = area.top(); r <= area.bottom(); ++r) + { + const int32* ysin_base = &ysin_theta(r-box.top(),0); + for (long c = area.left(); c <= area.right(); ++c) + { + const auto val = img[r][c]; + if (val != 0) + { + /* + // The code in this comment is equivalent to the more complex but + // faster code below. We keep this simple version of the Hough + // transform implementation here just to document what it's doing + // more clearly. + const point cent = center(box); + const long x = c - cent.x(); + const long y = r - cent.y(); + for (long t = 0; t < size(); ++t) + { + double theta = t*pi/even_size; + double radius = (x*std::cos(theta) + y*std::sin(theta))/sqrt_2 + even_size/2 + 0.5; + long rr = static_cast(radius); + + record_hit(point(t,rr), point(c,r), val); + } + continue; + */ + + // Run the speed optimized version of the code in the above + // comment. + const int32* ysin = ysin_base; + const int32* xcos = &xcos_theta(c-box.left(),0); + long t = 0; + while(t < max_n8) + { + long rr0 = (*xcos++ + *ysin++)>>16; + long rr1 = (*xcos++ + *ysin++)>>16; + long rr2 = (*xcos++ + *ysin++)>>16; + long rr3 = (*xcos++ + *ysin++)>>16; + long rr4 = (*xcos++ + *ysin++)>>16; + long rr5 = (*xcos++ + *ysin++)>>16; + long rr6 = (*xcos++ + *ysin++)>>16; + long rr7 = (*xcos++ + *ysin++)>>16; + + record_hit(point(t++,rr0), point(c,r), val); + record_hit(point(t++,rr1), point(c,r), val); + record_hit(point(t++,rr2), point(c,r), val); + record_hit(point(t++,rr3), point(c,r), val); + record_hit(point(t++,rr4), point(c,r), val); + record_hit(point(t++,rr5), point(c,r), val); + record_hit(point(t++,rr6), point(c,r), val); + record_hit(point(t++,rr7), point(c,r), val); + } + while(t < max_n4) + { + long rr0 = (*xcos++ + *ysin++)>>16; + long rr1 = (*xcos++ + *ysin++)>>16; + long rr2 = (*xcos++ + *ysin++)>>16; + long rr3 = (*xcos++ + *ysin++)>>16; + record_hit(point(t++,rr0), point(c,r), val); + record_hit(point(t++,rr1), point(c,r), val); + record_hit(point(t++,rr2), point(c,r), val); + record_hit(point(t++,rr3), point(c,r), val); + } + while(t < (long)size()) + { + long rr0 = (*xcos++ + *ysin++)>>16; + record_hit(point(t++,rr0), point(c,r), val); + } + } + } + } + } + + template < + typename in_image_type, + typename record_hit_function_type + > + void perform_generic_hough_transform ( + const in_image_type& img_, + record_hit_function_type record_hit + ) const + { + rectangle box(0,0, num_columns(img_)-1, num_rows(img_)-1); + perform_generic_hough_transform(img_, box, record_hit); + } + + private: + + unsigned long _size; + unsigned long even_size; // equal to _size if _size is even, otherwise equal to _size-1. + matrix xcos_theta, ysin_theta; + }; +} + +#endif // DLIB_HOUGH_tRANSFORM_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/hough_transform_abstract.h b/lib/3rdParty/dlib/include/dlib/image_transforms/hough_transform_abstract.h new file mode 100644 index 00000000..a8491b7b --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/hough_transform_abstract.h @@ -0,0 +1,365 @@ +// Copyright (C) 2014 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_HOUGH_tRANSFORM_ABSTRACT_Hh_ +#ifdef DLIB_HOUGH_tRANSFORM_ABSTRACT_Hh_ + +#include "../geometry.h" +#include "../image_processing/generic_image.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class hough_transform + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a tool for computing the line finding version of the Hough + transform given some kind of edge detection image as input. It also allows + the edge pixels to be weighted such that higher weighted edge pixels + contribute correspondingly more to the output of the Hough transform, + allowing stronger edges to create correspondingly stronger line detections + in the final Hough transform. + + THREAD SAFETY + It is safe for multiple threads to make concurrent accesses to this object + without synchronization. + !*/ + + public: + + explicit hough_transform ( + unsigned long size_ + ); + /*! + requires + - size_ > 0 + ensures + - This object will compute Hough transforms that are size_ by size_ pixels. + This is in terms of both the Hough accumulator array size as well as the + input image size. + - #size() == size_ + !*/ + + unsigned long size( + ) const; + /*! + ensures + - returns the size of the Hough transforms generated by this object. In + particular, this object creates Hough transform images that are size() by + size() pixels in size. + !*/ + + long nr( + ) const; + /*! + ensures + - returns size() + !*/ + + long nc( + ) const; + /*! + ensures + - returns size() + !*/ + + std::pair get_line ( + const point& p + ) const; + /*! + requires + - rectangle(0,0,size()-1,size()-1).contains(p) == true + (i.e. p must be a point inside the Hough accumulator array) + ensures + - returns the line segment in the original image space corresponding + to Hough transform point p. + - The returned points are inside rectangle(0,0,size()-1,size()-1). + !*/ + + double get_line_angle_in_degrees ( + const point& p + ) const; + /*! + requires + - rectangle(0,0,size()-1,size()-1).contains(p) == true + (i.e. p must be a point inside the Hough accumulator array) + ensures + - returns the angle, in degrees, of the line corresponding to the Hough + transform point p. + !*/ + + void get_line_properties ( + const point& p, + double& angle_in_degrees, + double& radius + ) const; + /*! + requires + - rectangle(0,0,size()-1,size()-1).contains(p) == true + (i.e. p must be a point inside the Hough accumulator array) + ensures + - Converts a point in the Hough transform space into an angle, in degrees, + and a radius, measured in pixels from the center of the input image. + - #angle_in_degrees == the angle of the line corresponding to the Hough + transform point p. Moreover: -90 <= #angle_in_degrees < 90. + - #radius == the distance from the center of the input image, measured in + pixels, and the line corresponding to the Hough transform point p. + Moreover: -sqrt(size()*size()/2) <= #radius <= sqrt(size()*size()/2) + !*/ + + template < + typename image_type + > + point get_best_hough_point ( + const point& p, + const image_type& himg + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h and it must contain grayscale pixels. + - himg.nr() == size() + - himg.nc() == size() + - rectangle(0,0,size()-1,size()-1).contains(p) == true + ensures + - This function interprets himg as a Hough image and p as a point in the + original image space. Given this, it finds the maximum scoring line that + passes though p. That is, it checks all the Hough accumulator bins in + himg corresponding to lines though p and returns the location with the + largest score. + - returns a point X such that get_rect(himg).contains(X) == true + !*/ + + template < + typename in_image_type, + typename out_image_type + > + void operator() ( + const in_image_type& img, + const rectangle& box, + out_image_type& himg + ) const; + /*! + requires + - in_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h and it must contain grayscale pixels. + - out_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h and it must contain grayscale pixels. + - box.width() == size() + - box.height() == size() + ensures + - Computes the Hough transform of the part of img contained within box. + In particular, we do a grayscale version of the Hough transform where any + non-zero pixel in img is treated as a potential component of a line and + accumulated into the Hough accumulator #himg. However, rather than + adding 1 to each relevant accumulator bin we add the value of the pixel + in img to each Hough accumulator bin. This means that, if all the + pixels in img are 0 or 1 then this routine performs a normal Hough + transform. However, if some pixels have larger values then they will be + weighted correspondingly more in the resulting Hough transform. + - #himg.nr() == size() + - #himg.nc() == size() + - #himg is the Hough transform of the part of img contained in box. Each + point in #himg corresponds to a line in the input box. In particular, + the line for #himg[y][x] is given by get_line(point(x,y)). Also, when + viewing the #himg image, the x-axis gives the angle of the line and the + y-axis the distance of the line from the center of the box. The + conversion between Hough coordinates and angle and pixel distance can be + obtained by calling get_line_properties(). + !*/ + + template < + typename in_image_type, + typename out_image_type + > + void operator() ( + const in_image_type& img, + out_image_type& himg + ) const; + /*! + requires + - in_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h and it must contain grayscale pixels. + - out_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h and it must contain grayscale pixels. + - num_rows(img) == size() + - num_columns(img) == size() + ensures + - performs: (*this)(img, get_rect(img), himg); + That is, just runs the hough transform on the whole input image. + !*/ + + template < + typename in_image_type + > + std::vector> find_pixels_voting_for_lines ( + const in_image_type& img, + const rectangle& box, + const std::vector& hough_points, + const unsigned long angle_window_size = 1, + const unsigned long radius_window_size = 1 + ) const; + /*! + requires + - in_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h and it must contain grayscale pixels. + - box.width() == size() + - box.height() == size() + - for all valid i: + - get_rect(*this).contains(hough_points[i]) == true + (i.e. hough_points must contain points in the output Hough transform + space generated by this object.) + - angle_window_size >= 1 + - radius_window_size >= 1 + ensures + - This function computes the Hough transform of the part of img contained + within box. It does the same computation as operator() defined above, + except instead of accumulating into an image we create an explicit list + of all the points in img that contributed to each line (i.e each point in + the Hough image). To do this we take a list of Hough points as input and + only record hits on these specifically identified Hough points. A + typical use of find_pixels_voting_for_lines() is to first run the normal + Hough transform using operator(), then find the lines you are interested + in, and then call find_pixels_voting_for_lines() to determine which + pixels in the input image belong to those lines. + - This routine returns a vector, CONSTITUENT_POINTS, with the following + properties: + - #CONSTITUENT_POINTS.size() == hough_points.size() + - for all valid i: + - Let HP[i] = centered_rect(hough_points[i], angle_window_size, radius_window_size) + - Any point in img with a non-zero value that lies on a line + corresponding to one of the Hough points in HP[i] is added to + CONSTITUENT_POINTS[i]. Therefore, when this routine finishes, + #CONSTITUENT_POINTS[i] will contain all the points in img that + voted for the lines associated with the Hough accumulator bins in + HP[i]. + - #CONSTITUENT_POINTS[i].size() == the number of points in img that + voted for any of the lines HP[i] in Hough space. Note, however, + that if angle_window_size or radius_window_size are made so large + that HP[i] overlaps HP[j] for i!=j then the overlapping regions + of Hough space are assign to HP[i] or HP[j] arbitrarily. + Therefore, all points in CONSTITUENT_POINTS are unique, that is, + there is no overlap in points between any two elements of + CONSTITUENT_POINTS. + !*/ + + template < + typename in_image_type + > + std::vector> find_pixels_voting_for_lines ( + const in_image_type& img, + const std::vector& hough_points, + const unsigned long angle_window_size = 1, + const unsigned long radius_window_size = 1 + ) const; + /*! + requires + - in_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h and it must contain grayscale pixels. + - num_rows(img) == size() + - num_columns(img) == size() + - for all valid i: + - get_rect(*this).contains(hough_points[i]) == true + (i.e. hough_points must contain points in the output Hough transform + space generated by this object.) + - angle_window_size >= 1 + - radius_window_size >= 1 + ensures + - performs: return find_pixels_voting_for_lines(img, get_rect(img), hough_points, angle_window_size, radius_window_size); + That is, just runs the routine on the whole input image. + !*/ + + template < + typename image_type, + typename thresh_type + > + std::vector find_strong_hough_points( + const image_type& himg, + const thresh_type hough_count_threshold, + const double angle_nms_thresh, + const double radius_nms_thresh + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h and it must contain grayscale pixels. + - himg.nr() == size() + - himg.nc() == size() + - angle_nms_thresh >= 0 + - radius_nms_thresh >= 0 + ensures + - This routine finds strong lines in a Hough transform and performs + non-maximum suppression on the detected lines. Recall that each point in + Hough space is associated with a line. Therefore, this routine finds all + the pixels in himg (a Hough transform image) with values >= + hough_count_threshold and performs non-maximum suppression on the + identified list of pixels. It does this by discarding lines that are + within angle_nms_thresh degrees of a stronger line or within + radius_nms_thresh distance (in terms of radius as defined by + get_line_properties()) to a stronger Hough point. + - The identified lines are returned as a list of coordinates in himg. + !*/ + + template < + typename in_image_type, + typename record_hit_function_type + > + void perform_generic_hough_transform ( + const in_image_type& img, + const rectangle& box, + record_hit_function_type record_hit + ) const; + /*! + requires + - in_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h and it must contain grayscale pixels. + - box.width() == size() + - box.height() == size() + - record_hit is a function object with the signature: + void record_hit(const point& hough_point, const point& img_point, in_image_pixel_type value) + ensures + - Computes the Hough transform of the part of img contained within box. + This routine is very general and allows you to implement a wide variety + of Hough transforms, in fact, the operator() and + find_pixels_voting_for_lines() routines defined above are implemented in + terms of perform_generic_hough_transform(). The behavior is described by + the following pseudo-code: + for (image_coordinate : all_coordinates_in_img) + for (hough_point : all_Hough_space_coordinates_for_lines_passing_through_image_coordinate) + record_hit(hough_point, image_coordinate, img[image_coordinate.y][image_coordinate.x()]); + That is, we perform the Hough transform, but rather than accumulating + into a Hough accumulator image, we call record_hit() and record_hit() + does whatever it wants. For example, in the operator() method defined + above record_hit() simply accumulates into an image, and therefor + performs the classic Hough transform. But there are many other options. + !*/ + + template < + typename in_image_type, + typename record_hit_function_type + > + void perform_generic_hough_transform ( + const in_image_type& img, + record_hit_function_type record_hit + ) const; + /*! + requires + - in_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h and it must contain grayscale pixels. + - record_hit is a function object with the signature: + void record_hit(const point& hough_point, const point& img_point, in_image_pixel_type value) + - num_rows(img) == size() + - num_columns(img) == size() + ensures + - performs: perform_generic_hough_transform(img, get_rect(img), record_hit); + That is, just runs the routine on the whole input image. + !*/ + + }; +} + +#endif // DLIB_HOUGH_tRANSFORM_ABSTRACT_Hh_ + + diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/image_pyramid.h b/lib/3rdParty/dlib/include/dlib/image_transforms/image_pyramid.h index a3248317..3efed30d 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/image_pyramid.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/image_pyramid.h @@ -62,36 +62,36 @@ namespace dlib // ----------------------------- - rectangle rect_up ( - const rectangle& rect + drectangle rect_up ( + const drectangle& rect ) const { - return rectangle(point_up(rect.tl_corner()), point_up(rect.br_corner())); + return drectangle(point_up(rect.tl_corner()), point_up(rect.br_corner())); } - rectangle rect_up ( - const rectangle& rect, + drectangle rect_up ( + const drectangle& rect, unsigned int levels ) const { - return rectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels)); + return drectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels)); } // ----------------------------- - rectangle rect_down ( - const rectangle& rect + drectangle rect_down ( + const drectangle& rect ) const { - return rectangle(point_down(rect.tl_corner()), point_down(rect.br_corner())); + return drectangle(point_down(rect.tl_corner()), point_down(rect.br_corner())); } - rectangle rect_down ( - const rectangle& rect, + drectangle rect_down ( + const drectangle& rect, unsigned int levels ) const { - return rectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels)); + return drectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels)); } // ----------------------------- @@ -156,8 +156,7 @@ namespace dlib const vector& p ) const { - //do return (p - vector(2,2))/2.0; - return p/2.0 - vector(1,1); + return p/2.0 - vector(1.25,0.75); } template @@ -165,7 +164,7 @@ namespace dlib const vector& p ) const { - return p*2 + vector(2,2); + return (p + vector(1.25,0.75))*2; } // ----------------------------- @@ -196,36 +195,36 @@ namespace dlib // ----------------------------- - rectangle rect_up ( - const rectangle& rect + drectangle rect_up ( + const drectangle& rect ) const { - return rectangle(point_up(rect.tl_corner()), point_up(rect.br_corner())); + return drectangle(point_up(rect.tl_corner()), point_up(rect.br_corner())); } - rectangle rect_up ( - const rectangle& rect, + drectangle rect_up ( + const drectangle& rect, unsigned int levels ) const { - return rectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels)); + return drectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels)); } // ----------------------------- - rectangle rect_down ( - const rectangle& rect + drectangle rect_down ( + const drectangle& rect ) const { - return rectangle(point_down(rect.tl_corner()), point_down(rect.br_corner())); + return drectangle(point_down(rect.tl_corner()), point_down(rect.br_corner())); } - rectangle rect_down ( - const rectangle& rect, + drectangle rect_down ( + const drectangle& rect, unsigned int levels ) const { - return rectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels)); + return drectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels)); } // ----------------------------- @@ -320,8 +319,8 @@ namespace dlib ptype temp = temp_img[r-2][c] + temp_img[r-1][c]*4 + temp_img[r ][c]*6 + - temp_img[r-1][c]*4 + - temp_img[r-2][c]; + temp_img[r+1][c]*4 + + temp_img[r+2][c]; assign_pixel(down[dr][c],temp/256); } @@ -444,18 +443,18 @@ namespace dlib temp.red = temp_img[r-2][c].red + temp_img[r-1][c].red*4 + temp_img[r ][c].red*6 + - temp_img[r-1][c].red*4 + - temp_img[r-2][c].red; + temp_img[r+1][c].red*4 + + temp_img[r+2][c].red; temp.green = temp_img[r-2][c].green + temp_img[r-1][c].green*4 + temp_img[r ][c].green*6 + - temp_img[r-1][c].green*4 + - temp_img[r-2][c].green; + temp_img[r+1][c].green*4 + + temp_img[r+2][c].green; temp.blue = temp_img[r-2][c].blue + temp_img[r-1][c].blue*4 + temp_img[r ][c].blue*6 + - temp_img[r-1][c].blue*4 + - temp_img[r-2][c].blue; + temp_img[r+1][c].blue*4 + + temp_img[r+2][c].blue; down[dr][c].red = temp.red/256; down[dr][c].green = temp.green/256; @@ -497,8 +496,7 @@ namespace dlib ) const { const double ratio = 2.0/3.0; - //do return (p - vector(1,1))*ratio; - return p*ratio - vector(ratio,ratio); + return p*ratio - vector(1,1); } template @@ -507,7 +505,7 @@ namespace dlib ) const { const double ratio = 3.0/2.0; - return p*ratio + vector(1,1); + return p*ratio + vector(ratio,ratio); } // ----------------------------- @@ -538,36 +536,36 @@ namespace dlib // ----------------------------- - rectangle rect_up ( - const rectangle& rect + drectangle rect_up ( + const drectangle& rect ) const { - return rectangle(point_up(rect.tl_corner()), point_up(rect.br_corner())); + return drectangle(point_up(rect.tl_corner()), point_up(rect.br_corner())); } - rectangle rect_up ( - const rectangle& rect, + drectangle rect_up ( + const drectangle& rect, unsigned int levels ) const { - return rectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels)); + return drectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels)); } // ----------------------------- - rectangle rect_down ( - const rectangle& rect + drectangle rect_down ( + const drectangle& rect ) const { - return rectangle(point_down(rect.tl_corner()), point_down(rect.br_corner())); + return drectangle(point_down(rect.tl_corner()), point_down(rect.br_corner())); } - rectangle rect_down ( - const rectangle& rect, + drectangle rect_down ( + const drectangle& rect, unsigned int levels ) const { - return rectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels)); + return drectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels)); } // ----------------------------- @@ -849,7 +847,7 @@ namespace dlib ) const { const double ratio = (N-1.0)/N; - return p*ratio; + return (p - 0.3)*ratio; } template @@ -858,7 +856,7 @@ namespace dlib ) const { const double ratio = N/(N-1.0); - return p*ratio; + return p*ratio + 0.3; } // ----------------------------- @@ -889,36 +887,36 @@ namespace dlib // ----------------------------- - rectangle rect_up ( - const rectangle& rect + drectangle rect_up ( + const drectangle& rect ) const { - return rectangle(point_up(rect.tl_corner()), point_up(rect.br_corner())); + return drectangle(point_up(rect.tl_corner()), point_up(rect.br_corner())); } - rectangle rect_up ( - const rectangle& rect, + drectangle rect_up ( + const drectangle& rect, unsigned int levels ) const { - return rectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels)); + return drectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels)); } // ----------------------------- - rectangle rect_down ( - const rectangle& rect + drectangle rect_down ( + const drectangle& rect ) const { - return rectangle(point_down(rect.tl_corner()), point_down(rect.br_corner())); + return drectangle(point_down(rect.tl_corner()), point_down(rect.br_corner())); } - rectangle rect_down ( - const rectangle& rect, + drectangle rect_down ( + const drectangle& rect, unsigned int levels ) const { - return rectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels)); + return drectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels)); } template < @@ -943,7 +941,7 @@ namespace dlib COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); - set_image_size(down, ((N-1)*num_rows(original))/N, ((N-1)*num_columns(original))/N); + set_image_size(down, ((N-1)*num_rows(original))/N+0.5, ((N-1)*num_columns(original))/N+0.5); resize_image(original, down); } @@ -971,6 +969,267 @@ namespace dlib // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template + double pyramid_rate(const pyramid_down&) + { + return (N-1.0)/N; + } + +// ---------------------------------------------------------------------------------------- + + template + void find_pyramid_down_output_image_size( + const pyramid_down& pyr, + long& nr, + long& nc + ) + { + const double rate = pyramid_rate(pyr); + nr = std::floor(rate*nr); + nc = std::floor(rate*nc); + } + + inline void find_pyramid_down_output_image_size( + const pyramid_down<3>& /*pyr*/, + long& nr, + long& nc + ) + { + nr = 2*(nr-2)/3; + nc = 2*(nc-2)/3; + } + + inline void find_pyramid_down_output_image_size( + const pyramid_down<2>& /*pyr*/, + long& nr, + long& nc + ) + { + nr = (nr-3)/2; + nc = (nc-3)/2; + } + + inline void find_pyramid_down_output_image_size( + const pyramid_down<1>& /*pyr*/, + long& nr, + long& nc + ) + { + nr = 0; + nc = 0; + } + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template + void compute_tiled_image_pyramid_details ( + const pyramid_type& pyr, + long nr, + long nc, + const unsigned long padding, + const unsigned long outer_padding, + std::vector& rects, + long& pyramid_image_nr, + long& pyramid_image_nc + ) + { + rects.clear(); + if (nr*nc == 0) + { + pyramid_image_nr = 0; + pyramid_image_nc = 0; + return; + } + + const long min_height = 5; + rects.reserve(100); + rects.push_back(rectangle(nc,nr)); + // build the whole pyramid + while(true) + { + find_pyramid_down_output_image_size(pyr, nr, nc); + if (nr*nc == 0 || nr < min_height) + break; + rects.push_back(rectangle(nc,nr)); + } + + // figure out output image size + long total_height = 0; + for (auto&& i : rects) + total_height += i.height()+padding; + total_height -= padding*2; // don't add unnecessary padding to the very right side. + long height = 0; + long prev_width = 0; + for (auto&& i : rects) + { + // Figure out how far we go on the first column. We go until the next image can + // fit next to the previous one, which means we can double back for the second + // column of images. + if (i.width() <= rects[0].width()-prev_width-(long)padding && + (height-rects[0].height())*2 >= (total_height-rects[0].height())) + { + break; + } + height += i.height() + padding; + prev_width = i.width(); + } + height -= padding; // don't add unnecessary padding to the very right side. + + const long width = rects[0].width(); + pyramid_image_nr = height+outer_padding*2; + pyramid_image_nc = width+outer_padding*2; + + + long y = outer_padding; + size_t i = 0; + while(y < height+(long)outer_padding && i < rects.size()) + { + rects[i] = translate_rect(rects[i],point(outer_padding,y)); + DLIB_ASSERT(rectangle(pyramid_image_nc,pyramid_image_nr).contains(rects[i])); + y += rects[i].height()+padding; + ++i; + } + y -= padding; + while (i < rects.size()) + { + point p1(outer_padding+width-1,y-1); + point p2 = p1 - rects[i].br_corner(); + rectangle rect(p1,p2); + DLIB_ASSERT(rectangle(pyramid_image_nc,pyramid_image_nr).contains(rect)); + // don't keep going on the last row if it would intersect the original image. + if (!rects[0].intersect(rect).is_empty()) + break; + + rects[i] = rect; + y -= rects[i].height()+padding; + ++i; + } + + // Delete any extraneous rectangles if we broke out of the above loop early due to + // intersection with the original image. + rects.resize(i); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename pyramid_type, + typename image_type1, + typename image_type2 + > + void create_tiled_pyramid ( + const image_type1& img, + image_type2& out_img, + std::vector& rects, + const unsigned long padding = 10, + const unsigned long outer_padding = 0 + ) + { + DLIB_ASSERT(!is_same_object(img, out_img)); + + long out_nr, out_nc; + pyramid_type pyr; + impl::compute_tiled_image_pyramid_details(pyr, img.nr(), img.nc(), padding, outer_padding, rects, out_nr, out_nc); + + set_image_size(out_img, out_nr, out_nc); + assign_all_pixels(out_img, 0); + + if (rects.size() == 0) + return; + + // now build the image pyramid into out_img + auto si = sub_image(out_img, rects[0]); + assign_image(si, img); + for (size_t i = 1; i < rects.size(); ++i) + { + auto s1 = sub_image(out_img, rects[i-1]); + auto s2 = sub_image(out_img, rects[i]); + pyr(s1,s2); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename pyramid_type + > + dpoint image_to_tiled_pyramid ( + const std::vector& rects, + double scale, + dpoint p + ) + { + DLIB_CASSERT(rects.size() > 0); + DLIB_CASSERT(0 < scale && scale <= 1); + pyramid_type pyr; + // This scale factor maps this many levels down the pyramid + long pyramid_down_iter = static_cast(std::log(scale)/std::log(pyramid_rate(pyr))+0.5); + pyramid_down_iter = put_in_range(0, (long)rects.size()-1, pyramid_down_iter); + + return rects[pyramid_down_iter].tl_corner() + pyr.point_down(p, pyramid_down_iter); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename pyramid_type + > + drectangle image_to_tiled_pyramid ( + const std::vector& rects, + double scale, + drectangle r + ) + { + DLIB_ASSERT(rects.size() > 0); + DLIB_ASSERT(0 < scale && scale <= 1); + return drectangle(image_to_tiled_pyramid(rects, scale, r.tl_corner()), + image_to_tiled_pyramid(rects, scale, r.br_corner())); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename pyramid_type + > + dpoint tiled_pyramid_to_image ( + const std::vector& rects, + dpoint p + ) + { + DLIB_CASSERT(rects.size() > 0); + + size_t pyramid_down_iter = nearest_rect(rects, p); + + p -= rects[pyramid_down_iter].tl_corner(); + pyramid_type pyr; + return pyr.point_up(p, pyramid_down_iter); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename pyramid_type + > + drectangle tiled_pyramid_to_image ( + const std::vector& rects, + drectangle r + ) + { + DLIB_CASSERT(rects.size() > 0); + + size_t pyramid_down_iter = nearest_rect(rects, dcenter(r)); + + dpoint origin = rects[pyramid_down_iter].tl_corner(); + r = drectangle(r.tl_corner()-origin, r.br_corner()-origin); + pyramid_type pyr; + return pyr.rect_up(r, pyramid_down_iter); + } + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/image_pyramid_abstract.h b/lib/3rdParty/dlib/include/dlib/image_transforms/image_pyramid_abstract.h index 8df393a4..ebd928c7 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/image_pyramid_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/image_pyramid_abstract.h @@ -109,21 +109,21 @@ namespace dlib point_up(point_down(P)) == P !*/ - rectangle rect_down ( - const rectangle& rect + drectangle rect_down ( + const drectangle& rect ) const; /*! ensures - - returns rectangle(point_down(rect.tl_corner()), point_down(rect.br_corner())); - (i.e. maps rect into a downsampled) + - returns drectangle(point_down(rect.tl_corner()), point_down(rect.br_corner())); + (i.e. maps rect into a downsampled image) !*/ - rectangle rect_up ( - const rectangle& rect + drectangle rect_up ( + const drectangle& rect ) const; /*! ensures - - returns rectangle(point_up(rect.tl_corner()), point_up(rect.br_corner())); + - returns drectangle(point_up(rect.tl_corner()), point_up(rect.br_corner())); (i.e. maps rect into a parent image) !*/ @@ -155,23 +155,23 @@ namespace dlib point_up(p,0) == p, etc. ) !*/ - rectangle rect_down ( - const rectangle& rect, + drectangle rect_down ( + const drectangle& rect, unsigned int levels ) const; /*! ensures - - returns rectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels)); + - returns drectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels)); (i.e. Basically applies rect_down() to rect levels times and returns the result.) !*/ - rectangle rect_up ( - const rectangle& rect, + drectangle rect_up ( + const drectangle& rect, unsigned int levels ) const; /*! ensures - - returns rectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels)); + - returns drectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels)); (i.e. Basically applies rect_up() to rect levels times and returns the result.) !*/ @@ -195,6 +195,186 @@ namespace dlib !*/ }; +// ---------------------------------------------------------------------------------------- + + template < + unsigned int N + > + double pyramid_rate( + const pyramid_down& pyr + ); + /*! + ensures + - returns (N-1.0)/N + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + unsigned int N + > + void find_pyramid_down_output_image_size( + const pyramid_down& pyr, + long& nr, + long& nc + ); + /*! + requires + - nr >= 0 + - nc >= 0 + ensures + - If pyr() were called on an image with nr by nc rows and columns, what would + be the size of the output image? This function finds the size of the output + image and stores it back into #nr and #nc. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename pyramid_type, + typename image_type1, + typename image_type2 + > + void create_tiled_pyramid ( + const image_type1& img, + image_type2& out_img, + std::vector& rects, + const unsigned long padding = 10, + const unsigned long outer_padding = 0 + ); + /*! + requires + - pyramid_type == one of the dlib::pyramid_down template instances defined above. + - is_same_object(img, out_img) == false + - image_type1 == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - image_type2 == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - for both pixel types P in the input and output images, we require: + - pixel_traits

::has_alpha == false + ensures + - Creates an image pyramid from the input image img. The pyramid is made using + pyramid_type. The highest resolution image is img and then all further + pyramid levels are generated from pyramid_type's downsampling. The entire + resulting pyramid is packed into a single image and stored in out_img. + - When packing pyramid levels into out_img, there will be padding pixels of + space between each sub-image. There will also be outer_padding pixels of + padding around the edge of the image. All padding pixels have a value of 0. + - The resulting pyramid will be composed of #rects.size() images packed into + out_img. Moreover, #rects[i] is the location inside out_img of the i-th + pyramid level. + - #rects.size() > 0 + - #rects[0] == get_rect(img). I.e. the first rectangle is the highest + resolution pyramid layer. Subsequent elements of #rects correspond to + smaller and smaller pyramid layers inside out_img. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename pyramid_type + > + dpoint image_to_tiled_pyramid ( + const std::vector& rects, + double scale, + dpoint p + ); + /*! + requires + - pyramid_type == one of the dlib::pyramid_down template instances defined above. + - 0 < scale <= 1 + - rects.size() > 0 + ensures + - The function create_tiled_pyramid() converts an image, img, to a "tiled + pyramid" called out_img. It also outputs a vector of rectangles, rect, that + show where each pyramid layer appears in out_img. Therefore, + image_to_tiled_pyramid() allows you to map from coordinates in img (i.e. p) + to coordinates in the tiled pyramid out_img, when given the rects metadata. + + So given a point p in img, you can ask, what coordinate in out_img + corresponds to img[p.y()][p.x()] when things are scale times smaller? This + new coordinate is a location in out_img and is what is returned by this + function. + - A scale of 1 means we don't move anywhere in the pyramid scale space relative + to the input image while smaller values of scale mean we move down the + pyramid. + - Assumes pyramid_type is the pyramid class used to produce the tiled image. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename pyramid_type + > + drectangle image_to_tiled_pyramid ( + const std::vector& rects, + double scale, + drectangle r + ); + /*! + requires + - pyramid_type == one of the dlib::pyramid_down template instances defined above. + - 0 < scale <= 1 + - rects.size() > 0 + ensures + - This function maps from input image space to tiled pyramid coordinate space + just as the above image_to_tiled_pyramid() does, except it operates on + rectangle objects instead of points. + - Assumes pyramid_type is the pyramid class used to produce the tiled image. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename pyramid_type + > + dpoint tiled_pyramid_to_image ( + const std::vector& rects, + dpoint p + ); + /*! + requires + - pyramid_type == one of the dlib::pyramid_down template instances defined above. + - rects.size() > 0 + ensures + - This function maps from a coordinate in a tiled pyramid to the corresponding + input image coordinate. Therefore, it is essentially the inverse of + image_to_tiled_pyramid(). + - It should be noted that this function isn't always an inverse of + image_to_tiled_pyramid(). This is because you can ask + image_to_tiled_pyramid() for the coordinates of points outside the input + image and they will be mapped to somewhere that doesn't have an inverse. But + for points actually inside the image this function performs an approximate + inverse mapping. + - Assumes pyramid_type is the pyramid class used to produce the tiled image. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename pyramid_type + > + drectangle tiled_pyramid_to_image ( + const std::vector& rects, + drectangle r + ); + /*! + requires + - pyramid_type == one of the dlib::pyramid_down template instances defined above. + - rects.size() > 0 + ensures + - This function maps from a coordinate in a tiled pyramid to the corresponding + input image coordinate. Therefore, it is essentially the inverse of + image_to_tiled_pyramid(). + - It should be noted that this function isn't always an inverse of + image_to_tiled_pyramid(). This is because you can ask + image_to_tiled_pyramid() for the coordinates of points outside the input + image and they will be mapped to somewhere that doesn't have an inverse. But + for points actually inside the image this function performs an approximate + inverse mapping. + - Assumes pyramid_type is the pyramid class used to produce the tiled image. + !*/ + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/interpolation.h b/lib/3rdParty/dlib/include/dlib/image_transforms/interpolation.h index f1c28a26..d7c9dee5 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/interpolation.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/interpolation.h @@ -3,6 +3,9 @@ #ifndef DLIB_INTERPOlATIONh_ #define DLIB_INTERPOlATIONh_ +#include "../threads.h" +#include + #include "interpolation_abstract.h" #include "../pixel.h" #include "../matrix.h" @@ -10,10 +13,189 @@ #include "image_pyramid.h" #include "../simd.h" #include "../image_processing/full_object_detection.h" +#include +#include +#include "../rand.h" namespace dlib { +// ---------------------------------------------------------------------------------------- + + template + struct sub_image_proxy + { + sub_image_proxy() = default; + + sub_image_proxy ( + T& img, + rectangle rect + ) + { + rect = rect.intersect(get_rect(img)); + typedef typename image_traits::pixel_type pixel_type; + + _nr = rect.height(); + _nc = rect.width(); + _width_step = width_step(img); + _data = (char*)image_data(img) + sizeof(pixel_type)*rect.left() + rect.top()*_width_step; + } + + void* _data = 0; + long _width_step = 0; + long _nr = 0; + long _nc = 0; + }; + + template + struct const_sub_image_proxy + { + const_sub_image_proxy() = default; + + const_sub_image_proxy ( + const T& img, + rectangle rect + ) + { + rect = rect.intersect(get_rect(img)); + typedef typename image_traits::pixel_type pixel_type; + + _nr = rect.height(); + _nc = rect.width(); + _width_step = width_step(img); + _data = (const char*)image_data(img) + sizeof(pixel_type)*rect.left() + rect.top()*_width_step; + } + + const void* _data = 0; + long _width_step = 0; + long _nr = 0; + long _nc = 0; + }; + + template + struct image_traits > + { + typedef typename image_traits::pixel_type pixel_type; + }; + template + struct image_traits > + { + typedef typename image_traits::pixel_type pixel_type; + }; + template + struct image_traits > + { + typedef typename image_traits::pixel_type pixel_type; + }; + template + struct image_traits > + { + typedef typename image_traits::pixel_type pixel_type; + }; + + template + inline long num_rows( const sub_image_proxy& img) { return img._nr; } + template + inline long num_columns( const sub_image_proxy& img) { return img._nc; } + + template + inline long num_rows( const const_sub_image_proxy& img) { return img._nr; } + template + inline long num_columns( const const_sub_image_proxy& img) { return img._nc; } + + template + inline void* image_data( sub_image_proxy& img) + { + return img._data; + } + template + inline const void* image_data( const sub_image_proxy& img) + { + return img._data; + } + + template + inline const void* image_data( const const_sub_image_proxy& img) + { + return img._data; + } + + template + inline long width_step( + const sub_image_proxy& img + ) { return img._width_step; } + + template + inline long width_step( + const const_sub_image_proxy& img + ) { return img._width_step; } + + template + void set_image_size(sub_image_proxy& img, long rows, long cols) + { + DLIB_CASSERT(img._nr == rows && img._nc == cols, "A sub_image can't be resized." + << "\n\t img._nr: "<< img._nr + << "\n\t img._nc: "<< img._nc + << "\n\t rows: "<< rows + << "\n\t cols: "<< cols + ); + } + + template < + typename image_type + > + sub_image_proxy sub_image ( + image_type& img, + const rectangle& rect + ) + { + return sub_image_proxy(img,rect); + } + + template < + typename image_type + > + const const_sub_image_proxy sub_image ( + const image_type& img, + const rectangle& rect + ) + { + return const_sub_image_proxy(img,rect); + } + + template + inline sub_image_proxy> sub_image ( + T* img, + long nr, + long nc, + long row_stride + ) + { + sub_image_proxy> tmp; + tmp._data = img; + tmp._nr = nr; + tmp._nc = nc; + tmp._width_step = row_stride*sizeof(T); + return tmp; + } + + template + inline const const_sub_image_proxy> sub_image ( + const T* img, + long nr, + long nc, + long row_stride + ) + { + const_sub_image_proxy> tmp; + tmp._data = img; + tmp._nr = nr; + tmp._nc = nc; + tmp._width_step = row_stride*sizeof(T); + return tmp; + } + +// ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- class interpolate_nearest_neighbor @@ -438,7 +620,7 @@ namespace dlib rect += rotate_point(center(rimg), rimg.tr_corner(), -angle); rect += rotate_point(center(rimg), rimg.bl_corner(), -angle); rect += rotate_point(center(rimg), rimg.br_corner(), -angle); - out_img.set_size(rect.height(), rect.width()); + set_image_size(out_img, rect.height(), rect.width()); const matrix R = rotation_matrix(angle); @@ -523,11 +705,6 @@ namespace dlib // ---------------------------------------------------------------------------------------- - template - struct is_rgb_image { const static bool value = pixel_traits::pixel_type>::rgb; }; - template - struct is_grayscale_image { const static bool value = pixel_traits::pixel_type>::grayscale; }; - // This is an optimized version of resize_image for the case where bilinear // interpolation is used. template < @@ -552,11 +729,8 @@ namespace dlib const_image_view in_img(in_img_); image_view out_img(out_img_); - if (out_img.nr() <= 1 || out_img.nc() <= 1) - { - assign_all_pixels(out_img, 0); + if (out_img.size() == 0 || in_img.size() == 0) return; - } typedef typename image_traits::pixel_type T; @@ -621,11 +795,24 @@ namespace dlib // ---------------------------------------------------------------------------------------- template < - typename image_type + typename image_type1, + typename image_type2 > - typename enable_if >::type resize_image ( + struct images_have_same_pixel_types + { + typedef typename image_traits::pixel_type ptype1; + typedef typename image_traits::pixel_type ptype2; + const static bool value = is_same_type::value; + }; + + template < + typename image_type, + typename image_type2 + > + typename enable_if_c::value && is_grayscale_image::value && images_have_same_pixel_types::value>::type + resize_image ( const image_type& in_img_, - image_type& out_img_, + image_type2& out_img_, interpolate_bilinear ) { @@ -637,13 +824,10 @@ namespace dlib ); const_image_view in_img(in_img_); - image_view out_img(out_img_); + image_view out_img(out_img_); - if (out_img.nr() <= 1 || out_img.nc() <= 1) - { - assign_all_pixels(out_img, 0); + if (out_img.size() == 0 || in_img.size() == 0) return; - } typedef typename image_traits::pixel_type T; const double x_scale = (in_img.nc()-1)/(double)std::max((out_img.nc()-1),1); @@ -688,8 +872,8 @@ namespace dlib simd4f bl(in_img[bottom][fleft[0]], in_img[bottom][fleft[1]], in_img[bottom][fleft[2]], in_img[bottom][fleft[3]]); simd4f br(in_img[bottom][fright[0]], in_img[bottom][fright[1]], in_img[bottom][fright[2]], in_img[bottom][fright[3]]); - simd4i out = simd4i(tlf*tl + trf*tr + blf*bl + brf*br); - int32 fout[4]; + simd4f out = simd4f(tlf*tl + trf*tr + blf*bl + brf*br); + float fout[4]; out.store(fout); out_img[r][c] = static_cast(fout[0]); @@ -741,11 +925,8 @@ namespace dlib const_image_view in_img(in_img_); image_view out_img(out_img_); - if (out_img.nr() <= 1 || out_img.nc() <= 1) - { - assign_all_pixels(out_img, 0); + if (out_img.size() == 0 || in_img.size() == 0) return; - } typedef typename image_traits::pixel_type T; @@ -867,6 +1048,29 @@ namespace dlib resize_image(in_img, out_img, interpolate_bilinear()); } +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void resize_image ( + double size_scale, + image_type& img + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( size_scale > 0 , + "\t void resize_image()" + << "\n\t Invalid inputs were given to this function." + << "\n\t size_scale: " << size_scale + ); + + image_type temp; + set_image_size(temp, std::round(size_scale*num_rows(img)), std::round(size_scale*num_columns(img))); + resize_image(img, temp); + swap(img, temp); + } + // ---------------------------------------------------------------------------------------- template < @@ -895,6 +1099,21 @@ namespace dlib return find_affine_transform(from,to); } +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + point_transform_affine flip_image_left_right ( + image_type& img + ) + { + image_type temp; + auto tform = flip_image_left_right(img, temp); + swap(temp,img); + return tform; + } + // ---------------------------------------------------------------------------------------- template < @@ -944,6 +1163,15 @@ namespace dlib return centered_rect(tran(center(rect)), rect.width(), rect.height()); } + inline mmod_rect tform_object ( + const point_transform_affine& tran, + mmod_rect rect + ) + { + rect.rect = tform_object(tran, rect.rect); + return rect; + } + inline full_object_detection tform_object( const point_transform_affine& tran, const full_object_detection& obj @@ -953,7 +1181,10 @@ namespace dlib parts.reserve(obj.num_parts()); for (unsigned long i = 0; i < obj.num_parts(); ++i) { - parts.push_back(tran(obj.part(i))); + if (obj.part(i) != OBJECT_PART_NOT_PRESENT) + parts.push_back(tran(obj.part(i))); + else + parts.push_back(OBJECT_PART_NOT_PRESENT); } return full_object_detection(tform_object(tran,obj.get_rect()), parts); } @@ -962,11 +1193,11 @@ namespace dlib // ---------------------------------------------------------------------------------------- template < - typename image_type, + typename image_array_type, typename T > void add_image_left_right_flips ( - dlib::array& images, + image_array_type& images, std::vector >& objects ) { @@ -978,7 +1209,7 @@ namespace dlib << "\n\t objects.size(): " << objects.size() ); - image_type temp; + typename image_array_type::value_type temp; std::vector rects; const unsigned long num = images.size(); @@ -990,7 +1221,7 @@ namespace dlib for (unsigned long i = 0; i < objects[j].size(); ++i) rects.push_back(impl::tform_object(tran, objects[j][i])); - images.push_back(temp); + images.push_back(std::move(temp)); objects.push_back(rects); } } @@ -998,12 +1229,12 @@ namespace dlib // ---------------------------------------------------------------------------------------- template < - typename image_type, + typename image_array_type, typename T, typename U > void add_image_left_right_flips ( - dlib::array& images, + image_array_type& images, std::vector >& objects, std::vector >& objects2 ) @@ -1018,7 +1249,7 @@ namespace dlib << "\n\t objects2.size(): " << objects2.size() ); - image_type temp; + typename image_array_type::value_type temp; std::vector rects; std::vector rects2; @@ -1026,7 +1257,7 @@ namespace dlib for (unsigned long j = 0; j < num; ++j) { const point_transform_affine tran = flip_image_left_right(images[j], temp); - images.push_back(temp); + images.push_back(std::move(temp)); rects.clear(); for (unsigned long i = 0; i < objects[j].size(); ++i) @@ -1042,9 +1273,9 @@ namespace dlib // ---------------------------------------------------------------------------------------- - template + template void flip_image_dataset_left_right ( - dlib::array& images, + image_array_type& images, std::vector >& objects ) { @@ -1056,7 +1287,7 @@ namespace dlib << "\n\t objects.size(): " << objects.size() ); - image_type temp; + typename image_array_type::value_type temp; for (unsigned long i = 0; i < images.size(); ++i) { flip_image_left_right(images[i], temp); @@ -1070,9 +1301,9 @@ namespace dlib // ---------------------------------------------------------------------------------------- - template + template void flip_image_dataset_left_right ( - dlib::array& images, + image_array_type& images, std::vector >& objects, std::vector >& objects2 ) @@ -1087,7 +1318,7 @@ namespace dlib << "\n\t objects2.size(): " << objects2.size() ); - image_type temp; + typename image_array_type::value_type temp; for (unsigned long i = 0; i < images.size(); ++i) { flip_image_left_right(images[i], temp); @@ -1107,11 +1338,12 @@ namespace dlib template < typename pyramid_type, - typename image_type + typename image_array_type > void upsample_image_dataset ( - dlib::array& images, - std::vector >& objects + image_array_type& images, + std::vector >& objects, + unsigned long max_image_size = std::numeric_limits::max() ) { // make sure requires clause is not broken @@ -1122,27 +1354,67 @@ namespace dlib << "\n\t objects.size(): " << objects.size() ); - image_type temp; + typename image_array_type::value_type temp; pyramid_type pyr; for (unsigned long i = 0; i < images.size(); ++i) { - pyramid_up(images[i], temp, pyr); - swap(temp, images[i]); - for (unsigned long j = 0; j < objects[i].size(); ++j) + const unsigned long img_size = num_rows(images[i])*num_columns(images[i]); + if (img_size <= max_image_size) { - objects[i][j] = pyr.rect_up(objects[i][j]); + pyramid_up(images[i], temp, pyr); + swap(temp, images[i]); + for (unsigned long j = 0; j < objects[i].size(); ++j) + { + objects[i][j] = pyr.rect_up(objects[i][j]); + } } } } template < typename pyramid_type, - typename image_type + typename image_array_type > void upsample_image_dataset ( - dlib::array& images, + image_array_type& images, + std::vector>& objects, + unsigned long max_image_size = std::numeric_limits::max() + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( images.size() == objects.size(), + "\t void upsample_image_dataset()" + << "\n\t Invalid inputs were given to this function." + << "\n\t images.size(): " << images.size() + << "\n\t objects.size(): " << objects.size() + ); + + typename image_array_type::value_type temp; + pyramid_type pyr; + for (unsigned long i = 0; i < images.size(); ++i) + { + const unsigned long img_size = num_rows(images[i])*num_columns(images[i]); + if (img_size <= max_image_size) + { + pyramid_up(images[i], temp, pyr); + swap(temp, images[i]); + for (unsigned long j = 0; j < objects[i].size(); ++j) + { + objects[i][j].rect = pyr.rect_up(objects[i][j].rect); + } + } + } + } + + template < + typename pyramid_type, + typename image_array_type + > + void upsample_image_dataset ( + image_array_type& images, std::vector >& objects, - std::vector >& objects2 + std::vector >& objects2, + unsigned long max_image_size = std::numeric_limits::max() ) { // make sure requires clause is not broken @@ -1155,29 +1427,33 @@ namespace dlib << "\n\t objects2.size(): " << objects2.size() ); - image_type temp; + typename image_array_type::value_type temp; pyramid_type pyr; for (unsigned long i = 0; i < images.size(); ++i) { - pyramid_up(images[i], temp, pyr); - swap(temp, images[i]); - for (unsigned long j = 0; j < objects[i].size(); ++j) + const unsigned long img_size = num_rows(images[i])*num_columns(images[i]); + if (img_size <= max_image_size) { - objects[i][j] = pyr.rect_up(objects[i][j]); - } - for (unsigned long j = 0; j < objects2[i].size(); ++j) - { - objects2[i][j] = pyr.rect_up(objects2[i][j]); + pyramid_up(images[i], temp, pyr); + swap(temp, images[i]); + for (unsigned long j = 0; j < objects[i].size(); ++j) + { + objects[i][j] = pyr.rect_up(objects[i][j]); + } + for (unsigned long j = 0; j < objects2[i].size(); ++j) + { + objects2[i][j] = pyr.rect_up(objects2[i][j]); + } } } } // ---------------------------------------------------------------------------------------- - template + template void rotate_image_dataset ( double angle, - dlib::array& images, + image_array_type& images, std::vector >& objects ) { @@ -1189,7 +1465,7 @@ namespace dlib << "\n\t objects.size(): " << objects.size() ); - image_type temp; + typename image_array_type::value_type temp; for (unsigned long i = 0; i < images.size(); ++i) { const point_transform_affine tran = rotate_image(images[i], temp, angle); @@ -1202,10 +1478,10 @@ namespace dlib } } - template + template void rotate_image_dataset ( double angle, - dlib::array& images, + image_array_type& images, std::vector >& objects, std::vector >& objects2 ) @@ -1220,7 +1496,7 @@ namespace dlib << "\n\t objects2.size(): " << objects2.size() ); - image_type temp; + typename image_array_type::value_type temp; for (unsigned long i = 0; i < images.size(); ++i) { const point_transform_affine tran = rotate_image(images[i], temp, angle); @@ -1241,14 +1517,14 @@ namespace dlib // ---------------------------------------------------------------------------------------- template < - typename image_type, + typename image_array_type, typename EXP, typename T, typename U > void add_image_rotations ( const matrix_exp& angles, - dlib::array& images, + image_array_type& images, std::vector >& objects, std::vector >& objects2 ) @@ -1266,33 +1542,29 @@ namespace dlib << "\n\t objects2.size(): " << objects2.size() ); - dlib::array new_images; - std::vector > new_objects; - std::vector > new_objects2; + using namespace impl; - using namespace impl; + image_array_type new_images(images.size() * angles.size()); + std::vector> new_objects(images.size() * angles.size()); + std::vector> new_objects2(images.size() * angles.size()); - std::vector objtemp; - std::vector objtemp2; - image_type temp; - for (long i = 0; i < angles.size(); ++i) - { - for (unsigned long j = 0; j < images.size(); ++j) + dlib::parallel_for(0, images.size(), [&](long j) { + typename image_array_type::value_type temp; + + long dst_base = j * angles.size(); + for (long i = 0; i < angles.size(); ++i) { + long dst = dst_base + i; const point_transform_affine tran = rotate_image(images[j], temp, angles(i)); - new_images.push_back(temp); + exchange(new_images[dst], temp); - objtemp.clear(); for (unsigned long k = 0; k < objects[j].size(); ++k) - objtemp.push_back(tform_object(tran, objects[j][k])); - new_objects.push_back(objtemp); + new_objects[dst].push_back(tform_object(tran, objects[j][k])); - objtemp2.clear(); for (unsigned long k = 0; k < objects2[j].size(); ++k) - objtemp2.push_back(tform_object(tran, objects2[j][k])); - new_objects2.push_back(objtemp2); + new_objects2[dst].push_back(tform_object(tran, objects2[j][k])); } - } + }); new_images.swap(images); new_objects.swap(objects); @@ -1302,13 +1574,13 @@ namespace dlib // ---------------------------------------------------------------------------------------- template < - typename image_type, + typename image_array_type, typename EXP, typename T > void add_image_rotations ( const matrix_exp& angles, - dlib::array& images, + image_array_type& images, std::vector >& objects ) { @@ -1426,17 +1698,52 @@ namespace dlib struct chip_details { chip_details() : angle(0), rows(0), cols(0) {} - chip_details(const rectangle& rect_, unsigned long size) : rect(rect_),angle(0) + chip_details(const rectangle& rect_) : rect(rect_),angle(0), rows(rect_.height()), cols(rect_.width()) {} + chip_details(const drectangle& rect_) : rect(rect_),angle(0), + rows((unsigned long)(rect_.height()+0.5)), cols((unsigned long)(rect_.width()+0.5)) {} + chip_details(const drectangle& rect_, unsigned long size) : rect(rect_),angle(0) { compute_dims_from_size(size); } - chip_details(const rectangle& rect_, unsigned long size, double angle_) : rect(rect_),angle(angle_) + chip_details(const drectangle& rect_, unsigned long size, double angle_) : rect(rect_),angle(angle_) { compute_dims_from_size(size); } - chip_details(const rectangle& rect_, const chip_dims& dims) : + chip_details(const drectangle& rect_, const chip_dims& dims) : rect(rect_),angle(0),rows(dims.rows), cols(dims.cols) {} - chip_details(const rectangle& rect_, const chip_dims& dims, double angle_) : + chip_details(const drectangle& rect_, const chip_dims& dims, double angle_) : rect(rect_),angle(angle_),rows(dims.rows), cols(dims.cols) {} - rectangle rect; + template + chip_details( + const std::vector >& chip_points, + const std::vector >& img_points, + const chip_dims& dims + ) : + rows(dims.rows), cols(dims.cols) + { + DLIB_CASSERT( chip_points.size() == img_points.size() && chip_points.size() >= 2, + "\t chip_details::chip_details(chip_points,img_points,dims)" + << "\n\t Invalid inputs were given to this function." + << "\n\t chip_points.size(): " << chip_points.size() + << "\n\t img_points.size(): " << img_points.size() + ); + + const point_transform_affine tform = find_similarity_transform(chip_points,img_points); + dlib::vector p(1,0); + p = tform.get_m()*p; + + // There are only 3 things happening in a similarity transform. There is a + // rescaling, a rotation, and a translation. So here we pick out the scale and + // rotation parameters. + angle = std::atan2(p.y(),p.x()); + // Note that the translation and scale part are represented by the extraction + // rectangle. So here we build the appropriate rectangle. + const double scale = length(p); + rect = centered_drect(tform(point(dims.cols,dims.rows)/2.0), + dims.cols*scale, + dims.rows*scale); + } + + + drectangle rect; double angle; unsigned long rows; unsigned long cols; @@ -1454,19 +1761,112 @@ namespace dlib const double relative_size = std::sqrt(size/(double)rect.area()); rows = static_cast(rect.height()*relative_size + 0.5); cols = static_cast(size/(double)rows + 0.5); + rows = std::max(1ul,rows); + cols = std::max(1ul,cols); } }; +// ---------------------------------------------------------------------------------------- + + inline point_transform_affine get_mapping_to_chip ( + const chip_details& details + ) + { + std::vector > from, to; + point p1(0,0); + point p2(details.cols-1,0); + point p3(details.cols-1, details.rows-1); + to.push_back(p1); + from.push_back(rotate_point(center(details.rect),details.rect.tl_corner(),details.angle)); + to.push_back(p2); + from.push_back(rotate_point(center(details.rect),details.rect.tr_corner(),details.angle)); + to.push_back(p3); + from.push_back(rotate_point(center(details.rect),details.rect.br_corner(),details.angle)); + return find_affine_transform(from, to); + } + +// ---------------------------------------------------------------------------------------- + + inline full_object_detection map_det_to_chip( + const full_object_detection& det, + const chip_details& details + ) + { + point_transform_affine tform = get_mapping_to_chip(details); + full_object_detection res(det); + // map the parts + for (unsigned long l = 0; l < det.num_parts(); ++l) + { + if (det.part(l) != OBJECT_PART_NOT_PRESENT) + res.part(l) = tform(det.part(l)); + else + res.part(l) = OBJECT_PART_NOT_PRESENT; + } + // map the main rectangle + rectangle rect; + rect += tform(det.get_rect().tl_corner()); + rect += tform(det.get_rect().tr_corner()); + rect += tform(det.get_rect().bl_corner()); + rect += tform(det.get_rect().br_corner()); + res.get_rect() = rect; + return res; + } + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template < + typename image_type1, + typename image_type2 + > + void basic_extract_image_chip ( + const image_type1& img, + const rectangle& location, + image_type2& chip + ) + /*! + ensures + - This function doesn't do any scaling or rotating. It just pulls out the + chip in the given rectangle. This also means the output image has the + same dimensions as the location rectangle. + !*/ + { + const_image_view vimg(img); + image_view vchip(chip); + + vchip.set_size(location.height(), location.width()); + + // location might go outside img so clip it + rectangle area = location.intersect(get_rect(img)); + + // find the part of the chip that corresponds to area in img. + rectangle chip_area = translate_rect(area, -location.tl_corner()); + + zero_border_pixels(chip, chip_area); + // now pull out the contents of area/chip_area. + for (long r = chip_area.top(), rr = area.top(); r <= chip_area.bottom(); ++r,++rr) + { + for (long c = chip_area.left(), cc = area.left(); c <= chip_area.right(); ++c,++cc) + { + assign_pixel(vchip[r][c], vimg[rr][cc]); + } + } + } + } + // ---------------------------------------------------------------------------------------- template < typename image_type1, - typename image_type2 + typename image_type2, + typename interpolation_type > void extract_image_chips ( const image_type1& img, const std::vector& chip_locations, - dlib::array& chips + dlib::array& chips, + const interpolation_type& interp ) { // make sure requires clause is not broken @@ -1491,22 +1891,36 @@ namespace dlib // interpolation. So we use an image pyramid to make sure the interpolation is // fast but also high quality. The first thing we do is figure out how deep the // image pyramid needs to be. + rectangle bounding_box; for (unsigned long i = 0; i < chip_locations.size(); ++i) { long depth = 0; - rectangle rect = pyr.rect_down(chip_locations[i].rect); + double grow = 2; + drectangle rect = pyr.rect_down(chip_locations[i].rect); while (rect.area() > chip_locations[i].size()) { rect = pyr.rect_down(rect); ++depth; + // We drop the image size by a factor of 2 each iteration and then assume a + // border of 2 pixels is needed to avoid any border effects of the crop. + grow = grow*2 + 2; } + drectangle rot_rect; + const vector cent = center(chip_locations[i].rect); + rot_rect += rotate_point(cent,chip_locations[i].rect.tl_corner(),chip_locations[i].angle); + rot_rect += rotate_point(cent,chip_locations[i].rect.tr_corner(),chip_locations[i].angle); + rot_rect += rotate_point(cent,chip_locations[i].rect.bl_corner(),chip_locations[i].angle); + rot_rect += rotate_point(cent,chip_locations[i].rect.br_corner(),chip_locations[i].angle); + bounding_box += grow_rect(rot_rect, grow).intersect(get_rect(img)); max_depth = std::max(depth,max_depth); } + //std::cout << "max_depth: " << max_depth << std::endl; + //std::cout << "crop amount: " << bounding_box.area()/(double)get_rect(img).area() << std::endl; // now make an image pyramid - dlib::array levels(max_depth); + dlib::array::pixel_type> > levels(max_depth); if (levels.size() != 0) - pyr(img,levels[0]); + pyr(sub_image(img,bounding_box),levels[0]); for (unsigned long i = 1; i < levels.size(); ++i) pyr(levels[i-1],levels[i]); @@ -1516,31 +1930,88 @@ namespace dlib chips.resize(chip_locations.size()); for (unsigned long i = 0; i < chips.size(); ++i) { - set_image_size(chips[i], chip_locations[i].rows, chip_locations[i].cols); - - // figure out which level in the pyramid to use to extract the chip - int level = -1; - rectangle rect = chip_locations[i].rect; - while (pyr.rect_down(rect).area() > chip_locations[i].size()) + // If the chip doesn't have any rotation or scaling then use the basic version + // of chip extraction that just does a fast copy. + if (chip_locations[i].angle == 0 && + chip_locations[i].rows == chip_locations[i].rect.height() && + chip_locations[i].cols == chip_locations[i].rect.width()) { - ++level; - rect = pyr.rect_down(rect); + impl::basic_extract_image_chip(img, chip_locations[i].rect, chips[i]); } - - // find the appropriate transformation that maps from the chip to the input - // image - from.clear(); - to.clear(); - from.push_back(get_rect(chips[i]).tl_corner()); to.push_back(rotate_point(center(rect),rect.tl_corner(),chip_locations[i].angle)); - from.push_back(get_rect(chips[i]).tr_corner()); to.push_back(rotate_point(center(rect),rect.tr_corner(),chip_locations[i].angle)); - from.push_back(get_rect(chips[i]).bl_corner()); to.push_back(rotate_point(center(rect),rect.bl_corner(),chip_locations[i].angle)); - point_transform_affine trns = find_affine_transform(from,to); - - // now extract the actual chip - if (level == -1) - transform_image(img,chips[i],interpolate_bilinear(),trns); else - transform_image(levels[level],chips[i],interpolate_bilinear(),trns); + { + set_image_size(chips[i], chip_locations[i].rows, chip_locations[i].cols); + + // figure out which level in the pyramid to use to extract the chip + int level = -1; + drectangle rect = translate_rect(chip_locations[i].rect, -bounding_box.tl_corner()); + while (pyr.rect_down(rect).area() > chip_locations[i].size()) + { + ++level; + rect = pyr.rect_down(rect); + } + + // find the appropriate transformation that maps from the chip to the input + // image + from.clear(); + to.clear(); + from.push_back(get_rect(chips[i]).tl_corner()); to.push_back(rotate_point(center(rect),rect.tl_corner(),chip_locations[i].angle)); + from.push_back(get_rect(chips[i]).tr_corner()); to.push_back(rotate_point(center(rect),rect.tr_corner(),chip_locations[i].angle)); + from.push_back(get_rect(chips[i]).bl_corner()); to.push_back(rotate_point(center(rect),rect.bl_corner(),chip_locations[i].angle)); + point_transform_affine trns = find_affine_transform(from,to); + + // now extract the actual chip + if (level == -1) + transform_image(sub_image(img,bounding_box),chips[i],interp,trns); + else + transform_image(levels[level],chips[i],interp,trns); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type1, + typename image_type2 + > + void extract_image_chips( + const image_type1& img, + const std::vector& chip_locations, + dlib::array& chips + ) + { + extract_image_chips(img, chip_locations, chips, interpolate_bilinear()); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type1, + typename image_type2, + typename interpolation_type + > + void extract_image_chip ( + const image_type1& img, + const chip_details& location, + image_type2& chip, + const interpolation_type& interp + ) + { + // If the chip doesn't have any rotation or scaling then use the basic version of + // chip extraction that just does a fast copy. + if (location.angle == 0 && + location.rows == location.rect.height() && + location.cols == location.rect.width()) + { + impl::basic_extract_image_chip(img, location.rect, chip); + } + else + { + std::vector chip_locations(1,location); + dlib::array chips; + extract_image_chips(img, chip_locations, chips, interp); + swap(chips[0], chip); } } @@ -1556,10 +2027,219 @@ namespace dlib image_type2& chip ) { - std::vector chip_locations(1,location); - dlib::array chips; - extract_image_chips(img, chip_locations, chips); - swap(chips[0], chip); + extract_image_chip(img, location, chip, interpolate_bilinear()); + } + +// ---------------------------------------------------------------------------------------- + + inline chip_details get_face_chip_details ( + const full_object_detection& det, + const unsigned long size = 200, + const double padding = 0.2 + ) + { + DLIB_CASSERT(det.num_parts() == 68 || det.num_parts() == 5, + "\t chip_details get_face_chip_details()" + << "\n\t You have to give either a 5 point or 68 point face landmarking output to this function. " + << "\n\t det.num_parts(): " << det.num_parts() + ); + DLIB_CASSERT(padding >= 0 && size > 0, + "\t chip_details get_face_chip_details()" + << "\n\t Invalid inputs were given to this function." + << "\n\t padding: " << padding + << "\n\t size: " << size + ); + + + std::vector from_points, to_points; + if (det.num_parts() == 5) + { + dpoint p0(0.8595674595992, 0.2134981538014); + dpoint p1(0.6460604764104, 0.2289674387677); + dpoint p2(0.1205750620789, 0.2137274526848); + dpoint p3(0.3340850613712, 0.2290642403242); + dpoint p4(0.4901123135679, 0.6277975316475); + + + p0 = (padding+p0)/(2*padding+1); + p1 = (padding+p1)/(2*padding+1); + p2 = (padding+p2)/(2*padding+1); + p3 = (padding+p3)/(2*padding+1); + p4 = (padding+p4)/(2*padding+1); + + from_points.push_back(p0*size); + to_points.push_back(det.part(0)); + + from_points.push_back(p1*size); + to_points.push_back(det.part(1)); + + from_points.push_back(p2*size); + to_points.push_back(det.part(2)); + + from_points.push_back(p3*size); + to_points.push_back(det.part(3)); + + from_points.push_back(p4*size); + to_points.push_back(det.part(4)); + } + else + { + // Average positions of face points 17-67 + const double mean_face_shape_x[] = { + 0.000213256, 0.0752622, 0.18113, 0.29077, 0.393397, 0.586856, 0.689483, 0.799124, + 0.904991, 0.98004, 0.490127, 0.490127, 0.490127, 0.490127, 0.36688, 0.426036, + 0.490127, 0.554217, 0.613373, 0.121737, 0.187122, 0.265825, 0.334606, 0.260918, + 0.182743, 0.645647, 0.714428, 0.793132, 0.858516, 0.79751, 0.719335, 0.254149, + 0.340985, 0.428858, 0.490127, 0.551395, 0.639268, 0.726104, 0.642159, 0.556721, + 0.490127, 0.423532, 0.338094, 0.290379, 0.428096, 0.490127, 0.552157, 0.689874, + 0.553364, 0.490127, 0.42689 + }; + const double mean_face_shape_y[] = { + 0.106454, 0.038915, 0.0187482, 0.0344891, 0.0773906, 0.0773906, 0.0344891, + 0.0187482, 0.038915, 0.106454, 0.203352, 0.307009, 0.409805, 0.515625, 0.587326, + 0.609345, 0.628106, 0.609345, 0.587326, 0.216423, 0.178758, 0.179852, 0.231733, + 0.245099, 0.244077, 0.231733, 0.179852, 0.178758, 0.216423, 0.244077, 0.245099, + 0.780233, 0.745405, 0.727388, 0.742578, 0.727388, 0.745405, 0.780233, 0.864805, + 0.902192, 0.909281, 0.902192, 0.864805, 0.784792, 0.778746, 0.785343, 0.778746, + 0.784792, 0.824182, 0.831803, 0.824182 + }; + + COMPILE_TIME_ASSERT(sizeof(mean_face_shape_x)/sizeof(double) == 68-17); + + for (unsigned long i = 17; i < det.num_parts(); ++i) + { + // Ignore the lower lip + if ((55 <= i && i <= 59) || (65 <= i && i <= 67)) + continue; + // Ignore the eyebrows + if (17 <= i && i <= 26) + continue; + + dpoint p; + p.x() = (padding+mean_face_shape_x[i-17])/(2*padding+1); + p.y() = (padding+mean_face_shape_y[i-17])/(2*padding+1); + from_points.push_back(p*size); + to_points.push_back(det.part(i)); + } + } + + return chip_details(from_points, to_points, chip_dims(size,size)); + } + +// ---------------------------------------------------------------------------------------- + + inline std::vector get_face_chip_details ( + const std::vector& dets, + const unsigned long size = 200, + const double padding = 0.2 + ) + { + std::vector res; + res.reserve(dets.size()); + for (unsigned long i = 0; i < dets.size(); ++i) + res.push_back(get_face_chip_details(dets[i], size, padding)); + return res; + } + +// ---------------------------------------------------------------------------------------- + + + template < + typename image_type + > + void extract_image_4points ( + const image_type& img_, + image_type& out_, + const std::array& pts + ) + { + const_image_view img(img_); + image_view out(out_); + if (out.size() == 0) + return; + + drectangle bounding_box; + for (auto& p : pts) + bounding_box += p; + + const std::array corners = {bounding_box.tl_corner(), bounding_box.tr_corner(), + bounding_box.bl_corner(), bounding_box.br_corner()}; + + matrix dists(4,4); + for (long r = 0; r < dists.nr(); ++r) + { + for (long c = 0; c < dists.nc(); ++c) + { + dists(r,c) = length_squared(corners[r] - pts[c]); + } + } + + matrix idists = matrix_cast(-round(std::numeric_limits::max()*(dists/max(dists)))); + + + const drectangle area = get_rect(out); + std::vector from_points = {area.tl_corner(), area.tr_corner(), + area.bl_corner(), area.br_corner()}; + + // find the assignment of corners to pts + auto assignment = max_cost_assignment(idists); + std::vector to_points(4); + for (size_t i = 0; i < assignment.size(); ++i) + to_points[i] = pts[assignment[i]]; + + auto tform = find_projective_transform(from_points, to_points); + transform_image(img_, out_, interpolate_bilinear(), tform); + } + + template < + typename image_type + > + void extract_image_4points ( + const image_type& img, + image_type& out, + const std::array& lines + ) + { + extract_image_4points(img, out, find_convex_quadrilateral(lines)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + image_type jitter_image( + const image_type& img, + dlib::rand& rnd + ) + { + DLIB_CASSERT(num_rows(img)*num_columns(img) != 0); + DLIB_CASSERT(num_rows(img)==num_columns(img)); + + const double max_rotation_degrees = 3; + const double min_object_height = 0.97; + const double max_object_height = 0.99999; + const double translate_amount = 0.02; + + + const auto rect = shrink_rect(get_rect(img),3); + + // perturb the location of the crop by a small fraction of the object's size. + const point rand_translate = dpoint(rnd.get_double_in_range(-translate_amount,translate_amount)*rect.width(), + rnd.get_double_in_range(-translate_amount,translate_amount)*rect.height()); + + // perturb the scale of the crop by a fraction of the object's size + const double rand_scale_perturb = rnd.get_double_in_range(min_object_height, max_object_height); + + const long box_size = rect.height()/rand_scale_perturb; + const auto crop_rect = centered_rect(center(rect)+rand_translate, box_size, box_size); + const double angle = rnd.get_double_in_range(-max_rotation_degrees, max_rotation_degrees)*pi/180; + image_type crop; + extract_image_chip(img, chip_details(crop_rect, chip_dims(num_rows(img),num_columns(img)), angle), crop); + if (rnd.get_random_double() > 0.5) + flip_image_left_right(crop); + + return crop; } // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/interpolation_abstract.h b/lib/3rdParty/dlib/include/dlib/image_transforms/interpolation_abstract.h index 6058a3c1..f1597068 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/interpolation_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/interpolation_abstract.h @@ -6,6 +6,7 @@ #include "../pixel.h" #include "../image_processing/full_object_detection_abstract.h" #include "../image_processing/generic_image.h" +#include namespace dlib { @@ -414,6 +415,28 @@ namespace dlib - Uses the bilinear interpolation to perform the necessary pixel interpolation. !*/ +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void resize_image ( + double size_scale, + image_type& img + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - pixel_traits::pixel_type>::has_alpha == false + ensures + - Resizes img so that each of it's dimensions are size_scale times larger than img. + In particular, we will have: + - #img.nr() == std::round(size_scale*img.nr()) + - #img.nc() == std::round(size_scale*img.nc()) + - #img == a bilinearly interpolated copy of the input image. + !*/ + // ---------------------------------------------------------------------------------------- template < @@ -443,18 +466,41 @@ namespace dlib // ---------------------------------------------------------------------------------------- template < - typename image_type, - typename T + typename image_type > - void add_image_left_right_flips ( - dlib::array& images, - std::vector >& objects + point_transform_affine flip_image_left_right ( + image_type& img ); /*! requires - image_type == an image object that implements the interface defined in dlib/image_processing/generic_image.h - - T == rectangle or full_object_detection + ensures + - This function is identical to the above version of flip_image_left_right() + except that it operates in-place. + - #img.nr() == img.nr() + - #img.nc() == img.nc() + - #img == a copy of img which has been flipped from left to right. + (i.e. it is flipped as if viewed though a mirror) + - returns a transformation object that maps points in img into their + corresponding location in #img. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename image_array_type, + typename T + > + void add_image_left_right_flips ( + image_array_type& images, + std::vector >& objects + ); + /*! + requires + - image_array_type == a dlib::array or std::vector of image objects that each + implement the interface defined in dlib/image_processing/generic_image.h + - T == rectangle, full_object_detection, or mmod_rect - images.size() == objects.size() ensures - This function computes all the left/right flips of the contents of images and @@ -472,23 +518,23 @@ namespace dlib // ---------------------------------------------------------------------------------------- template < - typename image_type, + typename image_array_type, typename T, typename U > void add_image_left_right_flips ( - dlib::array& images, + image_array_type& images, std::vector >& objects, std::vector >& objects2 ); /*! requires - - image_type == an image object that implements the interface defined in - dlib/image_processing/generic_image.h + - image_array_type == a dlib::array or std::vector of image objects that each + implement the interface defined in dlib/image_processing/generic_image.h - images.size() == objects.size() - images.size() == objects2.size() - - T == rectangle or full_object_detection - - U == rectangle or full_object_detection + - T == rectangle, full_object_detection, or mmod_rect + - U == rectangle, full_object_detection, or mmod_rect ensures - This function computes all the left/right flips of the contents of images and then appends them onto the end of the images array. It also finds the @@ -507,27 +553,27 @@ namespace dlib // ---------------------------------------------------------------------------------------- template < - typename image_type, + typename image_array_type, typename EXP, typename T, typename U > void add_image_rotations ( const matrix_exp& angles, - dlib::array& images, + image_array_type& images, std::vector >& objects, std::vector >& objects2 ); /*! requires - - image_type == an image object that implements the interface defined in - dlib/image_processing/generic_image.h + - image_array_type == a dlib::array or std::vector of image objects that each + implement the interface defined in dlib/image_processing/generic_image.h - is_vector(angles) == true - angles.size() > 0 - images.size() == objects.size() - images.size() == objects2.size() - - T == rectangle or full_object_detection - - U == rectangle or full_object_detection + - T == rectangle, full_object_detection, or mmod_rect + - U == rectangle, full_object_detection, or mmod_rect ensures - This function computes angles.size() different rotations of all the given images and then replaces the contents of images with those rotations of the @@ -547,23 +593,23 @@ namespace dlib // ---------------------------------------------------------------------------------------- template < - typename image_type, + typename image_array_type, typename EXP, typename T > void add_image_rotations ( const matrix_exp& angles, - dlib::array& images, + image_array_type& images, std::vector >& objects ); /*! requires - - image_type == an image object that implements the interface defined in - dlib/image_processing/generic_image.h + - image_array_type == a dlib::array or std::vector of image objects that each + implement the interface defined in dlib/image_processing/generic_image.h - is_vector(angles) == true - angles.size() > 0 - images.size() == objects.size() - - T == rectangle or full_object_detection + - T == rectangle, full_object_detection, or mmod_rect ensures - This function is identical to the add_image_rotations() define above except that it doesn't have objects2 as an argument. @@ -572,16 +618,16 @@ namespace dlib // ---------------------------------------------------------------------------------------- template < - typename image_type + typename image_array_type > void flip_image_dataset_left_right ( - dlib::array& images, + image_array_type& images, std::vector >& objects ); /*! requires - - image_type == an image object that implements the interface defined in - dlib/image_processing/generic_image.h + - image_array_type == a dlib::array or std::vector of image objects that each + implement the interface defined in dlib/image_processing/generic_image.h - images.size() == objects.size() ensures - This function replaces each image in images with the left/right flipped @@ -597,17 +643,17 @@ namespace dlib // ---------------------------------------------------------------------------------------- template < - typename image_type + typename image_array_type > void flip_image_dataset_left_right ( - dlib::array& images, + image_array_type& images, std::vector >& objects, std::vector >& objects2 ); /*! requires - - image_type == an image object that implements the interface defined in - dlib/image_processing/generic_image.h + - image_array_type == a dlib::array or std::vector of image objects that each + implement the interface defined in dlib/image_processing/generic_image.h - images.size() == objects.size() - images.size() == objects2.size() ensures @@ -628,16 +674,17 @@ namespace dlib template < typename pyramid_type, - typename image_type + typename image_array_type > void upsample_image_dataset ( - dlib::array& images, - std::vector >& objects + image_array_type& images, + std::vector >& objects, + unsigned long max_image_size = std::numeric_limits::max() ); /*! requires - - image_type == an image object that implements the interface defined in - dlib/image_processing/generic_image.h + - image_array_type == a dlib::array or std::vector of image objects that each + implement the interface defined in dlib/image_processing/generic_image.h - images.size() == objects.size() ensures - This function replaces each image in images with an upsampled version of that @@ -645,6 +692,7 @@ namespace dlib pyramid_type. Therefore, #images[i] will contain the larger upsampled version of images[i]. It also adjusts all the rectangles in objects so that they still bound the same visual objects in each image. + - Input images already containing more than max_image_size pixels are not upsampled. - #images.size() == image.size() - #objects.size() == objects.size() - for all valid i: @@ -655,17 +703,47 @@ namespace dlib template < typename pyramid_type, - typename image_type + typename image_array_type > void upsample_image_dataset ( - dlib::array& images, - std::vector >& objects, - std::vector >& objects2 + image_array_type& images, + std::vector>& objects, + unsigned long max_image_size = std::numeric_limits::max() ); /*! requires - - image_type == an image object that implements the interface defined in - dlib/image_processing/generic_image.h + - image_array_type == a dlib::array or std::vector of image objects that each + implement the interface defined in dlib/image_processing/generic_image.h + - images.size() == objects.size() + ensures + - This function replaces each image in images with an upsampled version of that + image. Each image is upsampled using pyramid_up() and the given + pyramid_type. Therefore, #images[i] will contain the larger upsampled + version of images[i]. It also adjusts all the rectangles in objects so that + they still bound the same visual objects in each image. + - Input images already containing more than max_image_size pixels are not upsampled. + - #images.size() == image.size() + - #objects.size() == objects.size() + - for all valid i: + #objects[i].size() == objects[i].size() + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename pyramid_type, + typename image_array_type, + > + void upsample_image_dataset ( + image_array_type& images, + std::vector >& objects, + std::vector >& objects2, + unsigned long max_image_size = std::numeric_limits::max() + ); + /*! + requires + - image_array_type == a dlib::array or std::vector of image objects that each + implement the interface defined in dlib/image_processing/generic_image.h - images.size() == objects.size() - images.size() == objects2.size() ensures @@ -674,6 +752,7 @@ namespace dlib pyramid_type. Therefore, #images[i] will contain the larger upsampled version of images[i]. It also adjusts all the rectangles in objects and objects2 so that they still bound the same visual objects in each image. + - Input images already containing more than max_image_size pixels are not upsampled. - #images.size() == image.size() - #objects.size() == objects.size() - #objects2.size() == objects2.size() @@ -685,16 +764,16 @@ namespace dlib // ---------------------------------------------------------------------------------------- - template + template void rotate_image_dataset ( double angle, - dlib::array& images, + image_array_type& images, std::vector >& objects ); /*! requires - - image_type == an image object that implements the interface defined in - dlib/image_processing/generic_image.h + - image_array_type == a dlib::array or std::vector of image objects that each + implement the interface defined in dlib/image_processing/generic_image.h - images.size() == objects.size() ensures - This function replaces each image in images with a rotated version of that @@ -715,17 +794,17 @@ namespace dlib // ---------------------------------------------------------------------------------------- - template + template void rotate_image_dataset ( double angle, - dlib::array& images, + image_array_type& images, std::vector >& objects, std::vector >& objects2 ); /*! requires - - image_type == an image object that implements the interface defined in - dlib/image_processing/generic_image.h + - image_array_type == a dlib::array or std::vector of image objects that each + implement the interface defined in dlib/image_processing/generic_image.h - images.size() == objects.size() - images.size() == objects2.size() ensures @@ -907,8 +986,8 @@ namespace dlib contained within the rectangle this->rect and that prior to extraction the image should be rotated counter-clockwise by this->angle radians. Finally, the extracted chip should have this->rows rows and this->cols columns in it - regardless of the shape of this->rect. - + regardless of the shape of this->rect. This means that the extracted chip + will be stretched to fit via bilinear interpolation when necessary. !*/ chip_details( @@ -923,7 +1002,31 @@ namespace dlib !*/ chip_details( - const rectangle& rect_, + const drectangle& rect_ + ); + /*! + ensures + - #rect == rect_ + - #size() == rect_.area() + - #angle == 0 + - #rows == rect_.height() + - #cols == rect_.width() + !*/ + + chip_details( + const rectangle& rect_ + ); + /*! + ensures + - #rect == rect_ + - #size() == rect_.area() + - #angle == 0 + - #rows == rect_.height() + - #cols == rect_.width() + !*/ + + chip_details( + const drectangle& rect_, unsigned long size_ ); /*! @@ -944,7 +1047,7 @@ namespace dlib !*/ chip_details( - const rectangle& rect_, + const drectangle& rect_, unsigned long size_, double angle_ ); @@ -966,7 +1069,7 @@ namespace dlib !*/ chip_details( - const rectangle& rect_, + const drectangle& rect_, const chip_dims& dims ); /*! @@ -979,7 +1082,7 @@ namespace dlib !*/ chip_details( - const rectangle& rect_, + const drectangle& rect_, const chip_dims& dims, double angle_ ); @@ -992,28 +1095,83 @@ namespace dlib - #cols == dims.cols !*/ + template + chip_details( + const std::vector >& chip_points, + const std::vector >& img_points, + const chip_dims& dims + ); + /*! + requires + - chip_points.size() == img_points.size() + - chip_points.size() >= 2 + ensures + - The chip will be extracted such that the pixel locations chip_points[i] + in the chip are mapped to img_points[i] in the original image by a + similarity transform. That is, if you know the pixelwize mapping you + want between the chip and the original image then you use this function + of chip_details constructor to define the mapping. + - #rows == dims.rows + - #cols == dims.cols + - #size() == dims.rows*dims.cols + - #rect and #angle are computed based on the given size of the output chip + (specified by dims) and the similarity transform between the chip and + image (specified by chip_points and img_points). + !*/ + inline unsigned long size() const { return rows*cols; } /*! ensures - returns the number of pixels in this chip. This is just rows*cols. !*/ - rectangle rect; + drectangle rect; double angle; unsigned long rows; unsigned long cols; }; +// ---------------------------------------------------------------------------------------- + + point_transform_affine get_mapping_to_chip ( + const chip_details& details + ); + /*! + ensures + - returns a transformation that maps from the pixels in the original image + to the pixels in the cropped image defined by the given details object. + !*/ + +// ---------------------------------------------------------------------------------------- + + full_object_detection map_det_to_chip ( + const full_object_detection& det, + const chip_details& details + ); + /*! + ensures + - Maps the given detection into the pixel space of the image chip defined by + the given details object. That is, this function returns an object D such + that: + - D.get_rect() == a box that bounds the same thing in the image chip as + det.get_rect() bounds in the original image the chip is extracted from. + - for all valid i: + - D.part(i) == the location in the image chip corresponding to + det.part(i) in the original image. + !*/ + // ---------------------------------------------------------------------------------------- template < typename image_type1, - typename image_type2 + typename image_type2, + typename interpolation_type > void extract_image_chips ( const image_type1& img, const std::vector& chip_locations, - dlib::array& chips + dlib::array& chips, + const interpolation_type& interp ); /*! requires @@ -1024,12 +1182,15 @@ namespace dlib - pixel_traits::pixel_type>::has_alpha == false - for all valid i: - chip_locations[i].rect.is_empty() == false - - chip_locations[i].size != 0 + - chip_locations[i].size() != 0 + - interpolation_type == interpolate_nearest_neighbor, interpolate_bilinear, + interpolate_quadratic, or a type with a compatible interface. ensures - This function extracts "chips" from an image. That is, it takes a list of rectangular sub-windows (i.e. chips) within an image and extracts those sub-windows, storing each into its own image. It also scales and rotates the image chips according to the instructions inside each chip_details object. + It uses the interpolation method supplied as a parameter. - #chips == the extracted image chips - #chips.size() == chip_locations.size() - for all valid i: @@ -1043,8 +1204,41 @@ namespace dlib - Any pixels in an image chip that go outside img are set to 0 (i.e. black). !*/ + template < + typename image_type1, + typename image_type2 + > + void extract_image_chips ( + const image_type1& img, + const std::vector& chip_locations, + dlib::array& chips + ); + /*! + ensures + - This function is a simple convenience / compatibility wrapper that calls the + above-defined extract_image_chips() function using bilinear interpolation. + !*/ + // ---------------------------------------------------------------------------------------- + template < + typename image_type1, + typename image_type2, + typename interpolation_type + > + void extract_image_chip ( + const image_type1& img, + const chip_details& chip_location, + image_type2& chip, + const interpolation_type& interp + ); + /*! + ensures + - This function simply calls extract_image_chips() with a single chip location + and stores the single output chip into #chip. It uses the provided + interpolation method. + !*/ + template < typename image_type1, typename image_type2 @@ -1056,11 +1250,281 @@ namespace dlib ); /*! ensures - - This function simply calls extract_image_chips() with a single chip location - and stores the single output chip into #chip. + - This function is a simple convenience / compatibility wrapper that calls the + above-defined extract_image_chip() function using bilinear interpolation. !*/ // ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + struct sub_image_proxy + { + /*! + REQUIREMENTS ON image_type + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + + WHAT THIS OBJECT REPRESENTS + This is a lightweight image object for referencing a subwindow of an image. + It implements the generic image interface and can therefore be used with + any function that expects a generic image, excepting that you cannot change + the size of a sub_image_proxy. + + Note that it only stores a pointer to the image data given to its + constructor and therefore does not perform a copy. Moreover, this means + that an instance of this object becomes invalid after the underlying image + data it references is destroyed. + !*/ + sub_image_proxy ( + T& img, + const rectangle& rect + ); + /*! + ensures + - This object is an image that represents the part of img contained within + rect. If rect is larger than img then rect is cropped so that it does + not go outside img. + !*/ + }; + + template < + typename image_type + > + sub_image_proxy sub_image ( + image_type& img, + const rectangle& rect + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + ensures + - returns sub_image_proxy(img,rect) + !*/ + + template + sub_image_proxy sub_image ( + T* img, + long nr, + long nc, + long row_stride + ); + /*! + requires + - img == a pointer to at least nr*row_stride T objects + - nr >= 0 + - nc >= 0 + - row_stride >= 0 + ensures + - This function returns an image that is just a thin wrapper around the given + pointer. It will have the dimensions defined by the supplied longs. To be + precise, this function returns an image object IMG such that: + - image_data(IMG) == img + - num_rows(IMG) == nr + - num_columns(IMG) == nc + - width_step(IMG) == row_stride*sizeof(T) + - IMG contains pixels of type T. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + struct const_sub_image_proxy + { + /*! + REQUIREMENTS ON image_type + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + + WHAT THIS OBJECT REPRESENTS + This object is just like sub_image_proxy except that it does not allow the + pixel data to be modified. + !*/ + const_sub_image_proxy ( + const T& img, + const rectangle& rect + ); + /*! + ensures + - This object is an image that represents the part of img contained within + rect. If rect is larger than img then rect is cropped so that it does + not go outside img. + !*/ + }; + + template < + typename image_type + > + const const_sub_image_proxy sub_image ( + const image_type& img, + const rectangle& rect + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + ensures + - returns const_sub_image_proxy(img,rect) + !*/ + + template + const const_sub_image_proxy sub_image ( + const T* img, + long nr, + long nc, + long row_stride + ); + /*! + requires + - img == a pointer to at least nr*row_stride T objects + - nr >= 0 + - nc >= 0 + - row_stride >= 0 + ensures + - This function returns an image that is just a thin wrapper around the given + pointer. It will have the dimensions defined by the supplied longs. To be + precise, this function returns an image object IMG such that: + - image_data(IMG) == img + - num_rows(IMG) == nr + - num_columns(IMG) == nc + - width_step(IMG) == row_stride*sizeof(T) + - IMG contains pixels of type T. + !*/ + +// ---------------------------------------------------------------------------------------- + + chip_details get_face_chip_details ( + const full_object_detection& det, + const unsigned long size = 200, + const double padding = 0.2 + ); + /*! + requires + - det.num_parts() == 68 || det.num_parts() == 5 + - size > 0 + - padding >= 0 + ensures + - This function assumes det contains a human face detection with face parts + annotated using the annotation scheme from the iBUG 300-W face landmark + dataset or a 5 point face annotation. Given these assumptions, it creates a + chip_details object that will extract a copy of the face that has been + rotated upright, centered, and scaled to a standard size when given to + extract_image_chip(). + - This function is specifically calibrated to work with one of these models: + - http://dlib.net/files/shape_predictor_5_face_landmarks.dat.bz2 + - http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2 + - The extracted chips will have size rows and columns in them. + - if padding == 0 then the chip will be closely cropped around the face. + Setting larger padding values will result a looser cropping. In particular, + a padding of 0.5 would double the width of the cropped area, a value of 1 + would triple it, and so forth. + - The 5 point face annotation scheme is assumed to be: + - det part 0 == left eye corner, outside part of eye. + - det part 1 == left eye corner, inside part of eye. + - det part 2 == right eye corner, outside part of eye. + - det part 3 == right eye corner, inside part of eye. + - det part 4 == immediately under the nose, right at the top of the philtrum. + !*/ + +// ---------------------------------------------------------------------------------------- + + std::vector get_face_chip_details ( + const std::vector& dets, + const unsigned long size = 200, + const double padding = 0.2 + ); + /*! + requires + - for all valid i: + - det[i].num_parts() == 68 + - size > 0 + - padding >= 0 + ensures + - This function is identical to the version of get_face_chip_details() defined + above except that it creates and returns an array of chip_details objects, + one for each input full_object_detection. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void extract_image_4points ( + const image_type& img, + image_type& out, + const std::array& pts + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - pixel_traits::pixel_type>::has_alpha == false + ensures + - The 4 points in pts define a convex quadrilateral and this function extracts + that part of the input image img and stores it into #out. Therefore, each + corner of the quadrilateral is associated to a corner of #out and bilinear + interpolation and a projective mapping is used to transform the pixels in the + quadrilateral into #out. To determine which corners of the quadrilateral map + to which corners of #out we fit the tightest possible rectangle to the + quadrilateral and map its vertices to their nearest rectangle corners. These + corners are then trivially mapped to #out (i.e. upper left corner to upper + left corner, upper right corner to upper right corner, etc.). + - #out.nr() == out.nr() && #out.nc() == out.nc(). + I.e. out should already be sized to whatever size you want it to be. + !*/ + + template < + typename image_type + > + void extract_image_4points ( + const image_type& img, + image_type& out, + const std::array& lines + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - pixel_traits::pixel_type>::has_alpha == false + ensures + - This routine finds the 4 intersecting points of the given lines which form a + convex quadrilateral and uses them in a call to the version of + extract_image_4points() defined above. i.e. extract_image_4points(img, out, + intersections_between_lines) + throws + - no_convex_quadrilateral: this is thrown if you can't make a convex + quadrilateral out of the given lines. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + image_type jitter_image( + const image_type& img, + dlib::rand& rnd + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - pixel_traits::pixel_type>::has_alpha == false + - img.size() > 0 + - img.nr() == img.nc() + ensures + - Randomly jitters the image a little bit and returns this new jittered image. + To be specific, the returned image has the same size as img and will look + generally similar. The difference is that the returned image will have been + slightly rotated, zoomed, and translated. There is also a 50% chance it will + be mirrored left to right. + !*/ + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/label_connected_blobs.h b/lib/3rdParty/dlib/include/dlib/image_transforms/label_connected_blobs.h index c25346c7..30685eff 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/label_connected_blobs.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/label_connected_blobs.h @@ -7,12 +7,29 @@ #include "../geometry.h" #include #include +#include "thresholding.h" +#include "assign_image.h" +#include namespace dlib { // ---------------------------------------------------------------------------------------- + struct neighbors_24 + { + void operator() ( + const point& p, + std::vector& neighbors + ) const + { + for (long i = -2; i <= 2; ++i) + for (long j = -2; j <= 2; ++j) + if (i!=0||j!=0) + neighbors.push_back(point(p.x()+i,p.y()+j)); + } + }; + struct neighbors_8 { void operator() ( @@ -180,6 +197,153 @@ namespace dlib return next; } + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + unsigned long label_connected_blobs_watershed ( + const in_image_type& img_, + out_image_type& labels_, + typename pixel_traits::pixel_type>::basic_pixel_type background_thresh, + const double smoothing = 0 + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(is_same_object(img_, labels_) == false, + "\t unsigned long segment_image_watersheds()" + << "\n\t The input images can't be the same object." + ); + + DLIB_ASSERT(smoothing >= 0); + COMPILE_TIME_ASSERT(is_unsigned_type::pixel_type>::value); + + + struct watershed_points + { + watershed_points() = default; + watershed_points(const point& p_, float score_, unsigned int label_): p(p_), score(score_), label(label_) {} + + point p; + float score = 0; + unsigned int label = std::numeric_limits::max(); + + bool is_seed() const { return label == std::numeric_limits::max(); } + + bool operator< (const watershed_points& rhs) const + { + // If two pixels have the same score then we take the one with the smallest + // label out of the priority queue first. We do this so that seed points + // that are downhill from some larger blob will be consumed by it if they + // haven't grown before the larger blob's flooding reaches them. Doing + // this helps a lot to avoid spuriously splitting blobs. + if (score == rhs.score) + { + return label > rhs.label; + } + return score < rhs.score; + } + + }; + + const_image_view img(img_); + image_view labels(labels_); + + labels.set_size(img.nr(), img.nc()); + // Initially, all pixels have the background label of 0. + assign_all_pixels(labels, 0); + + std::priority_queue next; + + + // Note that we never blur the image values we use to check against the + // background_thresh. We do however blur, if smoothing!=0, the pixel values used + // to do the watershed. + in_image_type img2_; + if (smoothing != 0) + gaussian_blur(img_, img2_, smoothing); + const_image_view img2view(img2_); + // point us at img2 if we are doing smoothing, otherwise point us at the input + // image. + const auto& img2 = smoothing!=0?img2view:img; + + // first find all the local maxima + for (long r = 1; r+1 < img.nr(); ++r) + { + for (long c = 1; c+1 < img.nc(); ++c) + { + + if (img[r][c] < background_thresh) + continue; + + auto val = img2[r][c]; + // if img2[r][c] isn't a local maximum then skip it + if (val < img2[r+1][c] || + val < img2[r-1][c] || + val < img2[r][c+1] || + val < img2[r][c-1] + ) + { + continue; + } + + next.push(watershed_points(point(c,r), val, std::numeric_limits::max())); + } + } + + + const rectangle area = get_rect(img); + + + unsigned int next_label = 1; + + + std::vector neighbors; + neighbors_8 get_neighbors; + while(next.size() > 0) + { + auto p = next.top(); + next.pop(); + + unsigned int label; + // If the next pixel is a seed of a new blob and is still labeled as a + // background pixel (i.e. it hasn't been flooded over by a neighboring blob and + // consumed by it) then we create a new label for this new blob. + if (p.is_seed() && labels[p.p.y()][p.p.x()] == 0) + label = next_label++; + else + label = p.label; + + + neighbors.clear(); + get_neighbors(p.p, neighbors); + for (auto& n : neighbors) + { + if (!area.contains(n) || labels[n.y()][n.x()] != 0 || img[n.y()][n.x()] < background_thresh) + continue; + + labels[n.y()][n.x()] = label; + next.push(watershed_points(n, img2[n.y()][n.x()], label)); + } + } + + return next_label; + } + + template < + typename in_image_type, + typename out_image_type + > + unsigned long label_connected_blobs_watershed ( + const in_image_type& img, + out_image_type& labels + ) + { + return label_connected_blobs_watershed(img, labels, partition_pixels(img)); + } + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/label_connected_blobs_abstract.h b/lib/3rdParty/dlib/include/dlib/image_transforms/label_connected_blobs_abstract.h index 5dc98400..d09ef04b 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/label_connected_blobs_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/label_connected_blobs_abstract.h @@ -12,6 +12,24 @@ namespace dlib // ---------------------------------------------------------------------------------------- + struct neighbors_24 + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a pixel neighborhood generating functor for + use with the label_connected_blobs() routine defined below. + !*/ + + void operator() ( + const point& p, + std::vector& neighbors + ) const; + /*! + ensures + - adds the 24 neighboring pixels surrounding p into neighbors + !*/ + }; + struct neighbors_8 { /*! @@ -191,6 +209,68 @@ namespace dlib called with points outside the image. !*/ +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + unsigned long label_connected_blobs_watershed ( + const in_image_type& img, + out_image_type& labels, + typename pixel_traits::pixel_type>::basic_pixel_type background_thresh, + const double smoothing = 0 + ); + /*! + requires + - in_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - out_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - in_image_type must contain a grayscale pixel type. + - out_image_type must contain an unsigned integer pixel type. + - is_same_object(img, labels) == false + - smoothing >= 0 + ensures + - This routine performs a watershed segmentation of the given input image and + labels each resulting flooding region with a unique integer label. It does + this by marking the brightest pixels as sources of flooding and then flood + fills the image outward from those sources. Each flooded area is labeled + with the identity of the source pixel and flooding stops when another flooded + area is reached or pixels with values < background_thresh are encountered. + - The flooding will also overrun a source pixel if that source pixel has yet to + label any neighboring pixels. This behavior helps to mitigate spurious + splits of objects due to noise. You can further control this behavior by + setting the smoothing parameter. The flooding will take place on an image + that has been Gaussian blurred with a sigma==smoothing. So setting smoothing + to a larger number will in general cause more regions to be merged together. + Note that the smoothing parameter has no effect on the interpretation of + background_thresh since the decision of "background or not background" is + always made relative to the unsmoothed input image. + - #labels.nr() == img.nr() + - #labels.nc() == img.nc() + - for all valid r and c: + - if (img[r][c] < background_thresh) then + - #labels[r][c] == 0, (i.e. the pixel is labeled as background) + - else + - #labels[r][c] == an integer value indicating the identity of the segment + containing the pixel img[r][c]. + - returns the number of labeled segments, including the background segment. + Therefore, the returned number is 1+(the max value in #labels). + !*/ + + template < + typename in_image_type, + typename out_image_type + > + unsigned long label_connected_blobs_watershed ( + const in_image_type& img, + out_image_type& labels + ); + /*! + simply invokes: return label_connected_blobs_watershed(img, labels, partition_pixels(img)); + !*/ + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/lbp.h b/lib/3rdParty/dlib/include/dlib/image_transforms/lbp.h new file mode 100644 index 00000000..b6bbac9c --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/lbp.h @@ -0,0 +1,307 @@ +// Copyright (C) 2014 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LBP_Hh_ +#define DLIB_LBP_Hh_ + +#include "lbp_abstract.h" +#include "../image_processing/generic_image.h" +#include "assign_image.h" +#include "../pixel.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type, + typename image_type2 + > + void make_uniform_lbp_image ( + const image_type& img_, + image_type2& lbp_ + ) + { + const static unsigned char uniform_lbps[] = { + 0, 1, 2, 3, 4, 58, 5, 6, 7, 58, 58, 58, 8, 58, 9, 10, 11, 58, 58, 58, 58, 58, + 58, 58, 12, 58, 58, 58, 13, 58, 14, 15, 16, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 17, 58, 58, 58, 58, 58, 58, 58, 18, 58, 58, 58, 19, 58, + 20, 21, 22, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 23, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 24, 58, 58, 58, 58, 58, 58, 58, 25, 58, + 58, 58, 26, 58, 27, 28, 29, 30, 58, 31, 58, 58, 58, 32, 58, 58, 58, 58, 58, 58, + 58, 33, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 34, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 35, 36, 37, 58, 38, 58, 58, 58, 39, 58, 58, + 58, 58, 58, 58, 58, 40, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 41, 42, 43, 58, 44, 58, 58, 58, 45, 58, 58, 58, 58, 58, 58, 58, 46, 47, 48, + 58, 49, 58, 58, 58, 50, 51, 52, 58, 53, 54, 55, 56, 57 + }; + + COMPILE_TIME_ASSERT(sizeof(uniform_lbps) == 256); + + const_image_view img(img_); + image_view lbp(lbp_); + + lbp.set_size(img.nr(), img.nc()); + + // set all the border pixels to the "non-uniform LBP value". + assign_border_pixels(lbp, 1, 1, 58); + + typedef typename image_traits::pixel_type pixel_type; + typedef typename pixel_traits::basic_pixel_type basic_pixel_type; + + for (long r = 1; r+1 < img.nr(); ++r) + { + for (long c = 1; c+1 < img.nc(); ++c) + { + const basic_pixel_type pix = get_pixel_intensity(img[r][c]); + unsigned char b1 = 0; + unsigned char b2 = 0; + unsigned char b3 = 0; + unsigned char b4 = 0; + unsigned char b5 = 0; + unsigned char b6 = 0; + unsigned char b7 = 0; + unsigned char b8 = 0; + + unsigned char x = 0; + if (get_pixel_intensity(img[r-1][c-1]) > pix) b1 = 0x80; + if (get_pixel_intensity(img[r-1][c ]) > pix) b2 = 0x40; + if (get_pixel_intensity(img[r-1][c+1]) > pix) b3 = 0x20; + x |= b1; + if (get_pixel_intensity(img[r ][c-1]) > pix) b4 = 0x10; + x |= b2; + if (get_pixel_intensity(img[r ][c+1]) > pix) b5 = 0x08; + x |= b3; + if (get_pixel_intensity(img[r+1][c-1]) > pix) b6 = 0x04; + x |= b4; + if (get_pixel_intensity(img[r+1][c ]) > pix) b7 = 0x02; + x |= b5; + if (get_pixel_intensity(img[r+1][c+1]) > pix) b8 = 0x01; + + x |= b6; + x |= b7; + x |= b8; + + lbp[r][c] = uniform_lbps[x]; + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type, + typename T + > + void extract_histogram_descriptors ( + const image_type& img_, + const point& loc, + std::vector& histograms, + const unsigned int cell_size = 10, + const unsigned int block_size = 4, + const unsigned int max_val = 58 + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(cell_size >= 1 && block_size >= 1 && max_val < 256 && + (unsigned int)max(mat(img_)) <= max_val, + "\t void extract_histogram_descriptors()" + << "\n\t Invalid inputs were given to this function." + << "\n\t cell_size: " << cell_size + << "\n\t block_size: " << block_size + << "\n\t max_val: " << max_val + << "\n\t max(mat(img_)): " << max(mat(img_)) + ); + + typedef typename image_traits::pixel_type pixel_type; + COMPILE_TIME_ASSERT((is_same_type::value)); + + const_image_view img(img_); + + const rectangle area = get_rect(img); + const rectangle window = centered_rect(loc, block_size*cell_size, block_size*cell_size); + unsigned int cell_top = window.top(); + for (unsigned int br = 0; br < block_size; ++br) + { + unsigned int cell_left = window.left(); + for (unsigned int bc = 0; bc < block_size; ++bc) + { + // figure out the cell boundaries + rectangle cell(cell_left, cell_top, cell_left+cell_size-1, cell_top+cell_size-1); + cell = cell.intersect(area); + + // make the actual histogram for this cell + unsigned int hist[256] = {0}; + for (long r = cell.top(); r <= cell.bottom(); ++r) + { + for (long c = cell.left(); c <= cell.right(); ++c) + { + hist[img[r][c]]++; + } + } + + // copy histogram into the output. + histograms.insert(histograms.end(), hist, hist + max_val+1); + + cell_left += cell_size; + } + cell_top += cell_size; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type, + typename T + > + void extract_uniform_lbp_descriptors ( + const image_type& img, + std::vector& feats, + const unsigned int cell_size = 10 + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(cell_size >= 1, + "\t void extract_uniform_lbp_descriptors()" + << "\n\t Invalid inputs were given to this function." + << "\n\t cell_size: " << cell_size + ); + + feats.clear(); + array2d lbp; + make_uniform_lbp_image(img, lbp); + for (long r = 0; r < lbp.nr(); r+=cell_size) + { + for (long c = 0; c < lbp.nc(); c+=cell_size) + { + const rectangle cell = rectangle(c,r,c+cell_size-1,r+cell_size-1).intersect(get_rect(lbp)); + // make the actual histogram for this cell + unsigned int hist[59] = {0}; + for (long r = cell.top(); r <= cell.bottom(); ++r) + { + for (long c = cell.left(); c <= cell.right(); ++c) + { + hist[lbp[r][c]]++; + } + } + + // copy histogram into the output. + feats.insert(feats.end(), hist, hist + 59); + } + } + + for (unsigned long i = 0; i < feats.size(); ++i) + feats[i] = std::sqrt(feats[i]); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type, + typename T + > + void extract_highdim_face_lbp_descriptors ( + const image_type& img, + const full_object_detection& det, + std::vector& feats + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(det.num_parts() == 68, + "\t void extract_highdim_face_lbp_descriptors()" + << "\n\t Invalid inputs were given to this function." + << "\n\t det.num_parts(): " << det.num_parts() + ); + + const unsigned long num_scales = 5; + feats.clear(); + dlib::vector l, r; + double cnt = 0; + // Find the center of the left eye by averaging the points around + // the eye. + for (unsigned long i = 36; i <= 41; ++i) + { + l += det.part(i); + ++cnt; + } + l /= cnt; + + // Find the center of the right eye by averaging the points around + // the eye. + cnt = 0; + for (unsigned long i = 42; i <= 47; ++i) + { + r += det.part(i); + ++cnt; + } + r /= cnt; + + // We only do feature extraction from these face parts. These are things like the + // corners of the eyes and mouth and stuff like that. + std::vector parts; + parts.reserve(30); + parts.push_back(l); + parts.push_back(r); + parts.push_back(det.part(17)); + parts.push_back(det.part(21)); + parts.push_back(det.part(22)); + parts.push_back(det.part(26)); + parts.push_back(det.part(36)); + parts.push_back(det.part(39)); + parts.push_back(det.part(42)); + parts.push_back(det.part(45)); + parts.push_back(det.part(27)); + parts.push_back(det.part(28)); + parts.push_back(det.part(29)); + parts.push_back(det.part(30)); + parts.push_back(det.part(31)); + parts.push_back(det.part(35)); + parts.push_back(det.part(33)); + parts.push_back(det.part(48)); + parts.push_back(det.part(54)); + parts.push_back(det.part(51)); + parts.push_back(det.part(57)); + + array2d lbp; + make_uniform_lbp_image(img, lbp); + for (unsigned long i = 0; i < parts.size(); ++i) + extract_histogram_descriptors(lbp, parts[i], feats); + + if (num_scales > 1) + { + pyramid_down<4> pyr; + image_type img_temp; + pyr(img, img_temp); + unsigned long num_pyr_calls = 1; + + // now pull the features out at coarser scales + for (unsigned long iter = 1; iter < num_scales; ++iter) + { + // now do the feature extraction + make_uniform_lbp_image(img_temp, lbp); + for (unsigned long i = 0; i < parts.size(); ++i) + extract_histogram_descriptors(lbp, pyr.point_down(parts[i],num_pyr_calls), feats); + + if (iter+1 < num_scales) + { + pyr(img_temp); + ++num_pyr_calls; + } + } + } + + for (unsigned long i = 0; i < feats.size(); ++i) + feats[i] = std::sqrt(feats[i]); + + DLIB_ASSERT(feats.size() == 99120, feats.size()); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_LBP_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/lbp_abstract.h b/lib/3rdParty/dlib/include/dlib/image_transforms/lbp_abstract.h new file mode 100644 index 00000000..1a20082a --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/lbp_abstract.h @@ -0,0 +1,139 @@ +// Copyright (C) 2014 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_LBP_ABSTRACT_Hh_ +#ifdef DLIB_LBP_ABSTRACT_Hh_ + +#include "../image_processing/generic_image.h" +#include "../pixel.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type, + typename image_type2 + > + void make_uniform_lbp_image ( + const image_type& img, + image_type2& lbp + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - image_type2 == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - image_type2 should contain a grayscale pixel type such as unsigned char. + ensures + - #lbp.nr() == img.nr() + - #lbp.nc() == img.nc() + - This function extracts the uniform local-binary-pattern feature at every pixel + and stores it into #lbp. In particular, we have the following for all valid + r and c: + - #lbp[r][c] == the uniform LBP for the 3x3 pixel window centered on img[r][c]. + In particular, this is a value in the range 0 to 58 inclusive. + - We use the idea of uniform LBPs from the paper: + Face Description with Local Binary Patterns: Application to Face Recognition + by Ahonen, Hadid, and Pietikainen. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type, + typename T + > + void extract_histogram_descriptors ( + const image_type& img, + const point& loc, + std::vector& histograms, + const unsigned int cell_size = 10, + const unsigned int block_size = 4, + const unsigned int max_val = 58 + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - image_type contains unsigned char valued pixels. + - T is some scalar type like int or double + - All pixel values in img are <= max_val + - cell_size >= 1 + - block_size >= 1 + - max_val < 256 + ensures + - This function extracts histograms of pixel values from block_size*block_size + windows in the area in img immediately around img[loc.y()][loc.x()]. The + histograms are appended onto the end of #histograms. Each window is + cell_size pixels wide and tall. Moreover, the windows do not overlap. + - #histograms.size() == histograms.size() + block_size*block_size*(max_val+1) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type, + typename T + > + void extract_uniform_lbp_descriptors ( + const image_type& img, + std::vector& feats, + const unsigned int cell_size = 10 + ); + /*! + requires + - cell_size >= 1 + - T is some scalar type like int or double + ensures + - Extracts histograms of uniform local-binary-patterns from img. The + histograms are from densely tiled windows that are cell_size pixels wide and + tall. The windows do not overlap and cover all of img. + - #feats.size() == 59*(number of windows that fit into img) + (i.e. #feats contains the LBP histograms) + - We will have taken the square root of all the histogram elements. That is, + #feats[i] is the square root of the number of LBPs that appeared in its + corresponding window. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type, + typename T + > + void extract_highdim_face_lbp_descriptors ( + const image_type& img, + const full_object_detection& det, + std::vector& feats + ); + /*! + requires + - T is some scalar type like int or double + - det.num_parts() == 68 + ensures + - This function extracts the high-dimensional LBP feature described in the + paper: + Blessing of Dimensionality: High-dimensional Feature and Its Efficient + Compression for Face Verification by Dong Chen, Xudong Cao, Fang Wen, and + Jian Sun + - #feats == the high-dimensional LBP descriptor. It is the concatenation of + many LBP histograms, each extracted from different scales and from different + windows around different face landmarks. We also take the square root of + each histogram element before storing it into #feats. + - #feats.size() == 99120 + - This function assumes img has already been aligned and normalized to a + standard size. + - This function assumes det contains a human face detection with face parts + annotated using the annotation scheme from the iBUG 300-W face landmark + dataset. This means that det.part(i) gives the locations of different face + landmarks according to the iBUG 300-W annotation scheme. + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_LBP_ABSTRACT_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/morphological_operations.h b/lib/3rdParty/dlib/include/dlib/image_transforms/morphological_operations.h index 6679c0fd..b4e0f3b2 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/morphological_operations.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/morphological_operations.h @@ -6,6 +6,7 @@ #include "../pixel.h" #include "thresholding.h" #include "morphological_operations_abstract.h" +#include "assign_image.h" namespace dlib { @@ -662,6 +663,266 @@ namespace dlib } // ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template + inline bool should_remove_pixel ( + const image_type& img, + long r, + long c, + int iter + ) + { + unsigned int p2 = img[r-1][c]; + unsigned int p3 = img[r-1][c+1]; + unsigned int p4 = img[r][c+1]; + unsigned int p5 = img[r+1][c+1]; + unsigned int p6 = img[r+1][c]; + unsigned int p7 = img[r+1][c-1]; + unsigned int p8 = img[r][c-1]; + unsigned int p9 = img[r-1][c-1]; + + int A = (p2 == 0 && p3 == 255) + (p3 == 0 && p4 == 255) + + (p4 == 0 && p5 == 255) + (p5 == 0 && p6 == 255) + + (p6 == 0 && p7 == 255) + (p7 == 0 && p8 == 255) + + (p8 == 0 && p9 == 255) + (p9 == 0 && p2 == 255); + int B = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9; + int m1 = iter == 0 ? (p2 * p4 * p6) : (p2 * p4 * p8); + int m2 = iter == 0 ? (p4 * p6 * p8) : (p2 * p6 * p8); + // Decide if we should remove the pixel img[r][c]. + return (A == 1 && (B >= 2*255 && B <= 6*255) && m1 == 0 && m2 == 0); + } + + template + inline void add_to_remove ( + std::vector& to_remove, + array2d& marker, + const image_type& img, + long r, + long c, + int iter + ) + { + if (marker[r][c]&&should_remove_pixel(img,r,c,iter)) + { + to_remove.push_back(point(c,r)); + marker[r][c] = 0; + } + } + + template + inline bool is_bw_border_pixel( + const image_type& img, + long r, + long c + ) + { + unsigned int p2 = img[r-1][c]; + unsigned int p3 = img[r-1][c+1]; + unsigned int p4 = img[r][c+1]; + unsigned int p5 = img[r+1][c+1]; + unsigned int p6 = img[r+1][c]; + unsigned int p7 = img[r+1][c-1]; + unsigned int p8 = img[r][c-1]; + unsigned int p9 = img[r-1][c-1]; + + int B = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9; + // If you are on but at least one of your neighbors isn't. + return B<8*255 && img[r][c]; + + } + + inline void add_if( + std::vector& to_check2, + const array2d& marker, + long c, + long r + ) + { + if (marker[r][c]) + to_check2.push_back(point(c,r)); + } + + } // end namespace impl + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void skeleton( + image_type& img_ + ) + { + /* + The implementation of this function is based on the paper + "A fast parallel algorithm for thinning digital patterns” by T.Y. Zhang and C.Y. Suen. + and also the excellent discussion of it at: + http://opencv-code.com/quick-tips/implementation-of-thinning-algorithm-in-opencv/ + */ + + typedef typename image_traits::pixel_type pixel_type; + + // This function only works on grayscale images + COMPILE_TIME_ASSERT(pixel_traits::grayscale); + + using namespace impl; + // Note that it's important to zero the border for 2 reasons. First, it allows + // thinning to being at the border of the image. But more importantly, it causes + // the mask to have a border of 0 pixels as well which we use later to avoid + // indexing outside the image inside add_to_remove(). + zero_border_pixels(img_,1,1); + image_view img(img_); + + // We use the marker to keep track of pixels we have committed to removing but + // haven't yet removed from img. + array2d marker(img.nr(), img.nc()); + assign_image(marker, img); + + + // Begin by making a list of the pixels on the borders of binary blobs. + std::vector to_remove, to_check, to_check2; + for (int r = 1; r < img.nr()-1; r++) + { + for (int c = 1; c < img.nc()-1; c++) + { + if (is_bw_border_pixel(img, r, c)) + { + to_check.push_back(point(c,r)); + } + } + } + + // Now start iteratively looking at the border pixels and removing them. + while(to_check.size() != 0) + { + for (int iter = 0; iter <= 1; ++iter) + { + // Check which pixels we should remove + to_remove.clear(); + for (unsigned long i = 0; i < to_check.size(); ++i) + { + long r = to_check[i].y(); + long c = to_check[i].x(); + add_to_remove(to_remove, marker, img, r, c, iter); + } + for (unsigned long i = 0; i < to_check2.size(); ++i) + { + long r = to_check2[i].y(); + long c = to_check2[i].x(); + add_to_remove(to_remove, marker, img, r, c, iter); + } + // Now remove those pixels. Also add their neighbors into the "to check" + // pixel list for the next iteration. + for (unsigned long i = 0; i < to_remove.size(); ++i) + { + long r = to_remove[i].y(); + long c = to_remove[i].x(); + // remove the pixel + img[r][c] = 0; + add_if(to_check2, marker, c-1, r-1); + add_if(to_check2, marker, c, r-1); + add_if(to_check2, marker, c+1, r-1); + add_if(to_check2, marker, c-1, r); + add_if(to_check2, marker, c+1, r); + add_if(to_check2, marker, c-1, r+1); + add_if(to_check2, marker, c, r+1); + add_if(to_check2, marker, c+1, r+1); + } + } + to_check.clear(); + to_check.swap(to_check2); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + unsigned char encode_8_pixel_neighbors ( + const const_image_view& img, + const point& p + ) + { + unsigned char ch = 0; + + const rectangle area = get_rect(img); + + auto check = [&](long r, long c) + { + ch <<= 1; + if (area.contains(c,r) && img[r][c]) + ch |= 1; + }; + + long r = p.y(); + long c = p.x(); + + check(r-1,c-1); + check(r-1,c); + check(r-1,c+1); + check(r,c+1); + check(r+1,c+1); + check(r+1,c); + check(r+1,c-1); + check(r,c-1); + + return ch; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + std::vector find_line_endpoints ( + const image_type& img_ + ) + { + const_image_view img(img_); + + std::array line_ending_patterns; + line_ending_patterns.fill(false); + line_ending_patterns[0b00000001] = true; + line_ending_patterns[0b00000010] = true; + line_ending_patterns[0b00000100] = true; + line_ending_patterns[0b00001000] = true; + line_ending_patterns[0b00010000] = true; + line_ending_patterns[0b00100000] = true; + line_ending_patterns[0b01000000] = true; + line_ending_patterns[0b10000000] = true; + line_ending_patterns[0b00000011] = true; + line_ending_patterns[0b00000110] = true; + line_ending_patterns[0b00001100] = true; + line_ending_patterns[0b00011000] = true; + line_ending_patterns[0b00110000] = true; + line_ending_patterns[0b01100000] = true; + line_ending_patterns[0b11000000] = true; + line_ending_patterns[0b10000001] = true; + + + std::vector results; + + for (long r = 0; r < img.nr(); ++r) + { + for (long c = 0; c < img.nc(); ++c) + { + if (img[r][c] && line_ending_patterns[encode_8_pixel_neighbors(img,point(c,r))]) + { + results.emplace_back(c,r); + } + } + } + + return results; + } + + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/morphological_operations_abstract.h b/lib/3rdParty/dlib/include/dlib/image_transforms/morphological_operations_abstract.h index d8a8ec9f..b8578d5f 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/morphological_operations_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/morphological_operations_abstract.h @@ -283,6 +283,84 @@ namespace dlib - calls binary_complement(img,img); !*/ +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void skeleton( + image_type& img + ); + /*! + requires + - image_type is an object that implement the interface defined in + dlib/image_processing/generic_image.h + - img must contain a grayscale pixel type. + - all pixels in img are set to either on_pixel or off_pixel. + (i.e. it must be a binary image) + ensures + - This function computes the skeletonization of img and stores the result in + #img. That is, given a binary image, we progressively thin the binary blobs + (composed of on_pixel values) until only a single pixel wide skeleton of the + original blobs remains. + - #img.nc() == img.nc() + - #img.nr() == img.nr() + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + unsigned char encode_8_pixel_neighbors ( + const const_image_view& img, + const point& p + ); + /*! + requires + - image_type is an object that implement the interface defined in + dlib/image_processing/generic_image.h + - img must contain a grayscale pixel type. + - all pixels in img are set to either on_pixel or off_pixel. + (i.e. it must be a binary image) + - get_rect(img).contains(p) == true + ensures + - This routine looks at the 8 pixels immediately surrounding the pixel + img[p.y()][p.x()] and encodes their on/off pattern into the bits of an + unsigned char and returns it. To be specific, the neighbors are read + clockwise starting from the upper left and written to the unsigned char + starting with the high order bits. Therefore, the mapping between + neighboring pixels to bits is: + 7 6 5 + 0 4 + 1 2 3 + Where 0 refers to the lowest order bit in the unsigned char and 7 to the + highest order bit. Finally, a bit in the unsigned char is 1 if and only if + the corresponding pixel is on_pixel. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + std::vector find_line_endpoints ( + const image_type& img + ); + /*! + requires + - image_type is an object that implements the interface defined in + dlib/image_processing/generic_image.h + - img must contain a grayscale pixel type. + - all pixels in img are set to either on_pixel or off_pixel. + (i.e. it must be a binary image) + ensures + - This routine finds endpoints of lines in a thinned binary image. For + example, if the image was produced by skeleton() or something like a Canny + edge detector then you can use find_line_endpoints() to find the pixels + sitting on the ends of lines. + !*/ + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/random_color_transform.h b/lib/3rdParty/dlib/include/dlib/image_transforms/random_color_transform.h new file mode 100644 index 00000000..7433da1f --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/random_color_transform.h @@ -0,0 +1,157 @@ +// Copyright (C) 2016 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_RANDOM_cOLOR_TRANSFORM_Hh_ +#define DLIB_RANDOM_cOLOR_TRANSFORM_Hh_ + +#include "random_color_transform_abstract.h" +#include "../image_processing/generic_image.h" +#include "../pixel.h" +#include "../rand.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class random_color_transform + { + public: + + random_color_transform ( + dlib::rand& rnd, + const double gamma_magnitude = 0.5, + const double color_magnitude = 0.2 + ) + { + // pick a random gamma correction factor. + double gamma = std::max(0.0, 1 + gamma_magnitude*(rnd.get_random_double()-0.5)); + + // pick a random color balancing scheme. + double red_scale = 1-rnd.get_random_double()*color_magnitude; + double green_scale = 1-rnd.get_random_double()*color_magnitude; + double blue_scale = 1-rnd.get_random_double()*color_magnitude; + const double m = 255*std::max(std::max(red_scale,green_scale),blue_scale); + red_scale /= m; + green_scale /= m; + blue_scale /= m; + + // Now compute a lookup table for all the color channels. The table tells us + // what the transform does. + table.resize(256*3); + unsigned long i = 0; + for (int k = 0; k < 256; ++k) + { + double v = 255*std::pow(k*red_scale, gamma); + table[i++] = (unsigned char)(v + 0.5); + } + for (int k = 0; k < 256; ++k) + { + double v = 255*std::pow(k*green_scale, gamma); + table[i++] = (unsigned char)(v + 0.5); + } + for (int k = 0; k < 256; ++k) + { + double v = 255*std::pow(k*blue_scale, gamma); + table[i++] = (unsigned char)(v + 0.5); + } + } + + rgb_pixel operator()(rgb_pixel p) const + { + p.red = table[(unsigned int)p.red]; + p.green = table[(unsigned int)p.green+256]; + p.blue = table[(unsigned int)p.blue+512]; + return p; + } + + private: + std::vector table; + }; + +// ---------------------------------------------------------------------------------------- + + template + void disturb_colors ( + image_type& img_, + dlib::rand& rnd, + const double gamma_magnitude = 0.5, + const double color_magnitude = 0.2 + ) + { + image_view img(img_); + random_color_transform tform(rnd, gamma_magnitude, color_magnitude); + for (long r = 0; r < img.nr(); ++r) + { + for (long c = 0; c < img.nc(); ++c) + { + rgb_pixel temp; + assign_pixel(temp, img[r][c]); + temp = tform(temp); + assign_pixel(img[r][c], temp); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template + void apply_random_color_offset ( + image_type& img_, + dlib::rand& rnd + ) + { + // Make a random color offset. This tform matrix came from looking at the + // covariance matrix of RGB values in a bunch of images. In particular, if you + // multiply Gaussian random vectors by tform it will result in vectors with the + // same covariance matrix as the original RGB data. Also, this color transform is + // what is suggested by the paper: + // Krizhevsky, Alex, Ilya Sutskever, and Geoffrey E. Hinton. "Imagenet + // classification with deep convolutional neural networks." Advances in neural + // information processing systems. 2012. + // Except that we used the square root of the eigenvalues (which I'm pretty sure is + // what the authors intended). + matrix tform; + tform = -66.379, 25.094, 6.79698, + -68.0492, -0.302309, -13.9539, + -68.4907, -24.0199, 7.27653; + matrix v; + v = rnd.get_random_gaussian(),rnd.get_random_gaussian(),rnd.get_random_gaussian(); + v = round(tform*0.1*v); + const int roffset = v(0); + const int goffset = v(1); + const int boffset = v(2); + + // Make up lookup tables that apply the color mapping so we don't have to put a + // bunch of complicated conditional branches in the loop below. + unsigned char rtable[256]; + unsigned char gtable[256]; + unsigned char btable[256]; + for (int i = 0; i < 256; ++i) + { + rtable[i] = put_in_range(0, 255, i+roffset); + gtable[i] = put_in_range(0, 255, i+goffset); + btable[i] = put_in_range(0, 255, i+boffset); + } + + // now transform the image. + image_view img(img_); + for (long r = 0; r < img.nr(); ++r) + { + for (long c = 0; c < img.nc(); ++c) + { + rgb_pixel temp; + assign_pixel(temp, img[r][c]); + temp.red = rtable[temp.red]; + temp.green = gtable[temp.green]; + temp.blue = btable[temp.blue]; + assign_pixel(img[r][c], temp); + } + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_RANDOM_cOLOR_TRANSFORM_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/random_color_transform_abstract.h b/lib/3rdParty/dlib/include/dlib/image_transforms/random_color_transform_abstract.h new file mode 100644 index 00000000..5826e16a --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/random_color_transform_abstract.h @@ -0,0 +1,94 @@ +// Copyright (C) 2016 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_RANDOM_cOLOR_TRANSFORM_ABSTRACT_Hh_ +#ifdef DLIB_RANDOM_cOLOR_TRANSFORM_ABSTRACT_Hh_ + +#include "../image_processing/generic_image.h" +#include "../pixel.h" +#include "../rand.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class random_color_transform + { + /*! + WHAT THIS OBJECT REPRESENTS + This object generates a random color balancing and gamma correction + transform. It then allows you to apply that specific transform to as many + rgb_pixel objects as you like. + !*/ + + public: + + random_color_transform ( + dlib::rand& rnd, + const double gamma_magnitude = 0.5, + const double color_magnitude = 0.2 + ); + /*! + requires + - 0 <= gamma_magnitude + - 0 <= color_magnitude <= 1 + ensures + - This constructor generates a random color transform which can be applied + by calling this object's operator() method. + - The color transform is a gamma correction and color rebalancing. If + gamma_magnitude == 0 and color_magnitude == 0 then the transform doesn't + change any colors at all. However, the larger these parameters the more + noticeable the resulting transform. + !*/ + + rgb_pixel operator()( + rgb_pixel p + ) const; + /*! + ensures + - returns the color transformed version of p. + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + template + void disturb_colors ( + image_type& img, + dlib::rand& rnd, + const double gamma_magnitude = 0.5, + const double color_magnitude = 0.2 + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + ensures + - Applies a random color transform to the given image. This is done by + creating a random_color_transform with the given parameters and then + transforming each pixel in the image with the resulting transform. + !*/ + +// ---------------------------------------------------------------------------------------- + + template + void apply_random_color_offset ( + image_type& img, + dlib::rand& rnd + ); + /*! + ensures + - Picks a random color offset vector and adds it to the given image. The offset + vector is selected using the method described in the paper: + Krizhevsky, Alex, Ilya Sutskever, and Geoffrey E. Hinton. "Imagenet + classification with deep convolutional neural networks." Advances in neural + information processing systems. 2012. + In particular, we sample an RGB value from the typical distribution of RGB + values, assuming it has a Gaussian distribution, and then divide it by 10. + This sampled RGB vector is added to each pixel of img. + !*/ + +// ---------------------------------------------------------------------------------------- + +#endif // DLIB_RANDOM_cOLOR_TRANSFORM_ABSTRACT_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/random_cropper.h b/lib/3rdParty/dlib/include/dlib/image_transforms/random_cropper.h new file mode 100644 index 00000000..2c754b60 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/random_cropper.h @@ -0,0 +1,361 @@ +// Copyright (C) 2016 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_RaNDOM_CROPPER_H_ +#define DLIB_RaNDOM_CROPPER_H_ + +#include "random_cropper_abstract.h" +#include "../threads.h" +#include +#include +#include "interpolation.h" +#include "../image_processing/full_object_detection.h" +#include "../rand.h" + +namespace dlib +{ + class random_cropper + { + chip_dims dims = chip_dims(300,300); + bool randomly_flip = true; + double max_rotation_degrees = 30; + long min_object_length_long_dim = 75; // cropped object will be at least this many pixels along its longest edge. + long min_object_length_short_dim = 30; // cropped object will be at least this many pixels along its shortest edge. + double max_object_size = 0.7; // cropped object will be at most this fraction of the size of the image. + double background_crops_fraction = 0.5; + double translate_amount = 0.10; + + std::mutex rnd_mutex; + dlib::rand rnd; + public: + + void set_seed ( + time_t seed + ) { rnd = dlib::rand(seed); } + + double get_translate_amount ( + ) const { return translate_amount; } + + void set_translate_amount ( + double value + ) + { + DLIB_CASSERT(0 <= value); + translate_amount = value; + } + + double get_background_crops_fraction ( + ) const { return background_crops_fraction; } + + void set_background_crops_fraction ( + double value + ) + { + DLIB_CASSERT(0 <= value && value <= 1); + background_crops_fraction = value; + } + + const chip_dims& get_chip_dims( + ) const { return dims; } + + void set_chip_dims ( + const chip_dims& dims_ + ) { dims = dims_; } + + void set_chip_dims ( + unsigned long rows, + unsigned long cols + ) { set_chip_dims(chip_dims(rows,cols)); } + + bool get_randomly_flip ( + ) const { return randomly_flip; } + + void set_randomly_flip ( + bool value + ) { randomly_flip = value; } + + double get_max_rotation_degrees ( + ) const { return max_rotation_degrees; } + void set_max_rotation_degrees ( + double value + ) { max_rotation_degrees = std::abs(value); } + + long get_min_object_length_long_dim ( + ) const { return min_object_length_long_dim; } + long get_min_object_length_short_dim ( + ) const { return min_object_length_short_dim; } + + void set_min_object_size ( + long long_dim, + long short_dim + ) + { + DLIB_CASSERT(0 < short_dim && short_dim <= long_dim); + min_object_length_long_dim = long_dim; + min_object_length_short_dim = short_dim; + } + + double get_max_object_size ( + ) const { return max_object_size; } + void set_max_object_size ( + double value + ) + { + DLIB_CASSERT(0 < value); + max_object_size = value; + } + + template < + typename array_type + > + void operator() ( + size_t num_crops, + const array_type& images, + const std::vector>& rects, + array_type& crops, + std::vector>& crop_rects + ) + { + DLIB_CASSERT(images.size() == rects.size()); + crops.clear(); + crop_rects.clear(); + append(num_crops, images, rects, crops, crop_rects); + } + + template < + typename array_type + > + void append ( + size_t num_crops, + const array_type& images, + const std::vector>& rects, + array_type& crops, + std::vector>& crop_rects + ) + { + DLIB_CASSERT(images.size() == rects.size()); + DLIB_CASSERT(crops.size() == crop_rects.size()); + auto original_size = crops.size(); + crops.resize(crops.size()+num_crops); + crop_rects.resize(crop_rects.size()+num_crops); + parallel_for(original_size, original_size+num_crops, [&](long i) { + (*this)(images, rects, crops[i], crop_rects[i]); + }); + } + + + template < + typename array_type, + typename image_type + > + void operator() ( + const array_type& images, + const std::vector>& rects, + image_type& crop, + std::vector& crop_rects + ) + { + DLIB_CASSERT(images.size() == rects.size()); + size_t idx; + { std::lock_guard lock(rnd_mutex); + idx = rnd.get_integer(images.size()); + } + (*this)(images[idx], rects[idx], crop, crop_rects); + } + + template < + typename image_type1 + > + image_type1 operator() ( + const image_type1& img + ) + { + image_type1 crop; + std::vector junk1, junk2; + (*this)(img, junk1, crop, junk2); + return crop; + } + + template < + typename image_type1, + typename image_type2 + > + void operator() ( + const image_type1& img, + const std::vector& rects, + image_type2& crop, + std::vector& crop_rects + ) + { + DLIB_CASSERT(num_rows(img)*num_columns(img) != 0); + chip_details crop_plan; + bool should_flip_crop; + make_crop_plan(img, rects, crop_plan, should_flip_crop); + + extract_image_chip(img, crop_plan, crop); + const rectangle_transform tform = get_mapping_to_chip(crop_plan); + + // copy rects into crop_rects and set ones that are outside the crop to ignore or + // drop entirely as appropriate. + crop_rects.clear(); + for (auto rect : rects) + { + // map to crop + rect.rect = tform(rect.rect); + + // if the rect is at least partly in the crop + if (get_rect(crop).intersect(rect.rect).area() != 0) + { + // set to ignore if not totally in the crop or if too small. + if (!get_rect(crop).contains(rect.rect) || + ((long)rect.rect.height() < min_object_length_long_dim && (long)rect.rect.width() < min_object_length_long_dim) || + ((long)rect.rect.height() < min_object_length_short_dim || (long)rect.rect.width() < min_object_length_short_dim)) + { + rect.ignore = true; + } + + crop_rects.push_back(rect); + } + } + + // Also randomly flip the image + if (should_flip_crop) + { + image_type2 temp; + flip_image_left_right(crop, temp); + swap(crop,temp); + for (auto&& rect : crop_rects) + rect.rect = impl::flip_rect_left_right(rect.rect, get_rect(crop)); + } + } + + private: + + template + void make_crop_plan ( + const image_type1& img, + const std::vector& rects, + chip_details& crop_plan, + bool& should_flip_crop + ) + { + std::lock_guard lock(rnd_mutex); + rectangle crop_rect; + if (has_non_ignored_box(rects) && rnd.get_random_double() >= background_crops_fraction) + { + auto rect = rects[randomly_pick_rect(rects)].rect; + + // perturb the location of the crop by a small fraction of the object's size. + const point rand_translate = dpoint(rnd.get_double_in_range(-translate_amount,translate_amount)*std::max(rect.height(),rect.width()), + rnd.get_double_in_range(-translate_amount,translate_amount)*std::max(rect.height(),rect.width())); + + // We are going to grow rect into the cropping rect. First, we grow it a + // little so that it has the desired minimum border around it. + drectangle drect = centered_drect(center(rect)+rand_translate, rect.width()/max_object_size, rect.height()/max_object_size); + + // Now make rect have the same aspect ratio as dims so that there won't be + // any funny stretching when we crop it. We do this by growing it along + // whichever dimension is too short. + const double target_aspect = dims.cols/(double)dims.rows; + if (drect.width()/drect.height() < target_aspect) + drect = centered_drect(drect, target_aspect*drect.height(), drect.height()); + else + drect = centered_drect(drect, drect.width(), drect.width()/target_aspect); + + // Now perturb the scale of the crop. We do this by shrinking it, but not + // so much that it gets smaller than the min object sizes require. + double current_width = dims.cols*rect.width()/drect.width(); + double current_height = dims.rows*rect.height()/drect.height(); + + // never make any dimension smaller than the short dim. + double min_scale1 = std::max(min_object_length_short_dim/current_width, min_object_length_short_dim/current_height); + // at least one dimension needs to be longer than the long dim. + double min_scale2 = std::min(min_object_length_long_dim/current_width, min_object_length_long_dim/current_height); + double min_scale = std::max(min_scale1, min_scale2); + + const double rand_scale_perturb = 1.0/rnd.get_double_in_range(min_scale, 1); + crop_rect = centered_drect(drect, drect.width()*rand_scale_perturb, drect.height()*rand_scale_perturb); + + } + else + { + crop_rect = make_random_cropping_rect(img); + } + should_flip_crop = randomly_flip && rnd.get_random_double() > 0.5; + const double angle = rnd.get_double_in_range(-max_rotation_degrees, max_rotation_degrees)*pi/180; + crop_plan = chip_details(crop_rect, dims, angle); + } + + bool has_non_ignored_box ( + const std::vector& rects + ) const + { + for (auto&& b : rects) + { + if (!b.ignore) + return true; + } + return false; + } + + size_t randomly_pick_rect ( + const std::vector& rects + ) + { + DLIB_CASSERT(has_non_ignored_box(rects)); + size_t idx = rnd.get_integer(rects.size()); + while(rects[idx].ignore) + idx = rnd.get_integer(rects.size()); + return idx; + } + + template + rectangle make_random_cropping_rect( + const image_type& img_ + ) + { + const_image_view img(img_); + // Figure out what rectangle we want to crop from the image. We are going to + // crop out an image of size this->dims, so we pick a random scale factor that + // lets this random box be either as big as it can be while still fitting in + // the image or as small as a 3x zoomed in box randomly somewhere in the image. + double mins = 1.0/3.0, maxs = std::min(img.nr()/(double)dims.rows, img.nc()/(double)dims.cols); + mins = std::min(mins, maxs); + auto scale = rnd.get_double_in_range(mins, maxs); + rectangle rect(scale*dims.cols, scale*dims.rows); + // randomly shift the box around + point offset(rnd.get_integer(1+img.nc()-rect.width()), + rnd.get_integer(1+img.nr()-rect.height())); + return move_rect(rect, offset); + } + + + + }; + +// ---------------------------------------------------------------------------------------- + + inline std::ostream& operator<< ( + std::ostream& out, + const random_cropper& item + ) + { + using std::endl; + out << "random_cropper details: " << endl; + out << " chip_dims.rows: " << item.get_chip_dims().rows << endl; + out << " chip_dims.cols: " << item.get_chip_dims().cols << endl; + out << " randomly_flip: " << std::boolalpha << item.get_randomly_flip() << endl; + out << " max_rotation_degrees: " << item.get_max_rotation_degrees() << endl; + out << " min_object_length_long_dim: " << item.get_min_object_length_long_dim() << endl; + out << " min_object_length_short_dim: " << item.get_min_object_length_short_dim() << endl; + out << " max_object_size: " << item.get_max_object_size() << endl; + out << " background_crops_fraction: " << item.get_background_crops_fraction() << endl; + out << " translate_amount: " << item.get_translate_amount() << endl; + return out; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_RaNDOM_CROPPER_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/random_cropper_abstract.h b/lib/3rdParty/dlib/include/dlib/image_transforms/random_cropper_abstract.h new file mode 100644 index 00000000..7603a1c4 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/random_cropper_abstract.h @@ -0,0 +1,346 @@ +// Copyright (C) 2016 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_RaNDOM_CROPPER_ABSTRACT_H_ +#ifdef DLIB_RaNDOM_CROPPER_ABSTRACT_H_ + +#include "../threads.h" +#include +#include +#include "interpolation.h" +#include "../image_processing/full_object_detection.h" +#include "../rand.h" + +namespace dlib +{ + class random_cropper + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a tool for extracting random crops of objects from a set of + images. The crops are randomly jittered in scale, translation, and + rotation but more or less centered on objects specified by mmod_rect + objects. + + THREAD SAFETY + It is safe for multiple threads to make concurrent calls to this object's + operator() methods. + !*/ + + public: + + random_cropper ( + ); + /*! + ensures + - #get_chip_dims() == chip_dims(300,300) + - #get_randomly_flip() == true + - #get_max_rotation_degrees() == 30 + - #get_min_object_length_long_dim() == 70 + - #get_min_object_length_short_dim() == 30 + - #get_max_object_size() == 0.7 + - #get_background_crops_fraction() == 0.5 + - #get_translate_amount() == 0.1 + !*/ + + void set_seed ( + time_t seed + ); + /*! + ensures + - Seeds the internal random number generator with the given seed. + !*/ + + double get_translate_amount ( + ) const; + /*! + ensures + - When a box is cropped out, it will be randomly translated prior to + cropping by #get_translate_amount()*(the box's height) up or down and + #get_translate_amount()*(the box's width) left or right. + !*/ + + void set_translate_amount ( + double value + ); + /*! + requires + - value >= 0 + ensures + - #get_translate_amount() == value + !*/ + + double get_background_crops_fraction ( + ) const; + /*! + ensures + - When making random crops, get_background_crops_fraction() fraction of + them will be from random background rather than being centered on some + object in the dataset. + !*/ + + void set_background_crops_fraction ( + double value + ); + /*! + requires + - 0 <= value <= 1 + ensures + - #get_background_crops_fraction() == value + !*/ + + const chip_dims& get_chip_dims( + ) const; + /*! + ensures + - returns the dimensions of image chips produced by this object. + !*/ + + void set_chip_dims ( + const chip_dims& dims + ); + /*! + ensures + - #get_chip_dims() == dims + !*/ + + void set_chip_dims ( + unsigned long rows, + unsigned long cols + ); + /*! + ensures + - #get_chip_dims() == chip_dims(rows,cols) + !*/ + + bool get_randomly_flip ( + ) const; + /*! + ensures + - if this object will randomly mirror chips left to right. + !*/ + + void set_randomly_flip ( + bool value + ); + /*! + ensures + - #get_randomly_flip() == value + !*/ + + double get_max_rotation_degrees ( + ) const; + /*! + ensures + - When extracting an image chip, this object will pick a random rotation + in the range [-get_max_rotation_degrees(), get_max_rotation_degrees()] + and rotate the chip by that amount. + !*/ + + void set_max_rotation_degrees ( + double value + ); + /*! + ensures + - #get_max_rotation_degrees() == std::abs(value) + !*/ + + long get_min_object_length_long_dim ( + ) const; + /*! + ensures + - When a chip is extracted around an object, the chip will be sized so that + the longest edge of the object (i.e. either its height or width, + whichever is longer) is at least #get_min_object_length_long_dim() pixels + in length. When we say "object" here we are referring specifically to + the rectangle in the mmod_rect output by the cropper. + !*/ + + long get_min_object_length_short_dim ( + ) const; + /*! + ensures + - When a chip is extracted around an object, the chip will be sized so that + the shortest edge of the object (i.e. either its height or width, + whichever is shorter) is at least #get_min_object_length_short_dim() + pixels in length. When we say "object" here we are referring + specifically to the rectangle in the mmod_rect output by the cropper. + !*/ + + void set_min_object_size ( + long long_dim, + long short_dim + ); + /*! + requires + - 0 < short_dim <= long_dim + ensures + - #get_min_object_length_short_dim() == short_dim + - #get_min_object_length_long_dim() == long_dim + !*/ + + double get_max_object_size ( + ) const; + /*! + ensures + - When a chip is extracted around an object, the chip will be sized so that + both the object's height and width are at most get_max_object_size() * + the chip's height and width, respectively. E.g. if the chip is 640x480 + pixels in size then the object will be at most 480*get_max_object_size() + pixels tall and 640*get_max_object_size() pixels wide. + !*/ + + void set_max_object_size ( + double value + ); + /*! + requires + - 0 < value + ensures + - #get_max_object_size() == value + !*/ + + template < + typename array_type + > + void append ( + size_t num_crops, + const array_type& images, + const std::vector>& rects, + array_type& crops, + std::vector>& crop_rects + ); + /*! + requires + - images.size() == rects.size() + - crops.size() == crop_rects.size() + - for all valid i: + - images[i].size() != 0 + - array_type is a type with an interface compatible with dlib::array or + std::vector and it must in turn contain image objects that implement the + interface defined in dlib/image_processing/generic_image.h + ensures + - Randomly extracts num_crops chips from images and appends them to the end + of crops. We also copy the object metadata for each extracted crop and + store it into #crop_rects. In particular, calling this function is the + same as making multiple calls to the version of operator() below that + outputs a single crop, except that append() will use multiple CPU cores + to do the processing and is therefore faster. + - #crops.size() == crops.size()+num_crops + - #crop_rects.size() == crop_rects.size()+num_crops + !*/ + + template < + typename array_type + > + void operator() ( + size_t num_crops, + const array_type& images, + const std::vector>& rects, + array_type& crops, + std::vector>& crop_rects + ); + /*! + requires + - images.size() == rects.size() + - for all valid i: + - images[i].size() != 0 + - array_type is a type with an interface compatible with dlib::array or + std::vector and it must in turn contain image objects that implement the + interface defined in dlib/image_processing/generic_image.h + ensures + - Randomly extracts num_crops chips from images. We also copy the object + metadata for each extracted crop and store it into #crop_rects. In + particular, calling this function is the same as invoking the version of + operator() below multiple times, except that this version of operator() + will use multiple CPU cores to do the processing and is therefore faster. + - #crops.size() == num_crops + - #crop_rects.size() == num_crops + !*/ + + template < + typename array_type, + typename image_type + > + void operator() ( + const array_type& images, + const std::vector>& rects, + image_type& crop, + std::vector& crop_rects + ); + /*! + requires + - images.size() == rects.size() + - for all valid i: + - images[i].size() != 0 + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - array_type is a type with an interface compatible with dlib::array or + std::vector and it must in turn contain image objects that implement the + interface defined in dlib/image_processing/generic_image.h + ensures + - Selects a random image and creates a random crop from it. Specifically, + we pick a random index IDX < images.size() and then execute + (*this)(images[IDX],rects[IDX],crop,crop_rects) + !*/ + + template < + typename image_type1, + typename image_type2 + > + void operator() ( + const image_type1& img, + const std::vector& rects, + image_type2& crop, + std::vector& crop_rects + ); + /*! + requires + - img.size() != 0 + - image_type1 == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - image_type2 == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + ensures + - Extracts a random crop from img and copies over the mmod_rect objects in + rects to #crop_rects if they are contained inside the crop. Moreover, + rectangles are marked as ignore if they aren't completely contained + inside the crop. + - #crop_rects.size() <= rects.size() + !*/ + + template < + typename image_type1 + > + image_type1 operator() ( + const image_type1& img + ); + /*! + requires + - img.size() != 0 + - image_type1 == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + ensures + - This function simply calls (*this)(img, junk1, crop, junk2) and returns + crop. Therefore it is simply a convenience function for extracting a + random background patch. + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + std::ostream& operator<< ( + std::ostream& out, + const random_cropper& item + ); + /*! + ensures + - Prints the state of all the parameters of item to out. + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_RaNDOM_CROPPER_ABSTRACT_H_ + + diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/segment_image.h b/lib/3rdParty/dlib/include/dlib/image_transforms/segment_image.h index 3b57e480..10eaa2d0 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/segment_image.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/segment_image.h @@ -8,6 +8,7 @@ #include #include "../geometry.h" #include "../disjoint_subsets.h" +#include "assign_image.h" #include "../set.h" namespace dlib @@ -722,6 +723,245 @@ namespace dlib find_candidate_object_locations(in_img, rects, linspace(50, 200, 3)); } +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template + void mbd_raster_scan( + const T& img, + array2d& dist, + array2d& lower, + array2d& upper, + bool do_left_right_scans + ) + { + auto area = shrink_rect(get_rect(img),1); + + auto check_neighbor = [&](long r, long c, long neighbor_r, long neighbor_c) + { + auto l = std::min(lower[neighbor_r][neighbor_c].red, img[r][c].red); + auto u = std::max(upper[neighbor_r][neighbor_c].red, img[r][c].red); + auto d = u-l; + if (d < dist[r][c].red) + { + lower[r][c].red = l; + upper[r][c].red = u; + dist[r][c].red = d; + } + + l = std::min(lower[neighbor_r][neighbor_c].green, img[r][c].green); + u = std::max(upper[neighbor_r][neighbor_c].green, img[r][c].green); + d = u-l; + if (d < dist[r][c].green) + { + lower[r][c].green = l; + upper[r][c].green = u; + dist[r][c].green = d; + } + + l = std::min(lower[neighbor_r][neighbor_c].blue, img[r][c].blue); + u = std::max(upper[neighbor_r][neighbor_c].blue, img[r][c].blue); + d = u-l; + if (d < dist[r][c].blue) + { + lower[r][c].blue = l; + upper[r][c].blue = u; + dist[r][c].blue = d; + } + }; + + // scan top to bottom + for (long r = area.top(); r <= area.bottom(); ++r) + { + for (long c = area.left(); c <= area.right(); ++c) + { + check_neighbor(r,c, r-1,c); + check_neighbor(r,c, r,c-1); + } + } + + // scan bottom to top + for (long r = area.bottom(); r >= area.top(); --r) + { + for (long c = area.right(); c >= area.left(); --c) + { + check_neighbor(r,c, r+1,c); + check_neighbor(r,c, r,c+1); + } + } + + if (do_left_right_scans) + { + // scan left to right + for (long c = area.left(); c <= area.right(); ++c) + { + for (long r = area.top(); r <= area.bottom(); ++r) + { + check_neighbor(r,c, r-1,c); + check_neighbor(r,c, r,c-1); + } + } + + // scan right to left + for (long c = area.right(); c >= area.left(); --c) + { + for (long r = area.bottom(); r >= area.top(); --r) + { + check_neighbor(r,c, r+1,c); + check_neighbor(r,c, r,c+1); + } + } + } + } + + // ------------------------------------------------------------------------------------ + + template + void mbd_raster_scan( + const T& img, + U& dist, + array2d& lower, + array2d& upper, + bool do_left_right_scans + ) + { + auto area = shrink_rect(get_rect(img),1); + + auto check_neighbor = [&](long r, long c, long neighbor_r, long neighbor_c) + { + auto l = std::min(lower[neighbor_r][neighbor_c], get_pixel_intensity(img[r][c])); + auto u = std::max(upper[neighbor_r][neighbor_c], get_pixel_intensity(img[r][c])); + auto d = u-l; + if (d < dist[r][c]) + { + lower[r][c] = l; + upper[r][c] = u; + dist[r][c] = d; + } + }; + + // scan top to bottom + for (long r = area.top(); r <= area.bottom(); ++r) + { + for (long c = area.left(); c <= area.right(); ++c) + { + check_neighbor(r,c, r-1,c); + check_neighbor(r,c, r,c-1); + } + } + + // scan bottom to top + for (long r = area.bottom(); r >= area.top(); --r) + { + for (long c = area.right(); c >= area.left(); --c) + { + check_neighbor(r,c, r+1,c); + check_neighbor(r,c, r,c+1); + } + } + + if (do_left_right_scans) + { + // scan left to right + for (long c = area.left(); c <= area.right(); ++c) + { + for (long r = area.top(); r <= area.bottom(); ++r) + { + check_neighbor(r,c, r-1,c); + check_neighbor(r,c, r,c-1); + } + } + + // scan right to left + for (long c = area.right(); c >= area.left(); --c) + { + for (long r = area.bottom(); r >= area.top(); --r) + { + check_neighbor(r,c, r+1,c); + check_neighbor(r,c, r,c+1); + } + } + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + typename disable_if_c::value>::type min_barrier_distance( + const in_image_type& img_, + out_image_type& dist_, + size_t iterations = 10, + bool do_left_right_scans = true + ) + { + DLIB_CASSERT(iterations > 0); + + static_assert(pixel_traits::pixel_type>::grayscale, + "min_barrier_distance() requires a grayscale output image."); + + const_image_view img(img_); + image_view dist(dist_); + + typedef typename image_traits::pixel_type pixel_type; + typedef typename pixel_traits::basic_pixel_type basic_pixel_type; + + + dist.set_size(img.nr(), img.nc()); + array2d lower, upper; + assign_all_pixels(dist, pixel_traits::max()); + zero_border_pixels(dist,1,1); + assign_image(lower, img); + assign_image(upper, img); + + for (size_t i = 0; i < iterations; ++i) + impl::mbd_raster_scan(img, dist, lower, upper, do_left_right_scans); + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + typename enable_if_c::value>::type min_barrier_distance( + const in_image_type& img_, + out_image_type& dist_, + size_t iterations = 10, + bool do_left_right_scans = true + ) + { + DLIB_CASSERT(iterations > 0); + + static_assert(pixel_traits::pixel_type>::grayscale, + "min_barrier_distance() requires a grayscale output image."); + + const_image_view img(img_); + image_view dist(dist_); + + typedef typename image_traits::pixel_type pixel_type; + + + array2d temp_dist(img.nr(), img.nc()); + array2d lower, upper; + assign_all_pixels(temp_dist, pixel_traits::max()); + zero_border_pixels(temp_dist,1,1); + assign_image(lower, img); + assign_image(upper, img); + + for (size_t i = 0; i < iterations; ++i) + impl::mbd_raster_scan(img, temp_dist, lower, upper, do_left_right_scans); + + // convert to grayscale for output. + assign_image(dist,temp_dist); + } + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/segment_image_abstract.h b/lib/3rdParty/dlib/include/dlib/image_transforms/segment_image_abstract.h index af1af46a..f35b2fe3 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/segment_image_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/segment_image_abstract.h @@ -117,6 +117,44 @@ namespace dlib instances. !*/ +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void min_barrier_distance( + const in_image_type& img, + out_image_type& dist, + size_t iterations = 10, + bool do_left_right_scans = true + ); + /*! + requires + - in_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - out_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - pixel_traits::pixel_type>::grayscale == true + (i.e. dist must be a grayscale image) + - iterations > 0 + ensures + - This function implements the salient object detection method described in the paper: + "Minimum barrier salient object detection at 80 fps" by Zhang, Jianming, et al. + In particular, we compute the minimum barrier distance between the borders of + the image and all the other pixels. The result is stored in dist. Note that + the paper talks about a bunch of other things you could do beyond computing + the minimum barrier distance, but this function doesn't do any of that. It's + just the vanilla MBD. + - We will perform iterations iterations of MBD passes over the image. Larger + values might give better results but run slower. + - During each MBD iteration we make raster scans over the image. These pass + from top->bottom, bottom->top, left->right, and right->left. If + do_left_right_scans==false then the left/right passes are not executed. + Skipping them makes the algorithm about 2x faster but might reduce the + quality of the output. + !*/ + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/spatial_filtering.h b/lib/3rdParty/dlib/include/dlib/image_transforms/spatial_filtering.h index 4f197a9a..91dcae32 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/spatial_filtering.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/spatial_filtering.h @@ -12,6 +12,7 @@ #include "../geometry/border_enumerator.h" #include "../simd.h" #include +#include "assign_image.h" namespace dlib { @@ -1217,7 +1218,7 @@ namespace dlib typename in_image_type, typename out_image_type > - void gaussian_blur ( + rectangle gaussian_blur ( const in_image_type& in_img, out_image_type& out_img, double sigma = 1, @@ -1233,15 +1234,25 @@ namespace dlib << "\n\t is_same_object(in_img,out_img): " << is_same_object(in_img,out_img) ); - typedef typename pixel_traits::pixel_type>::basic_pixel_type type; - typedef typename promote::type ptype; - - const matrix& filt = create_gaussian_filter(sigma, max_size); - - ptype scale = sum(filt); - scale = scale*scale; - - spatially_filter_image_separable(in_img, out_img, filt, filt, scale); + if (sigma < 18) + { + typedef typename pixel_traits::pixel_type>::basic_pixel_type type; + typedef typename promote::type ptype; + const matrix& filt = create_gaussian_filter(sigma, max_size); + ptype scale = sum(filt); + scale = scale*scale; + return spatially_filter_image_separable(in_img, out_img, filt, filt, scale); + } + else + { + // For large sigma we need to use a type with a lot of precision to avoid + // numerical problems. So we use double here. + typedef double ptype; + const matrix& filt = create_gaussian_filter(sigma, max_size); + ptype scale = sum(filt); + scale = scale*scale; + return spatially_filter_image_separable(in_img, out_img, filt, filt, scale); + } } diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/spatial_filtering_abstract.h b/lib/3rdParty/dlib/include/dlib/image_transforms/spatial_filtering_abstract.h index 513ed0a0..5e200aa9 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/spatial_filtering_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/spatial_filtering_abstract.h @@ -353,7 +353,7 @@ namespace dlib typename in_image_type, typename out_image_type > - void gaussian_blur ( + rectangle gaussian_blur ( const in_image_type& in_img, out_image_type& out_img, double sigma = 1, @@ -384,6 +384,8 @@ namespace dlib inside the image are set to zero. - #out_img.nc() == in_img.nc() - #out_img.nr() == in_img.nr() + - returns a rectangle which indicates what pixels in #out_img are considered + non-border pixels and therefore contain output from the filter. !*/ // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/thresholding.h b/lib/3rdParty/dlib/include/dlib/image_transforms/thresholding.h index 52cf05bd..4d2f437a 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/thresholding.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/thresholding.h @@ -6,6 +6,7 @@ #include "../pixel.h" #include "thresholding_abstract.h" #include "equalize_histogram.h" +#include "../enable_if.h" namespace dlib { @@ -15,6 +16,348 @@ namespace dlib const unsigned char on_pixel = 255; const unsigned char off_pixel = 0; +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template < + typename U, + typename V, + typename basic_pixel_type + > + void partition_pixels_float_work ( + unsigned long begin, + unsigned long end, + U&& cumsum, + V&& sorted, + basic_pixel_type& pix_thresh, + unsigned long& int_thresh + ) + { + + auto histsum = [&](long begin, long end) + { + return end-begin; + }; + auto histsumi = [&](long begin, long end) + { + return cumsum[end]-cumsum[begin]; + }; + + // If we split the pixels into two groups, those < thresh (the left group) and + // those >= thresh (the right group), what would the sum of absolute deviations of + // each pixel from the mean of its group be? total_abs(thresh) computes that + // value. + unsigned long left_idx = 0; + unsigned long right_idx = 0; + auto total_abs = [&](unsigned long thresh) + { + auto left_avg = histsumi(begin,thresh); + auto tmp = histsum(begin,thresh); + if (tmp != 0) + left_avg /= tmp; + auto right_avg = histsumi(thresh,end); + tmp = histsum(thresh,end); + if (tmp != 0) + right_avg /= tmp; + + + while(left_idx+1 < sorted.size() && sorted[left_idx] <= left_avg) + ++left_idx; + while(right_idx+1 < sorted.size() && sorted[right_idx] <= right_avg) + ++right_idx; + + double score = 0; + score += left_avg*histsum(begin,left_idx) - histsumi(begin,left_idx); + score -= left_avg*histsum(left_idx,thresh) - histsumi(left_idx,thresh); + score += right_avg*histsum(thresh,right_idx) - histsumi(thresh,right_idx); + score -= right_avg*histsum(right_idx,end) - histsumi(right_idx,end); + return score; + }; + + + + int_thresh = begin; + double min_sad = std::numeric_limits::infinity(); + for (unsigned long i = begin; i < end; ++i) + { + // You can't drop a threshold in-between pixels with identical values. So + // skip thresholds corresponding to this degenerate case. + if (i > 0 && sorted[i-1]==sorted[i]) + continue; + + double sad = total_abs(i); + if (sad <= min_sad) + { + min_sad = sad; + int_thresh = i; + } + } + + pix_thresh = sorted[int_thresh]; + } + + template < + typename U, + typename V, + typename basic_pixel_type + > + void recursive_partition_pixels_float ( + unsigned long begin, + unsigned long end, + U&& cumsum, + V&& sorted, + basic_pixel_type& pix_thresh + ) + { + unsigned long int_thresh; + partition_pixels_float_work(begin, end, cumsum, sorted, pix_thresh, int_thresh); + } + + template < + typename U, + typename V, + typename basic_pixel_type, + typename ...T + > + void recursive_partition_pixels_float ( + unsigned long begin, + unsigned long end, + U&& cumsum, + V&& sorted, + basic_pixel_type& pix_thresh, + T&& ...more_thresholds + ) + { + unsigned long int_thresh; + partition_pixels_float_work(begin, end, cumsum, sorted, pix_thresh, int_thresh); + recursive_partition_pixels_float(int_thresh, end, cumsum, sorted, more_thresholds...); + } + + template < + typename image_type, + typename ...T + > + void partition_pixels_float ( + const image_type& img_, + typename pixel_traits::pixel_type>::basic_pixel_type& pix_thresh, + T&& ...more_thresholds + ) + { + /* + This is a version of partition_pixels() that doesn't use the histogram to + perform a radix sort but rather uses std::sort() as the first processing + step. It is therefor useful in cases where the range of possible pixels is + too large for the faster histogram version. + */ + + COMPILE_TIME_ASSERT( pixel_traits::pixel_type>::has_alpha == false ); + + typedef typename pixel_traits::pixel_type>::basic_pixel_type basic_pixel_type; + + const_image_view img(img_); + + std::vector sorted; + sorted.reserve(img.size()); + + for (long r = 0; r < img.nr(); ++r) + { + for (long c = 0; c < img.nc(); ++c) + sorted.emplace_back(get_pixel_intensity(img[r][c])); + } + std::sort(sorted.begin(), sorted.end()); + + std::vector cumsum; + cumsum.reserve(sorted.size()+1); + + // create integral array + cumsum.emplace_back(0); + for (auto& v : sorted) + cumsum.emplace_back(cumsum.back()+v); + + + + recursive_partition_pixels_float(0, img.size(), cumsum, sorted, pix_thresh, more_thresholds...); + + } + + + template + struct is_u16img_or_less + { + typedef typename image_traits::pixel_type pixel_type; + typedef typename pixel_traits::basic_pixel_type basic_pixel_type; + + const static bool value = sizeof(basic_pixel_type) <= 2 && pixel_traits::is_unsigned; + }; + } + + template < + typename image_type, + typename ...T + > + typename disable_if>::type + partition_pixels ( + const image_type& img, + typename pixel_traits::pixel_type>::basic_pixel_type& pix_thresh, + T&& ...more_thresholds + ) + { + impl::partition_pixels_float(img, pix_thresh, more_thresholds...); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template < + typename U, + typename basic_pixel_type + > + void partition_pixels_work ( + unsigned long begin, + unsigned long end, + U&& total_abs, + basic_pixel_type& pix_thresh, + unsigned long& int_thresh + ) + { + int_thresh = begin; + double min_sad = std::numeric_limits::infinity(); + for (unsigned long i = begin; i < end; ++i) + { + double sad = total_abs(begin, i); + if (sad <= min_sad) + { + min_sad = sad; + int_thresh = i; + } + } + + pix_thresh = int_thresh; + } + + template < + typename U, + typename basic_pixel_type + > + void recursive_partition_pixels ( + unsigned long begin, + unsigned long end, + U&& total_abs, + basic_pixel_type& pix_thresh + ) + { + unsigned long int_thresh; + partition_pixels_work(begin, end, total_abs, pix_thresh, int_thresh); + } + + template < + typename U, + typename basic_pixel_type, + typename ...T + > + void recursive_partition_pixels ( + unsigned long begin, + unsigned long end, + U&& total_abs, + basic_pixel_type& pix_thresh, + T&& ...more_thresholds + ) + { + unsigned long int_thresh; + partition_pixels_work(begin, end, total_abs, pix_thresh, int_thresh); + recursive_partition_pixels(int_thresh, end, total_abs, more_thresholds...); + } + + } + + template < + typename image_type, + typename ...T + > + typename enable_if>::type + partition_pixels ( + const image_type& img, + typename pixel_traits::pixel_type>::basic_pixel_type& pix_thresh, + T&& ...more_thresholds + ) + { + COMPILE_TIME_ASSERT( pixel_traits::pixel_type>::has_alpha == false ); + COMPILE_TIME_ASSERT( pixel_traits::pixel_type>::is_unsigned == true ); + + + matrix hist; + get_histogram(img,hist); + + // create integral histograms + matrix cum_hist(hist.size()+1), cum_histi(hist.size()+1); + cum_hist(0) = 0; + cum_histi(0) = 0; + for (long i = 0; i < hist.size(); ++i) + { + cum_hist(i+1) = cum_hist(i) + hist(i); + cum_histi(i+1) = cum_histi(i) + hist(i)*(double)i; + } + + auto histsum = [&](long begin, long end) + { + return cum_hist(end)-cum_hist(begin); + }; + auto histsumi = [&](long begin, long end) + { + return cum_histi(end)-cum_histi(begin); + }; + + // If we split the pixels into two groups, those < thresh (the left group) and + // those >= thresh (the right group), what would the sum of absolute deviations of + // each pixel from the mean of its group be? total_abs(thresh) computes that + // value. + auto total_abs = [&](unsigned long begin, unsigned long thresh) + { + auto left_avg = histsumi(begin,thresh); + auto tmp = histsum(begin,thresh); + if (tmp != 0) + left_avg /= tmp; + auto right_avg = histsumi(thresh,hist.size()); + tmp = histsum(thresh,hist.size()); + if (tmp != 0) + right_avg /= tmp; + + + const long left_idx = (long)std::ceil(left_avg); + const long right_idx = (long)std::ceil(right_avg); + + double score = 0; + score += left_avg*histsum(begin,left_idx) - histsumi(begin,left_idx); + score -= left_avg*histsum(left_idx,thresh) - histsumi(left_idx,thresh); + score += right_avg*histsum(thresh,right_idx) - histsumi(thresh,right_idx); + score -= right_avg*histsum(right_idx,hist.size()) - histsumi(right_idx,hist.size()); + return score; + }; + + + impl::recursive_partition_pixels(0, hist.size(), total_abs, pix_thresh, more_thresholds...); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + typename pixel_traits::pixel_type>::basic_pixel_type + partition_pixels ( + const image_type& img + ) + { + typedef typename pixel_traits::pixel_type>::basic_pixel_type basic_pixel_type; + basic_pixel_type thresh; + partition_pixels(img, thresh); + return thresh; + } + +// ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- template < @@ -58,6 +401,18 @@ namespace dlib // ---------------------------------------------------------------------------------------- + template < + typename in_image_type, + typename out_image_type + > + void threshold_image ( + const in_image_type& in_img, + out_image_type& out_img + ) + { + threshold_image(in_img,out_img,partition_pixels(in_img)); + } + template < typename image_type > @@ -69,6 +424,18 @@ namespace dlib threshold_image(img,img,thresh); } +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void threshold_image ( + image_type& img + ) + { + threshold_image(img,img,partition_pixels(img)); + } + // ---------------------------------------------------------------------------------------- template < @@ -87,11 +454,10 @@ namespace dlib COMPILE_TIME_ASSERT(pixel_traits::pixel_type>::grayscale); - const_image_view in_img(in_img_); image_view out_img(out_img_); // if there isn't any input image then don't do anything - if (in_img.size() == 0) + if (image_size(in_img_) == 0) { out_img.clear(); return; @@ -100,7 +466,9 @@ namespace dlib unsigned long thresh; // find the threshold we should use matrix hist; - get_histogram(in_img,hist); + get_histogram(in_img_,hist); + + const_image_view in_img(in_img_); // Start our two means (a and b) out at the ends of the histogram long a = 0; @@ -208,11 +576,8 @@ namespace dlib COMPILE_TIME_ASSERT(pixel_traits::pixel_type>::grayscale); - DLIB_ASSERT( lower_thresh <= upper_thresh && is_same_object(in_img_, out_img_) == false, + DLIB_ASSERT(is_same_object(in_img_, out_img_) == false, "\tvoid hysteresis_threshold(in_img_, out_img_, lower_thresh, upper_thresh)" - << "\n\tYou can't use an upper_thresh that is less than your lower_thresh" - << "\n\tlower_thresh: " << lower_thresh - << "\n\tupper_thresh: " << upper_thresh << "\n\tis_same_object(in_img_,out_img_): " << is_same_object(in_img_,out_img_) ); @@ -322,15 +687,26 @@ namespace dlib } // end while (pos >= 0) } - else - { - out_img[r][c] = off_pixel; - } - } } } + template < + typename in_image_type, + typename out_image_type + > + void hysteresis_threshold ( + const in_image_type& in_img, + out_image_type& out_img + ) + { + using basic_pixel_type = typename pixel_traits::pixel_type>::basic_pixel_type; + + basic_pixel_type t1, t2; + partition_pixels(in_img, t1, t2); + hysteresis_threshold(in_img, out_img, t1, t2); + } + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/image_transforms/thresholding_abstract.h b/lib/3rdParty/dlib/include/dlib/image_transforms/thresholding_abstract.h index 0fd27aca..ca16d8ac 100644 --- a/lib/3rdParty/dlib/include/dlib/image_transforms/thresholding_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/image_transforms/thresholding_abstract.h @@ -13,6 +13,56 @@ namespace dlib const unsigned char on_pixel = 255; const unsigned char off_pixel = 0; +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + typename pixel_traits::pixel_type>::basic_pixel_type + partition_pixels ( + const image_type& img + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - pixel_traits::pixel_type>::has_alpha == false + ensures + - Finds a threshold value that would be reasonable to use with + threshold_image(img, threshold). It does this by finding the threshold that + partitions the pixels in img into two groups such that the sum of absolute + deviations between each pixel and the mean of its group is minimized. + !*/ + + template < + typename image_type, + typename ...T + > + void partition_pixels ( + const image_type& img, + typename pixel_traits::pixel_type>::basic_pixel_type& pix_thresh, + T&& ...more_thresholds + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - pixel_traits::pixel_type>::has_alpha == false + - more_thresholds == a bunch of parameters of the same type as pix_thresh. + ensures + - This version of partition_pixels() finds multiple partitions rather than just + one partition. It does this by first partitioning the pixels just as the + above partition_pixels(img) does. Then it forms a new image with only pixels + >= that first partition value and recursively partitions this new image. + However, the recursion is implemented in an efficient way which is faster than + explicitly forming these images and calling partition_pixels(), but the + output is the same as if you did. For example, suppose you called + partition_pixels(img, t1, t2, t3). Then we would have: + - t1 == partition_pixels(img) + - t2 == partition_pixels(an image with only pixels with values >= t1 in it) + - t3 == partition_pixels(an image with only pixels with values >= t2 in it) + !*/ + // ---------------------------------------------------------------------------------------- template < @@ -26,8 +76,10 @@ namespace dlib ); /*! requires - - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h - - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - in_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - out_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h - pixel_traits::pixel_type>::grayscale == true - pixel_traits::pixel_type>::has_alpha == false - pixel_traits::pixel_type>::has_alpha == false @@ -53,48 +105,32 @@ namespace dlib - calls threshold_image(img,img,thresh); !*/ -// ---------------------------------------------------------------------------------------- - template < typename in_image_type, typename out_image_type > - void auto_threshold_image ( + void threshold_image ( const in_image_type& in_img, out_image_type& out_img ); /*! requires - - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h - - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h - - pixel_traits::pixel_type>::max() <= 65535 - - pixel_traits::pixel_type>::has_alpha == false - - pixel_traits::pixel_type>::is_unsigned == true - - pixel_traits::pixel_type>::grayscale == true - - pixel_traits::pixel_type>::has_alpha == false - - pixel_traits::pixel_type>::is_unsigned == true + - it is valid to call threshold_image(in_img,out_img,partition_pixels(in_img)); ensures - - #out_img == the thresholded version of in_img (in_img is converted to a grayscale - intensity image if it is color). Pixels in in_img with grayscale values >= thresh - have an output value of on_pixel and all others have a value of off_pixel. - - The thresh value used is determined by performing a k-means clustering - on the input image histogram with a k of 2. The point between the two - means found is used as the thresh value. - - #out_img.nc() == in_img.nc() - - #out_img.nr() == in_img.nr() + - calls threshold_image(in_img,out_img,partition_pixels(in_img)); !*/ template < typename image_type > - void auto_threshold_image ( + void threshold_image ( image_type& img ); /*! requires - - it is valid to call auto_threshold_image(img,img); + - it is valid to call threshold_image(img,img,partition_pixels(img)); ensures - - calls auto_threshold_image(img,img); + - calls threshold_image(img,img,partition_pixels(img)); !*/ // ---------------------------------------------------------------------------------------- @@ -111,23 +147,49 @@ namespace dlib ); /*! requires - - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h - - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - in_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - out_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h - pixel_traits::pixel_type>::grayscale == true - pixel_traits::pixel_type>::has_alpha == false - pixel_traits::pixel_type>::has_alpha == false - - lower_thresh <= upper_thresh - is_same_object(in_img, out_img) == false ensures - #out_img == the hysteresis thresholded version of in_img (in_img is converted to a grayscale intensity image if it is color). Pixels in in_img with grayscale values >= upper_thresh have an output value of on_pixel and all others have a - value of off_pixel unless they are >= lower_thresh and are adjacent to a pixel - with a value >= upper_thresh in which case they have a value of on_pixel. + value of off_pixel unless they are >= lower_thresh and are connected to a pixel + with a value >= upper_thresh, in which case they have a value of on_pixel. Here + pixels are connected if there is a path between them composed of pixels that + would receive an output of on_pixel. - #out_img.nc() == in_img.nc() - #out_img.nr() == in_img.nr() !*/ + template < + typename in_image_type, + typename out_image_type + > + void hysteresis_threshold ( + const in_image_type& in_img, + out_image_type& out_img + ); + /*! + requires + - in_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - out_image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - pixel_traits::pixel_type>::grayscale == true + - pixel_traits::pixel_type>::has_alpha == false + - pixel_traits::pixel_type>::has_alpha == false + - is_same_object(in_img, out_img) == false + ensures + - performs: hysteresis_threshold(in_img, out_img, t1, t2) where the thresholds + are first obtained by calling partition_pixels(in_img, t1, t2). + !*/ + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/interfaces/enumerable.h b/lib/3rdParty/dlib/include/dlib/interfaces/enumerable.h index 0cd827b0..e8f5ae78 100644 --- a/lib/3rdParty/dlib/include/dlib/interfaces/enumerable.h +++ b/lib/3rdParty/dlib/include/dlib/interfaces/enumerable.h @@ -104,7 +104,7 @@ namespace dlib - returns false if there are no more elements in the container !*/ - virtual unsigned long size ( + virtual size_t size ( ) const = 0; /*! ensures diff --git a/lib/3rdParty/dlib/include/dlib/interfaces/remover.h b/lib/3rdParty/dlib/include/dlib/interfaces/remover.h index d41c23a3..f2098cba 100644 --- a/lib/3rdParty/dlib/include/dlib/interfaces/remover.h +++ b/lib/3rdParty/dlib/include/dlib/interfaces/remover.h @@ -54,7 +54,7 @@ namespace dlib - #at_start() == true !*/ - virtual unsigned long size ( + virtual size_t size ( ) const = 0; /*! ensures @@ -152,7 +152,7 @@ namespace dlib - #at_start() == true !*/ - virtual unsigned long size ( + virtual size_t size ( ) const = 0; /*! ensures diff --git a/lib/3rdParty/dlib/include/dlib/iomanip b/lib/3rdParty/dlib/include/dlib/iomanip deleted file mode 100644 index eb0e59e4..00000000 --- a/lib/3rdParty/dlib/include/dlib/iomanip +++ /dev/null @@ -1 +0,0 @@ -#include "dlib_include_path_tutorial.txt" diff --git a/lib/3rdParty/dlib/include/dlib/iosfwd b/lib/3rdParty/dlib/include/dlib/iosfwd deleted file mode 100644 index eb0e59e4..00000000 --- a/lib/3rdParty/dlib/include/dlib/iosfwd +++ /dev/null @@ -1 +0,0 @@ -#include "dlib_include_path_tutorial.txt" diff --git a/lib/3rdParty/dlib/include/dlib/iosockstream/iosockstream.h b/lib/3rdParty/dlib/include/dlib/iosockstream/iosockstream.h index e8b1a68f..e49d2e37 100644 --- a/lib/3rdParty/dlib/include/dlib/iosockstream/iosockstream.h +++ b/lib/3rdParty/dlib/include/dlib/iosockstream/iosockstream.h @@ -6,8 +6,9 @@ #include "iosockstream_abstract.h" #include +#include + #include "../sockstreambuf.h" -#include "../smart_pointers_thread_safe.h" #include "../timeout.h" #ifdef _MSC_VER @@ -59,6 +60,7 @@ namespace dlib const network_address& addr ) { + auto_mutex lock(class_mutex); close(); con.reset(connect(addr)); buf.reset(new sockstreambuf(con.get())); @@ -79,6 +81,7 @@ namespace dlib unsigned long timeout ) { + auto_mutex lock(class_mutex); close(timeout); con.reset(connect(addr.host_address, addr.port, timeout)); buf.reset(new sockstreambuf(con.get())); @@ -91,6 +94,7 @@ namespace dlib unsigned long timeout = 10000 ) { + auto_mutex lock(class_mutex); rdbuf(0); try { @@ -126,24 +130,34 @@ namespace dlib unsigned long timeout ) { + auto_mutex lock(class_mutex); if (con) { con_timeout.reset(new dlib::timeout(*this,&iosockstream::terminate_connection,timeout,con)); } } + void shutdown ( + ) + { + auto_mutex lock(class_mutex); + if (con) + con->shutdown(); + } + private: void terminate_connection( - shared_ptr_thread_safe thecon + std::shared_ptr thecon ) { thecon->shutdown(); } - scoped_ptr con_timeout; - shared_ptr_thread_safe con; - scoped_ptr buf; + std::unique_ptr con_timeout; + rmutex class_mutex; + std::shared_ptr con; + std::unique_ptr buf; }; diff --git a/lib/3rdParty/dlib/include/dlib/iosockstream/iosockstream_abstract.h b/lib/3rdParty/dlib/include/dlib/iosockstream/iosockstream_abstract.h index d5ff61e8..2328f426 100644 --- a/lib/3rdParty/dlib/include/dlib/iosockstream/iosockstream_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/iosockstream/iosockstream_abstract.h @@ -22,8 +22,10 @@ namespace dlib stream's output buffers. THREAD SAFETY - It is not safe to touch this object from more than one thread at a time. - Therefore, you should mutex lock it if you need to do so. + It is not safe for multiple threads to make concurrent accesses to the same + instance of this object (except for calls to shutdown() which are always + threadsafe). Therefore, you should mutex lock an instance of this object + if you need to touch it from multiple threads. !*/ public: @@ -147,6 +149,15 @@ namespace dlib - This function has no effect on this object. !*/ + void shutdown ( + ); + /*! + ensures + - Immediately closes the TCP connection and causes all I/O operations on + this object to return an error. + - It is safe to call this function from any thread, therefore, you can use + it to signal when you want a connection to terminate from another thread. + !*/ }; // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/iostream b/lib/3rdParty/dlib/include/dlib/iostream deleted file mode 100644 index eb0e59e4..00000000 --- a/lib/3rdParty/dlib/include/dlib/iostream +++ /dev/null @@ -1 +0,0 @@ -#include "dlib_include_path_tutorial.txt" diff --git a/lib/3rdParty/dlib/include/dlib/istream b/lib/3rdParty/dlib/include/dlib/istream deleted file mode 100644 index eb0e59e4..00000000 --- a/lib/3rdParty/dlib/include/dlib/istream +++ /dev/null @@ -1 +0,0 @@ -#include "dlib_include_path_tutorial.txt" diff --git a/lib/3rdParty/dlib/include/dlib/java/java_array.h b/lib/3rdParty/dlib/include/dlib/java/java_array.h new file mode 100644 index 00000000..6c4d5f03 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/java/java_array.h @@ -0,0 +1,605 @@ +// Copyright (C) 2017 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SWIG_JAVA_ARRAY_H_ +#define DLIB_SWIG_JAVA_ARRAY_H_ + + +/* + + This file defines three special classes: array, array_view, and array_view_crit. An + array is a simple opaque handle to a java array, like a double[] array. The array_view + and array_view_crit objects allow you to access the contents of an array. The + interfaces of these objects is shown below, but for an example use, suppose you had an + array of int in java and you wanted to pass it to C++. You could create a C++ function + like this: + + void my_function(const array_view& array); + + and then within java you could call it with code like this: + + int[] array = new int[100]; + my_function(array); + + and it will work just like you would expect. The array_view will usually result in + the JVM doing a copy in the background. However, you can also declare your function + like this: + + void my_function(const array_view_crit& array); + + and still call it the same way in java, however, using array_view_crit will usually + not result in any copying, and is therefore very fast. array_view_crit uses the JNI + routine GetPrimitiveArrayCritical() to get a lock on the java memory underlying the + array. So it will probably prevent the garbage collector from running while your + function is executing. The JNI documentation is somewhat vague on the limitations of + GetPrimitiveArrayCritical(), saying only that you shouldn't hold the lock on the array + for "an extended period" or call back into the JVM. Deciding whether or not this + matters in your application is left as an exercise for the reader. + + + There are two ways you can declare your methods if they take an array_view or + array_view_crit. Taking a const reference or a non-const reference. E.g. + void my_function(const array_view& array); + void my_function(array_view& array); + You can't declare them to be by value. The non-const version allows you to modify the + contents of the array and the modifications will be visible to java, as you would + expect. You can also make functions that take array objects directly, but that's only + useful if you want to store the array handle somewhere, like in a member of a long + lived class. You can also write functions that return arrays back to java. E.g. + array make_an_array(size_t s) + { + array arr(s); + array_view aview(arr); + // Use aview to put data into the array and generally do something useful. + ... + return arr; + } + This would create an array and return it as a java int[] array. + + + You can also of course use functions taking many arguments, as is normally the case + with SWIG. Finally, these classes work with the following primitive types: + - int16_t + - int32_t + - int64_t + - char (corresponding to java byte) + - float + - double + + + + +namespace java +{ + template + class array + { + /!* + WHAT THIS OBJECT REPRESENTS + This is a handle to a java array. I.e. a reference to an array instance in + java like a double[] or int[]. It doesn't do anything other than tell you + the size of the array and allow you to hold a reference to it. + + To access the array contents, you need to create an array_view or + array_view_crit from the array. + *!/ + public: + array(); + /!* + ensures + - #size() == 0 + - this array is a null reference, i.e. it doesn't reference any array. + *!/ + + explicit array(size_t new_size); + /!* + ensures + - #size() == new_size + - Allocates a new java array. + - This array is a reference to the newly allocated java array object. + *!/ + + size_t size() const; + /!* + ensures + - returns the number of elements in this java array. + *!/ + + void swap(array& item); + /!* + ensures + - swaps the state of *this and item. + *!/ + + array(const array& item); + array& operator= (const array& item) + array(array&& item); + array& operator= (array&& item); + /!* + ensures + - The array is copyable, assignable, and movable. All copies will + reference the same underlying array. So the copies are shallow, as is + normally the case with java reference semantics. + *!/ + }; + + + + template + class array_view + { + /!* + WHAT THIS OBJECT REPRESENTS + This is a view into a java array object. It allows you to access the + values stored in an array and modify them if you want to. + + You should only create array_view objects locally in a function since an + array_view is only valid as long as the array it references exists. So + don't store array_view objects in the member area of a class or globally. + *!/ + + public: + array_view(); + /!* + ensures + - #size() == 0 + - #data() == nullptr + *!/ + + array_view(const array& arr, bool might_be_modified=true); + /!* + ensures + - #size() == arr.size() + - #data() == a pointer to the beginning of the array data referenced by arr. + - When you get a view on a java array, sometimes the JVM will actually + give you a pointer to a copy of the original array. You therefore have + to tell the JVM if you modified the array when you are done using it. If + you say you modified it then the JVM will perform another copy from your + memory buffer back into the JVM. The state of might_be_modified controls + if we do this. So if you are going to modify the array via this + array_view you should set might_be_modified==true. + *!/ + + size_t size() const; + /!* + ensures + - returns the number of elements in this java array. + *!/ + + T* data(); + const T* data() const; + /!* + ensures + - returns a pointer to the beginning of the array. Or nullptr if this is a + handle to null, rather than an actual array instance. + *!/ + + T* begin(); + T* end(); + const T* begin() const; + const T* end() const; + /!* + ensures + - returns iterators to the start and one-past-the-end of the array, as is + the convention for iterator ranges in C++. + *!/ + + T& operator[](size_t i); + const T& operator[](size_t i) const; + /!* + ensures + - returns data()[i] + *!/ + + private: + // this object is non-copyable. + array_view(const array_view&); + array_view& operator=(const array_view&); + }; + + + template + class array_view_crit + { + /!* + WHAT THIS OBJECT REPRESENTS + This is just like an array_view and has an identical interface. The only + difference is that we use the JNI call GetPrimitiveArrayCritical() to get a + critical lock on the array's memory. Therefore, using array_view_crit is + usually faster than array_view since it avoids any unnecessary copying back + and forth between the JVM. + + However, this critical lock can block the JVM's garbage collector from + running. So don't create long lived array_view_crit objects. + *!/ + }; + +} +*/ + + + + + + + + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// IMPLEMENTATION DETAILS +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + + + + + + + +namespace java +{ + +template +class array_view_base +{ +public: + array_view_base() = default; + + size_t size() const { return sz; } + T* data() { return pdata; } + const T* data() const { return pdata; } + + T* begin() { return pdata; } + T* end() { return pdata+sz; } + const T* begin() const { return pdata; } + const T* end() const { return pdata+sz; } + + T& operator[](size_t i) { return pdata[i]; } + const T& operator[](size_t i) const { return pdata[i]; } + +protected: + T* pdata = nullptr; + size_t sz = 0; + +private: + // this object is non-copyable + array_view_base(const array_view_base&); + array_view_base& operator=(const array_view_base&); + +}; + + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + +template +struct find_java_array_type; + +template <> struct find_java_array_type { typedef jshortArray type; }; +template <> struct find_java_array_type { typedef jintArray type; }; +template <> struct find_java_array_type { typedef jlongArray type; }; +template <> struct find_java_array_type { typedef jbyteArray type; }; +template <> struct find_java_array_type { typedef jfloatArray type; }; +template <> struct find_java_array_type { typedef jdoubleArray type; }; + +jshortArray create_java_array(int16_t, size_t size) { return JNI_GetEnv()->NewShortArray(size); } +jintArray create_java_array(int32_t, size_t size) { return JNI_GetEnv()->NewIntArray(size); } +jlongArray create_java_array(int64_t, size_t size) { return JNI_GetEnv()->NewLongArray(size); } +jbyteArray create_java_array(char, size_t size) { return JNI_GetEnv()->NewByteArray(size); } +jfloatArray create_java_array(float, size_t size) { return JNI_GetEnv()->NewFloatArray(size); } +jdoubleArray create_java_array(double , size_t size) { return JNI_GetEnv()->NewDoubleArray(size); } + +template +class array +{ +public: + + typedef typename find_java_array_type::type java_type; + + array() {} + + explicit array(size_t size) + { + ref = create_java_array(T(),size); + is_global_ref = false; + } + + array(java_type ref_) + { + if (ref_) + { + ref = (java_type)JNI_GetEnv()->NewGlobalRef(ref_); + is_global_ref = true; + } + } + +#ifndef SWIG + array(array&& item) + { + ref = item.ref; + is_global_ref = item.is_global_ref; + item.ref = NULL; + item.is_global_ref = false; + } + array& operator= (array&& item) + { + array(std::move(item)).swap(*this); + return *this; + } +#endif + + ~array() + { + if (ref) + { + // Don't delete the reference if it's a local reference, since the only reason + // we will normally be using array object's that contain local references + // is because we plan on returning the newly constructed array back to the JVM, + // which automatically frees local references using the normal JVM garbage + // collection scheme. + if (is_global_ref) + JNI_GetEnv()->DeleteGlobalRef(ref); + + ref = NULL; + is_global_ref = false; + } + } + + size_t size() const + { + if (ref) + return JNI_GetEnv()->GetArrayLength(ref); + else + return 0; + } + + array(const array& item) + { + array(item.ref).swap(*this); + } + + array& operator= (const array& item) + { + array(item).swap(*this); + return *this; + } + + operator java_type() const { return ref;} + + void swap(array& item) + { + std::swap(ref, item.ref); + std::swap(is_global_ref, item.is_global_ref); + } + +private: + java_type ref = NULL; + bool is_global_ref = false; +}; + +#ifdef SWIG +// Tell SWIG to not use it's SwigValueWrapper stuff on array objects since they aren't +// needed and it causes superfluous construction and destruction of array objects. +%feature("novaluewrapper") array; +%template() array; +%feature("novaluewrapper") array; +%template() array; +%feature("novaluewrapper") array; +%template() array; +%feature("novaluewrapper") array; +%template() array; +%feature("novaluewrapper") array; +%template() array; +%feature("novaluewrapper") array; +%template() array; +#endif + +#ifdef SWIG +%define tostring(token) + #token +%enddef + +%define define_javaObjectRef_converion(type, java_type) + // Define array conversions for non-const arrays + %typemap(jtype) (array) "java_type[]" + %typemap(jstype) (array) "java_type[]" + %typemap(jni) (array) tostring(j##java_type##Array) + %typemap(javain) (array) "$javainput" + %typemap(in) (array) { $1 = java::array($input); } + %typemap(javaout) (array) {return $jnicall; } + %typemap(out) (array) {jresult = result;} + + %typemap(jtype) (array&) "java_type[]" + %typemap(jstype) (array&) "java_type[]" + %typemap(jni) (array&) tostring(j##java_type##Array) + %typemap(javain) (array&) "$javainput" + %typemap(arginit) (array&) { $1 = &temp$argnum; } + %typemap(in) (array&) (java::array temp) { *($1) = java::array($input); } + + %typemap(jtype) (const array&) "java_type[]" + %typemap(jstype) (const array&) "java_type[]" + %typemap(jni) (const array&) tostring(j##java_type##Array) + %typemap(javain) (const array&) "$javainput" + %typemap(arginit) (const array&) { $1 = &temp$argnum; } + %typemap(in) (const array&) (java::array temp) { *($1) = java::array($input); } +%enddef +define_javaObjectRef_converion(int16_t,short) +define_javaObjectRef_converion(int32_t,int) +define_javaObjectRef_converion(int64_t,long) +define_javaObjectRef_converion(char,byte) +define_javaObjectRef_converion(float,float) +define_javaObjectRef_converion(double,double) + +#endif +// ---------------------------------------------------------------------------------------- + +template class array_view; + +#define JAVA_ARRAY_CLASS_SPEC(ctype, type, Type) \ +template <> class array_view : public array_view_base \ +{ \ +public: \ + ~array_view() { clear(); } \ + array_view() {} \ + array_view(const array& arr, bool might_be_modified_=true){reset(JNI_GetEnv(),arr,might_be_modified_);} \ + void reset(JNIEnv* jenv_, j##type##Array arr, bool might_be_modified_) { \ + clear(); \ + jenv = jenv_; \ + oldArr = arr; \ + if (arr) { \ + pdata = (ctype*)jenv->Get##Type##ArrayElements(arr, 0); \ + sz = jenv->GetArrayLength(arr); \ + } \ + might_be_modified = might_be_modified_; \ + } \ +private: \ + void clear() { \ + if (pdata) { \ + jenv->Release##Type##ArrayElements(oldArr, (j##type*)pdata, might_be_modified?0:JNI_ABORT); \ + pdata = nullptr; \ + sz = 0; \ + } \ + } \ + JNIEnv* jenv = nullptr; \ + j##type##Array oldArr; \ + bool might_be_modified; \ +}; + +JAVA_ARRAY_CLASS_SPEC(int16_t,short, Short) +JAVA_ARRAY_CLASS_SPEC(int32_t,int, Int) +JAVA_ARRAY_CLASS_SPEC(int64_t,long, Long) +JAVA_ARRAY_CLASS_SPEC(char,byte, Byte) +JAVA_ARRAY_CLASS_SPEC(float,float, Float) +JAVA_ARRAY_CLASS_SPEC(double,double, Double) + + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + +template +class array_view_crit_base +{ +public: + array_view_crit_base() = default; + + size_t size() const { return sz; } + T* data() { return pdata; } + const T* data() const { return pdata; } + + T* begin() { return pdata; } + T* end() { return pdata+sz; } + const T* begin() const { return pdata; } + const T* end() const { return pdata+sz; } + T& operator[](size_t i) { return pdata[i]; } + const T& operator[](size_t i) const { return pdata[i]; } + + ~array_view_crit_base() { clear(); } + + void reset(JNIEnv* jenv_, JARR arr, bool might_be_modified_) + { + clear(); + jenv = jenv_; + oldArr = arr; + if (arr) + { + pdata = (T*)jenv->GetPrimitiveArrayCritical(arr, 0); + sz = jenv->GetArrayLength(arr); + } + might_be_modified = might_be_modified_; + } + +private: + + void clear() + { + if (pdata) { + jenv->ReleasePrimitiveArrayCritical(oldArr, pdata, might_be_modified?0:JNI_ABORT); + pdata = nullptr; + sz = 0; + } + } + + // this object is non-copyable + array_view_crit_base(const array_view_crit_base&); + array_view_crit_base& operator=(const array_view_crit_base&); + + T* pdata = nullptr; + size_t sz = 0; + JNIEnv* jenv = nullptr; + JARR oldArr; + bool might_be_modified; +}; + +template class array_view_crit; + +template <> class array_view_crit : public array_view_crit_base { public: array_view_crit(){} array_view_crit(const array& arr, bool might_be_modified_=true){reset(JNI_GetEnv(),arr,might_be_modified_);} }; +template <> class array_view_crit : public array_view_crit_base { public: array_view_crit(){} array_view_crit(const array& arr, bool might_be_modified_=true){reset(JNI_GetEnv(),arr,might_be_modified_);} }; +template <> class array_view_crit : public array_view_crit_base { public: array_view_crit(){} array_view_crit(const array& arr, bool might_be_modified_=true){reset(JNI_GetEnv(),arr,might_be_modified_);} }; +template <> class array_view_crit : public array_view_crit_base { public: array_view_crit(){} array_view_crit(const array& arr, bool might_be_modified_=true){reset(JNI_GetEnv(),arr,might_be_modified_);} }; +template <> class array_view_crit : public array_view_crit_base { public: array_view_crit(){} array_view_crit(const array& arr, bool might_be_modified_=true){reset(JNI_GetEnv(),arr,might_be_modified_);} }; +template <> class array_view_crit : public array_view_crit_base { public: array_view_crit(){} array_view_crit(const array& arr, bool might_be_modified_=true){reset(JNI_GetEnv(),arr,might_be_modified_);} }; + +// ---------------------------------------------------------------------------------------- + +// Define SWIG typemaps so SWIG will know what to do with the array_view and array_view_crit +// objects. +#ifdef SWIG +%define define_array_converion(type, java_type) + // Define array conversions for non-const arrays + %typemap(jtype) (array_view&) "java_type[]" + %typemap(jstype) (array_view&) "java_type[]" + %typemap(jni) (array_view&) tostring(j##java_type##Array) + %typemap(javain) (array_view&) "$javainput" + %typemap(arginit) (array_view&) { $1 = &temp$argnum; } + %typemap(in) (array_view&) (java::array_view temp) { $1->reset(jenv, $input, true); } + + %typemap(jtype) (const array_view&) "java_type[]" + %typemap(jstype) (const array_view&) "java_type[]" + %typemap(jni) (const array_view&) tostring(j##java_type##Array) + %typemap(javain) (const array_view&) "$javainput" + %typemap(arginit) (const array_view&) { $1 = &temp$argnum; } + %typemap(in) (const array_view&) (java::array_view temp) { $1->reset(jenv, $input, false); } +%enddef +define_array_converion(int16_t,short) +define_array_converion(int32_t,int) +define_array_converion(int64_t,long) +define_array_converion(char,byte) +define_array_converion(float,float) +define_array_converion(double,double) + + + +%define define_array_crit_converion(type, java_type) + // Define array conversions for non-const arrays + %typemap(jtype) (array_view_crit&) "java_type[]" + %typemap(jstype) (array_view_crit&) "java_type[]" + %typemap(jni) (array_view_crit&) tostring(j##java_type##Array) + %typemap(javain) (array_view_crit&) "$javainput" + %typemap(arginit) (array_view_crit&) { $1 = &temp$argnum; } + %typemap(in) (array_view_crit&) (java::array_view_crit temp) { $1->reset(jenv, $input, true); } + + %typemap(jtype) (const array_view_crit&) "java_type[]" + %typemap(jstype) (const array_view_crit&) "java_type[]" + %typemap(jni) (const array_view_crit&) tostring(j##java_type##Array) + %typemap(javain) (const array_view_crit&) "$javainput" + %typemap(arginit) (const array_view_crit&) { $1 = &temp$argnum; } + %typemap(in) (const array_view_crit&) (java::array_view_crit temp) { $1->reset(jenv, $input, false); } +%enddef +define_array_crit_converion(int16_t,short) +define_array_crit_converion(int32_t,int) +define_array_crit_converion(int64_t,long) +define_array_crit_converion(char,byte) +define_array_crit_converion(float,float) +define_array_crit_converion(double,double) + +#endif // SWIG + +} + +#endif // DLIB_SWIG_JAVA_ARRAY_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/java/swig_api.h b/lib/3rdParty/dlib/include/dlib/java/swig_api.h new file mode 100644 index 00000000..e807c6c8 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/java/swig_api.h @@ -0,0 +1,126 @@ +#ifndef EXAMPLE_SWIG_ApI_H_ +#define EXAMPLE_SWIG_ApI_H_ + +// This file is essentially a small unit test for the swig cmake scripts and the java array +// classes. All it does it define a few simple functions for writing to and summing +// arrays. The swig_test.java file then calls these C++ functions and checks if they work +// correctly. + + + +// Let's use java_array.h, a tool for efficiently binding java native arrays to C++ +// function arguments. You do this by putting this pair of include statements in your +// swig_api.h file. Then after that you can use the java::array, java::array_view, and +// java::array_view_crit classes. +#include +#ifdef SWIG +%include +#endif + + +using namespace java; + + +// SWIG can't expose templated functions to java. We declare these here as helper +// functions to make the non-templated routines swig will expose easier to write. You can +// see these java exposed methods below (i.e. sum(), sum_crit(), assign(), and +// assign_crit()). +template +T tsum(const array_view_crit& arr) +{ + T s = 0; + for (auto& v : arr) + s += v; + return s; +} +template +T tsum(const array_view& arr) +{ + T s = 0; + for (auto& v : arr) + s += v; + return s; +} +template +void tassign(T& arr) +{ + for (size_t i = 0; i < arr.size(); ++i) + arr[i] = i; +} + +// ---------------------------------------------------------------------------------------- + +// Now write some functions SWIG will expose to java. SWIG will automatically expose +// pretty much any non-template C++ code to java. So just by defining these functions here +// we expose them to java. +// +// All global C++ functions will appear in java as static member functions of class called +// "global", which is where these sum and assign routines will appear. You can see +// examples of java code that calls them in swig_test.java. + +inline int sum_crit(const array_view_crit& arr) { return tsum(arr); } +inline int sum(const array_view& arr) { return tsum(arr); } +inline void assign_crit(array_view_crit& arr) { tassign(arr); } +inline void assign(array_view& arr) { tassign(arr); } + + +inline int sum_crit(const array_view_crit& arr) { return tsum(arr); } +inline int sum(const array_view& arr) { return tsum(arr); } +inline void assign_crit(array_view_crit& arr) { tassign(arr); } +inline void assign(array_view& arr) { tassign(arr); } + + +inline int sum_crit(const array_view_crit& arr) { return tsum(arr); } +inline int sum(const array_view& arr) { return tsum(arr); } +inline void assign_crit(array_view_crit& arr) { tassign(arr); } +inline void assign(array_view& arr) { tassign(arr); } + + +inline int sum_crit(const array_view_crit& arr) { return tsum(arr); } +inline int sum(const array_view& arr) { return tsum(arr); } +inline void assign_crit(array_view_crit& arr) { tassign(arr); } +inline void assign(array_view& arr) { tassign(arr); } + + + +inline double sum_crit(const array_view_crit& arr) { return tsum(arr); } +inline double sum(const array_view& arr) { return tsum(arr); } +inline void assign_crit(array_view_crit& arr) { tassign(arr); } +inline void assign(array_view& arr) { tassign(arr); } + + +inline float sum_crit(array arr) +{ + array_view_crit a(arr); + return tsum(a); +} +inline float sum(const array& arr) +{ + array_view a(arr); + return tsum(a); +} +inline void assign_crit(array_view_crit& arr) { tassign(arr); } +inline void assign(array& arr) +{ + array_view a(arr); + tassign(a); +} + +array make_an_array(size_t s) +{ + array arr(s); + array_view_crit a(arr); + + for (size_t i = 0; i < a.size(); ++i) + a[i] = i; + + return arr; +} + + +// ---------------------------------------------------------------------------------------- + + +#endif // EXAMPLE_SWIG_ApI_H_ + + diff --git a/lib/3rdParty/dlib/include/dlib/linker/linker_kernel_1.cpp b/lib/3rdParty/dlib/include/dlib/linker/linker_kernel_1.cpp deleted file mode 100644 index e76009b3..00000000 --- a/lib/3rdParty/dlib/include/dlib/linker/linker_kernel_1.cpp +++ /dev/null @@ -1,357 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_LINKER_KERNEL_1_CPp_ -#define DLIB_LINKER_KERNEL_1_CPp_ -#include "linker_kernel_1.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // member function definitions -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - linker:: - linker ( - ) : - running(false), - running_signaler(running_mutex), - A(0), - B(0), - service_connection_running_signaler(service_connection_running_mutex) - { - } - -// ---------------------------------------------------------------------------------------- - - linker:: - linker ( - connection& a, - connection& b - ) : - running(false), - running_signaler(running_mutex), - A(0), - B(0), - service_connection_running_signaler(service_connection_running_mutex) - { - link(a,b); - } - -// ---------------------------------------------------------------------------------------- - - linker:: - ~linker ( - ) - { - clear(); - } - -// ---------------------------------------------------------------------------------------- - - void linker:: - clear ( - ) - { - - // shutdown the connections - cons_mutex.lock(); - if (A != 0 ) - { - A->shutdown(); - A = 0; - } - if (B != 0) - { - B->shutdown(); - B = 0; - } - cons_mutex.unlock(); - - - // wait for the other threads to signal that they have ended - running_mutex.lock(); - while (running == true) - { - running_signaler.wait(); - } - running_mutex.unlock(); - - } - -// ---------------------------------------------------------------------------------------- - - bool linker:: - is_running ( - ) const - { - running_mutex.lock(); - bool temp = running; - running_mutex.unlock(); - return temp; - } - -// ---------------------------------------------------------------------------------------- - - void linker:: - link ( - connection& a, - connection& b - ) - { - // make sure requires clause is not broken - DLIB_CASSERT( - this->is_running() == false , - "\tvoid linker::link" - << "\n\tis_running() == " << this->is_running() - << "\n\tthis: " << this - ); - - running_mutex.lock(); - running = true; - running_mutex.unlock(); - - cons_mutex.lock(); - A = &a; - B = &b; - cons_mutex.unlock(); - - - - service_connection_running_mutex.lock(); - service_connection_running = true; - service_connection_running_mutex.unlock(); - - service_connection_error_mutex.lock(); - service_connection_error = false; - service_connection_error_mutex.unlock(); - - // if we fail to make the thread - if (!create_new_thread(service_connection,this)) - { - a.shutdown(); - b.shutdown(); - - service_connection_running_mutex.lock(); - service_connection_running = false; - service_connection_running_mutex.unlock(); - - cons_mutex.lock(); - A = 0; - B = 0; - cons_mutex.unlock(); - - running_mutex.lock(); - running = false; - running_mutex.unlock(); - - - - throw dlib::thread_error ( - ECREATE_THREAD, - "failed to make new thread in linker::link()" - ); - } - - - - // forward data from a to b - char buf[200]; - int status; - bool error = false; // becomes true if one of the connections returns an error - while (true) - { - status = a.read(buf,sizeof(buf)); - // if there was an error reading from the socket - if (status == OTHER_ERROR) - { - error = true; - break; - } - else if (status == SHUTDOWN) - { - b.shutdown(); - } - - if (status <= 0) - { - // if a has closed normally - if (status == 0) - b.shutdown_outgoing(); - break; - } - - status = b.write(buf,status); - // if there was an error writing to the socket then break - if (status == OTHER_ERROR) - { - error = true; - break; - } - - if (status <= 0) - break; - } - - - // if there was an error then shutdown both connections - if (error) - { - a.shutdown(); - b.shutdown(); - } - - - - - // wait for the other thread to end - service_connection_running_mutex.lock(); - while(service_connection_running) - { - service_connection_running_signaler.wait(); - } - service_connection_running_mutex.unlock(); - - - // make sure connections are shutdown - a.shutdown(); - b.shutdown(); - - - // both threads have ended so the connections are no longer needed - cons_mutex.lock(); - A = 0; - B = 0; - cons_mutex.unlock(); - - - // if service_connection terminated due to an error then set error to true - service_connection_error_mutex.lock(); - if (service_connection_error) - error = true; - service_connection_error_mutex.unlock(); - - - // if we are ending because of an error - if (error) - { - - // signal that the link() function is ending - running_mutex.lock(); - running = false; - running_signaler.broadcast(); - running_mutex.unlock(); - - // throw the exception for this error - throw dlib::socket_error ( - ECONNECTION, - "a connection returned an error in linker::link()" - ); - - } - - // signal that the link() function is ending - running_mutex.lock(); - running = false; - running_signaler.broadcast(); - running_mutex.unlock(); - } - -// ---------------------------------------------------------------------------------------- - - void linker:: - service_connection ( - void* param - ) - { - linker& p = *static_cast(param); - - p.cons_mutex.lock(); - // if the connections are gone for whatever reason then return - if (p.A == 0 || p.B == 0) - { - // signal that this function is ending - p.service_connection_running_mutex.lock(); - p.service_connection_running = false; - p.service_connection_running_signaler.broadcast(); - p.service_connection_running_mutex.unlock(); - return; - } - connection& a = *p.A; - connection& b = *p.B; - p.cons_mutex.unlock(); - - - - // forward data from b to a - char buf[200]; - int status; - bool error = false; - while (true) - { - status = b.read(buf,sizeof(buf)); - // if there was an error reading from the socket - if (status == OTHER_ERROR) - { - error = true; - break; - } - else if (status == SHUTDOWN) - { - a.shutdown(); - } - - - if (status <= 0) - { - // if b has closed normally - if (status == 0) - a.shutdown_outgoing(); - break; - } - - - status = a.write(buf,status); - // if there was an error writing to the socket then break - if (status == OTHER_ERROR) - { - error = true; - break; - } - - if (status <= 0) - break; - } - - - // if there was an error then shutdown both connections - if (error) - { - a.shutdown(); - b.shutdown(); - } - - - // if there was an error then signal that - if (error) - { - p.service_connection_error_mutex.lock(); - p.service_connection_error = true; - p.service_connection_error_mutex.unlock(); - } - - // signal that this function is ending - p.service_connection_running_mutex.lock(); - p.service_connection_running = false; - p.service_connection_running_signaler.broadcast(); - p.service_connection_running_mutex.unlock(); - - } - -// ---------------------------------------------------------------------------------------- - -} -#endif // DLIB_LINKER_KERNEL_1_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/locale b/lib/3rdParty/dlib/include/dlib/locale deleted file mode 100644 index eb0e59e4..00000000 --- a/lib/3rdParty/dlib/include/dlib/locale +++ /dev/null @@ -1 +0,0 @@ -#include "dlib_include_path_tutorial.txt" diff --git a/lib/3rdParty/dlib/include/dlib/logger/extra_logger_headers.cpp b/lib/3rdParty/dlib/include/dlib/logger/extra_logger_headers.cpp deleted file mode 100644 index becc1ab2..00000000 --- a/lib/3rdParty/dlib/include/dlib/logger/extra_logger_headers.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_EXTRA_LOGGER_HEADERs_CPP_ -#define DLIB_EXTRA_LOGGER_HEADERs_CPP_ - -#include "extra_logger_headers.h" -#include -#include - -// ---------------------------------------------------------------------------------------- - -namespace dlib -{ - - void print_datetime_logger_header ( - std::ostream& out, - const std::string& logger_name, - const log_level& l, - const uint64 thread_id - ) - { - using namespace std; - char* buf; - - time_t t = time(0); - buf = ctime(&t); - // remove the trailing '\n' - size_t size = strlen(buf); - buf[size-1] = '\0'; - - out << l.name << " (" << buf << ") [" << thread_id << "] " << logger_name << ": "; - } - -} - -// ---------------------------------------------------------------------------------------- - -#endif // DLIB_EXTRA_LOGGER_HEADERs_CPP_ - - diff --git a/lib/3rdParty/dlib/include/dlib/logger/logger_config_file.cpp b/lib/3rdParty/dlib/include/dlib/logger/logger_config_file.cpp deleted file mode 100644 index 6595204f..00000000 --- a/lib/3rdParty/dlib/include/dlib/logger/logger_config_file.cpp +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright (C) 2007 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_LOGGER_CONFIg_FILE_CPP -#define DLIB_LOGGER_CONFIg_FILE_CPP - -#include "logger_config_file.h" -#include -#include "../config_reader.h" -#include -#include -#include "../error.h" -#include "../map.h" -#include "../string.h" - -// ---------------------------------------------------------------------------------------- - -namespace dlib -{ - - namespace logger_config_file_helpers - { - typedef config_reader::kernel_1a cr_type; - -// ---------------------------------------------------------------------------------------- - - std::ostream& get_file_stream ( - const std::string& file_name - ) - { - using namespace std; - static dlib::mutex m; - auto_mutex M(m); - static dlib::map::kernel_1a_c file_map; - - if (file_map.is_in_domain(file_name) == false) - { - // We won't ever delete this output stream. It should be around for the - // entire life of the program so just let the OS take care of it. - ostream* fout = new ofstream(file_name.c_str()); - if (!(*fout)) - { - delete fout; - throw error("logger_config: unable to open output file " + file_name); - } - - // add this file to our file map - string temp(file_name); - file_map.add(temp,fout); - } - - return *file_map[file_name]; - } - -// ---------------------------------------------------------------------------------------- - - log_level string_to_log_level ( - const std::string& level - ) - { - using namespace std; - if (level == "LALL" || level == "ALL" || level == "all") - return LALL; - else if (level == "LNONE" || level == "NONE" || level == "none") - return LNONE; - else if (level == "LTRACE" || level == "TRACE" || level == "trace") - return LTRACE; - else if (level == "LDEBUG" || level == "DEBUG" || level == "debug") - return LDEBUG; - else if (level == "LINFO" || level == "INFO" || level == "info") - return LINFO; - else if (level == "LWARN" || level == "WARN" || level == "warn") - return LWARN; - else if (level == "LERROR" || level == "ERROR" || level == "error") - return LERROR; - else if (level == "LFATAL" || level == "FATAL" || level == "fatal") - return LFATAL; - else - { - const int priority = string_cast(level); - return log_level(priority,"CONFIG_FILE_DEFINED"); - } - } - -// ---------------------------------------------------------------------------------------- - - void configure_sub_blocks ( - const cr_type& cr, - const std::string& name - ) - { - using namespace std; - - logger dlog(name.c_str()); - - if (cr.is_key_defined("logging_level")) - { - dlog.set_level(string_to_log_level(cr["logging_level"])); - } - - if (cr.is_key_defined("output")) - { - string output = cr["output"]; - if (output == "cout") - dlog.set_output_stream(cout); - else if (output == "cerr") - dlog.set_output_stream(cerr); - else if (output == "clog") - dlog.set_output_stream(clog); - else - { - istringstream sin(output); - string one, two, three; - sin >> one; - sin >> two; - sin >> three; - if (one == "file" && three.size() == 0) - dlog.set_output_stream(get_file_stream(two)); - else - throw error("logger_config: invalid argument to output option: " + output); - } - - } // if (cr.is_key_defined("output")) - - // now configure all the sub-blocks - std_vector_c blocks; - cr.get_blocks(blocks); - for (unsigned long i = 0; i < blocks.size(); ++i) - { - configure_sub_blocks(cr.block(blocks[i]), name + "." + blocks[i]); - } - - } - -// ---------------------------------------------------------------------------------------- - - } // namespace - -// ---------------------------------------------------------------------------------------- - - void configure_loggers_from_file ( - const std::string& file_name - ) - { - using namespace logger_config_file_helpers; - using namespace std; - ifstream fin(file_name.c_str()); - - if (!fin) - throw logger_config_file_error("logger_config: unable to open config file " + file_name); - - - cr_type main_cr; - main_cr.load_from(fin); - - - if (main_cr.is_block_defined("logger_config")) - { - const cr_type& cr = main_cr.block("logger_config"); - - if (cr.is_key_defined("logging_level")) - { - set_all_logging_levels(string_to_log_level(cr["logging_level"])); - } - - if (cr.is_key_defined("output")) - { - string output = cr["output"]; - if (output == "cout") - set_all_logging_output_streams(cout); - else if (output == "cerr") - set_all_logging_output_streams(cerr); - else if (output == "clog") - set_all_logging_output_streams(clog); - else - { - istringstream sin(output); - string one, two, three; - sin >> one; - sin >> two; - sin >> three; - if (one == "file" && three.size() == 0) - set_all_logging_output_streams(get_file_stream(two)); - else - throw logger_config_file_error("logger_config: invalid argument to output option: " + output); - } - - } // if (cr.is_key_defined("output")) - - // now configure all the sub-blocks - std_vector_c blocks; - cr.get_blocks(blocks); - for (unsigned long i = 0; i < blocks.size(); ++i) - { - configure_sub_blocks(cr.block(blocks[i]), blocks[i]); - } - - } - } - -// ---------------------------------------------------------------------------------------- - -} - -// ---------------------------------------------------------------------------------------- - -#endif // DLIB_LOGGER_CONFIg_FILE_CPP - - - diff --git a/lib/3rdParty/dlib/include/dlib/logger/logger_config_file.h b/lib/3rdParty/dlib/include/dlib/logger/logger_config_file.h index 02121992..b0a030f8 100644 --- a/lib/3rdParty/dlib/include/dlib/logger/logger_config_file.h +++ b/lib/3rdParty/dlib/include/dlib/logger/logger_config_file.h @@ -34,6 +34,19 @@ namespace dlib this exception is thrown if there is a problem reading the config file !*/ + void configure_loggers_from_file ( + const config_reader& cr + ); + /*! + ensures + - configures the loggers with the contents of cr. This function is just like + the above version that reads from a file except that it reads from an in-memory + config_reader instead. + throws + - dlib::logger_config_file_error + this exception is thrown if there is a problem reading the config file + !*/ + // ---------------------------------------------------------------------------------------- /*! diff --git a/lib/3rdParty/dlib/include/dlib/logger/logger_kernel_1.cpp b/lib/3rdParty/dlib/include/dlib/logger/logger_kernel_1.cpp deleted file mode 100644 index eb46c9f5..00000000 --- a/lib/3rdParty/dlib/include/dlib/logger/logger_kernel_1.cpp +++ /dev/null @@ -1,483 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_LOGGER_KERNEL_1_CPp_ -#define DLIB_LOGGER_KERNEL_1_CPp_ - -#include "logger_kernel_1.h" -#include -#include - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - void set_all_logging_output_streams ( - std::ostream& out_ - ) - { - logger::global_data& gd = logger::get_global_data(); - auto_mutex M(gd.m); - gd.loggers.reset(); - while (gd.loggers.move_next()) - { - gd.loggers.element()->out.rdbuf(out_.rdbuf()); - gd.loggers.element()->hook.clear(); - } - - gd.set_output_stream("",out_); - - // set the default hook to be an empty member function pointer - logger::hook_mfp hook; - gd.set_output_hook("",hook); - } - - void set_all_logging_levels ( - const log_level& new_level - ) - { - logger::global_data& gd = logger::get_global_data(); - auto_mutex M(gd.m); - gd.loggers.reset(); - while (gd.loggers.move_next()) - { - gd.loggers.element()->cur_level = new_level; - } - - gd.set_level("",new_level); - } - -// ---------------------------------------------------------------------------------------- - - namespace logger_helper_stuff - { - class helper - { - public: - helper() - { - std::ostringstream sout; - print_default_logger_header(sout,"some_name",LDEBUG,0); - } - }; - // do this to make sure all the static members of print_default_logger_header get - // initialized when the program turns on. - static helper a; - // make a logger to make extra sure the static global_data object gets - // initialized before any threads start up. Also do this so that there is always - // at least one logger so that the global data won't be deleted until the - // program is terminating. - static logger log("dlib"); - } - -// ---------------------------------------------------------------------------------------- - - void print_default_logger_header ( - std::ostream& out, - const std::string& logger_name, - const log_level& l, - const uint64 thread_id - ) - { - using namespace std; - static timestamper ts; - static const uint64 first_time = ts.get_timestamp(); - - const uint64 cur_time = (ts.get_timestamp() - first_time)/1000; - streamsize old_width = out.width(); out.width(5); - out << cur_time << " " << l.name; - out.width(old_width); - - out << " [" << thread_id << "] " << logger_name << ": "; - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// global_data stuff -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - logger::global_data:: - ~global_data ( - ) - { - unregister_thread_end_handler(*this,&global_data::thread_end_handler); - } - -// ---------------------------------------------------------------------------------------- - - logger::global_data:: - global_data( - ) : - next_thread_name(1) - { - // make sure the main program thread always has id 0. Since there is - // a global logger object declared in this file we should expect that - // the global_data object will be initialized in the main program thread - // so if we call get_thread_id() now we should get the main thread id. - thread_id_type main_id = get_thread_id(); - uint64 id_zero = 0; - thread_names.add(main_id,id_zero); - - // set up the defaults - auto_flush_table.val = true; - streambuf_table.val = std::cout.rdbuf(); - header_table.val = print_default_logger_header; - - // also allocate an initial buffer for hook based logging - hookbuf.buffer.reserve(1000); - } - - logger::global_data::level_container:: - level_container ( - ) : val(300,"ERROR") {} - -// ---------------------------------------------------------------------------------------- - - template - const T& search_tables ( - const T& c, - const std::string& name - ) - { - if (c.table.size() == 0 || name.size() == 0) - return c; - - const std::string::size_type pos = name.find_first_of("."); - const std::string first = name.substr(0,pos); - std::string last; - if (pos != std::string::npos) - last = name.substr(pos+1); - - if (c.table.is_in_domain(first)) - { - return search_tables(*c.table[first], last); - } - else - { - return c; - } - } - -// ---------------------------------------------------------------------------------------- - - template - void assign_tables ( - T& c, - const std::string& name, - const U& val - ) - { - if (name.size() == 0) - { - c.val = val; - c.table.clear(); - return; - } - - const std::string::size_type pos = name.find_first_of("."); - std::string first = name.substr(0,pos); - std::string last; - if (pos != std::string::npos) - last = name.substr(pos+1); - - if (c.table.is_in_domain(first)) - { - assign_tables(*c.table[first], last, val); - } - else - { - scoped_ptr temp (new T); - temp->val = c.val; - assign_tables(*temp, last, val); - c.table.add(first,temp); - } - } - -// ---------------------------------------------------------------------------------------- - - const log_level logger::global_data:: - level ( - const std::string& name - ) const - { - auto_mutex M(m); - return search_tables(level_table, name).val; - } - -// ---------------------------------------------------------------------------------------- - - void logger::global_data:: - set_level ( - const std::string& name, - const log_level& new_level - ) - { - auto_mutex M(m); - assign_tables(level_table, name, new_level); - } - -// ---------------------------------------------------------------------------------------- - - bool logger::global_data:: - auto_flush ( - const std::string& name - ) const - { - auto_mutex M(m); - return search_tables(auto_flush_table, name).val; - } - -// ---------------------------------------------------------------------------------------- - - void logger::global_data:: - set_auto_flush ( - const std::string& name, - bool enabled - ) - { - auto_mutex M(m); - assign_tables(auto_flush_table, name, enabled); - } - -// ---------------------------------------------------------------------------------------- - - std::streambuf* logger::global_data:: - output_streambuf ( - const std::string& name - ) - { - auto_mutex M(m); - return search_tables(streambuf_table, name).val; - } - -// ---------------------------------------------------------------------------------------- - - void logger::global_data:: - set_output_stream ( - const std::string& name, - std::ostream& out_ - ) - { - auto_mutex M(m); - assign_tables( streambuf_table, name, out_.rdbuf()); - } - -// ---------------------------------------------------------------------------------------- - - void logger::global_data:: - set_output_stream ( - const std::string& name, - std::streambuf& buf - ) - { - auto_mutex M(m); - assign_tables( streambuf_table, name, &buf); - } - -// ---------------------------------------------------------------------------------------- - - logger::hook_mfp logger::global_data:: - output_hook ( - const std::string& name - ) - { - auto_mutex M(m); - return search_tables(hook_table, name).val; - } - -// ---------------------------------------------------------------------------------------- - - void logger::global_data:: - set_output_hook ( - const std::string& name, - const hook_mfp& hook - ) - { - auto_mutex M(m); - assign_tables( hook_table, name, hook); - } - -// ---------------------------------------------------------------------------------------- - - logger::print_header_type logger::global_data:: - logger_header ( - const std::string& name - ) - { - auto_mutex M(m); - return search_tables(header_table, name).val; - } - -// ---------------------------------------------------------------------------------------- - - void logger::global_data:: - set_logger_header ( - const std::string& name, - print_header_type ph - ) - { - auto_mutex M(m); - assign_tables(header_table, name, ph); - } - -// ---------------------------------------------------------------------------------------- - - logger::global_data& logger::get_global_data() - { - // Allocate the global_data on the heap rather than on the stack because - // we want to guard against the case where this static object would be destroyed - // during program termination BEFORE all logger objects are destroyed. - static global_data* gd = new global_data; - return *gd; - } - -// ---------------------------------------------------------------------------------------- - - void logger::global_data:: - thread_end_handler ( - ) - { - auto_mutex M(m); - thread_id_type id = get_thread_id(); - thread_id_type junkd; - uint64 junkr; - thread_names.remove(id,junkd,junkr); - } - -// ---------------------------------------------------------------------------------------- - - uint64 logger::global_data:: - get_thread_name ( - ) - { - thread_id_type id = get_thread_id(); - uint64 thread_name; - if (thread_names.is_in_domain(id)) - { - thread_name = thread_names[id]; - } - else - { - if (is_dlib_thread(id)) - register_thread_end_handler(*this,&global_data::thread_end_handler); - thread_name = next_thread_name; - thread_names.add(id,thread_name); - thread_name = next_thread_name; - ++next_thread_name; - } - return thread_name; - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// logger_stream stuff -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void logger::logger_stream:: - print_header_and_stuff ( - ) - { - if (!been_used) - { - log.gd.m.lock(); - - // Check if the output hook is setup. If it isn't then we print the logger - // header like normal. Otherwise we need to remember to clear out the output - // stringstream we always write to. - if (log.hook.is_set() == false) - { - log.logger_header()(log.out,log.name(),l,log.gd.get_thread_name()); - } - else - { - // Make sure the hook buffer doesn't have any old data in it before we start - // logging a new message into it. - log.gd.hookbuf.buffer.resize(0); - } - been_used = true; - } - } - -// ---------------------------------------------------------------------------------------- - - void logger::logger_stream:: - print_end_of_line ( - ) - { - auto_unlock M(log.gd.m); - - if (log.hook.is_set() == false) - { - if (log.auto_flush_enabled) - log.out << std::endl; - else - log.out << "\n"; - } - else - { - // Make sure the buffer is a proper C-string - log.gd.hookbuf.buffer.push_back('\0'); - // call the output hook with all the info regarding this log message. - log.hook(log.name(), l, log.gd.get_thread_name(), &log.gd.hookbuf.buffer[0]); - } - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// logger stuff -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - logger:: - logger ( - const char* name_ - ) : - gd(get_global_data()), - logger_name(name_), - out(gd.output_streambuf(logger_name)), - cur_level(gd.level(logger_name)) - { - DLIB_ASSERT(name_[0] != '\0', - "\tlogger::logger()" - << "\n\tYou can't make a logger with an empty name" - << "\n\tthis: " << this - ); - - auto_mutex M(gd.m); - logger* temp = this; - gd.loggers.add(temp); - - // load the appropriate settings - print_header = gd.logger_header(logger_name); - auto_flush_enabled = gd.auto_flush(logger_name); - hook = gd.output_hook(logger_name); - } - -// ---------------------------------------------------------------------------------------- - - logger:: - ~logger ( - ) - { - gd.m.lock(); - gd.loggers.destroy(this); - // if this was the last logger then delete the global data - if (gd.loggers.size() == 0) - { - gd.m.unlock(); - delete &gd; - } - else - { - gd.m.unlock(); - } - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_LOGGER_KERNEL_1_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/logger/logger_kernel_1.h b/lib/3rdParty/dlib/include/dlib/logger/logger_kernel_1.h index 4204e938..528bd6f6 100644 --- a/lib/3rdParty/dlib/include/dlib/logger/logger_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/logger/logger_kernel_1.h @@ -3,20 +3,21 @@ #ifndef DLIB_LOGGER_KERNEl_1_ #define DLIB_LOGGER_KERNEl_1_ +#include +#include +#include +#include +#include + #include "../threads.h" #include "../misc_api.h" #include "../set.h" #include "logger_kernel_abstract.h" -#include -#include #include "../algs.h" #include "../assert.h" #include "../uintn.h" #include "../map.h" -#include "../smart_pointers.h" #include "../member_function_pointer.h" -#include -#include namespace dlib { @@ -70,6 +71,17 @@ namespace dlib const log_level& new_level ); + typedef void (*print_header_type)( + std::ostream& out, + const std::string& logger_name, + const log_level& l, + const uint64 thread_id + ); + + void set_all_logging_headers ( + const print_header_type& new_header + ); + // ---------------------------------------------------------------------------------------- void print_default_logger_header ( @@ -227,7 +239,7 @@ namespace dlib const uint64, const char*> hook_mfp; logger ( - const char* name_ + const std::string& name_ ); virtual ~logger ( @@ -352,13 +364,6 @@ namespace dlib gd.set_output_hook(logger_name, hook); } - typedef void (*print_header_type)( - std::ostream& out, - const std::string& logger_name, - const log_level& l, - const uint64 thread_id - ); - print_header_type logger_header ( ) const { return print_header; } @@ -441,7 +446,7 @@ namespace dlib level_container (); log_level val; - map >::kernel_1b_c table; + map >::kernel_1b_c table; } level_table; const log_level level ( @@ -469,7 +474,7 @@ namespace dlib struct auto_flush_container { bool val; - map >::kernel_1b_c table; + map >::kernel_1b_c table; } auto_flush_table; bool auto_flush ( @@ -497,7 +502,7 @@ namespace dlib struct output_streambuf_container { std::streambuf* val; - map >::kernel_1b_c table; + map >::kernel_1b_c table; } streambuf_table; std::streambuf* output_streambuf ( @@ -538,7 +543,7 @@ namespace dlib struct output_hook_container { hook_mfp val; - map >::kernel_1b_c table; + map >::kernel_1b_c table; } hook_table; hook_mfp output_hook ( @@ -566,7 +571,7 @@ namespace dlib struct logger_header_container { print_header_type val; - map >::kernel_1b_c table; + map >::kernel_1b_c table; } header_table; print_header_type logger_header ( @@ -602,6 +607,10 @@ namespace dlib const log_level& new_level ); + friend void set_all_logging_headers ( + const print_header_type& new_header + ); + friend void set_all_logging_output_streams ( std::ostream& out ); diff --git a/lib/3rdParty/dlib/include/dlib/logger/logger_kernel_abstract.h b/lib/3rdParty/dlib/include/dlib/logger/logger_kernel_abstract.h index 0da16a3c..b6a4367a 100644 --- a/lib/3rdParty/dlib/include/dlib/logger/logger_kernel_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/logger/logger_kernel_abstract.h @@ -79,6 +79,26 @@ namespace dlib - std::bad_alloc !*/ +// ---------------------------------------------------------------------------------------- + + typedef void (*print_header_type)( + std::ostream& out, + const std::string& logger_name, + const log_level& l, + const uint64 thread_id + ); + + void set_all_logging_headers ( + const print_header_type& new_header + ); + /*! + ensures + - for all loggers L (even loggers not yet constructed): + - #L.logger_header() == new_header + throws + - std::bad_alloc + !*/ + // ---------------------------------------------------------------------------------------- template < @@ -211,7 +231,7 @@ namespace dlib public: logger ( - const char* name_ + const std::string& name_ ); /*! requires @@ -361,13 +381,6 @@ namespace dlib - std::bad_alloc !*/ - typedef void (*print_header_type)( - std::ostream& out, - const std::string& logger_name, - const log_level& l, - const uint64 thread_id - ); - print_header_type logger_header ( ) const; /*! diff --git a/lib/3rdParty/dlib/include/dlib/lzp_buffer/lzp_buffer_kernel_1.h b/lib/3rdParty/dlib/include/dlib/lzp_buffer/lzp_buffer_kernel_1.h index 3ce1cb52..f24d74ee 100644 --- a/lib/3rdParty/dlib/include/dlib/lzp_buffer/lzp_buffer_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/lzp_buffer/lzp_buffer_kernel_1.h @@ -63,7 +63,7 @@ namespace dlib unsigned long& index ); - inline unsigned long size ( + inline size_t size ( ) const; inline unsigned char operator[] ( @@ -208,7 +208,7 @@ namespace dlib template < typename sbuf > - unsigned long lzp_buffer_kernel_1:: + size_t lzp_buffer_kernel_1:: size ( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/lzp_buffer/lzp_buffer_kernel_2.h b/lib/3rdParty/dlib/include/dlib/lzp_buffer/lzp_buffer_kernel_2.h index 9e503b7d..47c0443f 100644 --- a/lib/3rdParty/dlib/include/dlib/lzp_buffer/lzp_buffer_kernel_2.h +++ b/lib/3rdParty/dlib/include/dlib/lzp_buffer/lzp_buffer_kernel_2.h @@ -63,7 +63,7 @@ namespace dlib unsigned long& index ); - inline unsigned long size ( + inline size_t size ( ) const; inline unsigned char operator[] ( @@ -291,7 +291,7 @@ namespace dlib template < typename sbuf > - unsigned long lzp_buffer_kernel_2:: + size_t lzp_buffer_kernel_2:: size ( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/lzp_buffer/lzp_buffer_kernel_abstract.h b/lib/3rdParty/dlib/include/dlib/lzp_buffer/lzp_buffer_kernel_abstract.h index f3ced319..df8b8c80 100644 --- a/lib/3rdParty/dlib/include/dlib/lzp_buffer/lzp_buffer_kernel_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/lzp_buffer/lzp_buffer_kernel_abstract.h @@ -100,7 +100,7 @@ namespace dlib until clear() is called and succeeds !*/ - unsigned long size ( + size_t size ( ) const; /*! ensures diff --git a/lib/3rdParty/dlib/include/dlib/manifold_regularization/linear_manifold_regularizer.h b/lib/3rdParty/dlib/include/dlib/manifold_regularization/linear_manifold_regularizer.h index 10834222..95b8b112 100644 --- a/lib/3rdParty/dlib/include/dlib/manifold_regularization/linear_manifold_regularizer.h +++ b/lib/3rdParty/dlib/include/dlib/manifold_regularization/linear_manifold_regularizer.h @@ -40,7 +40,7 @@ namespace dlib typedef std::vector::const_iterator const_iterator; - unsigned long size ( + size_t size ( ) const /*! ensures diff --git a/lib/3rdParty/dlib/include/dlib/map/map_kernel_1.h b/lib/3rdParty/dlib/include/dlib/map/map_kernel_1.h index 324ca29a..1c79d179 100644 --- a/lib/3rdParty/dlib/include/dlib/map/map_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/map/map_kernel_1.h @@ -91,7 +91,7 @@ namespace dlib ); // functions from the enumerable interface - inline unsigned long size ( + inline size_t size ( ) const; inline bool at_start ( @@ -311,7 +311,7 @@ namespace dlib typename bst_base, typename mem_manager > - unsigned long map_kernel_1:: + size_t map_kernel_1:: size ( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/matlab/call_matlab.h b/lib/3rdParty/dlib/include/dlib/matlab/call_matlab.h new file mode 100644 index 00000000..cc06a681 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/matlab/call_matlab.h @@ -0,0 +1,852 @@ +// Copyright (C) 2012 Massachusetts Institute of Technology, Lincoln Laboratory +// License: Boost Software License See LICENSE.txt for the full license. +// Authors: Davis E. King (davis@dlib.net) +#ifndef MIT_LL_CALL_MATLAB_H__ +#define MIT_LL_CALL_MATLAB_H__ + +#include +#include +#include +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + +struct invalid_args_exception : error +{ + /*! + WHAT THIS OBJECT REPRESENTS + This is the exception thrown when the mex wrapper tries to convert a matlab + object into a C++ object but for whatever reason can't (usually because the + types don't match). + !*/ + invalid_args_exception(const std::string& msg_): error(msg_) {} + invalid_args_exception(const std::ostringstream& msg_): error(msg_.str()) {} +}; + +// ---------------------------------------------------------------------------------------- + +void check_for_matlab_ctrl_c(); +/*! + ensures + - If the user of MATLAB has pressed ctrl+c then this function will throw an + exception. +!*/ + +// ---------------------------------------------------------------------------------------- + +class matlab_object +{ + /*! + WHAT THIS OBJECT REPRESENTS + This object is a simple wrapper around matlab's generic mxArray, which is the + thing that is matlab's "anything object". So a matlab_object can be used as an + argument to a mex_function() that can bind to any matlab object at all. It can + also bind to "nothing" and so is inherently also an optional argument when + present in a mex_funciton(). + !*/ +public: + matlab_object() : handle(0),should_free(false),arg_idx(0) {} + matlab_object(const matlab_object&) = delete; + + ~matlab_object(); + + + // Check if a matlab object is bound to this object. + bool is_empty() const { return handle==0; } + operator bool() const { return handle!=0; } + + // Convert from MATLAB to C++, throw invalid_args_exception if not possible. + template operator T() const; + template void get(T& item) const; + + // Convert from a C++ object to MATLAB + template matlab_object& operator= (const T& new_val); + + + template bool try_get(T& item) const + { + try { get(item); return true; } + catch(invalid_args_exception&) { return false; } + } + + const void* get_handle() const { return handle; } + /*! + ensures + - returns a pointer to the mxArray object. Might be NULL. + !*/ + + + matlab_object& operator=(const matlab_object&) = delete; + + // Users shouldn't call these functions + const void* release_object_to_matlab() { const void* temp=handle; handle = 0; return temp; } + void set_object_handle(int arg_idx_, const void* sh) { DLIB_CASSERT(!handle); handle = sh; arg_idx=arg_idx_; } +private: + + const void* handle; + bool should_free; + int arg_idx; +}; + +// ---------------------------------------------------------------------------------------- + +class matlab_struct +{ + /*! + WHAT THIS OBJECT REPRESENTS + This object lets you interface with MATLAB structs from C++. For example, + given a MATLAB struct named mystruct, you could access it's fields like this: + MATLAB way: mystruct.field + C++ way: mystruct["field"] + MATLAB way: mystruct.field.subfield + C++ way: mystruct["field"]["subfield"] + + To get the values as C++ types you do something like this: + int val = mystruct["field"]; + or + int val; + mystruct["field"].get(val); + + See also example_mex_struct.cpp for an example that uses this part of the API. + !*/ + + class sub; +public: + matlab_struct() : struct_handle(0),should_free(false),arg_idx(0) {} + matlab_struct(const matlab_struct&) = delete; + ~matlab_struct(); + + const sub operator[] (const std::string& name) const; + sub operator[] (const std::string& name); + bool has_field(const std::string& name) const; + + const void* release_struct_to_matlab() { const void* temp=struct_handle; struct_handle = 0; return temp; } + void set_struct_handle(int arg_idx_, const void* sh) { DLIB_CASSERT(!struct_handle); struct_handle = sh; arg_idx=arg_idx_; } +private: + + class sub + { + public: + sub() : struct_handle(0), field_idx(-1) {} + + template operator T() const; + template void get(T& item) const; + template sub& operator= (const T& new_val); + const sub operator[] (const std::string& name) const; + sub operator[] (const std::string& name); + bool has_field(const std::string& name) const; + private: + friend class matlab_struct; + const void* struct_handle; + int field_idx; + sub& operator=(const sub&); + }; + const void* struct_handle; + bool should_free; + int arg_idx; + matlab_struct& operator=(const matlab_struct&); +}; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + +template +struct output_decorator +{ + output_decorator(T& item_):item(item_){} + T& item; +}; + +template +output_decorator returns(T& item) { return output_decorator(item); } +/*! + ensures + - decorates item as an output type. This stuff is used by the call_matlab() + functions to tell if an argument is an input to the function or is supposed + to be bound to one of the return arguments. +!*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + +struct function_handle +{ + /*! + WHAT THIS OBJECT REPRESENTS + This type is used to represent function handles passed from MATLAB into a + mex function. You can call the function referenced by the handle by + saying: + call_matlab(my_handle); + !*/ + + // These two lines are just implementation details, ignore them. + function_handle():h(0){} + void* const h; +}; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + +void call_matlab ( + const std::string& function_name +); +/*! + ensures + - Calls MATLAB's function of the given name +!*/ + +// ---------------------------------------------------------------------------------------- + +void call_matlab ( + const function_handle& funct +); +/*! + ensures + - Calls MATLAB's function represented by the handle funct +!*/ + +// ---------------------------------------------------------------------------------------- + +template < + typename T1 + > +void call_matlab ( + const std::string& function_name, + const T1& A1 +); +/*! + ensures + - calls MATLAB's function of the given name. + - if (A1 is not decorated as an output by returns()) then + - A1 is passed as an argument into the MATLAB function + - else + - A1 is treated as the first return value from the MATLAB function. +!*/ + +template < + typename T1 + > +void call_matlab ( + const function_handle& funct, + const T1& A1 +) { call_matlab("feval", funct, A1); } +/*! + ensures + - Calls MATLAB's function represented by the handle funct + - if (A1 is not decorated as an output by returns()) then + - A1 is passed as an argument into the MATLAB function + - else + - A1 is treated as the first return value from the MATLAB function. +!*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +/* + The rest of this file is just overloads of call_matlab() for up to 10 arguments (or + just 9 arguments if function_handle is used). They all do the same thing as the above + version of call_matlab(). Generally, any argument not decorated by returns() is an + input to the MATLAB function. On the other hand, all arguments decorated by returns() + are treated as outputs. +*/ +// ---------------------------------------------------------------------------------------- + +template < + typename T1, + typename T2 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, + const T2& A2 +); + +// ---------------------------------------------------------------------------------------- + +template < + typename T1, + typename T2, + typename T3 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, + const T2& A2, + const T3& A3 +); + +// ---------------------------------------------------------------------------------------- + +template < + typename T1, + typename T2, + typename T3, + typename T4 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, + const T2& A2, + const T3& A3, + const T4& A4 +); + +// ---------------------------------------------------------------------------------------- + +template < + typename T1, + typename T2, + typename T3, + typename T4, + typename T5 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, + const T2& A2, + const T3& A3, + const T4& A4, + const T5& A5 +); + +// ---------------------------------------------------------------------------------------- + +template < + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, + const T2& A2, + const T3& A3, + const T4& A4, + const T5& A5, + const T6& A6 +); + +// ---------------------------------------------------------------------------------------- + +template < + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, + const T2& A2, + const T3& A3, + const T4& A4, + const T5& A5, + const T6& A6, + const T7& A7 +); + +// ---------------------------------------------------------------------------------------- + +template < + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, + const T2& A2, + const T3& A3, + const T4& A4, + const T5& A5, + const T6& A6, + const T7& A7, + const T8& A8 +); + +// ---------------------------------------------------------------------------------------- + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9 +); + +// ---------------------------------------------------------------------------------------- + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10 +); + +// ---------------------------------------------------------------------------------------- + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11 +); + +// ---------------------------------------------------------------------------------------- + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11, typename T12 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& A12 +); + +// ---------------------------------------------------------------------------------------- + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& + A12, const T13& A13 +); + +// ---------------------------------------------------------------------------------------- + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, + typename T14 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& + A12, const T13& A13, const T14& A14 +); + +// ---------------------------------------------------------------------------------------- + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, + typename T14, typename T15 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& + A12, const T13& A13, const T14& A14, const T15& A15 +); + +// ---------------------------------------------------------------------------------------- + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, + typename T14, typename T15, typename T16 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& + A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16 +); + +// ---------------------------------------------------------------------------------------- + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, + typename T14, typename T15, typename T16, typename T17 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& + A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17 +); + +// ---------------------------------------------------------------------------------------- + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, + typename T14, typename T15, typename T16, typename T17, typename T18 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& + A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17, + const T18& A18 +); + +// ---------------------------------------------------------------------------------------- + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, + typename T14, typename T15, typename T16, typename T17, typename T18, typename T19 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& + A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17, + const T18& A18, const T19& A19 +); + +// ---------------------------------------------------------------------------------------- + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, + typename T14, typename T15, typename T16, typename T17, typename T18, typename T19, + typename T20 + > +void call_matlab ( + const std::string& function_name, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& + A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17, + const T18& A18, const T19& A19, const T20& A20 +); + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + +template < + typename T1, + typename T2 + > +void call_matlab ( + const function_handle& funct, + const T1& A1, + const T2& A2 +) +{ + call_matlab("feval", funct, A1, A2); +} + +template < + typename T1, + typename T2, + typename T3 + > +void call_matlab ( + const function_handle& funct, + const T1& A1, + const T2& A2, + const T3& A3 +) +{ + call_matlab("feval", funct, A1, A2, A3); +} + +template < + typename T1, + typename T2, + typename T3, + typename T4 + > +void call_matlab ( + const function_handle& funct, + const T1& A1, + const T2& A2, + const T3& A3, + const T4& A4 +) +{ + call_matlab("feval", funct, A1, A2, A3, A4); +} + +template < + typename T1, + typename T2, + typename T3, + typename T4, + typename T5 + > +void call_matlab ( + const function_handle& funct, + const T1& A1, + const T2& A2, + const T3& A3, + const T4& A4, + const T5& A5 +) +{ + call_matlab("feval", funct, A1, A2, A3, A4, A5); +} + +template < + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6 + > +void call_matlab ( + const function_handle& funct, + const T1& A1, + const T2& A2, + const T3& A3, + const T4& A4, + const T5& A5, + const T6& A6 +) +{ + call_matlab("feval", funct, A1, A2, A3, A4, A5, A6); +} + +template < + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7 + > +void call_matlab ( + const function_handle& funct, + const T1& A1, + const T2& A2, + const T3& A3, + const T4& A4, + const T5& A5, + const T6& A6, + const T7& A7 +) +{ + call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7); +} + +template < + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8 + > +void call_matlab ( + const function_handle& funct, + const T1& A1, + const T2& A2, + const T3& A3, + const T4& A4, + const T5& A5, + const T6& A6, + const T7& A7, + const T8& A8 +) +{ + call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8); +} + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9 + > +void call_matlab ( + const function_handle& funct, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9 +) +{ + call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9); +} + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10 + > +void call_matlab ( + const function_handle& funct, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10 +) +{ + call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10); +} + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11 + > +void call_matlab ( + const function_handle& funct, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11 +) +{ + call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11); +} + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11, typename T12 + > +void call_matlab ( + const function_handle& funct, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& + A12 +) +{ + call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12); +} + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13 + > +void call_matlab ( + const function_handle& funct, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& + A12, const T13& A13 +) +{ + call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13); +} + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, + typename T14 + > +void call_matlab ( + const function_handle& funct, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& + A12, const T13& A13, const T14& A14 +) +{ + call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14); +} + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, + typename T14, typename T15 + > +void call_matlab ( + const function_handle& funct, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& + A12, const T13& A13, const T14& A14, const T15& A15 +) +{ + call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15); +} + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, + typename T14, typename T15, typename T16 + > +void call_matlab ( + const function_handle& funct, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& + A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16 +) +{ + call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16); +} + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, + typename T14, typename T15, typename T16, typename T17 + > +void call_matlab ( + const function_handle& funct, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& + A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17 +) +{ + call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17); +} + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, + typename T14, typename T15, typename T16, typename T17, typename T18 + > +void call_matlab ( + const function_handle& funct, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& + A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17, + const T18& A18 +) +{ + call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18); +} + +template < + typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename + T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, + typename T14, typename T15, typename T16, typename T17, typename T18, typename T19 + > +void call_matlab ( + const function_handle& funct, + const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6, + const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& + A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17, + const T18& A18, const T19& A19 +) +{ + call_matlab("feval", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19); +} + +// ---------------------------------------------------------------------------------------- + +// We define this function here so that, if you write some code that has check_for_matlab_ctrl_c() +// sprinkled throughout it you can still compile that code outside the mex wrapper +// environment and these calls will simply be no-ops. +#ifndef MATLAB_MEX_FILE +inline void check_for_matlab_ctrl_c() {} +#endif + +} + +#endif // MIT_LL_CALL_MATLAB_H__ + diff --git a/lib/3rdParty/dlib/include/dlib/matlab/subprocess_stream.h b/lib/3rdParty/dlib/include/dlib/matlab/subprocess_stream.h new file mode 100644 index 00000000..b00904c1 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/matlab/subprocess_stream.h @@ -0,0 +1,223 @@ +// Copyright (C) 2016 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SUBPROCeSS_STREAM_H_ +#define DLIB_SUBPROCeSS_STREAM_H_ + +#include +#include +#include +#include +#include +#include +#include + + +namespace dlib +{ + +// -------------------------------------------------------------------------------------- + + // Call dlib's serialize and deserialize by default. The point of this version of + // serialize is to do something fast that normally we wouldn't do, like directly copy + // memory. This is safe since this is an interprocess communication happening the same + // machine. + template void interprocess_serialize ( const T& item, std::ostream& out) { serialize(item, out); } + template void interprocess_deserialize (T& item, std::istream& in) { deserialize(item, in); } + + // But have overloads for direct memory copies for some types since this is faster than + // their default serialization. + template + void interprocess_serialize(const dlib::matrix& item, std::ostream& out) + { + dlib::serialize(item.nr(), out); + dlib::serialize(item.nc(), out); + if (item.size() != 0) + out.write((const char*)&item(0,0), sizeof(T)*item.size()); + if (!out) + throw dlib::serialization_error("Error writing matrix to interprocess iostream."); + } + + template + void interprocess_deserialize(dlib::matrix& item, std::istream& in) + { + long nr, nc; + dlib::deserialize(nr, in); + dlib::deserialize(nc, in); + item.set_size(nr,nc); + if (item.size() != 0) + in.read((char*)&item(0,0), sizeof(T)*item.size()); + if (!in) + throw dlib::serialization_error("Error reading matrix from interprocess iostream."); + } + +// ---------------------------------------------------------------------------------------- + + namespace impl{ std::iostream& get_data_iostream(); } + + inline void send_to_parent_process() {impl::get_data_iostream().flush();} + template + void send_to_parent_process(U&& arg1, T&& ...args) + /*! + ensures + - sends all the arguments to send_to_parent_process() to the parent process by + serializing them with interprocess_serialize(). + !*/ + { + interprocess_serialize(arg1, impl::get_data_iostream()); + send_to_parent_process(std::forward(args)...); + if (!impl::get_data_iostream()) + throw dlib::error("Error sending object to parent process."); + } + + inline void receive_from_parent_process() {} + template + void receive_from_parent_process(U&& arg1, T&& ...args) + /*! + ensures + - receives all the arguments to receive_from_parent_process() from the parent + process by deserializing them from interprocess_serialize(). + !*/ + { + interprocess_deserialize(arg1, impl::get_data_iostream()); + receive_from_parent_process(std::forward(args)...); + if (!impl::get_data_iostream()) + throw dlib::error("Error receiving object from parent process."); + } + + +// ---------------------------------------------------------------------------------------- + + class filestreambuf; + + class subprocess_stream : noncopyable + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a tool for spawning a subprocess and communicating with it. Here + is an example: + + subprocess_stream s("/usr/bin/some_program"); + s.send(obj1, obj2, obj3); + s.receive(obj4, obj5); + s.wait(); // wait for sub process to terminate + + Then in the sub process you would have: + + receive_from_parent_process(obj1, obj2, obj3); + // do stuff + cout << "echo this text to parent cout" << endl; + send_to_parent_process(obj4, obj5); + + + Additionally, if the sub process writes to its standard out then that will + be echoed to std::cout in the parent process. Writing to std::cerr or + returning a non-zero value from main will also be noted by the parent + process and an appropriate exception will be thrown. + !*/ + + public: + + explicit subprocess_stream( + const char* program_name + ); + /*! + ensures + - spawns a sub process by executing the file with the given program_name. + !*/ + + ~subprocess_stream( + ); + /*! + ensures + - calls wait(). Note that the destructor never throws even though wait() can. + If an exception is thrown by wait() it is just logged to std::cerr. + !*/ + + void wait( + ); + /*! + ensures + - closes the input stream to the child process and then waits for the child + to terminate. + - If the child returns an error (by returning != 0 from its main) or + outputs to its standard error then wait() throws a dlib::error() with the + standard error output in it. + !*/ + + int get_child_pid() const { return child_pid; } + /*! + ensures + - returns the PID of the child process + !*/ + + template + void send(U&& arg1, T&& ...args) + /*! + ensures + - sends all the arguments to send() to the subprocess by serializing them + with interprocess_serialize(). + !*/ + { + interprocess_serialize(arg1, iosub); + send(std::forward(args)...); + if (!iosub) + { + std::ostringstream sout; + sout << stderr.rdbuf(); + throw dlib::error("Error sending object to child process.\n" + sout.str()); + } + } + void send() {iosub.flush();} + + template + void receive(U&& arg1, T&& ...args) + /*! + ensures + - receives all the arguments to receive() to the subprocess by deserializing + them with interprocess_deserialize(). + !*/ + { + interprocess_deserialize(arg1, iosub); + receive(std::forward(args)...); + if (!iosub) + { + std::ostringstream sout; + sout << stderr.rdbuf(); + throw dlib::error("Error receiving object from child process.\n" + sout.str() ); + } + } + void receive() {} + + + private: + + void send_eof(); + + class cpipe : noncopyable + { + private: + int fd[2]; + public: + cpipe() { if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fd)) throw dlib::error("Failed to create pipe"); } + ~cpipe() { close(); } + int parent_fd() const { return fd[0]; } + int child_fd() const { return fd[1]; } + void close() { ::close(fd[0]); ::close(fd[1]); } + }; + + cpipe data_pipe; + cpipe stdout_pipe; + cpipe stderr_pipe; + bool wait_called = false; + std::unique_ptr inout_buf; + std::unique_ptr err_buf; + int child_pid = -1; + std::istream stderr; + std::iostream iosub; + }; +} + +// ---------------------------------------------------------------------------------------- + +#endif // DLIB_SUBPROCeSS_STREAM_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/matrix/cblas_constants.h b/lib/3rdParty/dlib/include/dlib/matrix/cblas_constants.h index c22204e9..6ff89f14 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/cblas_constants.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/cblas_constants.h @@ -3,6 +3,7 @@ #ifndef DLIB_CBLAS_CONSTAnTS_Hh_ #define DLIB_CBLAS_CONSTAnTS_Hh_ +#ifndef CBLAS_H namespace dlib { namespace blas_bindings @@ -15,6 +16,7 @@ namespace dlib } } +#endif // if not CBLAS_H #endif // DLIB_CBLAS_CONSTAnTS_Hh_ diff --git a/lib/3rdParty/dlib/include/dlib/matrix/lapack/fortran_id.h b/lib/3rdParty/dlib/include/dlib/matrix/lapack/fortran_id.h index a5cd6380..deb9e3e2 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/lapack/fortran_id.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/lapack/fortran_id.h @@ -18,9 +18,13 @@ // First we need to know what the conventions for linking // C with Fortran is on this platform/toolset -#if defined(__GNUC__) || defined(__ICC) || defined(__sgi) || defined(__COMO__) || defined(__KCC) +#if defined(LAPACK_FORCE_UNDERSCORE) #define DLIB_BIND_FORTRAN_LOWERCASE_UNDERSCORE -#elif defined(__IBMCPP__) || defined(_MSC_VER) +#elif defined(LAPACK_FORCE_NOUNDERSCORE) +#define DLIB_BIND_FORTRAN_LOWERCASE +#elif defined(__GNUC__) || defined(__ICC) || defined(__sgi) || defined(__COMO__) || defined(__KCC) +#define DLIB_BIND_FORTRAN_LOWERCASE_UNDERSCORE +#elif defined(__IBMCPP__) || defined(_MSC_VER) || defined(__BORLANDC__) #define DLIB_BIND_FORTRAN_LOWERCASE #else #error do not know how to link with fortran for the given platform @@ -43,7 +47,7 @@ namespace dlib namespace lapack { // stuff from f2c used to define what exactly is an integer in fortran -#if defined(__alpha__) || defined(__sparc64__) || defined(__x86_64__) || defined(__ia64__) +#if (defined(__alpha__) || defined(__sparc64__) || defined(__x86_64__) || defined(__ia64__)) && !defined(MATLAB_MEX_FILE) && !defined(USE_64BIT_LAPACK_INTEGERS) typedef int integer; typedef unsigned int uinteger; #else diff --git a/lib/3rdParty/dlib/include/dlib/matrix/lapack/gees.h b/lib/3rdParty/dlib/include/dlib/matrix/lapack/gees.h index c1281b27..a8ee63ff 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/lapack/gees.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/lapack/gees.h @@ -42,12 +42,12 @@ namespace dlib integer info = 0; char sort = 'N'; L_fp fnil = 0; - logical nil = 0; + logical bwork = 0; integer sdim = 0; DLIB_FORTRAN_ID(dgees)(&jobvs, &sort, fnil, &n, a, &lda, &sdim, wr, wi, vs, &ldvs, work, - &lwork, &nil, &info); + &lwork, &bwork, &info); return info; } @@ -61,12 +61,12 @@ namespace dlib integer info = 0; char sort = 'N'; L_fp fnil = 0; - logical nil = 0; + logical bwork = 0; integer sdim = 0; DLIB_FORTRAN_ID(sgees)(&jobvs, &sort, fnil, &n, a, &lda, &sdim, wr, wi, vs, &ldvs, work, - &lwork, &nil, &info); + &lwork, &bwork, &info); return info; } diff --git a/lib/3rdParty/dlib/include/dlib/matrix/lapack/pbtrf.h b/lib/3rdParty/dlib/include/dlib/matrix/lapack/pbtrf.h new file mode 100644 index 00000000..23bcc127 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/matrix/lapack/pbtrf.h @@ -0,0 +1,178 @@ +// Copyright (C) 2010 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LAPACk_BDC_Hh_ +#define DLIB_LAPACk_BDC_Hh_ + +#include "fortran_id.h" +#include "../matrix.h" +namespace dlib +{ + namespace lapack + { + namespace binding + { + extern "C" + { + void DLIB_FORTRAN_ID(dpbtrf) (const char* uplo, const integer* n, const integer* kd, + double* ab, const integer* ldab, integer* info); + + void DLIB_FORTRAN_ID(spbtrf) (const char* uplo, const integer* n, const integer* kd, + float* ab, const integer* ldab, integer* info); + + } + + inline integer pbtrf (const char uplo, const integer n, const integer kd, + double* ab, const integer ldab) + { + integer info = 0; + DLIB_FORTRAN_ID(dpbtrf)(&uplo, &n, &kd, ab, &ldab, &info); + return info; + } + + inline integer pbtrf (const char uplo, const integer n, const integer kd, + float* ab, const integer ldab) + { + integer info = 0; + DLIB_FORTRAN_ID(spbtrf)(&uplo, &n, &kd, ab, &ldab, &info); + return info; + } + } + + // ------------------------------------------------------------------------------------ +/* DPBTRF(l) LAPACK routine (version 1.1) DPBTRF(l) + +NAME + DPBTRF - compute the Cholesky factorization of a real symmetric positive + definite band matrix A + +SYNOPSIS + + SUBROUTINE DPBTRF( UPLO, N, KD, AB, LDAB, INFO ) + + CHARACTER UPLO + + INTEGER INFO, KD, LDAB, N + + DOUBLE PRECISION AB( LDAB, * ) + +PURPOSE + DPBTRF computes the Cholesky factorization of a real symmetric positive + definite band matrix A. + + The factorization has the form + A = U**T * U, if UPLO = 'U', or + A = L * L**T, if UPLO = 'L', + where U is an upper triangular matrix and L is lower triangular. + +ARGUMENTS + + UPLO (input) CHARACTER*1 + = 'U': Upper triangle of A is stored; + = 'L': Lower triangle of A is stored. + + N (input) INTEGER + The order of the matrix A. N >= 0. + + KD (input) INTEGER + The number of superdiagonals of the matrix A if UPLO = 'U', or the + number of subdiagonals if UPLO = 'L'. KD >= 0. + + AB (input/output) DOUBLE PRECISION array, dimension (LDAB,N) + On entry, the upper or lower triangle of the symmetric band matrix + A, stored in the first KD+1 rows of the array. The j-th column of + A is stored in the j-th column of the array AB as follows: if UPLO + = 'U', AB(kd+1+i-j,j) = A(i,j) for max(1,j-kd)<=i<=j; if UPLO = + 'L', AB(1+i-j,j) = A(i,j) for j<=i<=min(n,j+kd). + + On exit, if INFO = 0, the triangular factor U or L from the Chole- + sky factorization A = U**T*U or A = L*L**T of the band matrix A, in + the same storage format as A. + + LDAB (input) INTEGER + The leading dimension of the array AB. LDAB >= KD+1. + + INFO (output) INTEGER + = 0: successful exit + < 0: if INFO = -i, the i-th argument had an illegal value + > 0: if INFO = i, the leading minor of order i is not positive + definite, and the factorization could not be completed. + +FURTHER DETAILS + The band storage scheme is illustrated by the following example, when N = + 6, KD = 2, and UPLO = 'U': + + On entry: On exit: + + * * a13 a24 a35 a46 * * u13 u24 u35 u46 + * a12 a23 a34 a45 a56 * u12 u23 u34 u45 u56 + a11 a22 a33 a44 a55 a66 u11 u22 u33 u44 u55 u66 + + Similarly, if UPLO = 'L' the format of A is as follows: + + On entry: On exit: + + a11 a22 a33 a44 a55 a66 l11 l22 l33 l44 l55 l66 + a21 a32 a43 a54 a65 * l21 l32 l43 l54 l65 * + a31 a42 a53 a64 * * l31 l42 l53 l64 * * + + Array elements marked * are not used by the routine. + + Contributed by + Peter Mayes and Giuseppe Radicati, IBM ECSEC, Rome, March 23, 1989 */ + + // ------------------------------------------------------------------------------------ + + template < + typename T, + long NR1, long NC1, + typename MM + > + int pbtrf ( + char uplo, matrix& ab + ) + { + const long ldab = ab.nr(); + const long n = ab.nc(); + const long kd = ldab - 1; // assume fully packed + + int info = binding::pbtrf(uplo, n, kd, &ab(0,0), ldab); + + return info; + } + + // ------------------------------------------------------------------------------------ + + + template < + typename T, + long NR1, long NC1, + typename MM + > + int pbtrf ( + char uplo, matrix& ab + ) + { + const long ldab = ab.nr(); + const long n = ab.nc(); + const long kd = ldab - 1; // assume fully packed + + matrix abt = trans(ab); + + int info = binding::pbtrf(uplo, n, kd, &abt(0,0), ldab); + + ab = trans(abt); + + return info; + } + + // ------------------------------------------------------------------------------------ + + } + +} + +// ---------------------------------------------------------------------------------------- + +#endif // DLIB_LAPACk_BDC_Hh_ + + diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix.h index 6fd3a7c4..5f958348 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix.h @@ -15,6 +15,14 @@ #include "matrix_data_layout.h" #include "matrix_assign_fwd.h" #include "matrix_op.h" +#include +#ifdef DLIB_HAS_INITIALIZER_LISTS +#include +#endif + +#ifdef MATLAB_MEX_FILE +#include +#endif #ifdef _MSC_VER // Disable the following warnings for Visual Studio @@ -25,6 +33,12 @@ // warning off and then turning it back on at the end of the file. #pragma warning(disable : 4355) +// "warning C4723: potential divide by 0" - This warning is triggered in +// matrix(const std::initializer_list& l) where the compiler can see that +// matrix<> was templated in a way making NR ending up 0, but division by 0 at runtime +// is not possible because the division operation is inside "if (NR!=0)" block. +#pragma warning(disable : 4723) + #endif namespace dlib @@ -957,6 +971,11 @@ namespace dlib // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- + template + struct op_pointer_to_mat; + template + struct op_pointer_to_col_vect; + template < typename T, long num_rows, @@ -1101,6 +1120,112 @@ namespace dlib matrix_assign(*this, m); } +#ifdef DLIB_HAS_INITIALIZER_LISTS + matrix(const std::initializer_list& l) + { + if (NR*NC != 0) + { + DLIB_ASSERT(l.size() == NR*NC, + "\t matrix::matrix(const std::initializer_list& l)" + << "\n\t You are trying to initialize a statically sized matrix with a list that doesn't have a matching size." + << "\n\t l.size(): "<< l.size() + << "\n\t NR*NC: "<< NR*NC); + + data.set_size(NR, NC); + } + else if (NR!=0) + { + DLIB_ASSERT(l.size()%NR == 0, + "\t matrix::matrix(const std::initializer_list& l)" + << "\n\t You are trying to initialize a statically sized matrix with a list that doesn't have a compatible size." + << "\n\t l.size(): "<< l.size() + << "\n\t NR: "<< NR); + + if (l.size() != 0) + data.set_size(NR, l.size()/NR); + } + else if (NC!=0) + { + DLIB_ASSERT(l.size()%NC == 0, + "\t matrix::matrix(const std::initializer_list& l)" + << "\n\t You are trying to initialize a statically sized matrix with a list that doesn't have a compatible size." + << "\n\t l.size(): "<< l.size() + << "\n\t NC: "<< NC); + + if (l.size() != 0) + data.set_size(l.size()/NC, NC); + } + else if (l.size() != 0) + { + data.set_size(l.size(),1); + } + + if (l.size() != 0) + { + T* d = &data(0,0); + for (auto&& v : l) + *d++ = v; + } + + } + + std::unique_ptr steal_memory( + ) + { + return data.steal_memory(); + } + + matrix& operator=(const std::initializer_list& l) + { + matrix temp(l); + temp.swap(*this); + return *this; + } +#endif // DLIB_HAS_INITIALIZER_LISTS + +#ifdef DLIB_HAS_RVALUE_REFERENCES + matrix(matrix&& item) + { + #ifdef MATLAB_MEX_FILE + // You can't move memory around when compiled in a matlab mex file and the + // different locations have different ownership settings. + if (data._private_is_owned_by_matlab() == item.data._private_is_owned_by_matlab()) + { + swap(item); + } + else + { + data.set_size(item.nr(),item.nc()); + matrix_assign(*this, item); + } + #else + swap(item); + #endif + } + + matrix& operator= ( + matrix&& rhs + ) + { + #ifdef MATLAB_MEX_FILE + // You can't move memory around when compiled in a matlab mex file and the + // different locations have different ownership settings. + if (data._private_is_owned_by_matlab() == rhs.data._private_is_owned_by_matlab()) + { + swap(rhs); + } + else + { + data.set_size(rhs.nr(),rhs.nc()); + matrix_assign(*this, rhs); + } + #else + swap(rhs); + #endif + return *this; + } +#endif // DLIB_HAS_RVALUE_REFERENCES + template explicit matrix ( U (&array)[len] @@ -1218,6 +1343,31 @@ namespace dlib return data(0); } +#ifdef MATLAB_MEX_FILE + void _private_set_mxArray( + mxArray* mem + ) + { + data._private_set_mxArray(mem); + } + + mxArray* _private_release_mxArray( + ) + { + return data._private_release_mxArray(); + } + + void _private_mark_owned_by_matlab() + { + data._private_mark_owned_by_matlab(); + } + + bool _private_is_owned_by_matlab() + { + return data._private_is_owned_by_matlab(); + } +#endif + void set_size ( long rows, long cols @@ -1390,6 +1540,9 @@ namespace dlib } else { + DLIB_ASSERT(size() == 0, + "\t const matrix::operator+=(m)" + << "\n\t You are trying to add two matrices that have incompatible dimensions."); *this = m; } return *this; @@ -1424,6 +1577,9 @@ namespace dlib } else { + DLIB_ASSERT(size() == 0, + "\t const matrix::operator-=(m)" + << "\n\t You are trying to subtract two matrices that have incompatible dimensions."); *this = -m; } return *this; @@ -1450,6 +1606,10 @@ namespace dlib } else { + DLIB_ASSERT(this->size() == 0, + "\t const matrix::operator+=(m)" + << "\n\t You are trying to add two matrices that have incompatible dimensions."); + set_size(m.nr(), m.nc()); for (long i = 0; i < size; ++i) data(i) = m.data(i); @@ -1469,6 +1629,9 @@ namespace dlib } else { + DLIB_ASSERT(this->size() == 0, + "\t const matrix::operator-=(m)" + << "\n\t You are trying to subtract two matrices that have incompatible dimensions."); set_size(m.nr(), m.nc()); for (long i = 0; i < size; ++i) data(i) = -m.data(i); @@ -1480,8 +1643,8 @@ namespace dlib const T val ) { - const long size = nr()*nc(); - for (long i = 0; i < size; ++i) + const size_t size = nr()*(size_t)nc(); + for (size_t i = 0; i < size; ++i) data(i) += val; return *this; @@ -1491,8 +1654,8 @@ namespace dlib const T val ) { - const long size = nr()*nc(); - for (long i = 0; i < size; ++i) + const size_t size = nr()*(size_t)nc(); + for (size_t i = 0; i < size; ++i) data(i) -= val; return *this; @@ -1549,6 +1712,13 @@ namespace dlib const matrix_exp& ) const { return false; } + // These two aliases() routines are defined in matrix_mat.h + bool aliases ( + const matrix_exp > >& item + ) const; + bool aliases ( + const matrix_exp > >& item + ) const; iterator begin() { @@ -1593,12 +1763,11 @@ namespace dlib literal_assign_helper(const literal_assign_helper& item) : m(item.m), r(item.r), c(item.c), has_been_used(false) {} explicit literal_assign_helper(matrix* m_): m(m_), r(0), c(0),has_been_used(false) {next();} - ~literal_assign_helper() + ~literal_assign_helper() noexcept(false) { - assert(!has_been_used || r == m->nr()); - //DLIB_CASSERT(!has_been_used || r == m->nr(), - // "You have used the matrix comma based assignment incorrectly by failing to\n" - // "supply a full set of values for every element of a matrix object.\n"); + DLIB_CASSERT(!has_been_used || r == m->nr(), + "You have used the matrix comma based assignment incorrectly by failing to\n" + "supply a full set of values for every element of a matrix object.\n"); } const literal_assign_helper& operator, ( @@ -1621,7 +1790,7 @@ namespace dlib private: - friend class matrix; + friend class matrix; void next ( ) const @@ -1655,13 +1824,9 @@ namespace dlib ) { // assign the given value to every spot in this matrix - for (long r = 0; r < nr(); ++r) - { - for (long c = 0; c < nc(); ++c) - { - data(r,c) = val; - } - } + const size_t size = nr()*(size_t)nc(); + for (size_t i = 0; i < size; ++i) + data(i) = val; // Now return the literal_assign_helper so that the user // can use the overloaded comma notation to initialize @@ -1770,6 +1935,50 @@ namespace dlib } } +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long NR, + long NC, + typename mm, + typename l + > + void serialize ( + const ramdump_t>& item_, + std::ostream& out + ) + { + auto& item = item_.item; + serialize(item.nr(), out); + serialize(item.nc(), out); + if (item.size() != 0) + out.write((char*)&item(0,0), sizeof(item(0,0))*item.size()); + } + + template < + typename T, + long NR, + long NC, + typename mm, + typename l + > + void deserialize ( + ramdump_t>&& item_, + std::istream& in + ) + { + auto& item = item_.item; + long nr, nc; + deserialize(nr, in); + deserialize(nc, in); + item.set_size(nr,nc); + if (item.size() != 0) + in.read((char*)&item(0,0), sizeof(item(0,0))*item.size()); + } + +// ---------------------------------------------------------------------------------------- + template < typename EXP > @@ -1944,11 +2153,15 @@ namespace dlib // ---------------------------------------------------------------------------------------- + typedef matrix matrix_colmajor; + typedef matrix fmatrix_colmajor; + } #ifdef _MSC_VER -// put that warning back to its default setting +// put warnings back to their default settings #pragma warning(default : 4355) +#pragma warning(default : 4723) #endif #endif // DLIB_MATRIx_ diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_abstract.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_abstract.h index 30d086b8..c6c60db1 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_abstract.h @@ -336,6 +336,30 @@ namespace dlib - #aliases(*this) == true - #ref().aliases(*this) == true !*/ + + matrix( + const std::initializer_list& l + ); + /*! + requires + - This matrix is capable of having a size() == l.size(). Therefore, if + NR*NC != 0 then l.size() must equal NR*NC. Alternatively, if NR or NC is + != 0 then l.size() must be a multiple of the non-zero NR or NC. + ensures + - #size() == l.size() + - The contents of l are enumerated and read into the matrix in row major order. + - if (NR != 0) then + - #nr() == NR + - #nc() == l.size()/NR + - if (NC != 0) then + - #nr() == l.size()/NC + - #nc() == NC + - if (NR*NC==0) then + - #nr() == l.size() + - #nc() == 1 + - #aliases(*this) == true + - #ref().aliases(*this) == true + !*/ T& operator() ( long r, @@ -456,6 +480,21 @@ namespace dlib - #nc() == 1 !*/ + std::unique_ptr steal_memory( + ); + /*! + requires + - NR*NC==0 + (i.e. this array isn't statically sized) + ensures + - Returns a pointer containing the memory block underlying this matrix. + After calling steal_memory() this matrix doesn't own the memory anymore + and is automatically set to the empty matrix. + - The returned pointer points to an array of size() T objects and in + particular is the pointer &(*this)(0,0). + - #size() == 0 + !*/ + template matrix& operator= ( U (&array)[len] @@ -470,6 +509,19 @@ namespace dlib - returns *this !*/ + matrix& operator=( + const std::initializer_list& l + ); + /*! + requires + - This matrix is capable of having a size() == l.size(). Therefore, if + NR*NC != 0 then l.size() must equal NR*NC. Alternatively, if NR or NC is + != 0 then l.size() must be a multiple of the non-zero NR or NC. + ensures + - Assigns the contents of l to *this by performing: matrix(l).swap(*this) + - returns *this + !*/ + template matrix& operator= ( const matrix_exp& m @@ -492,6 +544,10 @@ namespace dlib /*! requires - matrix_exp::type == T + - One of the following is true: + - nr() == m.nr() && nc() == m.nc() + - size() == 0 + (i.e. this matrix must have matching dimensions or it must be empty) ensures - if (nr() == m.nr() && nc() == m.nc()) then - #(*this) == *this + m @@ -509,6 +565,10 @@ namespace dlib /*! requires - matrix_exp::type == T + - One of the following is true: + - nr() == m.nr() && nc() == m.nc() + - size() == 0 + (i.e. this matrix must have matching dimensions or it must be empty) ensures - if (nr() == m.nr() && nc() == m.nc()) then - #(*this) == *this - m @@ -645,7 +705,18 @@ namespace dlib // ---------------------------------------------------------------------------------------- - template < + /*!A matrix_colmajor + This is just a typedef of the matrix object that uses column major layout. + !*/ + typedef matrix matrix_colmajor; + + /*!A fmatrix_colmajor + This is just a typedef of the matrix object that uses column major layout. + !*/ + typedef matrix fmatrix_colmajor; + +// ---------------------------------------------------------------------------------------- +template < typename T, long NR, long NC, @@ -733,6 +804,14 @@ namespace dlib from being parsed into a matrix then #in.fail() == true. !*/ + /*!A csv + This object is used to define an io manipulator for matrix expressions. In + particular, you can write statements like: + cout << csv << yourmatrix; + and have it print the matrix with commas separating each element. + !*/ + some_undefined_iomnaip_type csv; + // ---------------------------------------------------------------------------------------- template diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_assign.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_assign.h index db06048e..cf230d0d 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_assign.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_assign.h @@ -372,12 +372,12 @@ namespace dlib // This is a macro to help us add overloads for the matrix_assign_blas_helper template. // Using this macro it is easy to add overloads for arbitrary matrix expressions. #define DLIB_ADD_BLAS_BINDING(src_expression) \ - template struct BOOST_JOIN(blas,__LINE__) \ + template struct DLIB_BOOST_JOIN(blas,__LINE__) \ { const static bool value = sizeof(yes_type) == sizeof(test(src_expression)); }; \ \ template < typename dest_exp, typename src_exp > \ struct matrix_assign_blas_helper >::type > { \ + typename enable_if >::type > { \ static void assign ( \ dest_exp& dest, \ const src_exp& src, \ @@ -724,6 +724,29 @@ namespace dlib } } + // ------------------------------------------------------------------------------------ + + template < + typename T, + typename src_exp + > + void matrix_assign_blas ( + assignable_ptr_matrix& dest, + const src_exp& src + ) + { + if (src.aliases(mat(dest.ptr,dest.height,dest.width))) + { + matrix temp(dest.nr(),dest.nc()); + matrix_assign_blas_proxy(temp,src,1,false, false); + matrix_assign_default(dest,temp); + } + else + { + matrix_assign_blas_proxy(dest,src,1,false, false); + } + } + // ------------------------------------------------------------------------------------ template < @@ -888,6 +911,25 @@ namespace dlib blas_bindings::matrix_assign_blas(dest,src); } +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename src_exp + > + inline typename enable_if_c<(is_same_type::value || + is_same_type::value || + is_same_type >::value || + is_same_type >::value) && + blas_bindings::has_matrix_multiply::value + >::type matrix_assign_big ( + assignable_ptr_matrix& dest, + const src_exp& src + ) + { + blas_bindings::matrix_assign_blas(dest,src); + } + // ---------------------------------------------------------------------------------------- template < diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_assign_fwd.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_assign_fwd.h index 9d8f2e13..7d29baf0 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_assign_fwd.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_assign_fwd.h @@ -5,8 +5,9 @@ // GCC 4.8 gives false alarms about some variables being uninitialized. Disable these // false warnings. -#if ( defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 8) - #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#if defined(__GNUC__) && ((__GNUC__ >= 4 && __GNUC_MINOR__ >= 8) || (__GNUC__ > 4)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif #include "../enable_if.h" @@ -403,6 +404,10 @@ namespace dlib } +#if defined(__GNUC__) && ((__GNUC__ >= 4 && __GNUC_MINOR__ >= 8) || (__GNUC__ > 4)) +#pragma GCC diagnostic pop +#endif + #endif // DLIB_MATRIx_ASSIGn_FWD_ diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_blas_bindings.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_blas_bindings.h index 960548b3..e6fd67ec 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_blas_bindings.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_blas_bindings.h @@ -3,6 +3,7 @@ #ifndef DLIB_MATRIx_BLAS_BINDINGS_ #define DLIB_MATRIx_BLAS_BINDINGS_ + #ifndef DLIB_USE_BLAS #error "DLIB_USE_BLAS should be defined if you want to use the BLAS bindings" #endif @@ -10,6 +11,7 @@ #include "matrix_assign.h" #include "matrix_conj_trans.h" #include "cblas_constants.h" +#include //#include //using namespace std; @@ -44,95 +46,100 @@ namespace dlib #define DLIB_TEST_BLAS_BINDING_SCAL #endif +#ifndef CBLAS_H extern "C" { +#ifndef CBLAS_INT_TYPE +#define CBLAS_INT_TYPE int +#endif // Here we declare the prototypes for the CBLAS calls used by the BLAS bindings below - void cblas_saxpy(const int N, const float alpha, const float *X, - const int incX, float *Y, const int incY); - void cblas_daxpy(const int N, const double alpha, const double *X, - const int incX, double *Y, const int incY); - void cblas_caxpy(const int N, const void *alpha, const void *X, - const int incX, void *Y, const int incY); - void cblas_zaxpy(const int N, const void *alpha, const void *X, - const int incX, void *Y, const int incY); + void cblas_saxpy(const CBLAS_INT_TYPE N, const float alpha, const float *X, + const CBLAS_INT_TYPE incX, float *Y, const CBLAS_INT_TYPE incY); + void cblas_daxpy(const CBLAS_INT_TYPE N, const double alpha, const double *X, + const CBLAS_INT_TYPE incX, double *Y, const CBLAS_INT_TYPE incY); + void cblas_caxpy(const CBLAS_INT_TYPE N, const void *alpha, const void *X, + const CBLAS_INT_TYPE incX, void *Y, const CBLAS_INT_TYPE incY); + void cblas_zaxpy(const CBLAS_INT_TYPE N, const void *alpha, const void *X, + const CBLAS_INT_TYPE incX, void *Y, const CBLAS_INT_TYPE incY); - void cblas_sscal(const int N, const float alpha, float *X, const int incX); - void cblas_dscal(const int N, const double alpha, double *X, const int incX); - void cblas_cscal(const int N, const void *alpha, void *X, const int incX); - void cblas_zscal(const int N, const void *alpha, void *X, const int incX); + void cblas_sscal(const CBLAS_INT_TYPE N, const float alpha, float *X, const CBLAS_INT_TYPE incX); + void cblas_dscal(const CBLAS_INT_TYPE N, const double alpha, double *X, const CBLAS_INT_TYPE incX); + void cblas_cscal(const CBLAS_INT_TYPE N, const void *alpha, void *X, const CBLAS_INT_TYPE incX); + void cblas_zscal(const CBLAS_INT_TYPE N, const void *alpha, void *X, const CBLAS_INT_TYPE incX); - void cblas_sgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, - const enum CBLAS_TRANSPOSE TransB, const int M, const int N, - const int K, const float alpha, const float *A, - const int lda, const float *B, const int ldb, - const float beta, float *C, const int ldc); - void cblas_dgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, - const enum CBLAS_TRANSPOSE TransB, const int M, const int N, - const int K, const double alpha, const double *A, - const int lda, const double *B, const int ldb, - const double beta, double *C, const int ldc); - void cblas_cgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, - const enum CBLAS_TRANSPOSE TransB, const int M, const int N, - const int K, const void *alpha, const void *A, - const int lda, const void *B, const int ldb, - const void *beta, void *C, const int ldc); - void cblas_zgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, - const enum CBLAS_TRANSPOSE TransB, const int M, const int N, - const int K, const void *alpha, const void *A, - const int lda, const void *B, const int ldb, - const void *beta, void *C, const int ldc); - void cblas_sgemv(const enum CBLAS_ORDER order, - const enum CBLAS_TRANSPOSE TransA, const int M, const int N, - const float alpha, const float *A, const int lda, - const float *X, const int incX, const float beta, - float *Y, const int incY); - void cblas_dgemv(const enum CBLAS_ORDER order, - const enum CBLAS_TRANSPOSE TransA, const int M, const int N, - const double alpha, const double *A, const int lda, - const double *X, const int incX, const double beta, - double *Y, const int incY); - void cblas_cgemv(const enum CBLAS_ORDER order, - const enum CBLAS_TRANSPOSE TransA, const int M, const int N, - const void *alpha, const void *A, const int lda, - const void *X, const int incX, const void *beta, - void *Y, const int incY); - void cblas_zgemv(const enum CBLAS_ORDER order, - const enum CBLAS_TRANSPOSE TransA, const int M, const int N, - const void *alpha, const void *A, const int lda, - const void *X, const int incX, const void *beta, - void *Y, const int incY); - void cblas_sger(const enum CBLAS_ORDER order, const int M, const int N, - const float alpha, const float *X, const int incX, - const float *Y, const int incY, float *A, const int lda); - void cblas_dger(const enum CBLAS_ORDER order, const int M, const int N, - const double alpha, const double *X, const int incX, - const double *Y, const int incY, double *A, const int lda); - void cblas_cgerc(const enum CBLAS_ORDER order, const int M, const int N, - const void *alpha, const void *X, const int incX, - const void *Y, const int incY, void *A, const int lda); - void cblas_zgerc(const enum CBLAS_ORDER order, const int M, const int N, - const void *alpha, const void *X, const int incX, - const void *Y, const int incY, void *A, const int lda); - float cblas_sdot(const int N, const float *X, const int incX, - const float *Y, const int incY); - double cblas_ddot(const int N, const double *X, const int incX, - const double *Y, const int incY); - void cblas_cdotu_sub(const int N, const void *X, const int incX, - const void *Y, const int incY, void *dotu); - void cblas_zdotu_sub(const int N, const void *X, const int incX, - const void *Y, const int incY, void *dotu); - void cblas_cdotc_sub(const int N, const void *X, const int incX, - const void *Y, const int incY, void *dotc); - void cblas_zdotc_sub(const int N, const void *X, const int incX, - const void *Y, const int incY, void *dotc); - void cblas_cgeru(const enum CBLAS_ORDER order, const int M, const int N, - const void *alpha, const void *X, const int incX, - const void *Y, const int incY, void *A, const int lda); - void cblas_zgeru(const enum CBLAS_ORDER order, const int M, const int N, - const void *alpha, const void *X, const int incX, - const void *Y, const int incY, void *A, const int lda); + void cblas_sgemm(const CBLAS_ORDER Order, const CBLAS_TRANSPOSE TransA, + const CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const CBLAS_INT_TYPE K, const float alpha, const float *A, + const CBLAS_INT_TYPE lda, const float *B, const CBLAS_INT_TYPE ldb, + const float beta, float *C, const CBLAS_INT_TYPE ldc); + void cblas_dgemm(const CBLAS_ORDER Order, const CBLAS_TRANSPOSE TransA, + const CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const CBLAS_INT_TYPE K, const double alpha, const double *A, + const CBLAS_INT_TYPE lda, const double *B, const CBLAS_INT_TYPE ldb, + const double beta, double *C, const CBLAS_INT_TYPE ldc); + void cblas_cgemm(const CBLAS_ORDER Order, const CBLAS_TRANSPOSE TransA, + const CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const CBLAS_INT_TYPE K, const void *alpha, const void *A, + const CBLAS_INT_TYPE lda, const void *B, const CBLAS_INT_TYPE ldb, + const void *beta, void *C, const CBLAS_INT_TYPE ldc); + void cblas_zgemm(const CBLAS_ORDER Order, const CBLAS_TRANSPOSE TransA, + const CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const CBLAS_INT_TYPE K, const void *alpha, const void *A, + const CBLAS_INT_TYPE lda, const void *B, const CBLAS_INT_TYPE ldb, + const void *beta, void *C, const CBLAS_INT_TYPE ldc); + void cblas_sgemv(const CBLAS_ORDER order, + const CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const float alpha, const float *A, const CBLAS_INT_TYPE lda, + const float *X, const CBLAS_INT_TYPE incX, const float beta, + float *Y, const CBLAS_INT_TYPE incY); + void cblas_dgemv(const CBLAS_ORDER order, + const CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const double alpha, const double *A, const CBLAS_INT_TYPE lda, + const double *X, const CBLAS_INT_TYPE incX, const double beta, + double *Y, const CBLAS_INT_TYPE incY); + void cblas_cgemv(const CBLAS_ORDER order, + const CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *A, const CBLAS_INT_TYPE lda, + const void *X, const CBLAS_INT_TYPE incX, const void *beta, + void *Y, const CBLAS_INT_TYPE incY); + void cblas_zgemv(const CBLAS_ORDER order, + const CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *A, const CBLAS_INT_TYPE lda, + const void *X, const CBLAS_INT_TYPE incX, const void *beta, + void *Y, const CBLAS_INT_TYPE incY); + void cblas_sger(const CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const float alpha, const float *X, const CBLAS_INT_TYPE incX, + const float *Y, const CBLAS_INT_TYPE incY, float *A, const CBLAS_INT_TYPE lda); + void cblas_dger(const CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const double alpha, const double *X, const CBLAS_INT_TYPE incX, + const double *Y, const CBLAS_INT_TYPE incY, double *A, const CBLAS_INT_TYPE lda); + void cblas_cgerc(const CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda); + void cblas_zgerc(const CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda); + float cblas_sdot(const CBLAS_INT_TYPE N, const float *X, const CBLAS_INT_TYPE incX, + const float *Y, const CBLAS_INT_TYPE incY); + double cblas_ddot(const CBLAS_INT_TYPE N, const double *X, const CBLAS_INT_TYPE incX, + const double *Y, const CBLAS_INT_TYPE incY); + void cblas_cdotu_sub(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *dotu); + void cblas_zdotu_sub(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *dotu); + void cblas_cdotc_sub(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *dotc); + void cblas_zdotc_sub(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *dotc); + void cblas_cgeru(const CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda); + void cblas_zgeru(const CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N, + const void *alpha, const void *X, const CBLAS_INT_TYPE incX, + const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda); } +#endif // if not CBLAS_H // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- @@ -155,14 +162,14 @@ namespace dlib const int incX, std::complex *Y, const int incY) { DLIB_TEST_BLAS_BINDING_AXPY; - cblas_caxpy(N, &alpha, X, incX, Y, incY); + cblas_caxpy(N, (float*)&alpha, (float*)X, incX, (float*)Y, incY); } inline void cblas_axpy(const int N, const std::complex& alpha, const std::complex *X, const int incX, std::complex *Y, const int incY) { DLIB_TEST_BLAS_BINDING_AXPY; - cblas_zaxpy(N, &alpha, X, incX, Y, incY); + cblas_zaxpy(N, (double*)&alpha, (double*)X, incX, (double*)Y, incY); } // ---------------------------------------------------------------------------------------- @@ -182,19 +189,19 @@ namespace dlib inline void cblas_scal(const int N, const std::complex& alpha, std::complex *X) { DLIB_TEST_BLAS_BINDING_SCAL; - cblas_cscal(N, &alpha, X, 1); + cblas_cscal(N, (float*)&alpha, (float*)X, 1); } inline void cblas_scal(const int N, const std::complex& alpha, std::complex *X) { DLIB_TEST_BLAS_BINDING_SCAL; - cblas_zscal(N, &alpha, X, 1); + cblas_zscal(N, (double*)&alpha, (double*)X, 1); } // ---------------------------------------------------------------------------------------- - inline void cblas_gemm( const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, - const enum CBLAS_TRANSPOSE TransB, const int M, const int N, + inline void cblas_gemm( const CBLAS_ORDER Order, const CBLAS_TRANSPOSE TransA, + const CBLAS_TRANSPOSE TransB, const int M, const int N, const int K, const float alpha, const float *A, const int lda, const float *B, const int ldb, const float beta, float *C, const int ldc) @@ -204,8 +211,8 @@ namespace dlib K, alpha, A, lda, B, ldb, beta, C, ldc); } - inline void cblas_gemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, - const enum CBLAS_TRANSPOSE TransB, const int M, const int N, + inline void cblas_gemm(const CBLAS_ORDER Order, const CBLAS_TRANSPOSE TransA, + const CBLAS_TRANSPOSE TransB, const int M, const int N, const int K, const double alpha, const double *A, const int lda, const double *B, const int ldb, const double beta, double *C, const int ldc) @@ -215,32 +222,32 @@ namespace dlib K, alpha, A, lda, B, ldb, beta, C, ldc); } - inline void cblas_gemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, - const enum CBLAS_TRANSPOSE TransB, const int M, const int N, + inline void cblas_gemm(const CBLAS_ORDER Order, const CBLAS_TRANSPOSE TransA, + const CBLAS_TRANSPOSE TransB, const int M, const int N, const int K, const std::complex& alpha, const std::complex *A, const int lda, const std::complex *B, const int ldb, const std::complex& beta, std::complex *C, const int ldc) { DLIB_TEST_BLAS_BINDING_GEMM; cblas_cgemm( Order, TransA, TransB, M, N, - K, &alpha, A, lda, B, ldb, &beta, C, ldc); + K, (float*)&alpha, (float*)A, lda, (float*)B, ldb, (float*)&beta, (float*)C, ldc); } - inline void cblas_gemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, - const enum CBLAS_TRANSPOSE TransB, const int M, const int N, + inline void cblas_gemm(const CBLAS_ORDER Order, const CBLAS_TRANSPOSE TransA, + const CBLAS_TRANSPOSE TransB, const int M, const int N, const int K, const std::complex& alpha, const std::complex *A, const int lda, const std::complex *B, const int ldb, const std::complex& beta, std::complex *C, const int ldc) { DLIB_TEST_BLAS_BINDING_GEMM; cblas_zgemm( Order, TransA, TransB, M, N, - K, &alpha, A, lda, B, ldb, &beta, C, ldc); + K, (double*)&alpha, (double*)A, lda, (double*)B, ldb, (double*)&beta, (double*)C, ldc); } // ---------------------------------------------------------------------------------------- - inline void cblas_gemv(const enum CBLAS_ORDER order, - const enum CBLAS_TRANSPOSE TransA, const int M, const int N, + inline void cblas_gemv(const CBLAS_ORDER order, + const CBLAS_TRANSPOSE TransA, const int M, const int N, const float alpha, const float *A, const int lda, const float *X, const int incX, const float beta, float *Y, const int incY) @@ -249,8 +256,8 @@ namespace dlib cblas_sgemv(order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY); } - inline void cblas_gemv(const enum CBLAS_ORDER order, - const enum CBLAS_TRANSPOSE TransA, const int M, const int N, + inline void cblas_gemv(const CBLAS_ORDER order, + const CBLAS_TRANSPOSE TransA, const int M, const int N, const double alpha, const double *A, const int lda, const double *X, const int incX, const double beta, double *Y, const int incY) @@ -259,76 +266,76 @@ namespace dlib cblas_dgemv(order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY); } - inline void cblas_gemv(const enum CBLAS_ORDER order, - const enum CBLAS_TRANSPOSE TransA, const int M, const int N, + inline void cblas_gemv(const CBLAS_ORDER order, + const CBLAS_TRANSPOSE TransA, const int M, const int N, const std::complex& alpha, const std::complex *A, const int lda, const std::complex *X, const int incX, const std::complex& beta, std::complex *Y, const int incY) { DLIB_TEST_BLAS_BINDING_GEMV; - cblas_cgemv(order, TransA, M, N, &alpha, A, lda, X, incX, &beta, Y, incY); + cblas_cgemv(order, TransA, M, N, (float*)&alpha, (float*)A, lda, (float*)X, incX, (float*)&beta, (float*)Y, incY); } - inline void cblas_gemv(const enum CBLAS_ORDER order, - const enum CBLAS_TRANSPOSE TransA, const int M, const int N, + inline void cblas_gemv(const CBLAS_ORDER order, + const CBLAS_TRANSPOSE TransA, const int M, const int N, const std::complex& alpha, const std::complex *A, const int lda, const std::complex *X, const int incX, const std::complex& beta, std::complex *Y, const int incY) { DLIB_TEST_BLAS_BINDING_GEMV; - cblas_zgemv(order, TransA, M, N, &alpha, A, lda, X, incX, &beta, Y, incY); + cblas_zgemv(order, TransA, M, N, (double*)&alpha, (double*)A, lda, (double*)X, incX, (double*)&beta, (double*)Y, incY); } // ---------------------------------------------------------------------------------------- - inline void cblas_ger(const enum CBLAS_ORDER order, const int M, const int N, + inline void cblas_ger(const CBLAS_ORDER order, const int M, const int N, const std::complex& alpha, const std::complex *X, const int incX, const std::complex *Y, const int incY, std::complex *A, const int lda) { DLIB_TEST_BLAS_BINDING_GER; - cblas_cgeru (order, M, N, &alpha, X, incX, Y, incY, A, lda); + cblas_cgeru (order, M, N, (float*)&alpha, (float*)X, incX, (float*)Y, incY, (float*)A, lda); } - inline void cblas_ger(const enum CBLAS_ORDER order, const int M, const int N, + inline void cblas_ger(const CBLAS_ORDER order, const int M, const int N, const std::complex& alpha, const std::complex *X, const int incX, const std::complex *Y, const int incY, std::complex *A, const int lda) { DLIB_TEST_BLAS_BINDING_GER; - cblas_zgeru (order, M, N, &alpha, X, incX, Y, incY, A, lda); + cblas_zgeru (order, M, N, (double*)&alpha, (double*)X, incX, (double*)Y, incY, (double*)A, lda); } - inline void cblas_ger(const enum CBLAS_ORDER order, const int M, const int N, + inline void cblas_ger(const CBLAS_ORDER order, const int M, const int N, const float alpha, const float *X, const int incX, const float *Y, const int incY, float *A, const int lda) { DLIB_TEST_BLAS_BINDING_GER; - cblas_sger (order, M, N, alpha, X, incX, Y, incY, A, lda); + cblas_sger (order, M, N, alpha, (float*)X, incX, (float*)Y, incY, (float*)A, lda); } - inline void cblas_ger(const enum CBLAS_ORDER order, const int M, const int N, + inline void cblas_ger(const CBLAS_ORDER order, const int M, const int N, const double alpha, const double *X, const int incX, const double *Y, const int incY, double *A, const int lda) { DLIB_TEST_BLAS_BINDING_GER; - cblas_dger (order, M, N, alpha, X, incX, Y, incY, A, lda); + cblas_dger (order, M, N, alpha, (double*)X, incX, (double*)Y, incY, (double*)A, lda); } // ---------------------------------------------------------------------------------------- - inline void cblas_gerc(const enum CBLAS_ORDER order, const int M, const int N, + inline void cblas_gerc(const CBLAS_ORDER order, const int M, const int N, const std::complex& alpha, const std::complex *X, const int incX, const std::complex *Y, const int incY, std::complex *A, const int lda) { DLIB_TEST_BLAS_BINDING_GER; - cblas_cgerc (order, M, N, &alpha, X, incX, Y, incY, A, lda); + cblas_cgerc (order, M, N, (float*)&alpha, (float*)X, incX, (float*)Y, incY, (float*)A, lda); } - inline void cblas_gerc(const enum CBLAS_ORDER order, const int M, const int N, + inline void cblas_gerc(const CBLAS_ORDER order, const int M, const int N, const std::complex& alpha, const std::complex *X, const int incX, const std::complex *Y, const int incY, std::complex *A, const int lda) { DLIB_TEST_BLAS_BINDING_GER; - cblas_zgerc (order, M, N, &alpha, X, incX, Y, incY, A, lda); + cblas_zgerc (order, M, N, (double*)&alpha, (double*)X, incX, (double*)Y, incY, (double*)A, lda); } // ---------------------------------------------------------------------------------------- @@ -352,7 +359,7 @@ namespace dlib { DLIB_TEST_BLAS_BINDING_DOT; std::complex result; - cblas_cdotu_sub(N, X, incX, Y, incY, &result); + cblas_cdotu_sub(N, (float*)X, incX, (float*)Y, incY, (float*)&result); return result; } @@ -361,7 +368,7 @@ namespace dlib { DLIB_TEST_BLAS_BINDING_DOT; std::complex result; - cblas_zdotu_sub(N, X, incX, Y, incY, &result); + cblas_zdotu_sub(N, (double*)X, incX, (double*)Y, incY, (double*)&result); return result; } @@ -372,7 +379,7 @@ namespace dlib { DLIB_TEST_BLAS_BINDING_DOT; std::complex result; - cblas_cdotc_sub(N, X, incX, Y, incY, &result); + cblas_cdotc_sub(N, (float*)X, incX, (float*)Y, incY, (float*)&result); return result; } @@ -381,7 +388,7 @@ namespace dlib { DLIB_TEST_BLAS_BINDING_DOT; std::complex result; - cblas_zdotc_sub(N, X, incX, Y, incY, &result); + cblas_zdotc_sub(N, (double*)X, incX, (double*)Y, incY, (double*)&result); return result; } @@ -408,6 +415,21 @@ namespace dlib template int get_ld (const assignable_sub_matrix& m) { return m.m.nr(); } + template + int get_ld (const assignable_col_matrix& m) { return m.m.nc(); } + + template + int get_ld (const assignable_col_matrix& m) { return m.m.nr(); } + + template + int get_ld (const assignable_row_matrix& m) { return m.m.nc(); } + + template + int get_ld (const assignable_row_matrix& m) { return m.m.nr(); } + + template + int get_ld (const assignable_ptr_matrix& m) { return m.nc(); } + template int get_ld (const matrix_op > >& m) { return m.nc(); } template @@ -419,10 +441,14 @@ namespace dlib template int get_ld (const matrix_op >& m) { return m.nc(); } template - int get_ld (const matrix_op >& m) { return m.nc(); } + int get_ld (const matrix_op >& m) { return m.op.stride; } // -------- + // get_inc() returns the offset from one element to another. If an object has a + // non-uniform offset between elements then returns 0 (e.g. a subm() view could + // have a non-uniform offset between elements). + template int get_inc (const matrix_op > >& ) { return 1; } template @@ -434,11 +460,51 @@ namespace dlib template int get_inc (const matrix_op >& ) { return 1; } template - int get_inc (const matrix_op >& ) { return 1; } + int get_inc (const matrix_op >& m) { return m.op.stride==m.op.cols ? 1 : 0; } template int get_inc (const matrix& ) { return 1; } + template + int get_inc (const matrix_op > >& m) + { + // if the sub-view doesn't cover all the columns then it can't have a uniform + // layout. + if (m.nc() < m.op.m.nc()) + return 0; + else + return 1; + } + + template + int get_inc (const matrix_op > >& m) + { + if (m.nr() < m.op.m.nr()) + return 0; + else + return 1; + } + + template + int get_inc (const assignable_sub_matrix& m) + { + if (m.nc() < m.m.nc()) + return 0; + else + return 1; + } + template + int get_inc (const assignable_sub_matrix& m) + { + if (m.nr() < m.m.nr()) + return 0; + else + return 1; + } + + template + int get_inc (const assignable_ptr_matrix& ) { return 1; } + template int get_inc(const matrix_op > >& m) { @@ -548,6 +614,9 @@ namespace dlib template T* get_ptr (assignable_sub_matrix& m) { return &m(0,0); } + template + T* get_ptr (assignable_ptr_matrix& m) { return m.ptr; } + template const T* get_ptr (const matrix_op > >& m) { return &m.op.array[0][0]; } template @@ -589,18 +658,17 @@ namespace dlib { if (add_to) { - cblas_axpy(N, alpha, get_ptr(src), 1, get_ptr(dest), 1); + if (get_inc(src) && get_inc(dest)) + cblas_axpy(N, alpha, get_ptr(src), get_inc(src), get_ptr(dest), get_inc(dest)); + else + matrix_assign_default(dest, src, alpha, add_to); } else { if (get_ptr(src) == get_ptr(dest)) - { cblas_scal(N, alpha, get_ptr(dest)); - } else - { matrix_assign_default(dest, src, alpha, add_to); - } } } else @@ -618,18 +686,17 @@ namespace dlib { if (add_to) { - cblas_axpy(N, alpha, get_ptr(src), 1, get_ptr(dest), 1); + if (get_inc(src) && get_inc(dest)) + cblas_axpy(N, alpha, get_ptr(src), get_inc(src), get_ptr(dest), get_inc(dest)); + else + matrix_assign_default(dest, src, alpha, add_to); } else { if (get_ptr(src) == get_ptr(dest)) - { cblas_scal(N, alpha, get_ptr(dest)); - } else - { matrix_assign_default(dest, src, alpha, add_to); - } } } else @@ -647,18 +714,17 @@ namespace dlib { if (add_to) { - cblas_axpy(N, alpha, get_ptr(src), 1, get_ptr(dest), 1); + if (get_inc(src) && get_inc(dest)) + cblas_axpy(N, alpha, get_ptr(src), get_inc(src), get_ptr(dest), get_inc(dest)); + else + matrix_assign_default(dest, src, alpha, add_to); } else { if (get_ptr(src) == get_ptr(dest)) - { cblas_scal(N, alpha, get_ptr(dest)); - } else - { matrix_assign_default(dest, src, alpha, add_to); - } } } else diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_conv.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_conv.h index 3b541d3f..b90c388b 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_conv.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_conv.h @@ -5,6 +5,7 @@ #include "matrix_conv_abstract.h" #include "matrix.h" +#include "matrix_fft.h" namespace dlib { @@ -112,6 +113,55 @@ namespace dlib return matrix_op(op(m1.ref(),m2.ref())); } +// ---------------------------------------------------------------------------------------- + + namespace impl + { + inline size_t bounding_power_of_two ( + size_t n + ) + { + size_t s = 1; + for (unsigned int i = 0; i < sizeof(s)*8 && s < n; ++i) + s <<= 1; + return s; + } + } + + template < + typename EXP1, + typename EXP2 + > + typename EXP1::matrix_type xcorr_fft( + const matrix_exp& u, + const matrix_exp& v + ) + { + COMPILE_TIME_ASSERT((is_same_type::value == true)); + using T = typename EXP1::type; + COMPILE_TIME_ASSERT((is_same_type::value || is_same_type::value || is_same_type::value )); + + const long pad_nr = impl::bounding_power_of_two(u.nr() + v.nr() - 1); + const long pad_nc = impl::bounding_power_of_two(u.nc() + v.nc() - 1); + + matrix> U(pad_nr, pad_nc), V(pad_nr,pad_nc); + + U = 0; + V = 0; + set_subm(U,U.nr()-u.nr(),U.nc()-u.nc(),u.nr(),u.nc()) = u; + set_subm(V,get_rect(v)) = v; + + fft_inplace(U); + fft_inplace(V); + + return subm(real(ifft(pointwise_multiply(U, conj(V)))), + U.nr()-u.nr()-v.nr()+1, + U.nc()-u.nc()-v.nc()+1, + u.nr()+v.nr()-1, + u.nc()+v.nc()-1 + ); + } + // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_conv_abstract.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_conv_abstract.h index 0338fd0d..b342f266 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_conv_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_conv_abstract.h @@ -45,6 +45,23 @@ namespace dlib - R.nc() == m1.nc()+m2.nc()-1 !*/ +// ---------------------------------------------------------------------------------------- + + const matrix_exp xcorr_fft ( + const matrix_exp& m1, + const matrix_exp& m2 + ); + /*! + requires + - m1 and m2 both contain elements of the same type + - m1 and m2 contain real or complex values and must be double, float, or long + double valued. (e.g. not integers) + ensures + - This function is identical to xcorr() except that it uses a fast Fourier + transform to do the convolution and is therefore much faster when both m1 and + m2 are large. + !*/ + // ---------------------------------------------------------------------------------------- const matrix_exp conv_same ( diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_data_layout.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_data_layout.h index 6c1a8658..e8889f96 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_data_layout.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_data_layout.h @@ -6,11 +6,15 @@ #include "../algs.h" #include "matrix_fwd.h" #include "matrix_data_layout_abstract.h" +#ifdef MATLAB_MEX_FILE +#include +#endif // GCC 4.8 gives false alarms about some matrix operations going out of bounds. Disable // these false warnings. -#if ( defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 8) - #pragma GCC diagnostic ignored "-Warray-bounds" +#if defined(__GNUC__) && ((__GNUC__ >= 4 && __GNUC_MINOR__ >= 8) || (__GNUC__ > 4)) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" #endif namespace dlib @@ -38,21 +42,21 @@ namespace dlib public: T& operator() ( - long r, - long c + size_t r, + size_t c ); const T& operator() ( - long r, - long c + size_t r, + size_t c ); T& operator() ( - long i + size_t i ); const T& operator() ( - long i + size_t i ) const; void swap( @@ -66,8 +70,8 @@ namespace dlib ) const; void set_size ( - long nr_, - long nc_ + size_t nr_, + size_t nc_ ); }; }; @@ -137,21 +141,21 @@ namespace dlib layout() {} T& operator() ( - long r, - long c + size_t r, + size_t c ) { return *(data+r*num_cols + c); } const T& operator() ( - long r, - long c + size_t r, + size_t c ) const { return *(data+r*num_cols + c); } T& operator() ( - long i + size_t i ) { return data[i]; } const T& operator() ( - long i + size_t i ) const { return data[i]; } void swap( @@ -174,12 +178,19 @@ namespace dlib ) const { return num_cols; } void set_size ( - long , - long + size_t , + size_t ) { } +#ifdef MATLAB_MEX_FILE + void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, "This function should never be called."); } + mxArray* _private_release_mxArray(){DLIB_CASSERT(false, "This function should never be called."); } + void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, "This function should never be called."); } + bool _private_is_owned_by_matlab() const { return false; } +#endif + private: T data[num_rows*num_cols]; }; @@ -205,21 +216,21 @@ namespace dlib { pool.deallocate_array(data); } T& operator() ( - long r, - long c + size_t r, + size_t c ) { return data[r*num_cols + c]; } const T& operator() ( - long r, - long c + size_t r, + size_t c ) const { return data[r*num_cols + c]; } T& operator() ( - long i + size_t i ) { return data[i]; } const T& operator() ( - long i + size_t i ) const { return data[i]; } void swap( @@ -237,17 +248,24 @@ namespace dlib ) const { return num_cols; } void set_size ( - long , - long + size_t , + size_t ) { } +#ifdef MATLAB_MEX_FILE + void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, "This function should never be called."); } + mxArray* _private_release_mxArray(){DLIB_CASSERT(false, "This function should never be called."); } + void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, "This function should never be called."); } + bool _private_is_owned_by_matlab() const { return false; } +#endif + private: T* data; typename mem_manager::template rebind::other pool; - }; + }; // ------------------------------------------------------------------------------------ @@ -273,21 +291,21 @@ namespace dlib } T& operator() ( - long r, - long c + size_t r, + size_t c ) { return data[r*num_cols + c]; } const T& operator() ( - long r, - long c + size_t r, + size_t c ) const { return data[r*num_cols + c]; } T& operator() ( - long i + size_t i ) { return data[i]; } const T& operator() ( - long i + size_t i ) const { return data[i]; } void swap( @@ -306,8 +324,8 @@ namespace dlib ) const { return num_cols; } void set_size ( - long nr, - long nc + size_t nr, + size_t nc ) { if (data) @@ -318,12 +336,27 @@ namespace dlib nr_ = nr; } + std::unique_ptr steal_memory() + { + auto ret = pool.extract_array(data); + data = nullptr; + nr_ = 0; + return ret; + } + +#ifdef MATLAB_MEX_FILE + void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, "This function should never be called."); } + mxArray* _private_release_mxArray(){DLIB_CASSERT(false, "This function should never be called."); } + void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, "This function should never be called."); } + bool _private_is_owned_by_matlab() const { return false; } +#endif + private: T* data; long nr_; typename mem_manager::template rebind::other pool; - }; + }; // ------------------------------------------------------------------------------------ @@ -351,21 +384,21 @@ namespace dlib } T& operator() ( - long r, - long c + size_t r, + size_t c ) { return data[r*nc_ + c]; } const T& operator() ( - long r, - long c + size_t r, + size_t c ) const { return data[r*nc_ + c]; } T& operator() ( - long i + size_t i ) { return data[i]; } const T& operator() ( - long i + size_t i ) const { return data[i]; } void swap( @@ -384,8 +417,8 @@ namespace dlib ) const { return nc_; } void set_size ( - long nr, - long nc + size_t nr, + size_t nc ) { if (data) @@ -396,12 +429,27 @@ namespace dlib nc_ = nc; } + std::unique_ptr steal_memory() + { + auto ret = pool.extract_array(data); + data = nullptr; + nc_ = 0; + return ret; + } + +#ifdef MATLAB_MEX_FILE + void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, "This function should never be called."); } + mxArray* _private_release_mxArray(){DLIB_CASSERT(false, "This function should never be called."); } + void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, "This function should never be called."); } + bool _private_is_owned_by_matlab() const { return false; } +#endif + private: T* data; long nc_; typename mem_manager::template rebind::other pool; - }; + }; // ------------------------------------------------------------------------------------ @@ -429,21 +477,21 @@ namespace dlib } T& operator() ( - long r, - long c + size_t r, + size_t c ) { return data[r*nc_ + c]; } const T& operator() ( - long r, - long c + size_t r, + size_t c ) const { return data[r*nc_ + c]; } T& operator() ( - long i + size_t i ) { return data[i]; } const T& operator() ( - long i + size_t i ) const { return data[i]; } void swap( @@ -463,8 +511,8 @@ namespace dlib ) const { return nc_; } void set_size ( - long nr, - long nc + size_t nr, + size_t nc ) { if (data) @@ -476,12 +524,27 @@ namespace dlib nc_ = nc; } + std::unique_ptr steal_memory() + { + auto ret = pool.extract_array(data); + data = nullptr; + nr_ = 0; + nc_ = 0; + return ret; + } + +#ifdef MATLAB_MEX_FILE + void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, "This function should never be called."); } + mxArray* _private_release_mxArray(){DLIB_CASSERT(false, "This function should never be called."); } + void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, "This function should never be called."); } + bool _private_is_owned_by_matlab() const { return false; } +#endif private: T* data; long nr_; long nc_; typename mem_manager::template rebind::other pool; - }; + }; }; @@ -550,21 +613,21 @@ namespace dlib layout() {} T& operator() ( - long r, - long c + size_t r, + size_t c ) { return *(data+c*num_rows + r); } const T& operator() ( - long r, - long c + size_t r, + size_t c ) const { return *(data+c*num_rows + r); } T& operator() ( - long i + size_t i ) { return data[i]; } const T& operator() ( - long i + size_t i ) const { return data[i]; } void swap( @@ -587,12 +650,19 @@ namespace dlib ) const { return num_cols; } void set_size ( - long, - long + size_t, + size_t ) { } +#ifdef MATLAB_MEX_FILE + void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, "This function should never be called."); } + mxArray* _private_release_mxArray(){DLIB_CASSERT(false, "This function should never be called."); } + void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, "This function should never be called."); } + bool _private_is_owned_by_matlab() const { return false; } +#endif + private: T data[num_cols*num_rows]; }; @@ -618,21 +688,21 @@ namespace dlib { pool.deallocate_array(data); } T& operator() ( - long r, - long c + size_t r, + size_t c ) { return data[c*num_rows + r]; } const T& operator() ( - long r, - long c + size_t r, + size_t c ) const { return data[c*num_rows + r]; } T& operator() ( - long i + size_t i ) { return data[i]; } const T& operator() ( - long i + size_t i ) const { return data[i]; } void swap( @@ -650,17 +720,24 @@ namespace dlib ) const { return num_cols; } void set_size ( - long , - long + size_t , + size_t ) { } +#ifdef MATLAB_MEX_FILE + void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, "This function should never be called."); } + mxArray* _private_release_mxArray(){DLIB_CASSERT(false, "This function should never be called."); } + void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, "This function should never be called."); } + bool _private_is_owned_by_matlab() const { return false; } +#endif + private: T* data; typename mem_manager::template rebind::other pool; - }; + }; // ------------------------------------------------------------------------------------ @@ -686,21 +763,21 @@ namespace dlib } T& operator() ( - long r, - long c + size_t r, + size_t c ) { return data[c*nr_ + r]; } const T& operator() ( - long r, - long c + size_t r, + size_t c ) const { return data[c*nr_ + r]; } T& operator() ( - long i + size_t i ) { return data[i]; } const T& operator() ( - long i + size_t i ) const { return data[i]; } void swap( @@ -719,8 +796,8 @@ namespace dlib ) const { return num_cols; } void set_size ( - long nr, - long nc + size_t nr, + size_t nc ) { if (data) @@ -731,12 +808,27 @@ namespace dlib nr_ = nr; } + std::unique_ptr steal_memory() + { + auto ret = pool.extract_array(data); + data = nullptr; + nr_ = 0; + return ret; + } + +#ifdef MATLAB_MEX_FILE + void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, "This function should never be called."); } + mxArray* _private_release_mxArray(){DLIB_CASSERT(false, "This function should never be called."); } + void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, "This function should never be called."); } + bool _private_is_owned_by_matlab() const { return false; } +#endif + private: T* data; long nr_; typename mem_manager::template rebind::other pool; - }; + }; // ------------------------------------------------------------------------------------ @@ -764,21 +856,21 @@ namespace dlib } T& operator() ( - long r, - long c + size_t r, + size_t c ) { return data[c*num_rows + r]; } const T& operator() ( - long r, - long c + size_t r, + size_t c ) const { return data[c*num_rows + r]; } T& operator() ( - long i + size_t i ) { return data[i]; } const T& operator() ( - long i + size_t i ) const { return data[i]; } void swap( @@ -797,8 +889,8 @@ namespace dlib ) const { return nc_; } void set_size ( - long nr, - long nc + size_t nr, + size_t nc ) { if (data) @@ -809,12 +901,27 @@ namespace dlib nc_ = nc; } + std::unique_ptr steal_memory() + { + auto ret = pool.extract_array(data); + data = nullptr; + nc_ = 0; + return ret; + } + +#ifdef MATLAB_MEX_FILE + void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, "This function should never be called."); } + mxArray* _private_release_mxArray(){DLIB_CASSERT(false, "This function should never be called."); } + void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, "This function should never be called."); } + bool _private_is_owned_by_matlab() const { return false; } +#endif + private: T* data; long nc_; typename mem_manager::template rebind::other pool; - }; + }; // ------------------------------------------------------------------------------------ @@ -842,21 +949,21 @@ namespace dlib } T& operator() ( - long r, - long c + size_t r, + size_t c ) { return data[c*nr_ + r]; } const T& operator() ( - long r, - long c + size_t r, + size_t c ) const { return data[c*nr_ + r]; } T& operator() ( - long i + size_t i ) { return data[i]; } const T& operator() ( - long i + size_t i ) const { return data[i]; } void swap( @@ -869,6 +976,13 @@ namespace dlib pool.swap(item.pool); } +#ifdef MATLAB_MEX_FILE + void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, "This function should never be called."); } + mxArray* _private_release_mxArray(){DLIB_CASSERT(false, "This function should never be called."); } + void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, "This function should never be called."); } + bool _private_is_owned_by_matlab() const { return false; } +#endif + long nr ( ) const { return nr_; } @@ -876,8 +990,8 @@ namespace dlib ) const { return nc_; } void set_size ( - long nr, - long nc + size_t nr, + size_t nc ) { if (data) @@ -889,12 +1003,329 @@ namespace dlib nc_ = nc; } + std::unique_ptr steal_memory() + { + auto ret = pool.extract_array(data); + data = nullptr; + nr_ = 0; + nc_ = 0; + return ret; + } + private: T* data; long nr_; long nc_; typename mem_manager::template rebind::other pool; - }; + }; + +#ifdef MATLAB_MEX_FILE + template < + long num_rows, + long num_cols + > + class layout : noncopyable // when num_rows == 0 && num_cols == 0 + { + public: + const static long NR = num_rows; + const static long NC = num_cols; + + layout ( + ): data(0), nr_(0), nc_(0), owned_by_matlab(false),set_by_private_set_mxArray(false),mem(0) { } + + ~layout () + { + if (owned_by_matlab) + { + if (!set_by_private_set_mxArray && mem) + { + mxDestroyArray(mem); + mem = 0; + data = 0; + } + } + else if (data) + { + delete [] data; + data = 0; + } + } + + double& operator() ( + size_t r, + size_t c + ) { return data[c*nr_ + r]; } + + const double& operator() ( + size_t r, + size_t c + ) const { return data[c*nr_ + r]; } + + double& operator() ( + size_t i + ) { return data[i]; } + + const double& operator() ( + size_t i + ) const { return data[i]; } + + void _private_set_mxArray ( + mxArray* mem_ + ) + { + DLIB_CASSERT(mem == 0 && data == 0,"You can't call this function on an already allocated matrix."); + // We don't own the pointer, so make note of that so we won't try to free + // it. + set_by_private_set_mxArray = true; + owned_by_matlab = true; + mem = mem_; + data = mxGetPr(mem); + nr_ = mxGetM(mem); + nc_ = mxGetN(mem); + } + + mxArray* _private_release_mxArray() + { + DLIB_CASSERT(owned_by_matlab,""); + mxArray* temp = mem; + mem = 0; + set_by_private_set_mxArray = false; + data = 0; + nr_ = 0; + nc_ = 0; + return temp; + } + + void _private_mark_owned_by_matlab() + { + DLIB_CASSERT(mem == 0 && data == 0,"You can't say a matrix should be owned by matlab after it's been allocated."); + owned_by_matlab = true; + } + bool _private_is_owned_by_matlab() const + { + return owned_by_matlab; + } + + void swap( + layout& item + ) + { + std::swap(item.owned_by_matlab,owned_by_matlab); + std::swap(item.set_by_private_set_mxArray,set_by_private_set_mxArray); + std::swap(item.mem,mem); + std::swap(item.data,data); + std::swap(item.nc_,nc_); + std::swap(item.nr_,nr_); + } + + long nr ( + ) const { return nr_; } + + long nc ( + ) const { return nc_; } + + void set_size ( + size_t nr, + size_t nc + ) + { + if (owned_by_matlab) + { + if (!set_by_private_set_mxArray && mem) + { + mxDestroyArray(mem); + mem = 0; + data = 0; + } + set_by_private_set_mxArray = false; + + mem = mxCreateDoubleMatrix(nr, nc, mxREAL); + if (mem == 0) + throw std::bad_alloc(); + data = mxGetPr(mem); + } + else + { + if (data) + delete [] data; + data = new double[nr*nc]; + } + nr_ = nr; + nc_ = nc; + } + + std::unique_ptr steal_memory() + { + DLIB_CASSERT(!owned_by_matlab, "You can't steal the memory from a matrix if it's owned by MATLAB."); + std::unique_ptr ret(data); + data = nullptr; + nr_ = 0; + nc_ = 0; + return ret; + } + + private: + double* data; + long nr_; + long nc_; + bool owned_by_matlab; + bool set_by_private_set_mxArray; + mxArray* mem; + }; + + template < + long num_rows, + long num_cols + > + class layout : noncopyable // when num_rows == 0 && num_cols == 0 + { + public: + const static long NR = num_rows; + const static long NC = num_cols; + + layout ( + ): data(0), nr_(0), nc_(0), owned_by_matlab(false),set_by_private_set_mxArray(false),mem(0) { } + + ~layout () + { + if (owned_by_matlab) + { + if (!set_by_private_set_mxArray && mem) + { + mxDestroyArray(mem); + mem = 0; + data = 0; + } + } + else if (data) + { + delete [] data; + data = 0; + } + } + + float& operator() ( + size_t r, + size_t c + ) { return data[c*nr_ + r]; } + + const float& operator() ( + size_t r, + size_t c + ) const { return data[c*nr_ + r]; } + + float& operator() ( + size_t i + ) { return data[i]; } + + const float& operator() ( + size_t i + ) const { return data[i]; } + + void _private_set_mxArray ( + mxArray* mem_ + ) + { + DLIB_CASSERT(mem == 0 && data == 0,"You can't call this function on an already allocated matrix."); + // We don't own the pointer, so make note of that so we won't try to free + // it. + set_by_private_set_mxArray = true; + owned_by_matlab = true; + mem = mem_; + data = (float*)mxGetData(mem); + nr_ = mxGetM(mem); + nc_ = mxGetN(mem); + } + + mxArray* _private_release_mxArray() + { + DLIB_CASSERT(owned_by_matlab,""); + mxArray* temp = mem; + mem = 0; + set_by_private_set_mxArray = false; + data = 0; + nr_ = 0; + nc_ = 0; + return temp; + } + + void _private_mark_owned_by_matlab() + { + DLIB_CASSERT(mem == 0 && data == 0,"You can't say a matrix should be owned by matlab after it's been allocated."); + owned_by_matlab = true; + } + bool _private_is_owned_by_matlab() const + { + return owned_by_matlab; + } + + void swap( + layout& item + ) + { + std::swap(item.owned_by_matlab,owned_by_matlab); + std::swap(item.set_by_private_set_mxArray,set_by_private_set_mxArray); + std::swap(item.mem,mem); + std::swap(item.data,data); + std::swap(item.nc_,nc_); + std::swap(item.nr_,nr_); + } + + long nr ( + ) const { return nr_; } + + long nc ( + ) const { return nc_; } + + void set_size ( + size_t nr, + size_t nc + ) + { + if (owned_by_matlab) + { + if (!set_by_private_set_mxArray && mem) + { + mxDestroyArray(mem); + mem = 0; + data = 0; + } + set_by_private_set_mxArray = false; + + mem = mxCreateNumericMatrix(nr, nc, mxSINGLE_CLASS, mxREAL); + if (mem == 0) + throw std::bad_alloc(); + data = (float*)mxGetData(mem); + } + else + { + if (data) + delete [] data; + data = new float[nr*nc]; + } + nr_ = nr; + nc_ = nc; + } + + std::unique_ptr steal_memory() + { + DLIB_CASSERT(!owned_by_matlab, "You can't steal the memory from a matrix if it's owned by MATLAB."); + std::unique_ptr ret(data); + data = nullptr; + nr_ = 0; + nc_ = 0; + return ret; + } + + private: + float* data; + long nr_; + long nc_; + bool owned_by_matlab; + bool set_by_private_set_mxArray; + mxArray* mem; + }; +#endif }; @@ -902,5 +1333,9 @@ namespace dlib } +#if defined(__GNUC__) && ((__GNUC__ >= 4 && __GNUC_MINOR__ >= 8) || (__GNUC__ > 4)) +#pragma GCC diagnostic pop +#endif + #endif // DLIB_MATRIx_DATA_LAYOUT_ diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_eigenvalue.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_eigenvalue.h index 2764a1e9..3dc47e10 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_eigenvalue.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_eigenvalue.h @@ -193,6 +193,7 @@ namespace dlib lapack::integer temp; lapack::syevr('V','A','L',tempA,0,0,0,0,-1,temp,d,V,isupz); + return; } #endif // Tridiagonalize. @@ -611,7 +612,7 @@ namespace dlib type g = d(l); type p = (d(l+1) - g) / (2.0 * e(l)); - type r = hypot(p,1.0); + type r = hypot(p,(type)1.0); if (p < 0) { r = -r; diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_fft.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_fft.h index 93e0ceff..fbca6d34 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_fft.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_fft.h @@ -8,51 +8,20 @@ #include "../hash.h" #include "../algs.h" +#ifdef DLIB_USE_MKL_FFT +#include +#endif + +// No using FFTW until it becomes thread safe! +#if 0 #ifdef DLIB_USE_FFTW #include #endif // DLIB_USE_FFTW +#endif namespace dlib { -// ---------------------------------------------------------------------------------------- - - namespace impl - { - inline unsigned long reverse_bits ( - unsigned long val, - unsigned long num - ) - { - unsigned long temp = 0; - for (unsigned long i = 0; i < num; ++i) - { - temp <<= 1; - temp |= val&0x1; - val >>= 1; - } - return temp; - } - - template - void permute ( - const matrix_exp& data, - typename EXP::matrix_type& outdata - ) - { - outdata.set_size(data.size()); - if (data.size() == 0) - return; - - const unsigned long num = static_cast(std::log((double)data.size())/std::log(2.0) + 0.5); - for (unsigned long i = 0; i < (unsigned long)data.size(); ++i) - { - outdata(impl::reverse_bits(i,num)) = data(i); - } - } - - } - // ---------------------------------------------------------------------------------------- inline bool is_power_of_two ( @@ -67,147 +36,522 @@ namespace dlib // ---------------------------------------------------------------------------------------- - template - typename EXP::matrix_type fft ( - const matrix_exp& data - ) + namespace impl { - if (data.size() == 0) - return data; - // You have to give a complex matrix - COMPILE_TIME_ASSERT(is_complex::value); - // make sure requires clause is not broken - DLIB_CASSERT(is_vector(data) && is_power_of_two(data.size()), - "\t void ifft(data)" - << "\n\t data must be a vector with a size that is a power of two." - << "\n\t is_vector(data): " << is_vector(data) - << "\n\t data.size(): " << data.size() - ); + // ------------------------------------------------------------------------------------ - typedef typename EXP::type::value_type T; + /* + The next few functions related to doing FFTs are derived from Stefan + Gustavson's (stegu@itn.liu.se) public domain 2D Fourier transformation code. + The code has a long history, originally a FORTRAN implementation published in: + Programming for Digital Signal Processing, IEEE Press 1979, Section 1, by G. D. + Bergland and M. T. Dolan. In 2003 it was cleaned up and turned into modern C + by Steven Gustavson. Davis King then rewrote it in modern C++ in 2014 and also + changed the transform so that the outputs are identical to those given from FFTW. + */ - typename EXP::matrix_type outdata(data); + // ------------------------------------------------------------------------------------ - const long half = outdata.size()/2; - - typedef std::complex ct; - matrix twiddle_factors(half); - - // compute the complex root of unity w - const T temp = -2.0*pi/outdata.size(); - ct w = ct(std::cos(temp),std::sin(temp)); - - ct w_pow = 1; - - // compute the twiddle factors - for (long j = 0; j < twiddle_factors.size(); ++j) + /* Get binary log of integer argument - exact if n is a power of 2 */ + inline long fastlog2(long n) { - twiddle_factors(j) = w_pow; - w_pow *= w; + long log = -1; + while(n) { + log++; + n >>= 1; + } + return log ; } + // ------------------------------------------------------------------------------------ - // now compute the decimation in frequency. This first - // outer loop loops log2(outdata.size()) number of times - long skip = 1; - for (long step = half; step != 0; step >>= 1) + /* Radix-2 iteration subroutine */ + template + void R2TX(int nthpo, std::complex *c0, std::complex *c1) { - // do blocks of butterflies in this loop - for (long j = 0; j < outdata.size(); j += step*2) + for(int k=0; k temp = c0[k] + c1[k]; + c1[k] = c0[k] - c1[k]; + c0[k] = temp; + } + } + + // ------------------------------------------------------------------------------------ + + /* Radix-4 iteration subroutine */ + template + void R4TX(int nthpo, std::complex *c0, std::complex *c1, + std::complex *c2, std::complex *c3) + { + for(int k=0;k t1, t2, t3, t4; + t1 = c0[k] + c2[k]; + t2 = c0[k] - c2[k]; + t3 = c1[k] + c3[k]; + t4 = c1[k] - c3[k]; + + c0[k] = t1 + t3; + c1[k] = t1 - t3; + c2[k] = std::complex(t2.real()-t4.imag(), t2.imag()+t4.real()); + c3[k] = std::complex(t2.real()+t4.imag(), t2.imag()-t4.real()); + } + } + + // ------------------------------------------------------------------------------------ + + template + class twiddles + { + /*! + The point of this object is to cache the twiddle values so we don't + recompute them over and over inside R8TX(). + !*/ + public: + + twiddles() + { + data.resize(64); + } + + const std::complex* get_twiddles ( + int p + ) + /*! + requires + - 0 <= p <= 64 + ensures + - returns a pointer to the twiddle factors needed by R8TX if nxtlt == 2^p + !*/ + { + // Compute the twiddle factors for this p value if we haven't done so + // already. + if (data[p].size() == 0) { - const long a_idx = j+k; - const long b_idx = j+k+step; - const ct a = outdata(a_idx) + outdata(b_idx); - const ct b = (outdata(a_idx) - outdata(b_idx))*twiddle_factors(k*skip); - outdata(a_idx) = a; - outdata(b_idx) = b; + const int nxtlt = 0x1 << p; + data[p].reserve(nxtlt*7); + const T twopi = 6.2831853071795865; /* 2.0 * pi */ + const T scale = twopi/(nxtlt*8.0); + std::complex cs[7]; + for (int j = 0; j < nxtlt; ++j) + { + const T arg = j*scale; + cs[0] = std::complex(std::cos(arg),std::sin(arg)); + cs[1] = cs[0]*cs[0]; + cs[2] = cs[1]*cs[0]; + cs[3] = cs[1]*cs[1]; + cs[4] = cs[2]*cs[1]; + cs[5] = cs[2]*cs[2]; + cs[6] = cs[3]*cs[2]; + data[p].insert(data[p].end(), cs, cs+7); + } + } + + return &data[p][0]; + } + + private: + std::vector > > data; + }; + + // ---------------------------------------------------------------------------------------- + + /* Radix-8 iteration subroutine */ + template + void R8TX(int nxtlt, int nthpo, int length, const std::complex* cs, + std::complex *cc0, std::complex *cc1, std::complex *cc2, std::complex *cc3, + std::complex *cc4, std::complex *cc5, std::complex *cc6, std::complex *cc7) + { + const T irt2 = 0.707106781186548; /* 1.0/sqrt(2.0) */ + + for(int j=0; j a0, a1, a2, a3, a4, a5, a6, a7; + std::complex b0, b1, b2, b3, b4, b5, b6, b7; + a0 = cc0[k] + cc4[k]; + a1 = cc1[k] + cc5[k]; + a2 = cc2[k] + cc6[k]; + a3 = cc3[k] + cc7[k]; + a4 = cc0[k] - cc4[k]; + a5 = cc1[k] - cc5[k]; + a6 = cc2[k] - cc6[k]; + a7 = cc3[k] - cc7[k]; + + b0 = a0 + a2; + b1 = a1 + a3; + b2 = a0 - a2; + b3 = a1 - a3; + + b4 = std::complex(a4.real()-a6.imag(), a4.imag()+a6.real()); + b5 = std::complex(a5.real()-a7.imag(), a5.imag()+a7.real()); + b6 = std::complex(a4.real()+a6.imag(), a4.imag()-a6.real()); + b7 = std::complex(a5.real()+a7.imag(), a5.imag()-a7.real()); + + const std::complex tmp0(-b3.imag(), b3.real()); + const std::complex tmp1(irt2*(b5.real()-b5.imag()), irt2*(b5.real()+b5.imag())); + const std::complex tmp2(-irt2*(b7.real()+b7.imag()), irt2*(b7.real()-b7.imag())); + + cc0[k] = b0 + b1; + cc1[k] = b0 - b1; + cc2[k] = b2 + tmp0; + cc3[k] = b2 - tmp0; + cc4[k] = b4 + tmp1; + cc5[k] = b4 - tmp1; + cc6[k] = b6 + tmp2; + cc7[k] = b6 - tmp2; + if(j>0) + { + cc1[k] *= cs[3]; + cc2[k] *= cs[1]; + cc3[k] *= cs[5]; + cc4[k] *= cs[0]; + cc5[k] *= cs[4]; + cc6[k] *= cs[2]; + cc7[k] *= cs[6]; + } + } + + cs += 7; + } + } + + // ------------------------------------------------------------------------------------ + + template + void fft1d_inplace(matrix,NR,NC,MM,layout>& data, bool do_backward_fft, twiddles& cs) + /*! + requires + - is_vector(data) == true + - is_power_of_two(data.size()) == true + ensures + - This routine replaces the input std::complex vector by its finite + discrete complex fourier transform if do_backward_fft==true. It replaces + the input std::complex vector by its finite discrete complex + inverse fourier transform if do_backward_fft==false. + + The implementation is a radix-2 FFT, but with faster shortcuts for + radix-4 and radix-8. It performs as many radix-8 iterations as possible, + and then finishes with a radix-2 or -4 iteration if needed. + !*/ + { + COMPILE_TIME_ASSERT((is_same_type::value || is_same_type::value || is_same_type::value )); + + if (data.size() == 0) + return; + + std::complex* const b = &data(0); + int L[16],L1,L2,L3,L4,L5,L6,L7,L8,L9,L10,L11,L12,L13,L14,L15; + int j1,j2,j3,j4,j5,j6,j7,j8,j9,j10,j11,j12,j13,j14; + int j, ij, ji; + int n2pow, n8pow, nthpo, ipass, nxtlt, length; + + n2pow = fastlog2(data.size()); + nthpo = data.size(); + + n8pow = n2pow/3; + + if(n8pow) + { + /* Radix 8 iterations */ + for(ipass=1;ipass<=n8pow;ipass++) + { + const int p = n2pow - 3*ipass; + nxtlt = 0x1 << p; + length = 8*nxtlt; + R8TX(nxtlt, nthpo, length, cs.get_twiddles(p), + b, b+nxtlt, b+2*nxtlt, b+3*nxtlt, + b+4*nxtlt, b+5*nxtlt, b+6*nxtlt, b+7*nxtlt); + } + } + + if(n2pow%3 == 1) + { + /* A final radix 2 iteration is needed */ + R2TX(nthpo, b, b+1); + } + + if(n2pow%3 == 2) + { + /* A final radix 4 iteration is needed */ + R4TX(nthpo, b, b+1, b+2, b+3); + } + + for(j=1;j<=15;j++) + { + L[j] = 1; + if(j-n2pow <= 0) L[j] = 0x1 << (n2pow + 1 - j); + } + + L15=L[1];L14=L[2];L13=L[3];L12=L[4];L11=L[5];L10=L[6];L9=L[7]; + L8=L[8];L7=L[9];L6=L[10];L5=L[11];L4=L[12];L3=L[13];L2=L[14];L1=L[15]; + + ij = 0; + + for(j1=0;j1 + void fft2d_inplace( + matrix,NR,NC,MM,L>& data, + bool do_backward_fft + ) + { + if (data.size() == 0) + return; + + matrix > buff; + twiddles cs; + + // Compute transform row by row + for(long r=0; r >(rowm(data,r)); + fft1d_inplace(buff, do_backward_fft, cs); + set_rowm(data,r) = matrix_cast >(buff); + } + + // Compute transform column by column + for(long c=0; c >(colm(data,c)); + fft1d_inplace(buff, do_backward_fft, cs); + set_colm(data,c) = matrix_cast >(buff); + } + } + + // ---------------------------------------------------------------------------------------- + + template < + typename EXP, + typename T + > + void fft2d( + const matrix_exp& data, + matrix >& data_out, + bool do_backward_fft + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(is_power_of_two(data.nr()) && is_power_of_two(data.nc()), + "\t matrix fft(data)" + << "\n\t The number of rows and columns must be powers of two." + << "\n\t data.nr(): "<< data.nr() + << "\n\t data.nc(): "<< data.nc() + << "\n\t is_power_of_two(data.nr()): " << is_power_of_two(data.nr()) + << "\n\t is_power_of_two(data.nc()): " << is_power_of_two(data.nc()) + ); + + if (data.size() == 0) + return; + + matrix > buff; + data_out.set_size(data.nr(), data.nc()); + twiddles cs; + + // Compute transform row by row + for(long r=0; r >(rowm(data,r)); + fft1d_inplace(buff, do_backward_fft, cs); + set_rowm(data_out,r) = matrix_cast >(buff); + } + + // Compute transform column by column + for(long c=0; c >(colm(data_out,c)); + fft1d_inplace(buff, do_backward_fft, cs); + set_colm(data_out,c) = matrix_cast >(buff); + } + } + + // ------------------------------------------------------------------------------------ + + } // end namespace impl // ---------------------------------------------------------------------------------------- template - typename EXP::matrix_type ifft ( - const matrix_exp& data - ) + matrix fft (const matrix_exp& data) { - if (data.size() == 0) - return data; - // You have to give a complex matrix COMPILE_TIME_ASSERT(is_complex::value); // make sure requires clause is not broken - DLIB_CASSERT(is_vector(data) && is_power_of_two(data.size()), - "\t void ifft(data)" - << "\n\t data must be a vector with a size that is a power of two." - << "\n\t is_vector(data): " << is_vector(data) - << "\n\t data.size(): " << data.size() + DLIB_CASSERT(is_power_of_two(data.nr()) && is_power_of_two(data.nc()), + "\t matrix fft(data)" + << "\n\t The number of rows and columns must be powers of two." + << "\n\t data.nr(): "<< data.nr() + << "\n\t data.nc(): "<< data.nc() + << "\n\t is_power_of_two(data.nr()): " << is_power_of_two(data.nr()) + << "\n\t is_power_of_two(data.nc()): " << is_power_of_two(data.nc()) ); - - typedef typename EXP::type::value_type T; - - typename EXP::matrix_type outdata; - impl::permute(data,outdata); - - const long half = outdata.size()/2; - - typedef std::complex ct; - matrix twiddle_factors(half); - - // compute the complex root of unity w - const T temp = 2.0*pi/outdata.size(); - ct w = ct(std::cos(temp),std::sin(temp)); - - ct w_pow = 1; - - // compute the twiddle factors - for (long j = 0; j < twiddle_factors.size(); ++j) + if (data.nr() == 1 || data.nc() == 1) { - twiddle_factors(j) = w_pow; - w_pow *= w; + matrix temp(data); + impl::twiddles cs; + impl::fft1d_inplace(temp, false, cs); + return temp; } - - // now compute the inverse decimation in frequency. This first - // outer loop loops log2(outdata.size()) number of times - long skip = half; - for (long step = 1; step <= half; step <<= 1) + else { - // do blocks of butterflies in this loop - for (long j = 0; j < outdata.size(); j += step*2) - { - // do step butterflies - for (long k = 0; k < step; ++k) - { - const long a_idx = j+k; - const long b_idx = j+k+step; - outdata(b_idx) *= twiddle_factors(k*skip); - const ct a = outdata(a_idx) + outdata(b_idx); - const ct b = outdata(a_idx) - outdata(b_idx); - outdata(a_idx) = a; - outdata(b_idx) = b; - } - } - skip /= 2; + matrix temp; + impl::fft2d(data, temp, false); + return temp; } + } - outdata /= outdata.size(); - return outdata; + template + matrix ifft (const matrix_exp& data) + { + // You have to give a complex matrix + COMPILE_TIME_ASSERT(is_complex::value); + // make sure requires clause is not broken + DLIB_CASSERT(is_power_of_two(data.nr()) && is_power_of_two(data.nc()), + "\t matrix ifft(data)" + << "\n\t The number of rows and columns must be powers of two." + << "\n\t data.nr(): "<< data.nr() + << "\n\t data.nc(): "<< data.nc() + << "\n\t is_power_of_two(data.nr()): " << is_power_of_two(data.nr()) + << "\n\t is_power_of_two(data.nc()): " << is_power_of_two(data.nc()) + ); + + matrix temp; + if (data.size() == 0) + return temp; + + if (data.nr() == 1 || data.nc() == 1) + { + temp = data; + impl::twiddles cs; + impl::fft1d_inplace(temp, true, cs); + } + else + { + impl::fft2d(data, temp, true); + } + temp /= data.size(); + return temp; } // ---------------------------------------------------------------------------------------- + template < typename T, long NR, long NC, typename MM, typename L > + typename enable_if_c::type fft_inplace (matrix,NR,NC,MM,L>& data) + // Note that we don't divide the outputs by data.size() so this isn't quite the inverse. + { + // make sure requires clause is not broken + DLIB_CASSERT(is_power_of_two(data.nr()) && is_power_of_two(data.nc()), + "\t void fft_inplace(data)" + << "\n\t The number of rows and columns must be powers of two." + << "\n\t data.nr(): "<< data.nr() + << "\n\t data.nc(): "<< data.nc() + << "\n\t is_power_of_two(data.nr()): " << is_power_of_two(data.nr()) + << "\n\t is_power_of_two(data.nc()): " << is_power_of_two(data.nc()) + ); + + impl::twiddles cs; + impl::fft1d_inplace(data, false, cs); + } + + template < typename T, long NR, long NC, typename MM, typename L > + typename disable_if_c::type fft_inplace (matrix,NR,NC,MM,L>& data) + // Note that we don't divide the outputs by data.size() so this isn't quite the inverse. + { + // make sure requires clause is not broken + DLIB_CASSERT(is_power_of_two(data.nr()) && is_power_of_two(data.nc()), + "\t void fft_inplace(data)" + << "\n\t The number of rows and columns must be powers of two." + << "\n\t data.nr(): "<< data.nr() + << "\n\t data.nc(): "<< data.nc() + << "\n\t is_power_of_two(data.nr()): " << is_power_of_two(data.nr()) + << "\n\t is_power_of_two(data.nc()): " << is_power_of_two(data.nc()) + ); + + impl::fft2d_inplace(data, false); + } + +// ---------------------------------------------------------------------------------------- + + template < typename T, long NR, long NC, typename MM, typename L > + typename enable_if_c::type ifft_inplace (matrix,NR,NC,MM,L>& data) + { + // make sure requires clause is not broken + DLIB_CASSERT(is_power_of_two(data.nr()) && is_power_of_two(data.nc()), + "\t void ifft_inplace(data)" + << "\n\t The number of rows and columns must be powers of two." + << "\n\t data.nr(): "<< data.nr() + << "\n\t data.nc(): "<< data.nc() + << "\n\t is_power_of_two(data.nr()): " << is_power_of_two(data.nr()) + << "\n\t is_power_of_two(data.nc()): " << is_power_of_two(data.nc()) + ); + + impl::twiddles cs; + impl::fft1d_inplace(data, true, cs); + } + + template < typename T, long NR, long NC, typename MM, typename L > + typename disable_if_c::type ifft_inplace (matrix,NR,NC,MM,L>& data) + { + // make sure requires clause is not broken + DLIB_CASSERT(is_power_of_two(data.nr()) && is_power_of_two(data.nc()), + "\t void ifft_inplace(data)" + << "\n\t The number of rows and columns must be powers of two." + << "\n\t data.nr(): "<< data.nr() + << "\n\t data.nc(): "<< data.nc() + << "\n\t is_power_of_two(data.nr()): " << is_power_of_two(data.nr()) + << "\n\t is_power_of_two(data.nc()): " << is_power_of_two(data.nc()) + ); + + impl::fft2d_inplace(data, true); + } + +// ---------------------------------------------------------------------------------------- + + /* + I'm disabling any use of the FFTW bindings because FFTW is, as of this writing, not + threadsafe as a library. This means that if multiple threads were to make + concurrent calls to these fft routines then the program could crash. If at some + point FFTW is fixed I'll turn these bindings back on. + + See https://github.com/FFTW/fftw3/issues/16 + */ +#if 0 #ifdef DLIB_USE_FFTW template @@ -216,19 +560,27 @@ namespace dlib ) { // make sure requires clause is not broken - DLIB_CASSERT(is_vector(data) && is_power_of_two(data.size()), - "\t void fft(data)" - << "\n\t data must be a vector with a size that is a power of two." - << "\n\t is_vector(data): " << is_vector(data) - << "\n\t data.size(): " << data.size() + DLIB_CASSERT(is_power_of_two(data.nr()) && is_power_of_two(data.nc()), + "\t matrix fft(data)" + << "\n\t The number of rows and columns must be powers of two." + << "\n\t data.nr(): "<< data.nr() + << "\n\t data.nc(): "<< data.nc() + << "\n\t is_power_of_two(data.nr()): " << is_power_of_two(data.nr()) + << "\n\t is_power_of_two(data.nc()): " << is_power_of_two(data.nc()) ); + if (data.size() == 0) + return data; + matrix,NR,NC,MM,L> m2(data.nr(),data.nc()); fftw_complex *in, *out; fftw_plan p; - in = (fftw_complex*)&data(0); - out = (fftw_complex*)&m2(0); - p = fftw_plan_dft_1d(data.size(), in, out, FFTW_FORWARD, FFTW_ESTIMATE); + in = (fftw_complex*)&data(0,0); + out = (fftw_complex*)&m2(0,0); + if (data.nr() == 1 || data.nc() == 1) + p = fftw_plan_dft_1d(data.size(), in, out, FFTW_FORWARD, FFTW_ESTIMATE); + else + p = fftw_plan_dft_2d(data.nr(), data.nc(), in, out, FFTW_FORWARD, FFTW_ESTIMATE); fftw_execute(p); fftw_destroy_plan(p); return m2; @@ -240,38 +592,254 @@ namespace dlib ) { // make sure requires clause is not broken - DLIB_CASSERT(is_vector(data) && is_power_of_two(data.size()), - "\t void ifft(data)" - << "\n\t data must be a vector with a size that is a power of two." - << "\n\t is_vector(data): " << is_vector(data) - << "\n\t data.size(): " << data.size() + DLIB_CASSERT(is_power_of_two(data.nr()) && is_power_of_two(data.nc()), + "\t matrix ifft(data)" + << "\n\t The number of rows and columns must be powers of two." + << "\n\t data.nr(): "<< data.nr() + << "\n\t data.nc(): "<< data.nc() + << "\n\t is_power_of_two(data.nr()): " << is_power_of_two(data.nr()) + << "\n\t is_power_of_two(data.nc()): " << is_power_of_two(data.nc()) ); + if (data.size() == 0) + return data; + matrix,NR,NC,MM,L> m2(data.nr(),data.nc()); fftw_complex *in, *out; fftw_plan p; - in = (fftw_complex*)&data(0); - out = (fftw_complex*)&m2(0); - p = fftw_plan_dft_1d(data.size(), in, out, FFTW_BACKWARD, FFTW_ESTIMATE); + in = (fftw_complex*)&data(0,0); + out = (fftw_complex*)&m2(0,0); + if (data.nr() == 1 || data.nc() == 1) + p = fftw_plan_dft_1d(data.size(), in, out, FFTW_BACKWARD, FFTW_ESTIMATE); + else + p = fftw_plan_dft_2d(data.nr(), data.nc(), in, out, FFTW_BACKWARD, FFTW_ESTIMATE); fftw_execute(p); fftw_destroy_plan(p); - return m2/data.size(); + return m2; } // ---------------------------------------------------------------------------------------- // call FFTW for these cases: inline matrix,0,1> fft (const matrix,0,1>& data) {return call_fftw_fft(data);} - inline matrix,0,1> ifft(const matrix,0,1>& data) {return call_fftw_ifft(data);} + inline matrix,0,1> ifft(const matrix,0,1>& data) {return call_fftw_ifft(data)/data.size();} inline matrix,1,0> fft (const matrix,1,0>& data) {return call_fftw_fft(data);} - inline matrix,1,0> ifft(const matrix,1,0>& data) {return call_fftw_ifft(data);} + inline matrix,1,0> ifft(const matrix,1,0>& data) {return call_fftw_ifft(data)/data.size();} inline matrix > fft (const matrix >& data) {return call_fftw_fft(data);} - inline matrix > ifft(const matrix >& data) {return call_fftw_ifft(data);} + inline matrix > ifft(const matrix >& data) {return call_fftw_ifft(data)/data.size();} + + inline void fft_inplace (matrix,0,1>& data) {data = call_fftw_fft(data);} + inline void ifft_inplace(matrix,0,1>& data) {data = call_fftw_ifft(data);} + inline void fft_inplace (matrix,1,0>& data) {data = call_fftw_fft(data);} + inline void ifft_inplace(matrix,1,0>& data) {data = call_fftw_ifft(data);} + inline void fft_inplace (matrix >& data) {data = call_fftw_fft(data);} + inline void ifft_inplace(matrix >& data) {data = call_fftw_ifft(data);} #endif // DLIB_USE_FFTW +#endif // end of #if 0 // ---------------------------------------------------------------------------------------- +#ifdef DLIB_USE_MKL_FFT + +#define DLIB_DFTI_CHECK_STATUS(s) \ + if((s) != 0 && !DftiErrorClass((s), DFTI_NO_ERROR)) \ + { \ + throw dlib::error(DftiErrorMessage((s))); \ + } + + template < long NR, long NC, typename MM, typename L > + matrix,NR,NC,MM,L> call_mkl_fft( + const matrix,NR,NC,MM,L>& data, + bool do_backward_fft) + { + // make sure requires clause is not broken + DLIB_CASSERT(is_power_of_two(data.nr()) && is_power_of_two(data.nc()), + "\t matrix fft(data)" + << "\n\t The number of rows and columns must be powers of two." + << "\n\t data.nr(): "<< data.nr() + << "\n\t data.nc(): "<< data.nc() + << "\n\t is_power_of_two(data.nr()): " << is_power_of_two(data.nr()) + << "\n\t is_power_of_two(data.nc()): " << is_power_of_two(data.nc()) + ); + + if (data.size() == 0) + return data; + + DFTI_DESCRIPTOR_HANDLE h; + MKL_LONG status; + + if (data.nr() == 1 || data.nc() == 1) + { + status = DftiCreateDescriptor(&h, DFTI_DOUBLE, DFTI_COMPLEX, 1, data.size()); + DLIB_DFTI_CHECK_STATUS(status); + } + else + { + MKL_LONG size[2]; + size[0] = data.nr(); + size[1] = data.nc(); + + status = DftiCreateDescriptor(&h, DFTI_DOUBLE, DFTI_COMPLEX, 2, size); + DLIB_DFTI_CHECK_STATUS(status); + + MKL_LONG strides[3]; + strides[0] = 0; + strides[1] = size[1]; + strides[2] = 1; + + status = DftiSetValue(h, DFTI_INPUT_STRIDES, strides); + DLIB_DFTI_CHECK_STATUS(status); + status = DftiSetValue(h, DFTI_OUTPUT_STRIDES, strides); + DLIB_DFTI_CHECK_STATUS(status); + } + + status = DftiSetValue(h, DFTI_PLACEMENT, DFTI_NOT_INPLACE); + DLIB_DFTI_CHECK_STATUS(status); + + // Unless we use sequential mode, the fft results are not correct. + status = DftiSetValue(h, DFTI_THREAD_LIMIT, 1); + DLIB_DFTI_CHECK_STATUS(status); + + status = DftiCommitDescriptor(h); + DLIB_DFTI_CHECK_STATUS(status); + + matrix,NR,NC,MM,L> out(data.nr(), data.nc()); + + if (do_backward_fft) + status = DftiComputeBackward(h, (void *)(&data(0, 0)), &out(0,0)); + else + status = DftiComputeForward(h, (void *)(&data(0, 0)), &out(0,0)); + DLIB_DFTI_CHECK_STATUS(status); + + status = DftiFreeDescriptor(&h); + DLIB_DFTI_CHECK_STATUS(status); + + return out; + } + + template < long NR, long NC, typename MM, typename L > + void call_mkl_fft_inplace( + matrix,NR,NC,MM,L>& data, + bool do_backward_fft + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(is_power_of_two(data.nr()) && is_power_of_two(data.nc()), + "\t void ifft_inplace(data)" + << "\n\t The number of rows and columns must be powers of two." + << "\n\t data.nr(): "<< data.nr() + << "\n\t data.nc(): "<< data.nc() + << "\n\t is_power_of_two(data.nr()): " << is_power_of_two(data.nr()) + << "\n\t is_power_of_two(data.nc()): " << is_power_of_two(data.nc()) + ); + + if (data.size() == 0) + return; + + DFTI_DESCRIPTOR_HANDLE h; + MKL_LONG status; + + if (data.nr() == 1 || data.nc() == 1) + { + status = DftiCreateDescriptor(&h, DFTI_DOUBLE, DFTI_COMPLEX, 1, data.size()); + DLIB_DFTI_CHECK_STATUS(status); + } + else + { + MKL_LONG size[2]; + size[0] = data.nr(); + size[1] = data.nc(); + + status = DftiCreateDescriptor(&h, DFTI_DOUBLE, DFTI_COMPLEX, 2, size); + DLIB_DFTI_CHECK_STATUS(status); + + MKL_LONG strides[3]; + strides[0] = 0; + strides[1] = size[1]; + strides[2] = 1; + + status = DftiSetValue(h, DFTI_INPUT_STRIDES, strides); + DLIB_DFTI_CHECK_STATUS(status); + } + + // Unless we use sequential mode, the fft results are not correct. + status = DftiSetValue(h, DFTI_THREAD_LIMIT, 1); + DLIB_DFTI_CHECK_STATUS(status); + + status = DftiCommitDescriptor(h); + DLIB_DFTI_CHECK_STATUS(status); + + if (do_backward_fft) + status = DftiComputeBackward(h, &data(0, 0)); + else + status = DftiComputeForward(h, &data(0, 0)); + DLIB_DFTI_CHECK_STATUS(status); + + status = DftiFreeDescriptor(&h); + DLIB_DFTI_CHECK_STATUS(status); + + return; + } + +// ---------------------------------------------------------------------------------------- + + // Call the MKL DFTI implementation in these cases + + inline matrix,0,1> fft (const matrix,0,1>& data) + { + return call_mkl_fft(data, false); + } + inline matrix,0,1> ifft(const matrix,0,1>& data) + { + return call_mkl_fft(data, true) / data.size(); + } + inline matrix,1,0> fft (const matrix,1,0>& data) + { + return call_mkl_fft(data, false); + } + inline matrix,1,0> ifft(const matrix,1,0>& data) + { + return call_mkl_fft(data, true) / data.size(); + } + inline matrix > fft (const matrix >& data) + { + return call_mkl_fft(data, false); + } + inline matrix > ifft(const matrix >& data) + { + return call_mkl_fft(data, true) / data.size(); + } + + inline void fft_inplace (matrix,0,1>& data) + { + call_mkl_fft_inplace(data, false); + } + inline void ifft_inplace(matrix,0,1>& data) + { + call_mkl_fft_inplace(data, true); + } + inline void fft_inplace (matrix,1,0>& data) + { + call_mkl_fft_inplace(data, false); + } + inline void ifft_inplace(matrix,1,0>& data) + { + call_mkl_fft_inplace(data, true); + } + + inline void fft_inplace (matrix >& data) + { + call_mkl_fft_inplace(data, false); + } + inline void ifft_inplace(matrix >& data) + { + call_mkl_fft_inplace(data, true); + } + +#endif // DLIB_USE_MKL_FFT + +// ---------------------------------------------------------------------------------------- } #endif // DLIB_FFt_Hh_ diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_fft_abstract.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_fft_abstract.h index d6b95da2..25cdfcae 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_fft_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_fft_abstract.h @@ -28,22 +28,18 @@ namespace dlib ); /*! requires - - data contains elements of type std::complex<> - - is_vector(data) == true - - is_power_of_two(data.size()) == true + - data contains elements of type std::complex<> that itself contains double, float, or long double. + - is_power_of_two(data.nr()) == true + - is_power_of_two(data.nc()) == true ensures - - Computes the discrete Fourier transform of the given data vector and - returns it. In particular, we return a matrix D such that: + - Computes the 1 or 2 dimensional discrete Fourier transform of the given data + matrix and returns it. In particular, we return a matrix D such that: - D.nr() == data.nr() - D.nc() == data.nc() - - D(0) == the DC term of the Fourier transform. - - starting with D(0), D contains progressively higher frequency components + - D(0,0) == the DC term of the Fourier transform. + - starting with D(0,0), D contains progressively higher frequency components of the input data. - ifft(D) == D - - if DLIB_USE_FFTW is #defined then this function will use the very fast fftw - library when given double precision matrices instead of dlib's default fft - implementation. Note that you must also link to the fftw3 library to use - this feature. !*/ // ---------------------------------------------------------------------------------------- @@ -54,19 +50,64 @@ namespace dlib ); /*! requires - - data contains elements of type std::complex<> - - is_vector(data) == true - - is_power_of_two(data.size()) == true + - data contains elements of type std::complex<> that itself contains double, float, or long double. + - is_power_of_two(data.nr()) == true + - is_power_of_two(data.nc()) == true ensures - - Computes the inverse discrete Fourier transform of the given data vector and - returns it. In particular, we return a matrix D such that: + - Computes the 1 or 2 dimensional inverse discrete Fourier transform of the + given data vector and returns it. In particular, we return a matrix D such + that: - D.nr() == data.nr() - D.nc() == data.nc() - fft(D) == data - - if DLIB_USE_FFTW is #defined then this function will use the very fast fftw - library when given double precision matrices instead of dlib's default fft - implementation. Note that you must also link to the fftw3 library to use - this feature. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long NR, + long NC, + typename MM, + typename L + > + void fft_inplace ( + matrix,NR,NC,MM,L>& data + ); + /*! + requires + - data contains elements of type std::complex<> that itself contains double, float, or long double. + - is_power_of_two(data.nr()) == true + - is_power_of_two(data.nc()) == true + ensures + - This function is identical to fft() except that it does the FFT in-place. + That is, after this function executes we will have: + - #data == fft(data) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long NR, + long NC, + typename MM, + typename L + > + void ifft_inplace ( + matrix,NR,NC,MM,L>& data + ); + /*! + requires + - data contains elements of type std::complex<> that itself contains double, float, or long double. + - is_power_of_two(data.nr()) == true + - is_power_of_two(data.nc()) == true + ensures + - This function is identical to ifft() except that it does the inverse FFT + in-place. That is, after this function executes we will have: + - #data == ifft(data)*data.size() + - Note that the output needs to be divided by data.size() to complete the + inverse transformation. !*/ // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_generic_image.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_generic_image.h index a0a25091..0455af20 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_generic_image.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_generic_image.h @@ -19,6 +19,17 @@ namespace dlib typedef T pixel_type; }; + template < + typename T, + long NR, + long NC, + typename MM + > + struct image_traits > + { + typedef T pixel_type; + }; + template < typename T, long NR, diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_la.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_la.h index daab0cb9..35b5b42e 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_la.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_la.h @@ -6,6 +6,7 @@ #include "matrix_la_abstract.h" #include "matrix_utilities.h" #include "../sparse_vector.h" +#include "../optimization/optimization_line_search.h" // The 4 decomposition objects described in the matrix_la_abstract.h file are // actually implemented in the following 4 files. @@ -16,10 +17,15 @@ #ifdef DLIB_USE_LAPACK #include "lapack/potrf.h" +#include "lapack/pbtrf.h" #include "lapack/gesdd.h" #include "lapack/gesvd.h" #endif +#include "../threads.h" + +#include + namespace dlib { @@ -27,398 +33,30 @@ namespace dlib // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- - namespace nric + enum svd_u_mode { - // This namespace contains stuff adapted from the algorithms - // described in the book Numerical Recipes in C - - template - inline T pythag(const T& a, const T& b) - { - T absa,absb; - absa=std::abs(a); - absb=std::abs(b); - if (absa > absb) - { - T val = absb/absa; - val *= val; - return absa*std::sqrt(1.0+val); - } - else - { - if (absb == 0.0) - { - return 0.0; - } - else - { - T val = absa/absb; - val *= val; - return absb*std::sqrt(1.0+val); - } - } - } - - template - inline T sign(const T& a, const T& b) - { - if (b < 0) - { - return -std::abs(a); - } - else - { - return std::abs(a); - } - } - - - template < - typename T, - long M, long N, - long wN, long wX, - long vN, - long rN, long rX, - typename MM1, - typename MM2, - typename MM3, - typename MM4, - typename L1, - typename L2, - typename L3, - typename L4 - > - bool svdcmp( - matrix& a, - matrix& w, - matrix& v, - matrix& rv1 - ) - /*! ( this function is derived from the one in numerical recipes in C chapter 2.6) - requires - - w.nr() == a.nc() - - w.nc() == 1 - - v.nr() == a.nc() - - v.nc() == a.nc() - - rv1.nr() == a.nc() - - rv1.nc() == 1 - ensures - - computes the singular value decomposition of a - - let W be the matrix such that diag(W) == #w then: - - a == #a*W*trans(#v) - - trans(#a)*#a == identity matrix - - trans(#v)*#v == identity matrix - - #rv1 == some undefined value - - returns true for success and false for failure - !*/ - { - - DLIB_ASSERT( - w.nr() == a.nc() && - w.nc() == 1 && - v.nr() == a.nc() && - v.nc() == a.nc() && - rv1.nr() == a.nc() && - rv1.nc() == 1, ""); - - COMPILE_TIME_ASSERT(wX == 0 || wX == 1); - COMPILE_TIME_ASSERT(rX == 0 || rX == 1); - - const T one = 1.0; - const long max_iter = 300; - const long n = a.nc(); - const long m = a.nr(); - const T eps = std::numeric_limits::epsilon(); - long nm = 0, l = 0; - bool flag; - T anorm,c,f,g,h,s,scale,x,y,z; - g = 0.0; - scale = 0.0; - anorm = 0.0; - - for (long i = 0; i < n; ++i) - { - l = i+1; - rv1(i) = scale*g; - g = s = scale = 0.0; - if (i < m) - { - for (long k = i; k < m; ++k) - scale += std::abs(a(k,i)); - - if (scale) - { - for (long k = i; k < m; ++k) - { - a(k,i) /= scale; - s += a(k,i)*a(k,i); - } - f = a(i,i); - g = -sign(std::sqrt(s),f); - h = f*g - s; - a(i,i) = f - g; - for (long j = l; j < n; ++j) - { - s = 0.0; - for (long k = i; k < m; ++k) - s += a(k,i)*a(k,j); - - f = s/h; - - for (long k = i; k < m; ++k) - a(k,j) += f*a(k,i); - } - for (long k = i; k < m; ++k) - a(k,i) *= scale; - } - } - - w(i) = scale *g; - - g=s=scale=0.0; - - if (i < m && i < n-1) - { - for (long k = l; k < n; ++k) - scale += std::abs(a(i,k)); - - if (scale) - { - for (long k = l; k < n; ++k) - { - a(i,k) /= scale; - s += a(i,k)*a(i,k); - } - f = a(i,l); - g = -sign(std::sqrt(s),f); - h = f*g - s; - a(i,l) = f - g; - - for (long k = l; k < n; ++k) - rv1(k) = a(i,k)/h; - - for (long j = l; j < m; ++j) - { - s = 0.0; - for (long k = l; k < n; ++k) - s += a(j,k)*a(i,k); - - for (long k = l; k < n; ++k) - a(j,k) += s*rv1(k); - } - for (long k = l; k < n; ++k) - a(i,k) *= scale; - } - } - anorm = std::max(anorm,(std::abs(w(i))+std::abs(rv1(i)))); - } - for (long i = n-1; i >= 0; --i) - { - if (i < n-1) - { - if (g != 0) - { - for (long j = l; j < n ; ++j) - v(j,i) = (a(i,j)/a(i,l))/g; - - for (long j = l; j < n; ++j) - { - s = 0.0; - for (long k = l; k < n; ++k) - s += a(i,k)*v(k,j); - - for (long k = l; k < n; ++k) - v(k,j) += s*v(k,i); - } - } - - for (long j = l; j < n; ++j) - v(i,j) = v(j,i) = 0.0; - } - - v(i,i) = 1.0; - g = rv1(i); - l = i; - } - - for (long i = std::min(m,n)-1; i >= 0; --i) - { - l = i + 1; - g = w(i); - - for (long j = l; j < n; ++j) - a(i,j) = 0.0; - - if (g != 0) - { - g = 1.0/g; - - for (long j = l; j < n; ++j) - { - s = 0.0; - for (long k = l; k < m; ++k) - s += a(k,i)*a(k,j); - - f=(s/a(i,i))*g; - - for (long k = i; k < m; ++k) - a(k,j) += f*a(k,i); - } - for (long j = i; j < m; ++j) - a(j,i) *= g; - } - else - { - for (long j = i; j < m; ++j) - a(j,i) = 0.0; - } - - ++a(i,i); - } - - for (long k = n-1; k >= 0; --k) - { - for (long its = 1; its <= max_iter; ++its) - { - flag = true; - for (l = k; l >= 1; --l) - { - nm = l - 1; - if (std::abs(rv1(l)) <= eps*anorm) - { - flag = false; - break; - } - if (std::abs(w(nm)) <= eps*anorm) - { - break; - } - } - - if (flag) - { - c = 0.0; - s = 1.0; - for (long i = l; i <= k; ++i) - { - f = s*rv1(i); - rv1(i) = c*rv1(i); - if (std::abs(f) <= eps*anorm) - break; - - g = w(i); - h = pythag(f,g); - w(i) = h; - h = 1.0/h; - c = g*h; - s = -f*h; - for (long j = 0; j < m; ++j) - { - y = a(j,nm); - z = a(j,i); - a(j,nm) = y*c + z*s; - a(j,i) = z*c - y*s; - } - } - } - - z = w(k); - if (l == k) - { - if (z < 0.0) - { - w(k) = -z; - for (long j = 0; j < n; ++j) - v(j,k) = -v(j,k); - } - break; - } - - if (its == max_iter) - return false; - - x = w(l); - nm = k - 1; - y = w(nm); - g = rv1(nm); - h = rv1(k); - f = ((y-z)*(y+z) + (g-h)*(g+h))/(2.0*h*y); - g = pythag(f,one); - f = ((x-z)*(x+z) + h*((y/(f+sign(g,f)))-h))/x; - c = s = 1.0; - for (long j = l; j <= nm; ++j) - { - long i = j + 1; - g = rv1(i); - y = w(i); - h = s*g; - g = c*g; - z = pythag(f,h); - rv1(j) = z; - c = f/z; - s = h/z; - f = x*c + g*s; - g = g*c - x*s; - h = y*s; - y *= c; - for (long jj = 0; jj < n; ++jj) - { - x = v(jj,j); - z = v(jj,i); - v(jj,j) = x*c + z*s; - v(jj,i) = z*c - x*s; - } - z = pythag(f,h); - w(j) = z; - if (z != 0) - { - z = 1.0/z; - c = f*z; - s = h*z; - } - f = c*g + s*y; - x = c*y - s*g; - for (long jj = 0; jj < m; ++jj) - { - y = a(jj,j); - z = a(jj,i); - a(jj,j) = y*c + z*s; - a(jj,i) = z*c - y*s; - } - } - rv1(l) = 0.0; - rv1(k) = f; - w(k) = x; - } - } - return true; - } - - // ------------------------------------------------------------------------------------ - - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- + SVD_NO_U, + SVD_SKINNY_U, + SVD_FULL_U + }; template < typename EXP, long qN, long qX, - long uM, - long vN, + long uM, long uN, + long vM, long vN, typename MM1, typename MM2, typename MM3, typename L1 > - long svd2 ( - bool withu, + long svd4 ( + svd_u_mode u_mode, bool withv, const matrix_exp& a, - matrix& u, + matrix& u, matrix& q, - matrix& v + matrix& v ) { /* @@ -443,20 +81,13 @@ namespace dlib and v an n x n orthogonal matrix. eps and tol are tolerance constants. Suitable values are eps=1e-16 and tol=(1e-300)/eps if T == double. - If withu == false then u won't be computed and similarly if withv == false - then v won't be computed. + If u_mode == SVD_NO_U then u won't be computed and similarly if withv == false + then v won't be computed. If u_mode == SVD_SKINNY_U then u will be m x n instead of m x m. */ - const long NR = matrix_exp::NR; - const long NC = matrix_exp::NC; - - // make sure the output matrices have valid dimensions if they are statically dimensioned - COMPILE_TIME_ASSERT(qX == 0 || qX == 1); - COMPILE_TIME_ASSERT(NR == 0 || uM == 0 || NR == uM); - COMPILE_TIME_ASSERT(NC == 0 || vN == 0 || NC == vN); DLIB_ASSERT(a.nr() >= a.nc(), - "\tconst matrix_exp svd2()" + "\tconst matrix_exp svd4()" << "\n\tYou have given an invalidly sized matrix" << "\n\ta.nr(): " << a.nr() << "\n\ta.nc(): " << a.nc() @@ -466,30 +97,33 @@ namespace dlib typedef typename EXP::type T; #ifdef DLIB_USE_LAPACK - matrix temp(a); + matrix temp(a), vtemp; char jobu = 'A'; char jobvt = 'A'; - if (withu == false) + if (u_mode == SVD_NO_U) jobu = 'N'; + else if (u_mode == SVD_SKINNY_U) + jobu = 'S'; if (withv == false) jobvt = 'N'; int info; - if (withu == withv) + if (jobu == jobvt) { - info = lapack::gesdd(jobu, temp, q, u, v); + info = lapack::gesdd(jobu, temp, q, u, vtemp); } else { - info = lapack::gesvd(jobu, jobvt, temp, q, u, v); + info = lapack::gesvd(jobu, jobvt, temp, q, u, vtemp); } // pad q with zeros if it isn't the length we want if (q.nr() < a.nc()) q = join_cols(q, zeros_matrix(a.nc()-q.nr(),1)); - v = trans(v); + if (withv) + v = trans(vtemp); return info; #else @@ -506,7 +140,10 @@ namespace dlib matrix e(n,1); q.set_size(n,1); - u.set_size(m,m); + if (u_mode == SVD_FULL_U) + u.set_size(m,m); + else + u.set_size(m,n); retval = 0; if (withv) @@ -624,33 +261,34 @@ namespace dlib } /* end withv, parens added for clarity */ /* accumulation of left-hand transformations */ - if (withu) + if (u_mode != SVD_NO_U) { - for (i=n; i=0; i--) { l = i + 1; g = q(i); - for (j=l; j + long svd2 ( + bool withu, + bool withv, + const matrix_exp& a, + matrix& u, + matrix& q, + matrix& v + ) + { + const long NR = matrix_exp::NR; + const long NC = matrix_exp::NC; + + // make sure the output matrices have valid dimensions if they are statically dimensioned + COMPILE_TIME_ASSERT(qX == 0 || qX == 1); + COMPILE_TIME_ASSERT(NR == 0 || uM == 0 || NR == uM); + COMPILE_TIME_ASSERT(NC == 0 || vN == 0 || NC == vN); + + DLIB_ASSERT(a.nr() >= a.nc(), + "\tconst matrix_exp svd4()" + << "\n\tYou have given an invalidly sized matrix" + << "\n\ta.nr(): " << a.nr() + << "\n\ta.nc(): " << a.nc() + ); + + if (withu) + return svd4(SVD_FULL_U, withv, a,u,q,v); + else + return svd4(SVD_NO_U, withv, a,u,q,v); + } + // ---------------------------------------------------------------------------------------- template < typename T, long NR, long NC, - typename MM, - typename L + typename MM > void orthogonalize ( - matrix& m + matrix& m ) { - qr_decomposition >(m).get_q(m); + // We don't really need to use this temporary, but doing it this way runs a lot + // faster. + matrix temp; + qr_decomposition>(m).get_q(temp); + m = temp; + } + + template < + typename T, + long NR, + long NC, + typename MM + > + void orthogonalize ( + matrix& m + ) + { + qr_decomposition>(m).get_q(m); } // ---------------------------------------------------------------------------------------- @@ -963,13 +662,13 @@ convergence: Q.set_size(A.size(), l); // Compute Q = A*gaussian_randm() - for (long r = 0; r < Q.nr(); ++r) + parallel_for(0, Q.nr(), [&](long r) { for (long c = 0; c < Q.nc(); ++c) { Q(r,c) = dot(A[r], gaussian_randm(std::numeric_limits::max(), 1, c)); } - } + }); orthogonalize(Q); @@ -977,39 +676,45 @@ convergence: // span of the most important singular vectors of A. if (q != 0) { + dlib::mutex mut; const unsigned long n = max_index_plus_one(A); for (unsigned long itr = 0; itr < q; ++itr) { - matrix Z(n, l); + matrix Z; // Compute Z = trans(A)*Q - Z = 0; - for (unsigned long m = 0; m < A.size(); ++m) + parallel_for_blocked(0, A.size(), [&](long begin, long end) { - for (unsigned long r = 0; r < l; ++r) + matrix Zlocal(n,l); + Zlocal = 0; + for (long m = begin; m < end; ++m) { - typename sparse_vector_type::const_iterator i; - for (i = A[m].begin(); i != A[m].end(); ++i) + for (unsigned long r = 0; r < l; ++r) { - const unsigned long c = i->first; - const T val = i->second; + for (auto& i : A[m]) + { + const auto c = i.first; + const auto val = i.second; - Z(c,r) += Q(m,r)*val; + Zlocal(c,r) += Q(m,r)*val; + } } } - } + auto_mutex lock(mut); + Z += Zlocal; + },1); Q.set_size(0,0); // free RAM orthogonalize(Z); // Compute Q = A*Z Q.set_size(A.size(), l); - for (long r = 0; r < Q.nr(); ++r) + parallel_for(0, Q.nr(), [&](long r) { for (long c = 0; c < Q.nc(); ++c) { Q(r,c) = dot(A[r], colm(Z,c)); } - } + }); Z.set_size(0,0); // free RAM orthogonalize(Q); @@ -1019,6 +724,74 @@ convergence: // ---------------------------------------------------------------------------------------- + namespace simpl + { + template < + typename sparse_vector_type, + typename T, + long Unr, long Unc, + long Wnr, long Wnc, + long Vnr, long Vnc, + typename MM, + typename L + > + void svd_fast ( + bool compute_u, + const std::vector& A, + matrix& u, + matrix& w, + matrix& v, + unsigned long l, + unsigned long q + ) + { + const long n = max_index_plus_one(A); + const unsigned long k = std::min(l, std::min(A.size(),n)); + + DLIB_ASSERT(l > 0 && A.size() > 0 && n > 0, + "\t void svd_fast()" + << "\n\t Invalid inputs were given to this function." + << "\n\t l: " << l + << "\n\t n (i.e. max_index_plus_one(A)): " << n + << "\n\t A.size(): " << A.size() + ); + + matrix Q; + find_matrix_range(A, k, Q, q); + + // Compute trans(B) = trans(Q)*A. The reason we store B transposed + // is so that when we take its SVD later using svd3() it doesn't consume + // a whole lot of RAM. That is, we make sure the square matrix coming out + // of svd3() has size lxl rather than the potentially much larger nxn. + matrix B; + dlib::mutex mut; + parallel_for_blocked(0, A.size(), [&](long begin, long end) + { + matrix Blocal(n,k); + Blocal = 0; + for (long m = begin; m < end; ++m) + { + for (unsigned long r = 0; r < k; ++r) + { + for (auto& i : A[m]) + { + const auto c = i.first; + const auto val = i.second; + + Blocal(c,r) += Q(m,r)*val; + } + } + } + auto_mutex lock(mut); + B += Blocal; + },1); + + svd3(B, v,w,u); + if (compute_u) + u = Q*u; + } + } + template < typename sparse_vector_type, typename T, @@ -1037,43 +810,27 @@ convergence: unsigned long q = 1 ) { - const long n = max_index_plus_one(A); - const unsigned long k = std::min(l, std::min(A.size(),n)); + simpl::svd_fast(true, A,u,w,v,l,q); + } - DLIB_ASSERT(l > 0 && A.size() > 0 && n > 0, - "\t void svd_fast()" - << "\n\t Invalid inputs were given to this function." - << "\n\t l: " << l - << "\n\t n (i.e. max_index_plus_one(A)): " << n - << "\n\t A.size(): " << A.size() - ); - - matrix Q; - find_matrix_range(A, k, Q, q); - - // Compute trans(B) = trans(Q)*A. The reason we store B transposed - // is so that when we take its SVD later using svd3() it doesn't consume - // a whole lot of RAM. That is, we make sure the square matrix coming out - // of svd3() has size lxl rather than the potentially much larger nxn. - matrix B(n,k); - B = 0; - for (unsigned long m = 0; m < A.size(); ++m) - { - for (unsigned long r = 0; r < k; ++r) - { - typename sparse_vector_type::const_iterator i; - for (i = A[m].begin(); i != A[m].end(); ++i) - { - const unsigned long c = i->first; - const T val = i->second; - - B(c,r) += Q(m,r)*val; - } - } - } - - svd3(B, v,w,u); - u = Q*u; + template < + typename sparse_vector_type, + typename T, + long Wnr, long Wnc, + long Vnr, long Vnc, + typename MM, + typename L + > + void svd_fast ( + const std::vector& A, + matrix& w, + matrix& v, + unsigned long l, + unsigned long q = 1 + ) + { + matrix u; + simpl::svd_fast(false, A,u,w,v,l,q); } // ---------------------------------------------------------------------------------------- @@ -1089,7 +846,6 @@ convergence: const matrix_exp& m ) { - using namespace nric; // you can't invert a non-square matrix COMPILE_TIME_ASSERT(matrix_exp::NR == matrix_exp::NC || matrix_exp::NR == 0 || @@ -1440,7 +1196,78 @@ convergence: ); typename matrix_exp::matrix_type L(A.nr(),A.nc()); -#ifdef DLIB_USE_LAPACK + typedef typename EXP::type T; + + bool banded = false; + long bandwidth = 0; + + if (A.nr() > 4) // Only test for banded matrix if matrix is big enough + { + // Detect if matrix is banded and, if so, matrix bandwidth + banded = true; + for (long r = 0; r < A.nr(); ++r) + for (long c = (r + bandwidth + 1); c < A.nc(); ++c) + if (A(r, c) != 0) + { + bandwidth = c - r; + if (bandwidth > A.nr() / 2) + { + banded = false; + goto escape_banded_detection; + } + } + } +escape_banded_detection: + + if (banded) + { + // Store in compact form - use column major for LAPACK + matrix B(bandwidth + 1, A.nc()); + set_all_elements(B, 0); + + for (long r = 0; r < A.nr(); ++r) + for (long c = r; c < std::min(r + bandwidth + 1, A.nc()); ++c) + B(c - r, r) = A(r, c); + +#ifdef DLIB_USE_LAPACK + + lapack::pbtrf('L', B); + +#else + + // Peform compact Cholesky + for (long k = 0; k < A.nr(); ++k) + { + long last = std::min(k + bandwidth, A.nr() - 1) - k; + for (long j = 1; j <= last; ++j) + { + long i = k + j; + for (long c = 0; c <= (last - j); ++c) + B(c, i) -= B(j, k) / B(0, k) * B(c + j, k); + } + T norm = std::sqrt(B(0, k)); + for (long i = 0; i <= bandwidth; ++i) + B(i, k) /= norm; + } + for (long c = A.nc() - bandwidth + 1; c < A.nc(); ++c) + B(bandwidth, c) = 0; + +#endif + + // Unpack lower triangular area + set_all_elements(L, 0); + for (long c = 0; c < A.nc(); ++c) + for (long i = 0; i <= bandwidth; ++i) + { + long ind = c + i; + if (ind < A.nc()) + L(ind, c) = B(i, c); + } + + return L; + } + +#ifdef DLIB_USE_LAPACK // Only call LAPACK if the matrix is big enough. Otherwise, // our own code is faster, especially for statically dimensioned // matrices. @@ -1452,7 +1279,6 @@ convergence: return lowerm(L); } #endif - typedef typename EXP::type T; set_all_elements(L,0); // do nothing if the matrix is empty @@ -1556,13 +1382,21 @@ convergence: return; } #endif - v.set_size(m.nc(),m.nc()); + if (m.nr() >= m.nc()) + { + svd4(SVD_SKINNY_U,true, m, u,w,v); + } + else + { + svd4(SVD_FULL_U,true, trans(m), v,w,u); - u = m; - - w.set_size(m.nc(),1); - matrix::NC,1,MM1> rv1(m.nc(),1); - nric::svdcmp(u,w,v,rv1); + // if u isn't the size we want then pad it (and v) with zeros + if (u.nc() < m.nc()) + { + w = join_cols(w, zeros_matrix(m.nc()-u.nc(),1)); + u = join_rows(u, zeros_matrix(u.nr(), m.nc()-u.nc())); + } + } } // ---------------------------------------------------------------------------------------- @@ -1594,8 +1428,8 @@ convergence: const double machine_eps = std::numeric_limits::epsilon(); // compute a reasonable epsilon below which we round to zero before doing the - // reciprocal. Unless a non-zero tol is given then we just use tol. - const double eps = (tol!=0) ? tol : machine_eps*std::max(m.nr(),m.nc())*max(w); + // reciprocal. Unless a non-zero tol is given then we just use tol*max(w). + const double eps = (tol!=0) ? tol*max(w) : machine_eps*std::max(m.nr(),m.nc())*max(w); // now compute the pseudoinverse return tmp(scale_columns(v,reciprocal(round_zeros(w,eps))))*trans(u); @@ -1691,7 +1525,6 @@ convergence: const matrix_exp& m ) { - using namespace nric; COMPILE_TIME_ASSERT(matrix_exp::NR == matrix_exp::NC || matrix_exp::NR == 0 || matrix_exp::NC == 0 @@ -1834,6 +1667,137 @@ convergence: } } +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + dlib::vector max_point_interpolated ( + const matrix_exp& m + ) + { + DLIB_ASSERT(m.size() > 0, + "\tdlib::vector point max_point_interpolated(const matrix_exp& m)" + << "\n\tm can't be empty" + << "\n\tm.size(): " << m.size() + << "\n\tm.nr(): " << m.nr() + << "\n\tm.nc(): " << m.nc() + ); + const point p = max_point(m); + + // If this is a column vector then just do interpolation along a line. + if (m.nc()==1) + { + const long pos = p.y(); + if (0 < pos && pos+1 < m.nr()) + { + double v1 = dlib::impl::magnitude(m(pos-1)); + double v2 = dlib::impl::magnitude(m(pos)); + double v3 = dlib::impl::magnitude(m(pos+1)); + double y = lagrange_poly_min_extrap(pos-1,pos,pos+1, -v1, -v2, -v3); + return vector(0,y); + } + } + // If this is a row vector then just do interpolation along a line. + if (m.nr()==1) + { + const long pos = p.x(); + if (0 < pos && pos+1 < m.nc()) + { + double v1 = dlib::impl::magnitude(m(pos-1)); + double v2 = dlib::impl::magnitude(m(pos)); + double v3 = dlib::impl::magnitude(m(pos+1)); + double x = lagrange_poly_min_extrap(pos-1,pos,pos+1, -v1, -v2, -v3); + return vector(x,0); + } + } + + + // If it's on the border then just return the regular max point. + if (shrink_rect(get_rect(m),1).contains(p) == false) + return p; + + //matrix A(9,6); + //matrix G(9); + + matrix pix; + long i = 0; + for (long r = -1; r <= +1; ++r) + { + for (long c = -1; c <= +1; ++c) + { + pix(i) = dlib::impl::magnitude(m(p.y()+r,p.y()+c)); + /* + A(i,0) = c*c; + A(i,1) = c*r; + A(i,2) = r*r; + A(i,3) = c; + A(i,4) = r; + A(i,5) = 1; + G(i) = std::exp(-1*(r*r+c*c)/2.0); // Use a gaussian windowing function around p. + */ + ++i; + } + } + + // This bit of code is how we generated the derivative_filters matrix below. + //A = diagm(G)*A; + //std::cout << std::setprecision(20) << inv(trans(A)*A)*trans(A)*diagm(G) << std::endl; exit(1); + + const double m10 = 0.10597077880854270659; + const double m21 = 0.21194155761708535768; + const double m28 = 0.28805844238291455905; + const double m57 = 0.57611688476582878504; + // So this derivative_filters finds the parameters of the quadratic surface that best fits + // the 3x3 region around p. Then we find the maximizer of that surface within that + // small region and return that as the maximum location. + const double derivative_filters[] = { + // xx + m10,-m21,m10, + m28,-m57,m28, + m10,-m21,m10, + + // xy + 0.25 ,0,-0.25, + 0 ,0, 0, + -0.25,0,0.25, + + // yy + m10, m28, m10, + -m21,-m57,-m21, + m10, m28, m10, + + // x + -m10,0,m10, + -m28,0,m28, + -m10,0,m10, + + // y + -m10,-m28,-m10, + 0, 0, 0, + m10, m28, m10 + }; + const matrix filt(derivative_filters); + // Now w contains the parameters of the quadratic surface + const matrix w = filt*pix; + + + // Now newton step to the max point on the surface + matrix H; + matrix g; + H = 2*w(0), w(1), + w(1), 2*w(2); + g = w(3), + w(4); + const dlib::vector delta = -inv(H)*g; + + // if delta isn't in an ascent direction then just use the normal max point. + if (dot(delta, g) < 0) + return p; + else + return vector(p)+dlib::clamp(delta, -1, 1); + } + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_la_abstract.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_la_abstract.h index ea8fee5b..df6a5fd3 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_la_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_la_abstract.h @@ -44,7 +44,7 @@ namespace dlib - singular values less than max(m.nr(),m.nc()) times the machine epsilon times the largest singular value are ignored. - else - - singular values less than tol are ignored. + - singular values less than tol*max(singular value in m) are ignored. !*/ // ---------------------------------------------------------------------------------------- @@ -188,6 +188,9 @@ namespace dlib Finding Structure with Randomness: Probabilistic Algorithms for Constructing Approximate Matrix Decompositions by Halko et al. Therefore, it is very fast and suitable for use with very large matrices. + Moreover, q is the number of subspace iterations performed. Larger + values of q might increase the accuracy of the solution but the default + value should be good for many problems. !*/ // ---------------------------------------------------------------------------------------- @@ -241,6 +244,24 @@ namespace dlib Finding Structure with Randomness: Probabilistic Algorithms for Constructing Approximate Matrix Decompositions by Halko et al. Therefore, it is very fast and suitable for use with very large matrices. + Moreover, q is the number of subspace iterations performed. Larger + values of q might increase the accuracy of the solution but the default + value should be good for many problems. + !*/ + + template < + typename sparse_vector_type, + typename T + > + void svd_fast ( + const std::vector& A, + matrix& w, + matrix& v, + unsigned long l, + unsigned long q = 1 + ); + /*! + This function is identical to the above svd_fast() except it doesn't compute u. !*/ // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_mat.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_mat.h index e2543d8b..803d7d99 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_mat.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_mat.h @@ -239,7 +239,10 @@ namespace dlib // ---------------------------------------------------------------------------------------- template - struct op_pointer_to_col_vect : does_not_alias + struct op_pointer_to_mat; + + template + struct op_pointer_to_col_vect { op_pointer_to_col_vect( const T* ptr_, @@ -261,6 +264,31 @@ namespace dlib long nr () const { return size; } long nc () const { return 1; } + + template bool aliases ( const matrix_exp& ) const { return false; } + template bool destructively_aliases ( const matrix_exp& ) const { return false; } + + template + bool aliases ( + const matrix_exp >& item + ) const + { + if (item.size() == 0) + return false; + else + return (ptr == &item(0,0)); + } + + inline bool aliases ( + const matrix_exp > >& item + ) const; + + bool aliases ( + const matrix_exp > >& item + ) const + { + return item.ref().op.ptr == ptr; + } }; // ---------------------------------------------------------------------------------------- @@ -273,9 +301,9 @@ namespace dlib long nr ) { - DLIB_ASSERT(nr > 0 , + DLIB_ASSERT(nr >= 0 , "\tconst matrix_exp mat(ptr, nr)" - << "\n\t nr must be bigger than 0" + << "\n\t nr must be >= 0" << "\n\t nr: " << nr ); typedef op_pointer_to_col_vect op; @@ -285,17 +313,25 @@ namespace dlib // ---------------------------------------------------------------------------------------- template - struct op_pointer_to_mat : does_not_alias + struct op_pointer_to_mat { op_pointer_to_mat( const T* ptr_, const long nr_, const long nc_ - ) : ptr(ptr_), rows(nr_), cols(nc_){} + ) : ptr(ptr_), rows(nr_), cols(nc_), stride(nc_){} + + op_pointer_to_mat( + const T* ptr_, + const long nr_, + const long nc_, + const long stride_ + ) : ptr(ptr_), rows(nr_), cols(nc_), stride(stride_){} const T* ptr; const long rows; const long cols; + const long stride; const static long cost = 1; const static long NR = 0; @@ -305,12 +341,71 @@ namespace dlib typedef default_memory_manager mem_manager_type; typedef row_major_layout layout_type; - const_ret_type apply (long r, long c) const { return ptr[r*cols + c]; } + const_ret_type apply (long r, long c) const { return ptr[r*stride + c]; } long nr () const { return rows; } long nc () const { return cols; } + + template bool aliases ( const matrix_exp& ) const { return false; } + template bool destructively_aliases ( const matrix_exp& ) const { return false; } + + template + bool aliases ( + const matrix_exp >& item + ) const + { + if (item.size() == 0) + return false; + else + return (ptr == &item(0,0)); + } + + bool aliases ( + const matrix_exp > >& item + ) const + { + return item.ref().op.ptr == ptr; + } + + bool aliases ( + const matrix_exp > >& item + ) const + { + return item.ref().op.ptr == ptr; + } }; + template + bool op_pointer_to_col_vect:: + aliases ( + const matrix_exp > >& item + ) const + { + return item.ref().op.ptr == ptr; + } + + template + bool matrix::aliases ( + const matrix_exp > >& item + ) const + { + if (size() != 0) + return item.ref().op.ptr == &data(0,0); + else + return false; + } + + template + bool matrix::aliases ( + const matrix_exp > >& item + ) const + { + if (size() != 0) + return item.ref().op.ptr == &data(0,0); + else + return false; + } + // ---------------------------------------------------------------------------------------- template < @@ -322,9 +417,9 @@ namespace dlib long nc ) { - DLIB_ASSERT(nr > 0 && nc > 0 , + DLIB_ASSERT(nr >= 0 && nc >= 0 , "\tconst matrix_exp mat(ptr, nr, nc)" - << "\n\t nr and nc must be bigger than 0" + << "\n\t nr and nc must be >= 0" << "\n\t nr: " << nr << "\n\t nc: " << nc ); @@ -332,6 +427,27 @@ namespace dlib return matrix_op(op(ptr,nr,nc)); } + template < + typename T + > + const matrix_op > mat ( + const T* ptr, + long nr, + long nc, + long stride + ) + { + DLIB_ASSERT(nr >= 0 && nc >= 0 && stride > 0 , + "\tconst matrix_exp mat(ptr, nr, nc, stride)" + << "\n\t nr and nc must be >= 0 while stride > 0" + << "\n\t nr: " << nr + << "\n\t nc: " << nc + << "\n\t stride: " << stride + ); + typedef op_pointer_to_mat op; + return matrix_op(op(ptr,nr,nc,stride)); + } + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_mat_abstract.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_mat_abstract.h index 87d6c1b9..7026f60a 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_mat_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_mat_abstract.h @@ -114,8 +114,8 @@ namespace dlib ); /*! requires - - nr > 0 - - ptr == a pointer to at least nr T objects + - nr >= 0 + - ptr == a pointer to at least nr T objects (or the NULL pointer if nr==0) ensures - returns a matrix M such that: - M.nr() == nr @@ -138,9 +138,9 @@ namespace dlib ); /*! requires - - nr > 0 - - nc > 0 - - ptr == a pointer to at least nr*nc T objects + - nr >= 0 + - nc >= 0 + - ptr == a pointer to at least nr*nc T objects (or the NULL pointer if nr*nc==0) ensures - returns a matrix M such that: - M.nr() == nr @@ -153,6 +153,35 @@ namespace dlib the pointer and thus will not delete or free it. !*/ +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + const matrix_exp mat ( + const T* ptr, + long nr, + long nc, + long stride + ); + /*! + requires + - nr >= 0 + - nc >= 0 + - stride > 0 + - ptr == a pointer to at least (nr-1)*stride+nc T objects (or the NULL pointer if nr*nc==0) + ensures + - returns a matrix M such that: + - M.nr() == nr + - m.nc() == nc + - for all valid r and c: + M(r,c) == ptr[r*stride + c] + (i.e. the pointer is interpreted as a matrix laid out in memory + in row major order, with a row stride of the given stride amount.) + - Note that the returned matrix doesn't take "ownership" of + the pointer and thus will not delete or free it. + !*/ + // ---------------------------------------------------------------------------------------- template < diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_op.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_op.h index dd3e64dd..524a775e 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_op.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_op.h @@ -374,10 +374,10 @@ namespace dlib template bool destructively_aliases ( const matrix_exp& item) const \ { return m.destructively_aliases(item); } \ \ - }; + } #define DLIB_DEFINE_FUNCTION_M(op_name, name, function, extra_cost) \ - DLIB_DEFINE_OP_M(op_name, function, extra_cost) \ + DLIB_DEFINE_OP_M(op_name, function, extra_cost); \ template < typename M > \ const matrix_op > name ( const matrix_exp& m) \ { \ @@ -417,10 +417,10 @@ namespace dlib template bool destructively_aliases ( const matrix_exp& item) const \ { return m.destructively_aliases(item); } \ \ - }; - + } + #define DLIB_DEFINE_FUNCTION_MS(op_name, name, function, extra_cost) \ - DLIB_DEFINE_OP_MS(op_name, function, extra_cost) \ + DLIB_DEFINE_OP_MS(op_name, function, extra_cost); \ template < typename M, typename S > \ const matrix_op > name ( const matrix_exp& m, const S& s) \ { \ @@ -460,10 +460,10 @@ namespace dlib template bool destructively_aliases ( const matrix_exp& item) const \ { return m.destructively_aliases(item); } \ \ - }; - + } + #define DLIB_DEFINE_FUNCTION_SM(op_name, name, function, extra_cost) \ - DLIB_DEFINE_OP_SM(op_name, function, extra_cost) \ + DLIB_DEFINE_OP_SM(op_name, function, extra_cost); \ template < typename S, typename M > \ const matrix_op > name (const S& s, const matrix_exp& m) \ { \ diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_qr.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_qr.h index e63c8f32..086d481f 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_qr.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_qr.h @@ -62,8 +62,9 @@ namespace dlib const matrix_type get_q ( ) const; + template void get_q ( - matrix_type& Q + matrix& Q ) const; template @@ -270,9 +271,10 @@ namespace dlib // ---------------------------------------------------------------------------------------- template + template void qr_decomposition:: get_q( - matrix_type& X + matrix& X ) const { #ifdef DLIB_USE_LAPACK diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_subexp.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_subexp.h index f546cac5..668e5749 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_subexp.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_subexp.h @@ -8,6 +8,7 @@ #include "matrix.h" #include "../geometry/rectangle.h" #include "matrix_expressions.h" +#include "matrix_mat.h" @@ -120,6 +121,25 @@ namespace dlib return matrix_op(op(m.ref(),r,c,nr,nc)); } +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + const matrix_op > subm_clipped ( + const matrix_exp& m, + long r, + long c, + long nr, + long nc + ) + { + rectangle box(c,r,c+nc-1,r+nr-1); + box = box.intersect(get_rect(m)); + typedef op_subm op; + return matrix_op(op(m.ref(),box.top(),box.left(),box.height(),box.width())); + } + // ---------------------------------------------------------------------------------------- template < @@ -145,6 +165,22 @@ namespace dlib return matrix_op(op(m.ref(),rect.top(),rect.left(),rect.height(),rect.width())); } +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + const matrix_op > subm_clipped ( + const matrix_exp& m, + rectangle rect + ) + { + rect = rect.intersect(get_rect(m)); + + typedef op_subm op; + return matrix_op(op(m.ref(),rect.top(),rect.left(),rect.height(),rect.width())); + } + // ---------------------------------------------------------------------------------------- template @@ -522,6 +558,197 @@ namespace dlib // ---------------------------------------------------------------------------------------- + template + class assignable_ptr_matrix + { + public: + typedef T type; + typedef row_major_layout layout_type; + typedef matrix matrix_type; + + assignable_ptr_matrix( + T* ptr_, + long nr_, + long nc_ + ) : ptr(ptr_), height(nr_), width(nc_){} + + T& operator() ( + long r, + long c + ) + { + return ptr[r*width + c]; + } + + const T& operator() ( + long r, + long c + ) const + { + return ptr[r*width + c]; + } + + long nr() const { return height; } + long nc() const { return width; } + + template + assignable_ptr_matrix& operator= ( + const matrix_exp& exp + ) + { + // You can only assign to a set_ptrm() expression with a source matrix that + // contains the same type of elements as the target (i.e. you can't mix double + // and float types). + COMPILE_TIME_ASSERT((is_same_type::value == true)); + + DLIB_ASSERT( exp.nr() == height && exp.nc() == width, + "\tassignable_matrix_expression set_ptrm()" + << "\n\tYou have tried to assign to this object using a matrix that isn't the right size" + << "\n\texp.nr() (source matrix): " << exp.nr() + << "\n\texp.nc() (source matrix): " << exp.nc() + << "\n\twidth (target matrix): " << width + << "\n\theight (target matrix): " << height + ); + + if (exp.destructively_aliases(mat(ptr,height,width)) == false) + { + matrix_assign(*this, exp); + } + else + { + // make a temporary copy of the matrix we are going to assign to ptr to + // avoid aliasing issues during the copy + this->operator=(tmp(exp)); + } + + return *this; + } + + template + assignable_ptr_matrix& operator+= ( + const matrix_exp& exp + ) + { + // You can only assign to a set_ptrm() expression with a source matrix that + // contains the same type of elements as the target (i.e. you can't mix double + // and float types). + COMPILE_TIME_ASSERT((is_same_type::value == true)); + + DLIB_ASSERT( exp.nr() == height && exp.nc() == width, + "\tassignable_matrix_expression set_ptrm()" + << "\n\tYou have tried to assign to this object using a matrix that isn't the right size" + << "\n\texp.nr() (source matrix): " << exp.nr() + << "\n\texp.nc() (source matrix): " << exp.nc() + << "\n\twidth (target matrix): " << width + << "\n\theight (target matrix): " << height + ); + + if (exp.destructively_aliases(mat(ptr,height,width)) == false) + { + matrix_assign(*this, mat(ptr,height,width)+exp); + } + else + { + // make a temporary copy of the matrix we are going to assign to ptr to + // avoid aliasing issues during the copy + this->operator+=(tmp(exp)); + } + + return *this; + } + + template + assignable_ptr_matrix& operator-= ( + const matrix_exp& exp + ) + { + // You can only assign to a set_ptrm() expression with a source matrix that + // contains the same type of elements as the target (i.e. you can't mix double + // and float types). + COMPILE_TIME_ASSERT((is_same_type::value == true)); + + DLIB_ASSERT( exp.nr() == height && exp.nc() == width, + "\tassignable_matrix_expression set_ptrm()" + << "\n\tYou have tried to assign to this object using a matrix that isn't the right size" + << "\n\texp.nr() (source matrix): " << exp.nr() + << "\n\texp.nc() (source matrix): " << exp.nc() + << "\n\twidth (target matrix): " << width + << "\n\theight (target matrix): " << height + ); + + if (exp.destructively_aliases(mat(ptr,height,width)) == false) + { + matrix_assign(*this, mat(ptr,height,width)-exp); + } + else + { + // make a temporary copy of the matrix we are going to assign to ptr to + // avoid aliasing issues during the copy + this->operator-=(tmp(exp)); + } + + return *this; + } + + assignable_ptr_matrix& operator= ( + const T& value + ) + { + const long size = width*height; + for (long i = 0; i < size; ++i) + ptr[i] = value; + + return *this; + } + + assignable_ptr_matrix& operator+= ( + const T& value + ) + { + const long size = width*height; + for (long i = 0; i < size; ++i) + ptr[i] += value; + + return *this; + } + + assignable_ptr_matrix& operator-= ( + const T& value + ) + { + const long size = width*height; + for (long i = 0; i < size; ++i) + ptr[i] -= value; + + return *this; + } + + + T* ptr; + const long height; + const long width; + }; + + + template + assignable_ptr_matrix set_ptrm ( + T* ptr, + long nr, + long nc = 1 + ) + { + DLIB_ASSERT(nr >= 0 && nc >= 0, + "\t assignable_matrix_expression set_ptrm(T* ptr, long nr, long nc)" + << "\n\t The dimensions can't be negative." + << "\n\t nr: " << nr + << "\n\t nc: " << nc + ); + + + return assignable_ptr_matrix(ptr,nr,nc); + } + +// ---------------------------------------------------------------------------------------- template class assignable_sub_matrix diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_subexp_abstract.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_subexp_abstract.h index 42c32833..2665d1b9 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_subexp_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_subexp_abstract.h @@ -123,6 +123,46 @@ namespace dlib R(r, c) == m(r+rect.top(), c+rect.left()) !*/ +// ---------------------------------------------------------------------------------------- + + const matrix_exp subm_clipped ( + const matrix_exp& m, + long row, + long col, + long nr, + long nc + ); + /*! + ensures + - This function is just like subm() except that it will automatically clip the + indicated sub matrix window so that it does not extend outside m. + In particular: + - Let box = rectangle(col,row,col+nc-1,row+nr-1) + (i.e. the box that contains the indicated sub matrix) + - Let box_clipped = box.intersect(get_rect(m)) + - Then this function returns a matrix R such that: + - R.nr() == box_clipped.height() + - R.nc() == box_clipped.width() + - for all valid r and c: + R(r, c) == m(r+box_clipped.top(),c+box_clipped.left()) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp subm_clipped ( + const matrix_exp& m, + const rectangle& rect + ); + /*! + ensures + - Let box_clipped == rect.intersect(get_rect(m)) + - returns a matrix R such that: + - R.nr() == box_clipped.height() + - R.nc() == box_clipped.width() + - for all valid r and c: + R(r, c) == m(r+box_clipped.top(), c+box_clipped.left()) + !*/ + // ---------------------------------------------------------------------------------------- const matrix_exp rowm ( @@ -297,6 +337,35 @@ namespace dlib R(r,c) == m(r,cols(c)) !*/ +// ---------------------------------------------------------------------------------------- + + template + assignable_matrix_expression set_ptrm ( + T* ptr, + long nr, + long nc = 1 + ); + /*! + requires + - ptr == a pointer to nr*nc elements of type T + - nr >= 0 + - nc >= 0 + ensures + - statements of the following form: + - set_ptrm(ptr,nr,nc) = some_matrix; + result in it being the case that: + - mat(ptr,nr,nc) == some_matrix. + + - statements of the following form: + - set_ptrm(ptr,nr,nc) = scalar_value; + result in it being the case that: + - mat(ptr,nr,nc) == uniform_matrix(nr,nc,scalar_value). + + - In addition to the normal assignment statements using the = symbol, you may + also use the usual += and -= versions of the assignment operator. In these + cases, they have their usual effect. + !*/ + // ---------------------------------------------------------------------------------------- assignable_matrix_expression set_subm ( diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_trsm.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_trsm.h index 769cbe88..ef5ec5ed 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_trsm.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_trsm.h @@ -9,24 +9,27 @@ namespace dlib { namespace blas_bindings { - #ifndef CBLAS_H +#ifdef DLIB_USE_BLAS +#ifndef CBLAS_H extern "C" { - void cblas_strsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, - const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, - const enum CBLAS_DIAG Diag, const int M, const int N, + void cblas_strsm(const CBLAS_ORDER Order, const CBLAS_SIDE Side, + const CBLAS_UPLO Uplo, const CBLAS_TRANSPOSE TransA, + const CBLAS_DIAG Diag, const int M, const int N, const float alpha, const float *A, const int lda, float *B, const int ldb); - void cblas_dtrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, - const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, - const enum CBLAS_DIAG Diag, const int M, const int N, + void cblas_dtrsm(const CBLAS_ORDER Order, const CBLAS_SIDE Side, + const CBLAS_UPLO Uplo, const CBLAS_TRANSPOSE TransA, + const CBLAS_DIAG Diag, const int M, const int N, const double alpha, const double *A, const int lda, double *B, const int ldb); } +#endif // if not CBLAS_H +#endif // if DLIB_USE_BLAS // ------------------------------------------------------------------------------------ - #endif // if not CBLAS_H + /* Purpose */ /* ======= */ @@ -147,11 +150,11 @@ namespace dlib template void local_trsm( - const enum CBLAS_ORDER Order, - enum CBLAS_SIDE Side, - enum CBLAS_UPLO Uplo, - const enum CBLAS_TRANSPOSE TransA, - const enum CBLAS_DIAG Diag, + const CBLAS_ORDER Order, + CBLAS_SIDE Side, + CBLAS_UPLO Uplo, + const CBLAS_TRANSPOSE TransA, + const CBLAS_DIAG Diag, long m, long n, T alpha, @@ -512,9 +515,9 @@ namespace dlib // ------------------------------------------------------------------------------------ - inline void cblas_trsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, - const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, - const enum CBLAS_DIAG Diag, const int M, const int N, + inline void cblas_trsm(const CBLAS_ORDER Order, const CBLAS_SIDE Side, + const CBLAS_UPLO Uplo, const CBLAS_TRANSPOSE TransA, + const CBLAS_DIAG Diag, const int M, const int N, const float alpha, const float *A, const int lda, float *B, const int ldb) { @@ -528,9 +531,9 @@ namespace dlib local_trsm(Order, Side, Uplo, TransA, Diag, M, N, alpha, A, lda, B, ldb); } - inline void cblas_trsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, - const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, - const enum CBLAS_DIAG Diag, const int M, const int N, + inline void cblas_trsm(const CBLAS_ORDER Order, const CBLAS_SIDE Side, + const CBLAS_UPLO Uplo, const CBLAS_TRANSPOSE TransA, + const CBLAS_DIAG Diag, const int M, const int N, const double alpha, const double *A, const int lda, double *B, const int ldb) { @@ -544,9 +547,9 @@ namespace dlib local_trsm(Order, Side, Uplo, TransA, Diag, M, N, alpha, A, lda, B, ldb); } - inline void cblas_trsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side, - const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA, - const enum CBLAS_DIAG Diag, const int M, const int N, + inline void cblas_trsm(const CBLAS_ORDER Order, const CBLAS_SIDE Side, + const CBLAS_UPLO Uplo, const CBLAS_TRANSPOSE TransA, + const CBLAS_DIAG Diag, const int M, const int N, const long double alpha, const long double *A, const int lda, long double *B, const int ldb) { @@ -562,10 +565,10 @@ namespace dlib typename MM > inline void triangular_solver ( - const enum CBLAS_SIDE Side, - const enum CBLAS_UPLO Uplo, - const enum CBLAS_TRANSPOSE TransA, - const enum CBLAS_DIAG Diag, + const CBLAS_SIDE Side, + const CBLAS_UPLO Uplo, + const CBLAS_TRANSPOSE TransA, + const CBLAS_DIAG Diag, const matrix& A, const T alpha, matrix& B @@ -584,10 +587,10 @@ namespace dlib typename MM > inline void triangular_solver ( - const enum CBLAS_SIDE Side, - const enum CBLAS_UPLO Uplo, - const enum CBLAS_TRANSPOSE TransA, - const enum CBLAS_DIAG Diag, + const CBLAS_SIDE Side, + const CBLAS_UPLO Uplo, + const CBLAS_TRANSPOSE TransA, + const CBLAS_DIAG Diag, const matrix& A, const T alpha, matrix& B @@ -606,10 +609,10 @@ namespace dlib typename MM > inline void triangular_solver ( - const enum CBLAS_SIDE Side, - const enum CBLAS_UPLO Uplo, - const enum CBLAS_TRANSPOSE TransA, - const enum CBLAS_DIAG Diag, + const CBLAS_SIDE Side, + const CBLAS_UPLO Uplo, + const CBLAS_TRANSPOSE TransA, + const CBLAS_DIAG Diag, const matrix& A, matrix& B, long rows_of_B @@ -630,10 +633,10 @@ namespace dlib typename layout > inline void triangular_solver ( - const enum CBLAS_SIDE Side, - const enum CBLAS_UPLO Uplo, - const enum CBLAS_TRANSPOSE TransA, - const enum CBLAS_DIAG Diag, + const CBLAS_SIDE Side, + const CBLAS_UPLO Uplo, + const CBLAS_TRANSPOSE TransA, + const CBLAS_DIAG Diag, const matrix& A, matrix& B ) diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_utilities.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_utilities.h index e9c328e0..0c5091a4 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_utilities.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_utilities.h @@ -122,6 +122,76 @@ namespace dlib } } +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + point max_point ( + const matrix_exp& m + ) + { + DLIB_ASSERT(m.size() > 0, + "\tpoint max_point(const matrix_exp& m)" + << "\n\tm can't be empty" + << "\n\tm.size(): " << m.size() + << "\n\tm.nr(): " << m.nr() + << "\n\tm.nc(): " << m.nc() + ); + typedef typename matrix_exp::type type; + + point best_point(0,0); + type val = m(0,0); + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + type temp = m(r,c); + if (dlib::impl::magnitude(temp) > dlib::impl::magnitude(val)) + { + val = temp; + best_point = point(c,r); + } + } + } + return best_point; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + point min_point ( + const matrix_exp& m + ) + { + DLIB_ASSERT(m.size() > 0, + "\tpoint min_point(const matrix_exp& m)" + << "\n\tm can't be empty" + << "\n\tm.size(): " << m.size() + << "\n\tm.nr(): " << m.nr() + << "\n\tm.nc(): " << m.nc() + ); + typedef typename matrix_exp::type type; + + point best_point(0,0); + type val = m(0,0); + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + type temp = m(r,c); + if (dlib::impl::magnitude(temp) < dlib::impl::magnitude(val)) + { + val = temp; + best_point = point(c,r); + } + } + } + return best_point; + } + // ---------------------------------------------------------------------------------------- template < @@ -244,6 +314,188 @@ namespace dlib return val; } +// ---------------------------------------------------------------------------------------- + + template + struct op_binary_min : basic_op_mm + { + op_binary_min( const M1& m1_, const M2& m2_) : basic_op_mm(m1_,m2_){} + + typedef typename M1::type type; + typedef const type const_ret_type; + const static long cost = M1::cost + M2::cost + 1; + + const_ret_type apply ( long r, long c) const + { return std::min(this->m1(r,c),this->m2(r,c)); } + }; + + template < + typename EXP1, + typename EXP2 + > + inline const matrix_op > min_pointwise ( + const matrix_exp& a, + const matrix_exp& b + ) + { + COMPILE_TIME_ASSERT((is_same_type::value == true)); + COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0); + COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0); + DLIB_ASSERT(a.nr() == b.nr() && + a.nc() == b.nc(), + "\t const matrix_exp min_pointwise(const matrix_exp& a, const matrix_exp& b)" + << "\n\ta.nr(): " << a.nr() + << "\n\ta.nc(): " << a.nc() + << "\n\tb.nr(): " << b.nr() + << "\n\tb.nc(): " << b.nc() + ); + typedef op_binary_min op; + return matrix_op(op(a.ref(),b.ref())); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_min_pointwise3 : basic_op_mmm + { + op_min_pointwise3( const M1& m1_, const M2& m2_, const M3& m3_) : + basic_op_mmm(m1_,m2_,m3_){} + + typedef typename M1::type type; + typedef const typename M1::type const_ret_type; + const static long cost = M1::cost + M2::cost + M3::cost + 2; + + const_ret_type apply (long r, long c) const + { return std::min(this->m1(r,c),std::min(this->m2(r,c),this->m3(r,c))); } + }; + + template < + typename EXP1, + typename EXP2, + typename EXP3 + > + inline const matrix_op > + min_pointwise ( + const matrix_exp& a, + const matrix_exp& b, + const matrix_exp& c + ) + { + COMPILE_TIME_ASSERT((is_same_type::value == true)); + COMPILE_TIME_ASSERT((is_same_type::value == true)); + COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0); + COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NR == 0 || EXP2::NC == 0); + COMPILE_TIME_ASSERT(EXP2::NR == EXP3::NR || EXP2::NR == 0 || EXP3::NR == 0); + COMPILE_TIME_ASSERT(EXP2::NC == EXP3::NC || EXP2::NC == 0 || EXP3::NC == 0); + DLIB_ASSERT(a.nr() == b.nr() && + a.nc() == b.nc() && + b.nr() == c.nr() && + b.nc() == c.nc(), + "\tconst matrix_exp min_pointwise(a,b,c)" + << "\n\tYou can only make a do a pointwise min between equally sized matrices" + << "\n\ta.nr(): " << a.nr() + << "\n\ta.nc(): " << a.nc() + << "\n\tb.nr(): " << b.nr() + << "\n\tb.nc(): " << b.nc() + << "\n\tc.nr(): " << c.nr() + << "\n\tc.nc(): " << c.nc() + ); + + typedef op_min_pointwise3 op; + return matrix_op(op(a.ref(),b.ref(),c.ref())); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_binary_max : basic_op_mm + { + op_binary_max( const M1& m1_, const M2& m2_) : basic_op_mm(m1_,m2_){} + + typedef typename M1::type type; + typedef const type const_ret_type; + const static long cost = M1::cost + M2::cost + 1; + + const_ret_type apply ( long r, long c) const + { return std::max(this->m1(r,c),this->m2(r,c)); } + }; + + template < + typename EXP1, + typename EXP2 + > + inline const matrix_op > max_pointwise ( + const matrix_exp& a, + const matrix_exp& b + ) + { + COMPILE_TIME_ASSERT((is_same_type::value == true)); + COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0); + COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0); + DLIB_ASSERT(a.nr() == b.nr() && + a.nc() == b.nc(), + "\t const matrix_exp max_pointwise(const matrix_exp& a, const matrix_exp& b)" + << "\n\ta.nr(): " << a.nr() + << "\n\ta.nc(): " << a.nc() + << "\n\tb.nr(): " << b.nr() + << "\n\tb.nc(): " << b.nc() + ); + typedef op_binary_max op; + return matrix_op(op(a.ref(),b.ref())); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_max_pointwise3 : basic_op_mmm + { + op_max_pointwise3( const M1& m1_, const M2& m2_, const M3& m3_) : + basic_op_mmm(m1_,m2_,m3_){} + + typedef typename M1::type type; + typedef const typename M1::type const_ret_type; + const static long cost = M1::cost + M2::cost + M3::cost + 2; + + const_ret_type apply (long r, long c) const + { return std::max(this->m1(r,c),std::max(this->m2(r,c),this->m3(r,c))); } + }; + + template < + typename EXP1, + typename EXP2, + typename EXP3 + > + inline const matrix_op > + max_pointwise ( + const matrix_exp& a, + const matrix_exp& b, + const matrix_exp& c + ) + { + COMPILE_TIME_ASSERT((is_same_type::value == true)); + COMPILE_TIME_ASSERT((is_same_type::value == true)); + COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0); + COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NR == 0 || EXP2::NC == 0); + COMPILE_TIME_ASSERT(EXP2::NR == EXP3::NR || EXP2::NR == 0 || EXP3::NR == 0); + COMPILE_TIME_ASSERT(EXP2::NC == EXP3::NC || EXP2::NC == 0 || EXP3::NC == 0); + DLIB_ASSERT(a.nr() == b.nr() && + a.nc() == b.nc() && + b.nr() == c.nr() && + b.nc() == c.nc(), + "\tconst matrix_exp max_pointwise(a,b,c)" + << "\n\tYou can only make a do a pointwise max between equally sized matrices" + << "\n\ta.nr(): " << a.nr() + << "\n\ta.nc(): " << a.nc() + << "\n\tb.nr(): " << b.nr() + << "\n\tb.nc(): " << b.nc() + << "\n\tc.nr(): " << c.nr() + << "\n\tc.nc(): " << c.nc() + ); + + typedef op_max_pointwise3 op; + return matrix_op(op(a.ref(),b.ref(),c.ref())); + } + // ---------------------------------------------------------------------------------------- template < @@ -1345,6 +1597,16 @@ namespace dlib return typename matrix_exp::matrix_type (m); } +// ---------------------------------------------------------------------------------------- + + template + constexpr bool is_row_major ( + const matrix_exp& + ) + { + return is_same_type::value; + } + // ---------------------------------------------------------------------------------------- template < @@ -1357,11 +1619,24 @@ namespace dlib typedef typename matrix_exp::type type; type val = 0; - for (long r = 0; r < m.nr(); ++r) + if (is_row_major(m)) + { + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + val += m(r,c); + } + } + } + else { for (long c = 0; c < m.nc(); ++c) { - val += m(r,c); + for (long r = 0; r < m.nr(); ++r) + { + val += m(r,c); + } } } return val; @@ -2503,7 +2778,8 @@ namespace dlib pixel_traits

::grayscale, pixel_traits

::rgb, pixel_traits

::hsi, - pixel_traits

::rgb_alpha + pixel_traits

::rgb_alpha, + pixel_traits

::lab >::value > struct pixel_to_vector_helper; @@ -2567,6 +2843,21 @@ namespace dlib } }; + template + struct pixel_to_vector_helper + { + template + static void assign ( + M& m, + const P& pixel + ) + { + m(0) = static_cast(pixel.l); + m(1) = static_cast(pixel.a); + m(2) = static_cast(pixel.b); + } + }; + template < typename T, @@ -2590,7 +2881,8 @@ namespace dlib pixel_traits

::grayscale, pixel_traits

::rgb, pixel_traits

::hsi, - pixel_traits

::rgb_alpha + pixel_traits

::rgb_alpha, + pixel_traits

::lab >::value > struct vector_to_pixel_helper; @@ -2654,6 +2946,21 @@ namespace dlib } }; + template + struct vector_to_pixel_helper + { + template + static void assign ( + P& pixel, + const M& m + ) + { + pixel.l = static_cast(m(0)); + pixel.a = static_cast(m(1)); + pixel.b = static_cast(m(2)); + } + }; + template < typename P, typename EXP @@ -3951,9 +4258,10 @@ namespace dlib template struct op_join_rows { - op_join_rows(const M1& m1_, const M2& m2_) : m1(m1_),m2(m2_) {} + op_join_rows(const M1& m1_, const M2& m2_) : m1(m1_),m2(m2_),_nr(std::max(m1.nr(),m2.nr())) {} const M1& m1; const M2& m2; + const long _nr; template struct type_selector; @@ -3984,7 +4292,7 @@ namespace dlib return m2(r,c-m1.nc()); } - long nr () const { return m1.nr(); } + long nr () const { return _nr; } long nc () const { return m1.nc()+m2.nc(); } template bool aliases ( const matrix_exp& item) const @@ -4025,9 +4333,10 @@ namespace dlib template struct op_join_cols { - op_join_cols(const M1& m1_, const M2& m2_) : m1(m1_),m2(m2_) {} + op_join_cols(const M1& m1_, const M2& m2_) : m1(m1_),m2(m2_),_nc(std::max(m1.nc(),m2.nc())) {} const M1& m1; const M2& m2; + const long _nc; template struct type_selector; @@ -4061,7 +4370,8 @@ namespace dlib } long nr () const { return m1.nr()+m2.nr(); } - long nc () const { return m1.nc(); } + long nc () const { return _nc; } + template bool aliases ( const matrix_exp& item) const { return m1.aliases(item) || m2.aliases(item); } diff --git a/lib/3rdParty/dlib/include/dlib/matrix/matrix_utilities_abstract.h b/lib/3rdParty/dlib/include/dlib/matrix/matrix_utilities_abstract.h index cd02c03d..ad4c9116 100644 --- a/lib/3rdParty/dlib/include/dlib/matrix/matrix_utilities_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/matrix/matrix_utilities_abstract.h @@ -16,6 +16,17 @@ namespace dlib // ---------------------------------------------------------------------------------------- // Simple matrix utilities // ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template + constexpr bool is_row_major ( + const matrix_exp& + ); + /*! + ensures + - returns true if and only if the given matrix expression uses the row_major_layout. + !*/ + // ---------------------------------------------------------------------------------------- const matrix_exp diag ( @@ -1350,6 +1361,34 @@ namespace dlib according to std::norm(). !*/ +// ---------------------------------------------------------------------------------------- + + const matrix_exp min_pointwise ( + const matrix_exp& a, + const matrix_exp& b + ); + /*! + requires + - a.nr() == b.nr() + - a.nc() == b.nc() + - a and b both contain the same type of element + ensures + - returns a matrix R such that: + - R::type == the same type that was in a and b. + - R has the same dimensions as a and b. + - for all valid r and c: + R(r,c) == std::min(a(r,c), b(r,c)) + !*/ + + const matrix_exp min_pointwise ( + const matrix_exp& a, + const matrix_exp& b, + const matrix_exp& c + ); + /*! + performs min_pointwise(a,min_pointwise(b,c)); + !*/ + // ---------------------------------------------------------------------------------------- const matrix_exp::type max ( @@ -1364,6 +1403,34 @@ namespace dlib according to std::norm(). !*/ +// ---------------------------------------------------------------------------------------- + + const matrix_exp max_pointwise ( + const matrix_exp& a, + const matrix_exp& b + ); + /*! + requires + - a.nr() == b.nr() + - a.nc() == b.nc() + - a and b both contain the same type of element + ensures + - returns a matrix R such that: + - R::type == the same type that was in a and b. + - R has the same dimensions as a and b. + - for all valid r and c: + R(r,c) == std::max(a(r,c), b(r,c)) + !*/ + + const matrix_exp max_pointwise ( + const matrix_exp& a, + const matrix_exp& b, + const matrix_exp& c + ); + /*! + performs max_pointwise(a,max_pointwise(b,c)); + !*/ + // ---------------------------------------------------------------------------------------- void find_min_and_max ( @@ -1409,6 +1476,47 @@ namespace dlib (i.e. m(index_of_min(m)) == min(m)) !*/ +// ---------------------------------------------------------------------------------------- + + point max_point ( + const matrix_exp& m + ); + /*! + requires + - m.size() > 0 + ensures + - returns the location of the maximum element of the array, that is, if the + returned point is P then it will be the case that: m(P.y(),P.x()) == max(m). + !*/ + +// ---------------------------------------------------------------------------------------- + + dlib::vector max_point_interpolated ( + const matrix_exp& m + ); + /*! + requires + - m.size() > 0 + ensures + - Like max_point(), this function finds the location in m with the largest + value. However, we additionally use some quadratic interpolation to find the + location of the maximum point with sub-pixel accuracy. Therefore, the + returned point is equal to max_point(m) + some small sub-pixel delta. + !*/ + +// ---------------------------------------------------------------------------------------- + + point min_point ( + const matrix_exp& m + ); + /*! + requires + - m.size() > 0 + ensures + - returns the location of the minimum element of the array, that is, if the + returned point is P then it will be the case that: m(P.y(),P.x()) == min(m). + !*/ + // ---------------------------------------------------------------------------------------- const matrix_exp::type sum ( @@ -1601,7 +1709,7 @@ namespace dlib typename T, typename P > - const matrix_exp pixel_to_vector ( + const matrix::num,1> pixel_to_vector ( const P& pixel ); /*! diff --git a/lib/3rdParty/dlib/include/dlib/md5/md5_kernel_1.cpp b/lib/3rdParty/dlib/include/dlib/md5/md5_kernel_1.cpp deleted file mode 100644 index f073f925..00000000 --- a/lib/3rdParty/dlib/include/dlib/md5/md5_kernel_1.cpp +++ /dev/null @@ -1,617 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_MD5_KERNEL_1_CPp_ -#define DLIB_MD5_KERNEL_1_CPp_ -#include "md5_kernel_1.h" -#include "../uintn.h" - -#include -#include - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - namespace md5_stuff - { - - inline uint32 F ( - uint32 x, - uint32 y, - uint32 z - ) - { - return ( (x&y) | ((~x)&z) ); - } - - // ------------------------------------------------------------------------------------ - - inline uint32 G ( - uint32 x, - uint32 y, - uint32 z - ) - { - return ( (x&z) | (y&(~z)) ); - } - - // ------------------------------------------------------------------------------------ - - inline uint32 H ( - uint32 x, - uint32 y, - uint32 z - ) - { - return ( x^y^z ); - } - - // ------------------------------------------------------------------------------------ - - inline uint32 I ( - uint32 x, - uint32 y, - uint32 z - ) - { - return ( y ^ (x|(~z)) ); - } - - // ------------------------------------------------------------------------------------ - - inline uint32 rotate_left ( - uint32 x, - uint32 n - ) - { - return ( (x<>(32-n)) ); - } - - // ------------------------------------------------------------------------------------ - - inline void FF ( - uint32& a, - uint32 b, - uint32 c, - uint32 d, - uint32 x, - uint32 s, - uint32 ac - ) - { - a += F(b, c, d) + x + ac; - a = rotate_left(a, s); - a += b; - } - - // ------------------------------------------------------------------------------------ - - inline void GG ( - uint32& a, - uint32 b, - uint32 c, - uint32 d, - uint32 x, - uint32 s, - uint32 ac - ) - { - a += G(b, c, d) + x + ac; - a = rotate_left(a, s); - a += b; - } - - // ------------------------------------------------------------------------------------ - - inline void HH ( - uint32& a, - uint32 b, - uint32 c, - uint32 d, - uint32 x, - uint32 s, - uint32 ac - ) - { - a += H(b, c, d) + x + ac; - a = rotate_left(a, s); - a += b; - } - - // ------------------------------------------------------------------------------------ - - inline void II ( - uint32& a, - uint32 b, - uint32 c, - uint32 d, - uint32 x, - uint32 s, - uint32 ac - ) - { - a += I(b, c, d) + x + ac; - a = rotate_left(a, s); - a += b; - } - - // ------------------------------------------------------------------------------------ - - void scramble_block ( - uint32& a, - uint32& b, - uint32& c, - uint32& d, - uint32* x - ) - { - const uint32 S11 = 7; - const uint32 S12 = 12; - const uint32 S13 = 17; - const uint32 S14 = 22; - const uint32 S21 = 5; - const uint32 S22 = 9; - const uint32 S23 = 14; - const uint32 S24 = 20; - const uint32 S31 = 4; - const uint32 S32 = 11; - const uint32 S33 = 16; - const uint32 S34 = 23; - const uint32 S41 = 6; - const uint32 S42 = 10; - const uint32 S43 = 15; - const uint32 S44 = 21; - - - // round 1 - FF (a, b, c, d, x[ 0], S11, 0xd76aa478); // 1 - FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); // 2 - FF (c, d, a, b, x[ 2], S13, 0x242070db); // 3 - FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); // 4 - FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); // 5 - FF (d, a, b, c, x[ 5], S12, 0x4787c62a); // 6 - FF (c, d, a, b, x[ 6], S13, 0xa8304613); // 7 - FF (b, c, d, a, x[ 7], S14, 0xfd469501); // 8 - FF (a, b, c, d, x[ 8], S11, 0x698098d8); // 9 - FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); // 10 - FF (c, d, a, b, x[10], S13, 0xffff5bb1); // 11 - FF (b, c, d, a, x[11], S14, 0x895cd7be); // 12 - FF (a, b, c, d, x[12], S11, 0x6b901122); // 13 - FF (d, a, b, c, x[13], S12, 0xfd987193); // 14 - FF (c, d, a, b, x[14], S13, 0xa679438e); // 15 - FF (b, c, d, a, x[15], S14, 0x49b40821); // 16 - - // Round 2 - GG (a, b, c, d, x[ 1], S21, 0xf61e2562); // 17 - GG (d, a, b, c, x[ 6], S22, 0xc040b340); // 18 - GG (c, d, a, b, x[11], S23, 0x265e5a51); // 19 - GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); // 20 - GG (a, b, c, d, x[ 5], S21, 0xd62f105d); // 21 - GG (d, a, b, c, x[10], S22, 0x2441453); // 22 - GG (c, d, a, b, x[15], S23, 0xd8a1e681); // 23 - GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); // 24 - GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); // 25 - GG (d, a, b, c, x[14], S22, 0xc33707d6); // 26 - GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); // 27 - GG (b, c, d, a, x[ 8], S24, 0x455a14ed); // 28 - GG (a, b, c, d, x[13], S21, 0xa9e3e905); // 29 - GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); // 30 - GG (c, d, a, b, x[ 7], S23, 0x676f02d9); // 31 - GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); // 32 - - // Round 3 - HH (a, b, c, d, x[ 5], S31, 0xfffa3942); // 33 - HH (d, a, b, c, x[ 8], S32, 0x8771f681); // 34 - HH (c, d, a, b, x[11], S33, 0x6d9d6122); // 35 - HH (b, c, d, a, x[14], S34, 0xfde5380c); // 36 - HH (a, b, c, d, x[ 1], S31, 0xa4beea44); // 37 - HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); // 38 - HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); // 39 - HH (b, c, d, a, x[10], S34, 0xbebfbc70); // 40 - HH (a, b, c, d, x[13], S31, 0x289b7ec6); // 41 - HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); // 42 - HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); // 43 - HH (b, c, d, a, x[ 6], S34, 0x4881d05); // 44 - HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); // 45 - HH (d, a, b, c, x[12], S32, 0xe6db99e5); // 46 - HH (c, d, a, b, x[15], S33, 0x1fa27cf8); // 47 - HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); // 48 - - // Round 4 - II (a, b, c, d, x[ 0], S41, 0xf4292244); // 49 - II (d, a, b, c, x[ 7], S42, 0x432aff97); // 50 - II (c, d, a, b, x[14], S43, 0xab9423a7); // 51 - II (b, c, d, a, x[ 5], S44, 0xfc93a039); // 52 - II (a, b, c, d, x[12], S41, 0x655b59c3); // 53 - II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); // 54 - II (c, d, a, b, x[10], S43, 0xffeff47d); // 55 - II (b, c, d, a, x[ 1], S44, 0x85845dd1); // 56 - II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); // 57 - II (d, a, b, c, x[15], S42, 0xfe2ce6e0); // 58 - II (c, d, a, b, x[ 6], S43, 0xa3014314); // 59 - II (b, c, d, a, x[13], S44, 0x4e0811a1); // 60 - II (a, b, c, d, x[ 4], S41, 0xf7537e82); // 61 - II (d, a, b, c, x[11], S42, 0xbd3af235); // 62 - II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); // 63 - II (b, c, d, a, x[ 9], S44, 0xeb86d391); // 64 - } - - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - - const std::string md5 ( - const std::string& input - ) - { - unsigned char output[16]; - md5 ( - reinterpret_cast(input.data()), - static_cast(input.size()), - output - ); - - - std::stringstream temp; - for (int i = 0; i < 16; ++i) - { - temp.fill('0'); - temp.width(2); - temp << std::hex << static_cast(output[i]); - } - - return temp.str(); - } - -// ---------------------------------------------------------------------------------------- - - void md5 ( - const unsigned char* input, - unsigned long len, - unsigned char* output - ) - { - using namespace md5_stuff; - - - - - // make a temp version of input with enough space for padding and len appended - unsigned long extra_len = 64-len%64; - if (extra_len <= 8) - extra_len += 64; - unsigned char* temp = new unsigned char[extra_len + len]; - - // number of 16 word blocks - const unsigned long N = (extra_len + len)/64; - - const unsigned char* input2 = input; - unsigned char* temp2 = temp; - unsigned char* end = temp+len; - - // copy input into temp - while (temp2 != end) - { - *temp2 = *input2; - ++temp2; - ++input2; - } - - // pad temp - end += extra_len-8; - *temp2 = static_cast(0x80); - ++temp2; - while (temp2 != end) - { - *temp2 = 0; - ++temp2; - } - - // make len the number of bits in the original message - // but first multiply len by 8 and since len is only 32 bits the number might - // overflow so we will carry out the multiplication manually and end up with - // the result in the base 65536 number with three digits - // result = low + high*65536 + upper*65536*65536 - unsigned long low = len & 0xFFFF; - unsigned long high = len >> 16; - unsigned long upper; - unsigned long tmp; - tmp = low * 8; - low = tmp & 0xFFFF; - tmp = high * 8 + (tmp>>16); - high = tmp & 0xFFFF; - upper = tmp >> 16; - - - // append the length - *temp2 = static_cast(low&0xFF); - ++temp2; - *temp2 = static_cast((low>>8)&0xFF); - ++temp2; - *temp2 = static_cast((high)&0xFF); - ++temp2; - *temp2 = static_cast((high>>8)&0xFF); - ++temp2; - *temp2 = static_cast((upper)&0xFF);; - ++temp2; - *temp2 = static_cast((upper>>8)&0xFF);; - ++temp2; - *temp2 = 0; - ++temp2; - *temp2 = 0; - - - uint32 a = 0x67452301; - uint32 b = 0xefcdab89; - uint32 c = 0x98badcfe; - uint32 d = 0x10325476; - - - // an array of 16 words - uint32 x[16]; - - for (unsigned long i = 0; i < N; ++i) - { - - // copy a block of 16 words from m into x - for (unsigned long j = 0; j < 16; ++j) - { - x[j] = ( - (static_cast(temp[4*(j + 16*i) + 3]) << 24) | - (static_cast(temp[4*(j + 16*i) + 2]) << 16) | - (static_cast(temp[4*(j + 16*i) + 1]) << 8 ) | - (static_cast(temp[4*(j + 16*i) ]) ) - ); - } - - uint32 aa = a; - uint32 bb = b; - uint32 cc = c; - uint32 dd = d; - - - scramble_block(a,b,c,d,x); - - - a = a + aa; - b = b + bb; - c = c + cc; - d = d + dd; - - } - - - // put a, b, c, and d into output - output[0] = static_cast((a) &0xFF); - output[1] = static_cast((a>>8) &0xFF); - output[2] = static_cast((a>>16)&0xFF); - output[3] = static_cast((a>>24)&0xFF); - - output[4] = static_cast((b) &0xFF); - output[5] = static_cast((b>>8) &0xFF); - output[6] = static_cast((b>>16)&0xFF); - output[7] = static_cast((b>>24)&0xFF); - - output[8] = static_cast((c) &0xFF); - output[9] = static_cast((c>>8) &0xFF); - output[10] = static_cast((c>>16)&0xFF); - output[11] = static_cast((c>>24)&0xFF); - - output[12] = static_cast((d) &0xFF); - output[13] = static_cast((d>>8) &0xFF); - output[14] = static_cast((d>>16)&0xFF); - output[15] = static_cast((d>>24)&0xFF); - - delete [] temp; - } - -// ---------------------------------------------------------------------------------------- - - const std::string md5 ( - std::istream& input - ) - { - unsigned char output[16]; - md5 ( - input, - output - ); - - - std::stringstream temp; - for (int i = 0; i < 16; ++i) - { - temp.fill('0'); - temp.width(2); - temp << std::hex << static_cast(output[i]); - } - - return temp.str(); - } - -// ---------------------------------------------------------------------------------------- - - void md5 ( - std::istream& input, - unsigned char* output - ) - { - using namespace md5_stuff; - - - - - uint32 a = 0x67452301; - uint32 b = 0xefcdab89; - uint32 c = 0x98badcfe; - uint32 d = 0x10325476; - - - - unsigned long len = 0; - - // an array of 16 words - uint32 x[16]; - unsigned char temp[64]; - - - - bool write_length = false; - bool at_end = false; - std::streambuf& inputbuf = *input.rdbuf(); - while(!at_end) - { - int num = inputbuf.sgetn(reinterpret_cast(temp),64); - len += num; - - // if we hit the end of the stream then pad and add length - if (num < 64) - { - at_end = true; - unsigned char* temp2 = temp; - unsigned char* end; - if (num < 56) - end = temp+56; - else - end = temp+64; - - temp2 += num; - - // apply padding - *temp2 = 0x80; - ++temp2; - while (temp2 != end) - { - *temp2 = 0; - ++temp2; - } - - - if (num < 56) - { - write_length = true; - // make len the number of bits in the original message - // but first multiply len by 8 and since len is only 32 bits the number might - // overflow so we will carry out the multiplication manually and end up with - // the result in the base 65536 number with three digits - // result = low + high*65536 + upper*65536*65536 - unsigned long low = len & 0xFFFF; - unsigned long high = len >> 16; - unsigned long upper; - unsigned long tmp; - tmp = low * 8; - low = tmp & 0xFFFF; - tmp = high * 8 + (tmp>>16); - high = tmp & 0xFFFF; - upper = tmp >> 16; - - - // append the length - *temp2 = static_cast(low&0xFF); - ++temp2; - *temp2 = static_cast((low>>8)&0xFF); - ++temp2; - *temp2 = static_cast((high)&0xFF); - ++temp2; - *temp2 = static_cast((high>>8)&0xFF); - ++temp2; - *temp2 = static_cast((upper)&0xFF);; - ++temp2; - *temp2 = static_cast((upper>>8)&0xFF);; - ++temp2; - *temp2 = 0; - ++temp2; - *temp2 = 0; - } - - - } - - - // copy a block of 16 words from m into x - for (unsigned long i = 0; i < 16; ++i) - { - x[i] = ( - (static_cast(temp[4*i + 3]) << 24) | - (static_cast(temp[4*i + 2]) << 16) | - (static_cast(temp[4*i + 1]) << 8 ) | - (static_cast(temp[4*i ]) ) - ); - } - - - uint32 aa = a; - uint32 bb = b; - uint32 cc = c; - uint32 dd = d; - - - scramble_block(a,b,c,d,x); - - - a = a + aa; - b = b + bb; - c = c + cc; - d = d + dd; - - } - - if (!write_length) - { - uint64 temp = len*8; - - uint32 aa = a; - uint32 bb = b; - uint32 cc = c; - uint32 dd = d; - - std::memset(x, 0, sizeof(x)); - x[15] = (temp>>32); - x[14] = (temp&0xFFFFFFFF); - - scramble_block(a,b,c,d,x); - - - a = a + aa; - b = b + bb; - c = c + cc; - d = d + dd; - - } - - - // put a, b, c, and d into output - output[0] = static_cast((a) &0xFF); - output[1] = static_cast((a>>8) &0xFF); - output[2] = static_cast((a>>16)&0xFF); - output[3] = static_cast((a>>24)&0xFF); - - output[4] = static_cast((b) &0xFF); - output[5] = static_cast((b>>8) &0xFF); - output[6] = static_cast((b>>16)&0xFF); - output[7] = static_cast((b>>24)&0xFF); - - output[8] = static_cast((c) &0xFF); - output[9] = static_cast((c>>8) &0xFF); - output[10] = static_cast((c>>16)&0xFF); - output[11] = static_cast((c>>24)&0xFF); - - output[12] = static_cast((d) &0xFF); - output[13] = static_cast((d>>8) &0xFF); - output[14] = static_cast((d>>16)&0xFF); - output[15] = static_cast((d>>24)&0xFF); - - input.clear(std::ios::eofbit); - } - -// ---------------------------------------------------------------------------------------- - -} -#endif // DLIB_MD5_KERNEL_1_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/memory_manager/memory_manager_kernel_1.h b/lib/3rdParty/dlib/include/dlib/memory_manager/memory_manager_kernel_1.h index 557a19fc..8333aca6 100644 --- a/lib/3rdParty/dlib/include/dlib/memory_manager/memory_manager_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/memory_manager/memory_manager_kernel_1.h @@ -14,7 +14,7 @@ namespace dlib template < typename T, - unsigned long max_pool_size + size_t max_pool_size > class memory_manager_kernel_1 { @@ -86,11 +86,11 @@ namespace dlib } } - unsigned long get_number_of_allocations ( + size_t get_number_of_allocations ( ) const { return allocations; } T* allocate_array ( - unsigned long size + size_t size ) { T* temp = new T[size]; @@ -183,9 +183,9 @@ namespace dlib private: // data members - unsigned long allocations; + size_t allocations; node* next; - unsigned long pool_size; + size_t pool_size; // restricted functions memory_manager_kernel_1(memory_manager_kernel_1&); // copy constructor @@ -231,11 +231,11 @@ namespace dlib { } - unsigned long get_number_of_allocations ( + size_t get_number_of_allocations ( ) const { return allocations; } T* allocate_array ( - unsigned long size + size_t size ) { T* temp = new T[size]; @@ -277,7 +277,7 @@ namespace dlib private: // data members - unsigned long allocations; + size_t allocations; // restricted functions memory_manager_kernel_1(memory_manager_kernel_1&); // copy constructor @@ -288,7 +288,7 @@ namespace dlib template < typename T, - unsigned long max_pool_size + size_t max_pool_size > inline void swap ( memory_manager_kernel_1& a, diff --git a/lib/3rdParty/dlib/include/dlib/memory_manager/memory_manager_kernel_2.h b/lib/3rdParty/dlib/include/dlib/memory_manager/memory_manager_kernel_2.h index 8f026bc4..5134afa7 100644 --- a/lib/3rdParty/dlib/include/dlib/memory_manager/memory_manager_kernel_2.h +++ b/lib/3rdParty/dlib/include/dlib/memory_manager/memory_manager_kernel_2.h @@ -13,7 +13,7 @@ namespace dlib template < typename T, - unsigned long chunk_size + size_t chunk_size > class memory_manager_kernel_2 { @@ -103,11 +103,11 @@ namespace dlib } } - unsigned long get_number_of_allocations ( + size_t get_number_of_allocations ( ) const { return allocations; } T* allocate_array ( - unsigned long size + size_t size ) { T* temp = new T[size]; @@ -184,7 +184,7 @@ namespace dlib ++block; // now add the rest of the block into the linked list of free nodes. - for (unsigned long i = 0; i < chunk_size-1; ++i) + for (size_t i = 0; i < chunk_size-1; ++i) { block->next = next; next = block; @@ -223,7 +223,7 @@ namespace dlib private: // data members - unsigned long allocations; + size_t allocations; node* next; chunk_node* first_chunk; @@ -238,7 +238,7 @@ namespace dlib template < typename T, - unsigned long chunk_size + size_t chunk_size > inline void swap ( memory_manager_kernel_2& a, diff --git a/lib/3rdParty/dlib/include/dlib/memory_manager/memory_manager_kernel_3.h b/lib/3rdParty/dlib/include/dlib/memory_manager/memory_manager_kernel_3.h index 1f922977..4b859904 100644 --- a/lib/3rdParty/dlib/include/dlib/memory_manager/memory_manager_kernel_3.h +++ b/lib/3rdParty/dlib/include/dlib/memory_manager/memory_manager_kernel_3.h @@ -16,7 +16,7 @@ namespace dlib template < typename T, - unsigned long chunk_size + size_t chunk_size > class memory_manager_kernel_3 { @@ -126,11 +126,11 @@ namespace dlib } } - unsigned long get_number_of_allocations ( + size_t get_number_of_allocations ( ) const { return allocations; } T* allocate_array ( - unsigned long size + size_t size ) { size_t block_size = sizeof(T)*size + sizeof(size_t)*2; @@ -252,7 +252,7 @@ namespace dlib ++block; // now add the rest of the block into the linked list of free nodes. - for (unsigned long i = 0; i < chunk_size-1; ++i) + for (size_t i = 0; i < chunk_size-1; ++i) { block->next = next; next = block; @@ -292,7 +292,7 @@ namespace dlib private: // data members - unsigned long allocations; + size_t allocations; node* next; chunk_node* first_chunk; @@ -370,7 +370,7 @@ namespace dlib template < typename T, - unsigned long chunk_size + size_t chunk_size > inline void swap ( memory_manager_kernel_3& a, diff --git a/lib/3rdParty/dlib/include/dlib/memory_manager/memory_manager_kernel_abstract.h b/lib/3rdParty/dlib/include/dlib/memory_manager/memory_manager_kernel_abstract.h index 8439caf8..5269db3b 100644 --- a/lib/3rdParty/dlib/include/dlib/memory_manager/memory_manager_kernel_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/memory_manager/memory_manager_kernel_abstract.h @@ -52,7 +52,7 @@ namespace dlib causes a memory leak. !*/ - unsigned long get_number_of_allocations ( + size_t get_number_of_allocations ( ) const; /*! ensures @@ -86,7 +86,7 @@ namespace dlib !*/ T* allocate_array ( - unsigned long size + size_t size ); /*! ensures diff --git a/lib/3rdParty/dlib/include/dlib/memory_manager_global/memory_manager_global_kernel_1.h b/lib/3rdParty/dlib/include/dlib/memory_manager_global/memory_manager_global_kernel_1.h index 4cf418d2..7c43048d 100644 --- a/lib/3rdParty/dlib/include/dlib/memory_manager_global/memory_manager_global_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/memory_manager_global/memory_manager_global_kernel_1.h @@ -43,7 +43,7 @@ namespace dlib virtual ~memory_manager_global_kernel_1( ) {} - unsigned long get_number_of_allocations ( + size_t get_number_of_allocations ( ) const { return global_mm->get_number_of_allocations(); } mm_global_type& get_global_memory_manager ( @@ -63,7 +63,7 @@ namespace dlib } T* allocate_array ( - unsigned long size + size_t size ) { return global_mm->allocate_array(size); diff --git a/lib/3rdParty/dlib/include/dlib/memory_manager_global/memory_manager_global_kernel_abstract.h b/lib/3rdParty/dlib/include/dlib/memory_manager_global/memory_manager_global_kernel_abstract.h index a35e38b5..20b1c6f2 100644 --- a/lib/3rdParty/dlib/include/dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/memory_manager_global/memory_manager_global_kernel_abstract.h @@ -81,7 +81,7 @@ namespace dlib get_global_memory_manager(). !*/ - unsigned long get_number_of_allocations ( + size_t get_number_of_allocations ( ) const; /*! ensures @@ -122,7 +122,7 @@ namespace dlib !*/ T* allocate_array ( - unsigned long size + size_t size ); /*! ensures diff --git a/lib/3rdParty/dlib/include/dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h b/lib/3rdParty/dlib/include/dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h index 0d5794d5..a99b7f02 100644 --- a/lib/3rdParty/dlib/include/dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h @@ -4,6 +4,7 @@ #define DLIB_MEMORY_MANAGER_STATELESs_1_ #include "memory_manager_stateless_kernel_abstract.h" +#include namespace dlib { @@ -47,7 +48,7 @@ namespace dlib } T* allocate_array ( - unsigned long size + size_t size ) { return new T[size]; @@ -63,6 +64,20 @@ namespace dlib void swap (memory_manager_stateless_kernel_1&) {} + std::unique_ptr extract( + T* item + ) + { + return std::unique_ptr(item); + } + + std::unique_ptr extract_array( + T* item + ) + { + return std::unique_ptr(item); + } + private: // restricted functions diff --git a/lib/3rdParty/dlib/include/dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h b/lib/3rdParty/dlib/include/dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h index 7c4bf76f..7d76f89d 100644 --- a/lib/3rdParty/dlib/include/dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +++ b/lib/3rdParty/dlib/include/dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h @@ -60,7 +60,7 @@ namespace dlib } T* allocate_array ( - unsigned long size + size_t size ) { auto_mutex M(global_mutex()); diff --git a/lib/3rdParty/dlib/include/dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h b/lib/3rdParty/dlib/include/dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h index 2c5b1e73..ffca1865 100644 --- a/lib/3rdParty/dlib/include/dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h @@ -4,6 +4,7 @@ #ifdef DLIB_MEMORY_MANAGER_STATELESs_ABSTRACT_ #include "../algs.h" +#include namespace dlib { @@ -81,7 +82,7 @@ namespace dlib !*/ T* allocate_array ( - unsigned long size + size_t size ); /*! ensures @@ -113,10 +114,40 @@ namespace dlib /*! ensures - this function has no effect on *this or item. It is just provided - to make this object's interface more compatable with the other + to make this object's interface more compatible with the other memory managers. !*/ + std::unique_ptr extract( + T* item + ); + /*! + requires + - item == is a pointer to memory that was obtained from a call to + allocate(). + ensures + - returns a unique_ptr that owns item. That is, if the returned ptr is + PTR then PTR.get() == item. Therefore, this function extracts item + from the memory manager's internal pool. Therefore, you shouldn't + call deallocate(item) after this. + - Note that not all memory managers implement extract(). + !*/ + + std::unique_ptr extract_array( + T* item + ); + /*! + requires + - item == is a pointer to memory that was obtained from a call to + allocate_array(). + ensures + - returns a unique_ptr that owns item. That is, if the returned ptr is + PTR then PTR.get() == item. Therefore, this function extracts item + from the memory manager's internal pool. Therefore, you shouldn't + call deallocate_array(item) after this. + - Note that not all memory managers implement extract(). + !*/ + private: // restricted functions diff --git a/lib/3rdParty/dlib/include/dlib/metaprogramming.h b/lib/3rdParty/dlib/include/dlib/metaprogramming.h new file mode 100644 index 00000000..bc63041f --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/metaprogramming.h @@ -0,0 +1,71 @@ +// Copyright (C) 2017 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_METApROGRAMMING_Hh_ +#define DLIB_METApROGRAMMING_Hh_ + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template + struct compile_time_integer_list + { + /*! + WHAT THIS OBJECT REPRESENTS + The point of this type is to, as the name suggests, hold a compile time list of integers. + As an example, here is something simple you could do with it: + + template + void print_compile_time_ints ( + compile_time_integer_list + ) + { + print(ints...); + } + + int main() + { + print_compile_time_ints(compile_time_integer_list<0,4,9>()); + } + + Which just calls: print(0,4,9); + + This is a simple example, but this kind of thing is useful in larger and + more complex template metaprogramming constructs. + !*/ + + template + struct push_back + { + typedef compile_time_integer_list type; + }; + }; + +// ---------------------------------------------------------------------------------------- + + template + struct make_compile_time_integer_range + { + /*! + WHAT THIS OBJECT REPRESENTS + This object makes a compile_time_integer_list containing the integers in the range [1,max] inclusive. + For example: + make_compile_time_integer_range<4>::type + evaluates to: + compile_time_integer_list<1,2,3,4> + !*/ + + typedef typename make_compile_time_integer_range::type::template push_back::type type; + }; + // base case + template <> struct make_compile_time_integer_range<0> { typedef compile_time_integer_list<> type; }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_METApROGRAMMING_Hh_ + + diff --git a/lib/3rdParty/dlib/include/dlib/misc_api/misc_api_kernel_1.cpp b/lib/3rdParty/dlib/include/dlib/misc_api/misc_api_kernel_1.cpp deleted file mode 100644 index 9ca50945..00000000 --- a/lib/3rdParty/dlib/include/dlib/misc_api/misc_api_kernel_1.cpp +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (C) 2004 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_MISC_API_KERNEL_1_CPp_ -#define DLIB_MISC_API_KERNEL_1_CPp_ - -#include "../platform.h" -#include "../threads.h" - -#ifdef WIN32 - -#include "misc_api_kernel_1.h" - -#include "../windows_magic.h" -#include - -#ifdef __BORLANDC__ -// Apparently the borland compiler doesn't define this. -#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) -#endif - -namespace dlib -{ -// ---------------------------------------------------------------------------------------- - - void sleep ( - unsigned long milliseconds - ) - { - ::Sleep(milliseconds); - } - -// ---------------------------------------------------------------------------------------- - - namespace - { - mutex& cwd_mutex() - { - static mutex m; - return m; - } - // Make sure the above mutex gets constructed before main() - // starts. This way we can be pretty sure it will be constructed - // before any threads could possibly call set_current_dir() or - // get_current_dir() simultaneously. - struct construct_cwd_mutex - { - construct_cwd_mutex() - { - cwd_mutex(); - } - } oaimvweoinvwe; - } - - std::string get_current_dir ( - ) - { - // need to lock a mutex here because getting and setting the - // current working directory is not thread safe on windows. - auto_mutex lock(cwd_mutex()); - char buf[1024]; - if (GetCurrentDirectoryA(sizeof(buf),buf) == 0) - { - return std::string(); - } - else - { - return std::string(buf); - } - } - -// ---------------------------------------------------------------------------------------- - - void set_current_dir ( - const std::string& new_dir - ) - { - // need to lock a mutex here because getting and setting the - // current working directory is not thread safe on windows. - auto_mutex lock(cwd_mutex()); - if (SetCurrentDirectoryA(new_dir.c_str()) == 0) - { - throw set_current_dir_error("Error changing current dir to '" + new_dir + "'"); - } - } - -// ---------------------------------------------------------------------------------------- - - uint64 timestamper:: - get_timestamp ( - ) const - { - unsigned long temp = GetTickCount(); - if (temp >= last_time) - { - last_time = temp; - return (offset + temp)*1000; - } - else - { - last_time = temp; - - // there was overflow since the last call so we need to make the offset - // bigger to account for that - offset += dword_max; - return (offset + temp)*1000; - } - } - -// ---------------------------------------------------------------------------------------- - - void create_directory ( - const std::string& dir - ) - { - if (CreateDirectoryA(dir.c_str(),0) == 0) - { - // an error has occurred - if (GetLastError() == ERROR_ALREADY_EXISTS) - { - // make sure this is actually a directory - DWORD attribs = GetFileAttributesA(dir.c_str()); - if (attribs == INVALID_FILE_ATTRIBUTES || - (attribs&FILE_ATTRIBUTE_DIRECTORY) == 0) - { - // it isn't a directory - throw dir_create_error(dir); - } - } - else - { - throw dir_create_error(dir); - } - } - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // WIN32 - -#endif // DLIB_MISC_API_KERNEL_1_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/misc_api/misc_api_kernel_2.cpp b/lib/3rdParty/dlib/include/dlib/misc_api/misc_api_kernel_2.cpp deleted file mode 100644 index e6dc772d..00000000 --- a/lib/3rdParty/dlib/include/dlib/misc_api/misc_api_kernel_2.cpp +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (C) 2004 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_MISC_API_KERNEL_2_CPp_ -#define DLIB_MISC_API_KERNEL_2_CPp_ -#include "../platform.h" - -#ifdef POSIX - -#include -#include "misc_api_kernel_2.h" -#include -#include -#include -#include - -namespace dlib -{ -// ---------------------------------------------------------------------------------------- - - void sleep ( - unsigned long milliseconds - ) - { - // in HP-UX you can only usleep for less than a second -#ifdef HPUX - if (milliseconds >= 1000) - { - ::sleep(milliseconds/1000); - unsigned long remaining = milliseconds%1000; - if (remaining > 0) - ::usleep(remaining*1000); - } - else - { - ::usleep(milliseconds*1000); - } -#else - ::usleep(milliseconds*1000); -#endif - } - -// ---------------------------------------------------------------------------------------- - - std::string get_current_dir ( - ) - { - char buf[1024]; - if (getcwd(buf,sizeof(buf)) == 0) - { - return std::string(); - } - else - { - return std::string(buf); - } - } - -// ---------------------------------------------------------------------------------------- - - void set_current_dir ( - const std::string& new_dir - ) - { - if (chdir(new_dir.c_str())) - { - throw set_current_dir_error("Error changing current dir to '" + new_dir + "'"); - } - } - -// ---------------------------------------------------------------------------------------- - - uint64 timestamper:: - get_timestamp ( - ) const - { - uint64 ts; - timeval curtime; - gettimeofday(&curtime,0); - - ts = curtime.tv_sec; - ts *= 1000000; - ts += curtime.tv_usec; - return ts; - } - -// ---------------------------------------------------------------------------------------- - - void create_directory ( - const std::string& dir - ) - { - if (mkdir(dir.c_str(),0777)) - { - // an error has occurred - if (errno == EEXIST) - { - struct stat buffer; - // now check that this is actually a valid directory - if (::stat(dir.c_str(),&buffer)) - { - // the directory was not found - throw dir_create_error(dir); - } - else if (S_ISDIR(buffer.st_mode) == 0) - { - // It is not a directory - throw dir_create_error(dir); - } - } - else - { - throw dir_create_error(dir); - } - } - } - -// ---------------------------------------------------------------------------------------- -} - -#endif // POSIX - -#endif // DLIB_MISC_API_KERNEL_2_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/misc_api/misc_api_kernel_abstract.h b/lib/3rdParty/dlib/include/dlib/misc_api/misc_api_kernel_abstract.h index 103aa661..47749b91 100644 --- a/lib/3rdParty/dlib/include/dlib/misc_api/misc_api_kernel_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/misc_api/misc_api_kernel_abstract.h @@ -90,7 +90,16 @@ namespace dlib ); /*! ensures - - calls set_current_dir(old_dir()) + - if (revert() hasn't already been called) then + - calls set_current_dir(old_dir()) + !*/ + + void revert ( + ); + /*! + ensures + - if (revert() hasn't already been called) then + - calls set_current_dir(old_dir()) !*/ }; diff --git a/lib/3rdParty/dlib/include/dlib/misc_api/misc_api_shared.h b/lib/3rdParty/dlib/include/dlib/misc_api/misc_api_shared.h index 79af1a84..6b84dd64 100644 --- a/lib/3rdParty/dlib/include/dlib/misc_api/misc_api_shared.h +++ b/lib/3rdParty/dlib/include/dlib/misc_api/misc_api_shared.h @@ -18,13 +18,14 @@ namespace dlib const std::string& new_dir ) { + reverted = false; _old_dir = get_current_dir(); set_current_dir(new_dir); } ~locally_change_current_dir() { - set_current_dir(_old_dir); + revert(); } const std::string& old_dir ( @@ -33,7 +34,18 @@ namespace dlib return _old_dir; } + void revert ( + ) + { + if (!reverted) + { + set_current_dir(_old_dir); + reverted = true; + } + } + private: + bool reverted; std::string _old_dir; }; diff --git a/lib/3rdParty/dlib/include/dlib/noncopyable.h b/lib/3rdParty/dlib/include/dlib/noncopyable.h index b620d572..20b9866e 100644 --- a/lib/3rdParty/dlib/include/dlib/noncopyable.h +++ b/lib/3rdParty/dlib/include/dlib/noncopyable.h @@ -19,8 +19,8 @@ namespace dlib !*/ protected: - noncopyable() {} - ~noncopyable() {} + noncopyable() = default; + ~noncopyable() = default; private: // emphasize the following members are private noncopyable(const noncopyable&); const noncopyable& operator=(const noncopyable&); @@ -28,4 +28,5 @@ namespace dlib }; } -#endif // DLIB_BOOST_NONCOPYABLE_HPP_INCLUDED \ No newline at end of file +#endif // DLIB_BOOST_NONCOPYABLE_HPP_INCLUDED + diff --git a/lib/3rdParty/dlib/include/dlib/opencv.h b/lib/3rdParty/dlib/include/dlib/opencv.h index 14041079..c48a6ec5 100644 --- a/lib/3rdParty/dlib/include/dlib/opencv.h +++ b/lib/3rdParty/dlib/include/dlib/opencv.h @@ -1,5 +1,9 @@ // Copyright (C) 2009 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. +#ifdef DLIB_ALL_SOURCE_END +#include "dlib_basic_cpp_build_tutorial.txt" +#endif + #ifndef DLIB_OPEnCV_HEADER #define DLIB_OPEnCV_HEADER diff --git a/lib/3rdParty/dlib/include/dlib/opencv/cv_image.h b/lib/3rdParty/dlib/include/dlib/opencv/cv_image.h index 632dae07..5f224d00 100644 --- a/lib/3rdParty/dlib/include/dlib/opencv/cv_image.h +++ b/lib/3rdParty/dlib/include/dlib/opencv/cv_image.h @@ -3,6 +3,8 @@ #ifndef DLIB_CvIMAGE_H_ #define DLIB_CvIMAGE_H_ +#include +#include #include "cv_image_abstract.h" #include "../algs.h" #include "../pixel.h" @@ -23,11 +25,15 @@ namespace dlib cv_image (const cv::Mat img) { - assert(img.depth() == cv::DataType::basic_pixel_type>::depth && - img.channels() == pixel_traits::num); - //DLIB_CASSERT(img.depth() == cv::DataType::basic_pixel_type>::depth && - // img.channels() == pixel_traits::num, - // "The pixel type you gave doesn't match pixel used by the open cv Mat object."); + DLIB_CASSERT(img.depth() == cv::DataType::basic_pixel_type>::depth && + img.channels() == pixel_traits::num, + "The pixel type you gave doesn't match pixel used by the open cv Mat object." + << "\n\t img.depth(): " << img.depth() + << "\n\t img.cv::DataType::basic_pixel_type>::depth: " + << cv::DataType::basic_pixel_type>::depth + << "\n\t img.channels(): " << img.channels() + << "\n\t img.pixel_traits::num: " << pixel_traits::num + ); IplImage temp = img; init(&temp); } @@ -44,7 +50,7 @@ namespace dlib cv_image() : _data(0), _widthStep(0), _nr(0), _nc(0) {} - unsigned long size () const { return static_cast(_nr*_nc); } + size_t size () const { return static_cast(_nr*_nc); } inline pixel_type* operator[](const long row ) { @@ -74,6 +80,32 @@ namespace dlib return reinterpret_cast( _data + _widthStep*row); } + inline const pixel_type& operator()(const long row, const long column) const + { + DLIB_ASSERT(0<= column && column < nc(), + "\tcont pixel_type& cv_image::operator()(const long rown const long column)" + << "\n\t you have asked for an out of bounds column " + << "\n\t column: " << column + << "\n\t nc(): " << nc() + << "\n\t this: " << this + ); + + return (*this)[row][column]; + } + + inline pixel_type& operator()(const long row, const long column) + { + DLIB_ASSERT(0<= column && column < nc(), + "\tcont pixel_type& cv_image::operator()(const long rown const long column)" + << "\n\t you have asked for an out of bounds column " + << "\n\t column: " << column + << "\n\t nc(): " << nc() + << "\n\t this: " << this + ); + + return (*this)[row][column]; + } + long nr() const { return _nr; } long nc() const { return _nc; } long width_step() const { return _widthStep; } diff --git a/lib/3rdParty/dlib/include/dlib/opencv/cv_image_abstract.h b/lib/3rdParty/dlib/include/dlib/opencv/cv_image_abstract.h index f395fe45..6fbc56b4 100644 --- a/lib/3rdParty/dlib/include/dlib/opencv/cv_image_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/opencv/cv_image_abstract.h @@ -3,6 +3,8 @@ #undef DLIB_OPENCV_IMAGE_AbSTRACT_H_ #ifdef DLIB_OPENCV_IMAGE_AbSTRACT_H_ +#include +#include #include "../algs.h" #include "../pixel.h" @@ -125,7 +127,7 @@ namespace dlib - returns the number of columns in this image !*/ - unsigned long size ( + size_t size ( ) const; /*! ensures @@ -155,6 +157,30 @@ namespace dlib of this image !*/ + inline const pixel_type& operator()( + const long row, const long column + ) const + /*! + requires + - 0 <= row < nr() + - 0 <= column < nc() + ensures + - returns a const reference to the pixel at coordinates (row, column) + of this image + !*/ + + inline pixel_type& operator()( + const long row, const long column + ) + /*! + requires + - 0 <= row < nr() + - 0 <= column < nc() + ensures + - returns a reference to the pixel at coordinates (row, column) + of this image + !*/ + cv_image& operator= ( const cv_image& item ); diff --git a/lib/3rdParty/dlib/include/dlib/opencv/to_open_cv.h b/lib/3rdParty/dlib/include/dlib/opencv/to_open_cv.h index bcd9c753..02b7bf6f 100644 --- a/lib/3rdParty/dlib/include/dlib/opencv/to_open_cv.h +++ b/lib/3rdParty/dlib/include/dlib/opencv/to_open_cv.h @@ -3,6 +3,7 @@ #ifndef DLIB_TO_OPEN_Cv_Hh_ #define DLIB_TO_OPEN_Cv_Hh_ +#include #include "to_open_cv_abstract.h" #include "../pixel.h" #include "../matrix/matrix.h" @@ -23,9 +24,10 @@ namespace dlib return cv::Mat(); typedef typename image_traits::pixel_type type; + typedef typename pixel_traits::basic_pixel_type basic_pixel_type; if (pixel_traits::num == 1) { - return cv::Mat(num_rows(img), num_columns(img), cv::DataType::type, image_data(img), width_step(img)); + return cv::Mat(num_rows(img), num_columns(img), cv::DataType::type, image_data(img), width_step(img)); } else { diff --git a/lib/3rdParty/dlib/include/dlib/opencv/to_open_cv_abstract.h b/lib/3rdParty/dlib/include/dlib/opencv/to_open_cv_abstract.h index 0b33ada7..43307e02 100644 --- a/lib/3rdParty/dlib/include/dlib/opencv/to_open_cv_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/opencv/to_open_cv_abstract.h @@ -3,6 +3,7 @@ #undef DLIB_TO_OPEN_Cv_ABSTRACTh_ #ifdef DLIB_TO_OPEN_Cv_ABSTRACTh_ +#include #include "../pixel.h" namespace dlib diff --git a/lib/3rdParty/dlib/include/dlib/optimization.h b/lib/3rdParty/dlib/include/dlib/optimization.h index 9c80ba75..260eacc1 100644 --- a/lib/3rdParty/dlib/include/dlib/optimization.h +++ b/lib/3rdParty/dlib/include/dlib/optimization.h @@ -16,6 +16,7 @@ #include "optimization/find_max_factor_graph_nmplp.h" #include "optimization/find_max_factor_graph_viterbi.h" #include "optimization/find_max_parse_cky.h" +#include "optimization/isotonic_regression.h" #endif // DLIB_OPTIMIZATIOn_HEADER diff --git a/lib/3rdParty/dlib/include/dlib/optimization/elastic_net.h b/lib/3rdParty/dlib/include/dlib/optimization/elastic_net.h new file mode 100644 index 00000000..6c4b6d0b --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/optimization/elastic_net.h @@ -0,0 +1,389 @@ +// Copyright (C) 2016 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ElASTIC_NET_Hh_ +#define DLIB_ElASTIC_NET_Hh_ + +#include "../matrix.h" +#include "elastic_net_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class elastic_net + { + public: + + template + explicit elastic_net( + const matrix_exp& XX + ) : eps(1e-5), max_iterations(50000), verbose(false) + { + // make sure requires clause is not broken + DLIB_ASSERT(XX.size() > 0 && + XX.nr() == XX.nc(), + "\t elastic_net::elastic_net(XX)" + << " \n\t XX must be a non-empty square matrix." + << " \n\t XX.nr(): " << XX.nr() + << " \n\t XX.nc(): " << XX.nc() + << " \n\t this: " << this + ); + + + // If the number of columns in X is big and in particular bigger than the number of + // rows then we can get rid of them by doing some SVD magic. Doing this doesn't + // make the final results of anything change but makes all the matrices have + // dimensions that are X.nr() in size, which can be much smaller. + matrix s; + svd3(XX,u,eig_vals,eig_vects); + s = sqrt(eig_vals); + X = eig_vects*diagm(s); + u = eig_vects*inv(diagm(s)); + + + + samples.resize(X.nr()*2); + + for (size_t i = 0; i < samples.size(); ++i) + index.push_back(i); + active_size = index.size(); + + + // setup the training samples used in the SVM optimizer below + for (size_t i = 0; i < samples.size(); ++i) + { + auto& x = samples[i]; + const long idx = i/2; + if (i%2 == 0) + x.label = +1; + else + x.label = -1; + + x.r = idx%X.nr(); + } + } + + template + elastic_net( + const matrix_exp& XX, + const matrix_exp& XY + ) : elastic_net(XX) + { + // make sure requires clause is not broken + DLIB_ASSERT(XX.size() > 0 && + XX.nr() == XX.nc() && + is_col_vector(XY) && + XX.nc() == XY.size() , + "\t elastic_net::elastic_net(XX,XY)" + << " \n\t Invalid inputs were given to this function." + << " \n\t XX.size(): " << XX.size() + << " \n\t is_col_vector(XY): " << is_col_vector(XY) + << " \n\t XX.nr(): " << XX.nr() + << " \n\t XX.nc(): " << XX.nc() + << " \n\t XY.size(): " << XY.size() + << " \n\t this: " << this + ); + + set_xy(XY); + } + + long size ( + ) const { return u.nr(); } + + template + void set_xy( + const matrix_exp& XY + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(is_col_vector(XY) && + XY.size() == size(), + "\t void elastic_net::set_y(Y)" + << " \n\t Invalid inputs were given to this function." + << " \n\t is_col_vector(XY): " << is_col_vector(XY) + << " \n\t size(): " << size() + << " \n\t XY.size(): " << XY.size() + << " \n\t this: " << this + ); + + Y = trans(u)*XY; + // We can use the ynorm after it has been projected because the only place Y + // appears in the algorithm is in terms of dot products with w and x vectors. + // But those vectors are always in the span of X and therefore we only see the + // part of the norm of Y that is in the span of X (and hence u since u and X + // have the same span by construction) + ynorm = length_squared(Y); + xdoty = X*Y; + eig_vects_xdoty = trans(eig_vects)*xdoty; + + w.set_size(Y.size()); + // zero out any memory of previous solutions + alpha.assign(X.nr()*2, 0); + } + + bool have_target_values ( + ) const { return Y.size() != 0; } + + void set_epsilon( + double eps_ + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(eps_ > 0, + "\t void elastic_net::set_epsilon()" + << " \n\t eps_ must be greater than 0" + << " \n\t eps_: " << eps_ + << " \n\t this: " << this + ); + + eps = eps_; + } + + unsigned long get_max_iterations ( + ) const { return max_iterations; } + + void set_max_iterations ( + unsigned long max_iter + ) + { + max_iterations = max_iter; + } + + void be_verbose ( + ) + { + verbose = true; + } + + void be_quiet ( + ) + { + verbose = false; + } + + double get_epsilon ( + ) const { return eps; } + + matrix operator() ( + double ridge_lambda, + double lasso_budget = std::numeric_limits::infinity() + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(have_target_values() && + ridge_lambda > 0 && + lasso_budget > 0 , + "\t matrix elastic_net::operator()()" + << " \n\t Invalid inputs were given to this function." + << " \n\t have_target_values(): " << have_target_values() + << " \n\t ridge_lambda: " << ridge_lambda + << " \n\t lasso_budget: " << lasso_budget + << " \n\t this: " << this + ); + + + // First check if lasso_budget is so big that it isn't even active. We do this + // by doing just ridge regression and checking the result. + matrix betas = eig_vects*tmp(inv(diagm(eig_vals + ridge_lambda))*eig_vects_xdoty); + if (sum(abs(betas)) <= lasso_budget) + return betas; + + + // Set w back to 0. We will compute the w corresponding to what is currently + // in alpha layer on. This way w and alpha are always in sync. + w = 0; + wy_mult = 0; + wdoty = 0; + + + // return dot(w,x) + auto dot = [&](const matrix& w, const en_sample2& x) + { + const double xmul = -x.label*(1/lasso_budget); + // Do the base dot product but don't forget to add in the -(1/t)*y part from the svm reduction paper + double val = rowm(X,x.r)*w + xmul*wdoty + wy_mult*xdoty(x.r) + xmul*wy_mult*ynorm; + + return val; + }; + + + // perform w += scale*x; + auto add_to = [&](matrix& w, double scale, const en_sample2& x) + { + const double xmul = -x.label*(1/lasso_budget); + wy_mult += scale*xmul; + wdoty += scale*xdoty(x.r); + w += scale*trans(rowm(X,x.r)); + + }; + + const double Dii = ridge_lambda; + + // setup the training samples used in the SVM optimizer below + for (size_t i = 0; i < samples.size(); ++i) + { + auto& x = samples[i]; + + const double xmul = -x.label*(1/lasso_budget); + x.xdotx = xmul*xmul*ynorm; + for (long c = 0; c < X.nc(); ++c) + x.xdotx += std::pow(X(x.r,c)+xmul*Y(c), 2.0) - std::pow(xmul*Y(c),2.0); + + // compute the correct w given whatever might be in alpha. + if (alpha[i] != 0) + add_to(w, x.label*alpha[i], samples[i]); + } + + + // Now run the optimizer + double PG_max_prev = std::numeric_limits::infinity(); + double PG_min_prev = -std::numeric_limits::infinity(); + + + unsigned int iter; + for (iter = 0; iter < max_iterations; ++iter) + { + // randomly shuffle the indices + for (unsigned long i = 0; i < active_size; ++i) + { + // pick a random index >= i + const long j = i + rnd.get_random_32bit_number()%(active_size-i); + std::swap(index[i], index[j]); + } + + double PG_max = -std::numeric_limits::infinity(); + double PG_min = std::numeric_limits::infinity(); + for (size_t ii = 0; ii < active_size; ++ii) + { + const auto i = index[ii]; + const auto& x = samples[i]; + double G = x.label*dot(w, x) - 1 + Dii*alpha[i]; + + double PG = 0; + if (alpha[i] == 0) + { + if (G > PG_max_prev) + { + // shrink the active set of training examples + --active_size; + std::swap(index[ii], index[active_size]); + --ii; + continue; + } + + if (G < 0) + PG = G; + } + else + { + PG = G; + } + + if (PG > PG_max) + PG_max = PG; + if (PG < PG_min) + PG_min = PG; + + // if PG != 0 + if (std::abs(PG) > 1e-12) + { + const double alpha_old = alpha[i]; + alpha[i] = std::max(alpha[i] - G/(x.xdotx+Dii), (double)0.0); + const double delta = (alpha[i]-alpha_old)*x.label; + add_to(w, delta, x); + } + } + + if (verbose) + { + using namespace std; + cout << "gap: " << PG_max - PG_min << endl; + cout << "active_size: " << active_size << endl; + cout << "iter: " << iter << endl; + cout << endl; + } + + if (PG_max - PG_min <= eps) + { + // stop if we are within eps tolerance and the last iteration + // was over all the samples + if (active_size == index.size()) + break; + + // Turn off shrinking on the next iteration. We will stop if the + // tolerance is still <= eps when shrinking is off. + active_size = index.size(); + PG_max_prev = std::numeric_limits::infinity(); + PG_min_prev = -std::numeric_limits::infinity(); + } + else + { + PG_max_prev = PG_max; + PG_min_prev = PG_min; + if (PG_max_prev <= 0) + PG_max_prev = std::numeric_limits::infinity(); + if (PG_min_prev >= 0) + PG_min_prev = -std::numeric_limits::infinity(); + } + + + // recalculate wdoty every so often to avoid drift. + if (iter%100 == 0) + wdoty = dlib::dot(Y, w); + } + + + betas.set_size(alpha.size()/2); + for (long i = 0; i < betas.size(); ++i) + betas(i) = lasso_budget*(alpha[2*i] - alpha[2*i+1]); + betas /= sum(mat(alpha)); + return betas; + } + + + private: + + struct en_sample2 + { + // X location + long r; + + + double label; + + double xdotx; + }; + + std::vector samples; + std::vector alpha; + double ynorm; + matrix X; + matrix Y; + matrix xdoty; + double wdoty; + double wy_mult; // logically, the real w is what is in the w vector + wy_mult*Y + matrix w; + std::vector index; + unsigned long active_size; + + matrix eig_vects_xdoty; + matrix eig_vals; + matrix eig_vects; + matrix u; + + dlib::rand rnd; + + + double eps; + unsigned long max_iterations; + bool verbose; + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ElASTIC_NET_Hh_ + + diff --git a/lib/3rdParty/dlib/include/dlib/optimization/elastic_net_abstract.h b/lib/3rdParty/dlib/include/dlib/optimization/elastic_net_abstract.h new file mode 100644 index 00000000..8ae69e37 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/optimization/elastic_net_abstract.h @@ -0,0 +1,190 @@ +// Copyright (C) 2016 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_ElASTIC_NET_ABSTRACT_Hh_ +#ifdef DLIB_ElASTIC_NET_ABSTRACT_Hh_ + +#include "../matrix.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class elastic_net + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a tool for solving the following optimization problem: + + min_w: length_squared(X*w - Y) + ridge_lambda*length_squared(w) + such that: sum(abs(w)) <= lasso_budget + + That is, it solves the elastic net optimization problem. This object also + has the special property that you can quickly obtain different solutions + for different settings of ridge_lambda, lasso_budget, and target Y values. + + This is because a large amount of work is precomputed in the constructor. + The solver will also remember the previous solution and will use that to + warm start subsequent invocations. Therefore, you can efficiently get + solutions for a wide range of regularization parameters. + + + The particular algorithm used to solve it is described in the paper: + Zhou, Quan, et al. "A reduction of the elastic net to support vector + machines with an application to gpu computing." arXiv preprint + arXiv:1409.1976 (2014). APA + + And for the SVM solver sub-component we use the algorithm from: + Hsieh, Cho-Jui, et al. "A dual coordinate descent method for large-scale + linear SVM." Proceedings of the 25th international conference on Machine + learning. ACM, 2008. + !*/ + + public: + + template + explicit elastic_net( + const matrix_exp& XX + ); + /*! + requires + - XX.size() != 0 + - XX.nr() == XX.nc() + ensures + - #get_epsilon() == 1e-5 + - #get_max_iterations() == 50000 + - This object will not be verbose unless be_verbose() is called. + - #size() == XX.nc() + - #have_target_values() == false + - We interpret XX as trans(X)*X where X is as defined in the objective + function discussed above in WHAT THIS OBJECT REPRESENTS. + !*/ + + template + elastic_net( + const matrix_exp& XX, + const matrix_exp& XY + ); + /*! + requires + - XX.size() != 0 + - XX.nr() == XX.nc() + - is_col_vector(XY) + - XX.nc() == Y.size() + ensures + - constructs this object by calling the elastic_net(XX) constructor and + then calling this->set_xy(XY). + - #have_target_values() == true + - We interpret XX as trans(X)*X where X is as defined in the objective + function discussed above in WHAT THIS OBJECT REPRESENTS. Similarly, XY + should be trans(X)*Y. + !*/ + + long size ( + ) const; + /*! + ensures + - returns the dimensionality of the data loaded into this object. That is, + how many elements are in the optimal w vector? This function returns + that number. + !*/ + + bool have_target_values ( + ) const; + /*! + ensures + - returns true if set_xy() has been called and false otherwise. + !*/ + + template + void set_xy( + const matrix_exp& XY + ); + /*! + requires + - is_col_vector(Y) + - Y.size() == size() + ensures + - #have_target_values() == true + - Sets the target values of the regression. Note that we expect the given + matrix, XY, to be equal to trans(X)*Y, where X and Y have the definitions + discussed above in WHAT THIS OBJECT REPRESENTS. + !*/ + + void set_epsilon( + double eps + ); + /*! + requires + - eps > 0 + ensures + - #get_epsilon() == eps + !*/ + + double get_epsilon ( + ) const; + /*! + ensures + - returns the error epsilon that determines when the solver should stop. + Smaller values may result in a more accurate solution but take longer to + execute. + !*/ + + unsigned long get_max_iterations ( + ) const; + /*! + ensures + - returns the maximum number of iterations the optimizer is allowed to run + before it is required to stop and return a result. + !*/ + + void set_max_iterations ( + unsigned long max_iter + ); + /*! + ensures + - #get_max_iterations() == max_iter + !*/ + + void be_verbose ( + ); + /*! + ensures + - This object will print status messages to standard out so that a + user can observe the progress of the algorithm. + !*/ + + void be_quiet ( + ); + /*! + ensures + - this object will not print anything to standard out. + !*/ + + + matrix operator() ( + double ridge_lambda, + double lasso_budget = std::numeric_limits::infinity() + ); + /*! + requires + - have_target_values() == true + - ridge_lambda > 0 + - lasso_budget > 0 + ensures + - Solves the optimization problem described in the WHAT THIS OBJECT + REPRESENTS section above and returns the optimal w. + - The returned vector has size() elements. + - if (lasso_budget == infinity) then + - The lasso constraint is ignored + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ElASTIC_NET_ABSTRACT_Hh_ + + diff --git a/lib/3rdParty/dlib/include/dlib/optimization/find_optimal_parameters.h b/lib/3rdParty/dlib/include/dlib/optimization/find_optimal_parameters.h new file mode 100644 index 00000000..0884778c --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/optimization/find_optimal_parameters.h @@ -0,0 +1,117 @@ +// Copyright (C) 2016 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_fIND_OPTIMAL_PARAMETERS_Hh_ +#define DLIB_fIND_OPTIMAL_PARAMETERS_Hh_ + +#include "../matrix.h" +#include "find_optimal_parameters_abstract.h" +#include "optimization_bobyqa.h" +#include "optimization_line_search.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + double find_optimal_parameters ( + double initial_search_radius, + double eps, + const unsigned int max_f_evals, + matrix& x, + const matrix& x_lower, + const matrix& x_upper, + const funct& f + ) + { + DLIB_CASSERT(x.size() == x_lower.size() && x_lower.size() == x_upper.size() && x.size() > 0, + "\t double find_optimal_parameters()" + << "\n\t x.size(): " << x.size() + << "\n\t x_lower.size(): " << x_lower.size() + << "\n\t x_upper.size(): " << x_upper.size() + ); + + // check the requirements. Also split the assert up so that the error message isn't huge. + DLIB_CASSERT(max_f_evals > 1 && eps > 0 && initial_search_radius > eps, + "\t double find_optimal_parameters()" + << "\n\t Invalid arguments have been given to this function" + << "\n\t initial_search_radius: " << initial_search_radius + << "\n\t eps: " << eps + << "\n\t max_f_evals: " << max_f_evals + ); + + DLIB_CASSERT( min(x_upper - x_lower) > 0 && + min(x - x_lower) >= 0 && min(x_upper - x) >= 0, + "\t double find_optimal_parameters()" + << "\n\t The bounds constraints have to make sense and also contain the starting point." + << "\n\t min(x_upper - x_lower): " << min(x_upper - x_lower) + << "\n\t min(x - x_lower) >= 0 && min(x_upper - x) >= 0: " << (min(x - x_lower) >= 0 && min(x_upper - x) >= 0) + ); + + // if the search radius is too big then shrink it so it fits inside the bounds. + if (initial_search_radius*2 >= min(x_upper-x_lower)) + initial_search_radius = 0.5*min(x_upper-x_lower)*0.99; + + + double objective_val = std::numeric_limits::infinity(); + size_t num_iter_used = 0; + if (x.size() == 1) + { + // BOBYQA requires x to have at least 2 variables in it. So we can't call it in + // this case. Instead we call find_min_single_variable(). + matrix temp(1); + auto ff = [&](const double& xx) + { + temp = xx; + double obj = f(temp); + ++num_iter_used; + // keep track of the best x. + if (obj < objective_val) + { + objective_val = obj; + x = temp; + } + return obj; + }; + try + { + double dx = x(0); + find_min_single_variable(ff, dx, x_lower(0), x_upper(0), eps, max_f_evals, initial_search_radius); + } catch (optimize_single_variable_failure& ) + { + } + } + else + { + auto ff = [&](const matrix& xx) + { + double obj = f(xx); + ++num_iter_used; + // keep track of the best x. + if (obj < objective_val) + { + objective_val = obj; + x = xx; + } + return obj; + }; + try + { + matrix start_x = x; + find_min_bobyqa(ff, start_x, 2*x.size()+1, x_lower, x_upper, initial_search_radius, eps, max_f_evals); + } catch (bobyqa_failure& ) + { + } + } + + return objective_val; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_fIND_OPTIMAL_PARAMETERS_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/optimization/find_optimal_parameters_abstract.h b/lib/3rdParty/dlib/include/dlib/optimization/find_optimal_parameters_abstract.h new file mode 100644 index 00000000..96dcee89 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/optimization/find_optimal_parameters_abstract.h @@ -0,0 +1,58 @@ +// Copyright (C) 2016 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_fIND_OPTIMAL_PARAMETERS_ABSTRACT_Hh_ +#ifdef DLIB_fIND_OPTIMAL_PARAMETERS_ABSTRACT_Hh_ + +#include "../matrix.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename funct + > + double find_optimal_parameters ( + double initial_search_radius, + double eps, + const unsigned int max_f_evals, + matrix& x, + const matrix& x_lower, + const matrix& x_upper, + const funct& f + ); + /*! + requires + - f(x) must be a valid expression that evaluates to a double + - x.size() == x_lower.size() == x_upper.size() + - x.size() > 0 + - 0 < eps < initial_search_radius + - max_f_evals > 1 + - min(x_upper - x_lower) > 0 + - min(x - x_lower) >= 0 && min(x_upper - x) >= 0 + (i.e. the given x should be within the bounds defined by x_lower and x_upper) + ensures + - Performs a constrained minimization of the function f() starting from + the initial point x. + - This function does not require derivatives of f(). Instead, it uses + derivative free methods to find the best setting of x. In particular, it + will begin by searching within a sphere of radius initial_search_radius + around x and will continue searching until either f() has been called + max_f_evals times or the search area has been shrunk to less than eps radius. + - #x == the value of x (within the bounds defined by x_lower and x_upper) that + was found to minimize f(). More precisely, it will always be true that: + - min(#x - x_lower) >= 0 && min(x_upper - #x) >= 0 + - returns f(#x). + throws + - No exception is thrown for executing max_f_evals iterations. This function + will simply output the best x it has seen if it runs out of iterations. + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_fIND_OPTIMAL_PARAMETERS_ABSTRACT_Hh_ + + diff --git a/lib/3rdParty/dlib/include/dlib/optimization/isotonic_regression.h b/lib/3rdParty/dlib/include/dlib/optimization/isotonic_regression.h new file mode 100644 index 00000000..e89e70b4 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/optimization/isotonic_regression.h @@ -0,0 +1,169 @@ +// Copyright (C) 2018 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ISOTONIC_ReGRESSION_H_ +#define DLIB_ISOTONIC_ReGRESSION_H_ + +#include "isotonic_regression_abstract.h" +#include +#include + +namespace dlib +{ + class isotonic_regression + { + public: + + template < + typename const_iterator, + typename iterator + > + void operator() ( + const_iterator begin, + const_iterator end, + iterator obegin + ) + { + do_isotonic_regression(begin, end); + + // unpack blocks to output + for (auto& block : blocks) + { + for (size_t k = 0; k < block.num; ++k) + set_val(*obegin++, block.avg); + } + + blocks.clear(); + } + + void operator() ( + std::vector& vect + ) { (*this)(vect.begin(), vect.end(), vect.begin()); } + + template + void operator() ( + std::vector>& vect + ) { (*this)(vect.begin(), vect.end(), vect.begin()); } + + + template < + typename const_iterator, + typename iterator + > + void fit_with_linear_output_interpolation ( + const_iterator begin, + const_iterator end, + iterator obegin + ) + { + do_isotonic_regression(begin, end); + + // Unpack blocks to output, but here instead of producing the step function + // output we linearly interpolate. Note that this actually fits the data less + // than the step-function, but in many applications might be closer to what you + // really when when using isotonic_regression than the step function. + for (size_t i = 0; i < blocks.size(); ++i) + { + auto& block = blocks[i]; + + double prev = (blocks.front().avg + block.avg)/2; + if (i > 0) + prev = (blocks[i-1].avg+block.avg)/2; + + double next = (blocks.back().avg + block.avg)/2; + if (i+1 < blocks.size()) + next = (blocks[i+1].avg+block.avg)/2; + + for (size_t k = 0; k < block.num; ++k) + { + const auto mid = block.num/2.0; + if (k < mid) + { + const double alpha = k/mid; + set_val(*obegin++, (1-alpha)*prev + alpha*block.avg); + } + else + { + const double alpha = k/mid-1; + set_val(*obegin++, alpha*next + (1-alpha)*block.avg); + } + } + } + + blocks.clear(); + } + + void fit_with_linear_output_interpolation ( + std::vector& vect + ) { fit_with_linear_output_interpolation(vect.begin(), vect.end(), vect.begin()); } + + template + void fit_with_linear_output_interpolation ( + std::vector>& vect + ) { fit_with_linear_output_interpolation(vect.begin(), vect.end(), vect.begin()); } + + private: + + template < + typename const_iterator + > + void do_isotonic_regression ( + const_iterator begin, + const_iterator end + ) + { + blocks.clear(); + + // Do the actual isotonic regression. The output is a step-function and is + // stored in the vector of blocks. + for (auto i = begin; i != end; ++i) + { + blocks.emplace_back(get_val(*i)); + while (blocks.size() > 1 && prev_block().avg > current_block().avg) + { + // merge the last two blocks. + prev_block() = prev_block() + current_block(); + blocks.pop_back(); + } + } + } + + + template + static double get_val(const T& v) { return v;} + + template + static double get_val(const std::pair& v) { return v.second;} + + template + static void set_val(T& v, double val) { v = val;} + + template + static void set_val(std::pair& v, double val) { v.second = val;} + + + + struct block_t + { + block_t(double val) : num(1), avg(val) {} + block_t(size_t n, double val) : num(n), avg(val) {} + + size_t num; + double avg; + + inline block_t operator+(const block_t& rhs) const + { + return block_t(num+rhs.num, + (num*avg + rhs.num*rhs.avg)/(num+rhs.num)); + } + }; + + inline block_t& prev_block() { return blocks[blocks.size()-2]; } + inline block_t& current_block() { return blocks.back(); } + + std::vector blocks; + }; +} + +#endif // DLIB_ISOTONIC_ReGRESSION_H_ + + diff --git a/lib/3rdParty/dlib/include/dlib/optimization/isotonic_regression_abstract.h b/lib/3rdParty/dlib/include/dlib/optimization/isotonic_regression_abstract.h new file mode 100644 index 00000000..b00334be --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/optimization/isotonic_regression_abstract.h @@ -0,0 +1,128 @@ +// Copyright (C) 2018 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_ISOTONIC_ReGRESSION_ABSTRACT_H_ +#ifdef DLIB_ISOTONIC_ReGRESSION_ABSTRACT_H_ + +#include +#include + +namespace dlib +{ + class isotonic_regression + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a tool for performing 1-D isotonic regression. That is, it + finds the least squares fit of a non-parametric curve to some user supplied + data, subject to the constraint that the fitted curve is non-decreasing. + + This is done using the fast O(n) pool adjacent violators algorithm. + !*/ + + public: + + template < + typename const_iterator, + typename iterator + > + void operator() ( + const_iterator begin, + const_iterator end, + iterator obegin + ); + /*! + requires + - [begin,end) is an iterator range of float or doubles or a range of + std::pair or std::pair where T an be anything. + - obegin points to an iterator range at least std::distance(begin,end). + - obegin points to an iterator range of objects of type float, double, std::pair, or std::pair. + ensures + - Given the range of real values stored in [begin,end), this method performs isotonic regression + on this data and writes the results to obegin. To be specific: + - let IN refer to the input values stored in the iterator range [begin,end). + - let OUT refer to the output values stored in the iterator range [obegin, obegin+std::distance(begin,end)). + - This function populates OUT with values such that the sum_i of + (IN[i]-OUT[i])^2 is minimized, subject to the constraint that + OUT[i] <= OUT[i+1], i.e. that OUT is monotonic. + - It is OK for [begin,end) to overlap with the range pointed to by obegin. + That is, this function can run in-place. + - Note that when the inputs or outputs are std::pairs this algorithm only + looks at the .second field of the pair. It therefore still treats these + iterator ranges as ranges of reals since it only looks at the .second + field, which is a real number. The .first field is entirely ignored. + !*/ + + void operator() ( + std::vector& vect + ) { (*this)(vect.begin(), vect.end(), vect.begin()); } + /*! + ensures + - performs in-place isotonic regression. Therefore, #vect will contain the + isotonic regression of vect. + - #vect.size() == vect.size() + !*/ + + template + void operator() ( + std::vector>& vect + ) { (*this)(vect.begin(), vect.end(), vect.begin()); } + /*! + ensures + - performs in-place isotonic regression. Therefore, #vect will contain the + isotonic regression of vect. + - #vect.size() == vect.size() + !*/ + + + template < + typename const_iterator, + typename iterator + > + void fit_with_linear_output_interpolation ( + const_iterator begin, + const_iterator end, + iterator obegin + ); + /*! + requires + - [begin,end) is an iterator range of float or doubles or a range of + std::pair or std::pair where T an be anything. + - obegin points to an iterator range at least std::distance(begin,end). + - obegin points to an iterator range of objects of type float, double, std::pair, or std::pair. + ensures + - This function behaves just like (*this)(begin,end,obegin) except that the + output is interpolated. To explain, not that the optimal output of + isotonic regression is a step function. However, in many applications + that isn't really what you want. You want something smoother. So + fit_with_linear_output_interpolation() does isotonic regression and then + linearly interpolates the step function into a piecewise linear function. + !*/ + + void fit_with_linear_output_interpolation ( + std::vector& vect + ) { fit_with_linear_output_interpolation(vect.begin(), vect.end(), vect.begin()); } + /*! + ensures + - performs in-place isotonic regression. Therefore, #vect will contain the + isotonic regression of vect. + - #vect.size() == vect.size() + !*/ + + template + void fit_with_linear_output_interpolation ( + std::vector>& vect + ) { fit_with_linear_output_interpolation(vect.begin(), vect.end(), vect.begin()); } + /*! + ensures + - performs in-place isotonic regression. Therefore, #vect will contain the + isotonic regression of vect. + - #vect.size() == vect.size() + !*/ + + }; +} + +#endif // DLIB_ISOTONIC_ReGRESSION_ABSTRACT_H_ + + + diff --git a/lib/3rdParty/dlib/include/dlib/optimization/optimization.h b/lib/3rdParty/dlib/include/dlib/optimization/optimization.h index 63662db7..561d6437 100644 --- a/lib/3rdParty/dlib/include/dlib/optimization/optimization.h +++ b/lib/3rdParty/dlib/include/dlib/optimization/optimization.h @@ -42,7 +42,7 @@ namespace dlib e(i) = old_val - eps; const double delta_minus = f(e); - der(i) = (delta_plus - delta_minus)/(2*eps); + der(i) = (delta_plus - delta_minus)/((old_val+eps)-(old_val-eps)); // and finally restore the old value of this element e(i) = old_val; @@ -68,7 +68,7 @@ namespace dlib e(i) = old_val - eps; const double delta_minus = f(item,e); - der(i) = (delta_plus - delta_minus)/(2*eps); + der(i) = (delta_plus - delta_minus)/((old_val+eps)-(old_val-eps)); // and finally restore the old value of this element e(i) = old_val; @@ -80,7 +80,7 @@ namespace dlib double operator()(const double& x) const { - return (f(x+eps)-f(x-eps))/(2*eps); + return (f(x+eps)-f(x-eps))/((x+eps)-(x-eps)); } private: @@ -176,8 +176,10 @@ namespace dlib double f_value = f(x); g = der(x); - DLIB_ASSERT(is_finite(f_value), "The objective function generated non-finite outputs"); - DLIB_ASSERT(is_finite(g), "The objective function generated non-finite outputs"); + if (!is_finite(f_value)) + throw error("The objective function generated non-finite outputs"); + if (!is_finite(g)) + throw error("The objective function generated non-finite outputs"); while(stop_strategy.should_continue_search(x, f_value, g) && f_value > min_f) { @@ -194,8 +196,10 @@ namespace dlib // Take the search step indicated by the above line search x += alpha*s; - DLIB_ASSERT(is_finite(f_value), "The objective function generated non-finite outputs"); - DLIB_ASSERT(is_finite(g), "The objective function generated non-finite outputs"); + if (!is_finite(f_value)) + throw error("The objective function generated non-finite outputs"); + if (!is_finite(g)) + throw error("The objective function generated non-finite outputs"); } return f_value; @@ -238,8 +242,10 @@ namespace dlib double f_value = -f(x); g = -der(x); - DLIB_ASSERT(is_finite(f_value), "The objective function generated non-finite outputs"); - DLIB_ASSERT(is_finite(g), "The objective function generated non-finite outputs"); + if (!is_finite(f_value)) + throw error("The objective function generated non-finite outputs"); + if (!is_finite(g)) + throw error("The objective function generated non-finite outputs"); while(stop_strategy.should_continue_search(x, f_value, g) && f_value > -max_f) { @@ -262,8 +268,10 @@ namespace dlib g *= -1; f_value *= -1; - DLIB_ASSERT(is_finite(f_value), "The objective function generated non-finite outputs"); - DLIB_ASSERT(is_finite(g), "The objective function generated non-finite outputs"); + if (!is_finite(f_value)) + throw error("The objective function generated non-finite outputs"); + if (!is_finite(g)) + throw error("The objective function generated non-finite outputs"); } return -f_value; @@ -303,8 +311,10 @@ namespace dlib double f_value = f(x); g = derivative(f,derivative_eps)(x); - DLIB_ASSERT(is_finite(f_value), "The objective function generated non-finite outputs"); - DLIB_ASSERT(is_finite(g), "The objective function generated non-finite outputs"); + if (!is_finite(f_value)) + throw error("The objective function generated non-finite outputs"); + if (!is_finite(g)) + throw error("The objective function generated non-finite outputs"); while(stop_strategy.should_continue_search(x, f_value, g) && f_value > min_f) { @@ -325,8 +335,10 @@ namespace dlib g = derivative(f,derivative_eps)(x); - DLIB_ASSERT(is_finite(f_value), "The objective function generated non-finite outputs"); - DLIB_ASSERT(is_finite(g), "The objective function generated non-finite outputs"); + if (!is_finite(f_value)) + throw error("The objective function generated non-finite outputs"); + if (!is_finite(g)) + throw error("The objective function generated non-finite outputs"); } return f_value; @@ -415,7 +427,7 @@ namespace dlib for (long i = 0; i < gradient.size(); ++i) { const double tol = eps*std::abs(x(i)); - // if x(i) is an active bound constraint then we should set it's search + // If x(i) is an active bound constraint then we should set its search // direction such that a single step along the direction either does nothing or // closes the gap of size tol before hitting the bound exactly. if (x_lower(i)+tol >= x(i) && gradient(i) > 0) @@ -470,7 +482,7 @@ namespace dlib << "\n\t x_upper.size(): " << x_upper.size() ); DLIB_ASSERT ( - min(x_upper-x_lower) > 0, + min(x_upper-x_lower) >= 0, "\tdouble find_min_box_constrained()" << "\n\t You have to supply proper box constraints to this function." << "\n\r min(x_upper-x_lower): " << min(x_upper-x_lower) @@ -481,8 +493,10 @@ namespace dlib double f_value = f(x); g = der(x); - DLIB_ASSERT(is_finite(f_value), "The objective function generated non-finite outputs"); - DLIB_ASSERT(is_finite(g), "The objective function generated non-finite outputs"); + if (!is_finite(f_value)) + throw error("The objective function generated non-finite outputs"); + if (!is_finite(g)) + throw error("The objective function generated non-finite outputs"); // gap_eps determines how close we have to get to a bound constraint before we // start basically dropping it from the optimization and consider it to be an @@ -513,11 +527,13 @@ namespace dlib last_alpha = alpha; // Take the search step indicated by the above line search - x = clamp(x + alpha*s, x_lower, x_upper); + x = dlib::clamp(x + alpha*s, x_lower, x_upper); g = der(x); - DLIB_ASSERT(is_finite(f_value), "The objective function generated non-finite outputs"); - DLIB_ASSERT(is_finite(g), "The objective function generated non-finite outputs"); + if (!is_finite(f_value)) + throw error("The objective function generated non-finite outputs"); + if (!is_finite(g)) + throw error("The objective function generated non-finite outputs"); } return f_value; @@ -594,7 +610,7 @@ namespace dlib << "\n\t x_upper.size(): " << x_upper.size() ); DLIB_ASSERT ( - min(x_upper-x_lower) > 0, + min(x_upper-x_lower) >= 0, "\tdouble find_max_box_constrained()" << "\n\t You have to supply proper box constraints to this function." << "\n\r min(x_upper-x_lower): " << min(x_upper-x_lower) @@ -608,8 +624,10 @@ namespace dlib double f_value = -f(x); g = -der(x); - DLIB_ASSERT(is_finite(f_value), "The objective function generated non-finite outputs"); - DLIB_ASSERT(is_finite(g), "The objective function generated non-finite outputs"); + if (!is_finite(f_value)) + throw error("The objective function generated non-finite outputs"); + if (!is_finite(g)) + throw error("The objective function generated non-finite outputs"); // gap_eps determines how close we have to get to a bound constraint before we // start basically dropping it from the optimization and consider it to be an @@ -640,15 +658,17 @@ namespace dlib last_alpha = alpha; // Take the search step indicated by the above line search - x = clamp(x + alpha*s, x_lower, x_upper); + x = dlib::clamp(x + alpha*s, x_lower, x_upper); g = -der(x); // Don't forget to negate the output from the line search since it is from the // unnegated version of f() f_value *= -1; - DLIB_ASSERT(is_finite(f_value), "The objective function generated non-finite outputs"); - DLIB_ASSERT(is_finite(g), "The objective function generated non-finite outputs"); + if (!is_finite(f_value)) + throw error("The objective function generated non-finite outputs"); + if (!is_finite(g)) + throw error("The objective function generated non-finite outputs"); } return -f_value; diff --git a/lib/3rdParty/dlib/include/dlib/optimization/optimization_abstract.h b/lib/3rdParty/dlib/include/dlib/optimization/optimization_abstract.h index 8a3223c0..f3c42c2b 100644 --- a/lib/3rdParty/dlib/include/dlib/optimization/optimization_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/optimization/optimization_abstract.h @@ -297,7 +297,7 @@ namespace dlib - is_col_vector(x_upper) == true - x.size() == x_lower.size() == x_upper.size() (i.e. x, x_lower, and x_upper need to all be column vectors of the same dimensionality) - - min(x_upper-x_lower) > 0 + - min(x_upper-x_lower) >= 0 (i.e. x_upper must contain upper bounds relative to x_lower) ensures - Performs a box constrained minimization of the function f() using the given @@ -391,7 +391,7 @@ namespace dlib - is_col_vector(x_upper) == true - x.size() == x_lower.size() == x_upper.size() (i.e. x, x_lower, and x_upper need to all be column vectors of the same dimensionality) - - min(x_upper-x_lower) > 0 + - min(x_upper-x_lower) >= 0 (i.e. x_upper must contain upper bounds relative to x_lower) ensures - Performs a box constrained maximization of the function f() using the given diff --git a/lib/3rdParty/dlib/include/dlib/optimization/optimization_bobyqa.h b/lib/3rdParty/dlib/include/dlib/optimization/optimization_bobyqa.h index 5632dff8..6fbc40c0 100644 --- a/lib/3rdParty/dlib/include/dlib/optimization/optimization_bobyqa.h +++ b/lib/3rdParty/dlib/include/dlib/optimization/optimization_bobyqa.h @@ -18,8 +18,9 @@ #include #include +#include + #include "../matrix.h" -#include "../smart_pointers.h" #include "optimization_bobyqa_abstract.h" #include "optimization.h" @@ -59,7 +60,7 @@ namespace dlib { const unsigned long n = x.size(); const unsigned long w_size = (npt+5)*(npt+n)+3*n*(n+5)/2; - scoped_ptr w(new doublereal[w_size]); + std::unique_ptr w(new doublereal[w_size]); // make these temporary matrices becuse U might be some // kind of matrix_exp that doesn't support taking the address @@ -3360,7 +3361,7 @@ L210: DLIB_CASSERT(is_col_vector(x) && is_col_vector(x_lower) && is_col_vector(x_upper) && x.size() == x_lower.size() && x_lower.size() == x_upper.size() && x.size() > 1 && max_f_evals > 1, - "\tvoid find_min_bobyqa()" + "\tdouble find_min_bobyqa()" << "\n\t Invalid arguments have been given to this function" << "\n\t is_col_vector(x): " << is_col_vector(x) << "\n\t is_col_vector(x_lower): " << is_col_vector(x_lower) @@ -3375,7 +3376,7 @@ L210: 0 < rho_end && rho_end < rho_begin && min(x_upper - x_lower) > 2*rho_begin && min(x - x_lower) >= 0 && min(x_upper - x) >= 0, - "\tvoid find_min_bobyqa()" + "\tdouble find_min_bobyqa()" << "\n\t Invalid arguments have been given to this function" << "\n\t ntp in valid range: " << (x.size() + 2 <= npt && npt <= (x.size()+1)*(x.size()+2)/2) << "\n\t npt: " << npt diff --git a/lib/3rdParty/dlib/include/dlib/optimization/optimization_line_search.h b/lib/3rdParty/dlib/include/dlib/optimization/optimization_line_search.h index 889d815a..aa778ed7 100644 --- a/lib/3rdParty/dlib/include/dlib/optimization/optimization_line_search.h +++ b/lib/3rdParty/dlib/include/dlib/optimization/optimization_line_search.h @@ -127,7 +127,8 @@ namespace dlib double f0, double d0, double f1, - double d1 + double d1, + double limit = 1 ) { const double n = 3*(f1 - f0) - 2*d0 - d1; @@ -161,8 +162,8 @@ namespace dlib else x = x2; - // now make sure the minimum is within the allowed range of (0,1) - return put_in_range(0,1,x); + // now make sure the minimum is within the allowed range of [0,limit] + return put_in_range(0,limit,x); } // ---------------------------------------------------------------------------------------- @@ -194,7 +195,10 @@ namespace dlib double f_x2 ) { - DLIB_ASSERT(0 < x1 && x1 < x2,"Invalid inputs were given to this function"); + DLIB_ASSERT(0 < x1 && x1 < x2,"Invalid inputs were given to this function.\n" + << "x1: " << x1 + << " x2: " << x2 + ); // The contents of this function follow the equations described on page 58 of the // book Numerical Optimization by Nocedal and Wright, second edition. matrix m; @@ -211,7 +215,7 @@ namespace dlib double temp = aa2*aa1*(x1-x2); // just take a guess if this happens - if (temp == 0) + if (temp == 0 || std::fpclassify(temp) == FP_SUBNORMAL) { return x1/2.0; } @@ -305,8 +309,10 @@ namespace dlib // the book Practical Methods of Optimization by R. Fletcher. The sectioning // phase is an implementation of 2.6.4 from the same book. - // tau1 > 1. Controls the alpha jump size during the search - const double tau1 = 9; + // 1 <= tau1a < tau1b. Controls the alpha jump size during the bracketing phase of + // the search. + const double tau1a = 1.4; + const double tau1b = 9; // it must be the case that 0 < tau2 < tau3 <= 1/2 for the algorithm to function // correctly but the specific values of tau2 and tau3 aren't super important. @@ -315,7 +321,7 @@ namespace dlib // Stop right away and return a step size of 0 if the gradient is 0 at the starting point - if (std::abs(d0) < std::numeric_limits::epsilon()) + if (std::abs(d0) <= std::abs(f0)*std::numeric_limits::epsilon()) return 0; // Stop right away if the current value is good enough according to min_f @@ -390,34 +396,34 @@ namespace dlib break; } - if (mu <= 2*alpha - last_alpha) + + + const double temp = alpha; + // Pick a larger range [first, last]. We will pick the next alpha in that + // range. + double first, last; + if (mu > 0) { - last_alpha = alpha; - alpha = mu; + first = std::min(mu, alpha + tau1a*(alpha - last_alpha)); + last = std::min(mu, alpha + tau1b*(alpha - last_alpha)); } else { - const double temp = alpha; - - double first = 2*alpha - last_alpha; - double last; - if (mu > 0) - last = std::min(mu, alpha + tau1*(alpha - last_alpha)); - else - last = std::max(mu, alpha + tau1*(alpha - last_alpha)); - - - // pick a point between first and last by doing some kind of interpolation - if (last_alpha < alpha) - alpha = last_alpha + (alpha-last_alpha)*poly_min_extrap(last_val, last_val_der, val, val_der); - else - alpha = alpha + (last_alpha-alpha)*poly_min_extrap(val, val_der, last_val, last_val_der); - - alpha = put_in_range(first,last,alpha); - - - last_alpha = temp; + first = std::max(mu, alpha + tau1a*(alpha - last_alpha)); + last = std::max(mu, alpha + tau1b*(alpha - last_alpha)); } + + + + // pick a point between first and last by doing some kind of interpolation + if (last_alpha < alpha) + alpha = last_alpha + (alpha-last_alpha)*poly_min_extrap(last_val, last_val_der, val, val_der, 1e10); + else + alpha = alpha + (last_alpha-alpha)*poly_min_extrap(val, val_der, last_val, last_val_der, 1e10); + + alpha = put_in_range(first,last,alpha); + + last_alpha = temp; last_val = val; last_val_der = val_der; @@ -450,6 +456,14 @@ namespace dlib return b; } + // If alpha has basically become zero then just stop. Think of it like this, + // if we take the largest possible alpha step will the objective function + // change at all? If not then there isn't any point looking for a better + // alpha. + const double max_possible_alpha = std::max(std::abs(a),std::abs(b)); + if (std::abs(max_possible_alpha*d0) <= std::abs(f0)*std::numeric_limits::epsilon()) + return alpha; + if (val > f0 + rho*alpha*d0 || val >= a_val) { @@ -771,13 +785,16 @@ namespace dlib // make sure one side of the bracket isn't super huge compared to the other // side. If it is then contract it. const double bracket_ratio = abs(p1-p2)/abs(p2-p3); - if ( !( bracket_ratio < 10 && bracket_ratio > 0.1) ) - { - // Force p_min to be on a reasonable side. But only if lagrange_poly_min_extrap() - // didn't put it on a good side already. - if (bracket_ratio > 1 && p_min > p2) + // Force p_min to be on a reasonable side. But only if lagrange_poly_min_extrap() + // didn't put it on a good side already. + if (bracket_ratio >= 10) + { + if (p_min > p2) p_min = (p1+p2)/2; - else if (p_min < p2) + } + else if (bracket_ratio <= 0.1) + { + if (p_min < p2) p_min = (p2+p3)/2; } diff --git a/lib/3rdParty/dlib/include/dlib/optimization/optimization_line_search_abstract.h b/lib/3rdParty/dlib/include/dlib/optimization/optimization_line_search_abstract.h index e9e05fd6..2aa221da 100644 --- a/lib/3rdParty/dlib/include/dlib/optimization/optimization_line_search_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/optimization/optimization_line_search_abstract.h @@ -91,7 +91,8 @@ namespace dlib double f0, double d0, double f1, - double d1 + double d1, + double limit = 1 ); /*! ensures @@ -100,7 +101,7 @@ namespace dlib - c(1) == f1 - derivative of c(x) at x==0 is d0 - derivative of c(x) at x==1 is d1 - - returns the point in the range [0,1] that minimizes the polynomial c(x) + - returns the point in the range [0,limit] that minimizes the polynomial c(x) !*/ // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/optimization/optimization_oca.h b/lib/3rdParty/dlib/include/dlib/optimization/optimization_oca.h index 7963c024..4ca9cd7a 100644 --- a/lib/3rdParty/dlib/include/dlib/optimization/optimization_oca.h +++ b/lib/3rdParty/dlib/include/dlib/optimization/optimization_oca.h @@ -117,7 +117,21 @@ namespace dlib ) const { matrix_type empty_prior; - return oca_impl(problem, w, empty_prior, false, num_nonnegative, force_weight_to_1); + return oca_impl(problem, w, empty_prior, false, num_nonnegative, force_weight_to_1, 0); + } + + template < + typename matrix_type + > + typename matrix_type::type solve_with_elastic_net ( + const oca_problem& problem, + matrix_type& w, + double lasso_lambda, + unsigned long force_weight_to_1 = std::numeric_limits::max() + ) const + { + matrix_type empty_prior; + return oca_impl(problem, w, empty_prior, false, 0, force_weight_to_1, lasso_lambda); } template < @@ -141,7 +155,7 @@ namespace dlib // disable the force weight to 1 option for this mode. We also disable the // non-negative constraints. unsigned long force_weight_to_1 = std::numeric_limits::max(); - return oca_impl(problem, w, prior, true, 0, force_weight_to_1); + return oca_impl(problem, w, prior, true, 0, force_weight_to_1, 0); } private: @@ -152,24 +166,37 @@ namespace dlib typename matrix_type::type oca_impl ( const oca_problem& problem, matrix_type& w, - const matrix_type prior, + const matrix_type& prior, bool have_prior, unsigned long num_nonnegative, - unsigned long force_weight_to_1 + unsigned long force_weight_to_1, + const double lasso_lambda ) const { const unsigned long num_dims = problem.get_num_dimensions(); // make sure requires clause is not broken DLIB_ASSERT(problem.get_c() > 0 && - problem.get_num_dimensions() > 0, + problem.get_num_dimensions() > 0 && + 0 <= lasso_lambda && lasso_lambda < 1, "\t scalar_type oca::operator()" << "\n\t The oca_problem is invalid" << "\n\t problem.get_c(): " << problem.get_c() << "\n\t problem.get_num_dimensions(): " << num_dims + << "\n\t lasso_lambda: " << lasso_lambda << "\n\t this: " << this ); + if (have_prior) + { + DLIB_ASSERT(lasso_lambda == 0, "Solver doesn't support using a prior with lasso."); + DLIB_ASSERT(num_nonnegative == 0, "Solver doesn't support using a prior with non-negative constraints."); + } + else if (lasso_lambda != 0) + { + DLIB_ASSERT(num_nonnegative == 0, "Solver doesn't support using lasso with non-negative constraints."); + } + const double ridge_lambda = 1-lasso_lambda; if (num_nonnegative > num_dims) num_nonnegative = num_dims; @@ -184,7 +211,7 @@ namespace dlib typename sequence::kernel_2a planes; std::vector bs, miss_count; - vect_type new_plane, alpha; + vect_type new_plane, alpha, btemp; w.set_size(num_dims, 1); w = 0; @@ -198,6 +225,12 @@ namespace dlib scalar_type cp_obj = 0; matrix K, Ktmp; + matrix lambda, d; + if (lasso_lambda != 0) + d.set_size(num_dims); + else + d.set_size(num_nonnegative); + d = lasso_lambda*ones_matrix(d); scalar_type R_lower_bound; if (problem.risk_has_lower_bound(R_lower_bound)) @@ -253,7 +286,7 @@ namespace dlib else alpha = join_cols(alpha,zeros_matrix(1,1)); - const scalar_type wnorm = 0.5*trans(w)*w; + const scalar_type wnorm = 0.5*ridge_lambda*trans(w)*w + lasso_lambda*sum(abs(w)); const double prior_part = have_prior? dot(w,prior) : 0; cur_obj = wnorm + C*cur_risk + prior_norm-prior_part; @@ -280,21 +313,36 @@ namespace dlib // solve the cutting plane subproblem for the next w. We solve it to an - // accuracy that is related to how big the error gap is - scalar_type eps = std::min(sub_eps, 0.1*(cur_obj-cp_obj)) ; + // accuracy that is related to how big the error gap is. Also, we multiply + // by ridge_lambda because the objective function for the QP we solve was + // implicitly scaled by ridge_lambda. That is, we want to ask the QP + // solver to solve the problem until the duality gap is 0.1 times smaller + // than what it is now. So the factor of ridge_lambda is necessary to make + // this happen. + scalar_type eps = std::min(sub_eps, 0.1*ridge_lambda*(cur_obj-cp_obj)); // just a sanity check if (eps < 1e-16) eps = 1e-16; // Note that we warm start this optimization by using the alpha from the last // iteration as the starting point. - if (num_nonnegative != 0) + if (lasso_lambda != 0) + { + // copy planes into a matrix so we can call solve_qp4_using_smo() + matrix planes_mat(num_dims,planes.size()); + for (unsigned long i = 0; i < planes.size(); ++i) + set_colm(planes_mat,i) = planes[i]; + + btemp = ridge_lambda*mat(bs) - trans(planes_mat)*d; + solve_qp4_using_smo(planes_mat, K, btemp, d, alpha, lambda, eps, sub_max_iter, (scalar_type)(2*lasso_lambda)); + } + else if (num_nonnegative != 0) { // copy planes into a matrix so we can call solve_qp4_using_smo() matrix planes_mat(num_nonnegative,planes.size()); for (unsigned long i = 0; i < planes.size(); ++i) set_colm(planes_mat,i) = colm(planes[i],0,num_nonnegative); - solve_qp4_using_smo(planes_mat, K, mat(bs), alpha, eps, sub_max_iter); + solve_qp4_using_smo(planes_mat, K, mat(bs), d, alpha, lambda, eps, sub_max_iter); } else { @@ -305,8 +353,9 @@ namespace dlib w = -alpha(0)*planes[0]; for (unsigned long i = 1; i < planes.size(); ++i) w -= alpha(i)*planes[i]; - // threshold the first num_nonnegative w elements if necessary. - if (num_nonnegative != 0) + if (lasso_lambda != 0) + w = (lambda-d+w)/ridge_lambda; + else if (num_nonnegative != 0) // threshold the first num_nonnegative w elements if necessary. set_rowm(w,range(0,num_nonnegative-1)) = lowerbound(rowm(w,range(0,num_nonnegative-1)),0); for (long i = 0; i < alpha.size(); ++i) @@ -319,7 +368,7 @@ namespace dlib // Compute the lower bound on the true objective given to us by the cutting // plane subproblem. - cp_obj = -0.5*trans(w)*w + trans(alpha)*mat(bs); + cp_obj = -0.5*ridge_lambda*trans(w)*w + trans(alpha)*mat(bs); if (have_prior) w += prior; diff --git a/lib/3rdParty/dlib/include/dlib/optimization/optimization_oca_abstract.h b/lib/3rdParty/dlib/include/dlib/optimization/optimization_oca_abstract.h index f8129b28..859dbdcf 100644 --- a/lib/3rdParty/dlib/include/dlib/optimization/optimization_oca_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/optimization/optimization_oca_abstract.h @@ -31,6 +31,13 @@ namespace dlib Where prior is a user supplied vector and R(w) has the same interpretation as above. + Or it can use the elastic net regularizer: + Minimize: f(w) == 0.5*(1-lasso_lambda)*length_squared(w) + lasso_lambda*sum(abs(w)) + C*R(w) + + Where lasso_lambda is a number in the range [0, 1) and controls + trade-off between doing L1 and L2 regularization. R(w) has the same + interpretation as above. + Note that the stopping condition must be provided by the user in the form of the optimization_status() function. @@ -142,6 +149,13 @@ namespace dlib Where prior is a user supplied vector and R(w) has the same interpretation as above. + Or it can use the elastic net regularizer: + Minimize: f(w) == 0.5*(1-lasso_lambda)*length_squared(w) + lasso_lambda*sum(abs(w)) + C*R(w) + + Where lasso_lambda is a number in the range [0, 1) and controls + trade-off between doing L1 and L2 regularization. R(w) has the same + interpretation as above. + For a detailed discussion you should consult the following papers from the Journal of Machine Learning Research: @@ -221,6 +235,39 @@ namespace dlib - returns the objective value at the solution #w !*/ + template < + typename matrix_type + > + typename matrix_type::type solve_with_elastic_net ( + const oca_problem& problem, + matrix_type& w, + scalar_type lasso_lambda, + unsigned long force_weight_to_1 = std::numeric_limits::max() + ) const; + /*! + requires + - problem.get_c() > 0 + - problem.get_num_dimensions() > 0 + - 0 <= lasso_lambda < 1 + ensures + - Solves the given oca problem and stores the solution in #w, but uses an + elastic net regularizer instead of the normal L2 regularizer. In + particular, this function solves: + Minimize: f(w) == 0.5*(1-lasso_lambda)*length_squared(w) + lasso_lambda*sum(abs(w)) + C*R(w) + - The optimization algorithm runs until problem.optimization_status() + indicates it is time to stop. + - returns the objective value at the solution #w + - if (force_weight_to_1 < problem.get_num_dimensions()) then + - The optimizer enforces the following constraints: + - #w(force_weight_to_1) == 1 + - for all i > force_weight_to_1: + - #w(i) == 0 + - That is, the element in the weight vector at the index indicated + by force_weight_to_1 will have a value of 1 upon completion of + this function, while all subsequent elements of w will have + values of 0. + !*/ + void set_subproblem_epsilon ( double eps ); diff --git a/lib/3rdParty/dlib/include/dlib/optimization/optimization_solve_qp_using_smo.h b/lib/3rdParty/dlib/include/dlib/optimization/optimization_solve_qp_using_smo.h index be08f332..e589df9a 100644 --- a/lib/3rdParty/dlib/include/dlib/optimization/optimization_solve_qp_using_smo.h +++ b/lib/3rdParty/dlib/include/dlib/optimization/optimization_solve_qp_using_smo.h @@ -5,6 +5,8 @@ #include "optimization_solve_qp_using_smo_abstract.h" #include "../matrix.h" +#include +#include "../unordered_pair.h" namespace dlib { @@ -93,7 +95,7 @@ namespace dlib min(alpha) >= 0 && eps > 0 && max_iter > 0, - "\t void solve_qp_using_smo()" + "\t unsigned long solve_qp_using_smo()" << "\n\t Invalid arguments were given to this function" << "\n\t Q.nr(): " << Q.nr() << "\n\t Q.nc(): " << Q.nc() @@ -215,15 +217,20 @@ namespace dlib typename EXP1, typename EXP2, typename EXP3, - typename T, long NR, long NC, typename MM, typename L + typename EXP4, + typename T, long NR, long NC, typename MM, typename L, + long NR2, long NC2 > unsigned long solve_qp4_using_smo ( const matrix_exp& A, const matrix_exp& Q, const matrix_exp& b, + const matrix_exp& d, matrix& alpha, + matrix& lambda, T eps, - unsigned long max_iter + unsigned long max_iter, + T max_lambda = std::numeric_limits::infinity() ) { // make sure requires clause is not broken @@ -251,6 +258,15 @@ namespace dlib << "\n\t eps: " << eps << "\n\t max_iter: " << max_iter ); + DLIB_ASSERT(is_col_vector(d) == true && + max_lambda >= 0 && + d.size() == A.nr(), + "\t void solve_qp4_using_smo()" + << "\n\t Invalid arguments were given to this function" + << "\n\t A.nr(): " << A.nr() + << "\n\t d.size(): " << d.size() + << "\n\t max_lambda: " << max_lambda + ); const T C = sum(alpha); @@ -263,9 +279,14 @@ namespace dlib solve_qp_using_smo() routine. */ + const bool d_is_zero = d==zeros_matrix(d); + // compute optimal lambda for current alpha - matrix lambda = A*alpha; - lambda = lowerbound(lambda, 0); + if (d_is_zero) + lambda = A*alpha; + else + lambda = A*alpha + d; + lambda = dlib::clamp(lambda, 0, max_lambda); // Compute f'(alpha) (i.e. the gradient of f(alpha) with respect to alpha) for the current alpha. matrix df = Q*alpha - b - trans(A)*lambda; @@ -308,8 +329,11 @@ namespace dlib { // compute optimal lambda and recheck the duality gap to make // sure we have really converged. - lambda = A*alpha; - lambda = lowerbound(lambda, 0); + if (d_is_zero) + lambda = A*alpha; + else + lambda = A*alpha + d; + lambda = dlib::clamp(lambda, 0, max_lambda); df = Q*alpha - b - trans(A)*lambda; if (trans(alpha)*df - C*min(df) < eps) @@ -347,8 +371,11 @@ namespace dlib if ((iter%300) == 299) { // compute the optimal lambda for the current alpha - lambda = A*alpha; - lambda = lowerbound(lambda, 0); + if (d_is_zero) + lambda = A*alpha; + else + lambda = A*alpha + d; + lambda = dlib::clamp(lambda, 0, max_lambda); // Perform this form of the update every so often because doing so can help // avoid the buildup of numerical errors you get with the alternate update @@ -376,6 +403,547 @@ namespace dlib */ + return iter+1; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP1, + typename EXP2, + typename T, long NR, long NC, typename MM, typename L + > + unsigned long solve_qp_box_constrained ( + const matrix_exp& Q, + const matrix_exp& b, + matrix& alpha, + const matrix& lower, + const matrix& upper, + T eps = 1e-10, + unsigned long max_iter = 30000 + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(Q.nr() == Q.nc() && + alpha.size() == lower.size() && + alpha.size() == upper.size() && + is_col_vector(b) && + is_col_vector(alpha) && + is_col_vector(lower) && + is_col_vector(upper) && + b.size() == alpha.size() && + b.size() == Q.nr() && + alpha.size() > 0 && + 0 <= min(alpha-lower) && + 0 <= max(upper-alpha) && + eps > 0 && + max_iter > 0, + "\t unsigned long solve_qp_box_constrained()" + << "\n\t Invalid arguments were given to this function" + << "\n\t Q.nr(): " << Q.nr() + << "\n\t Q.nc(): " << Q.nc() + << "\n\t is_col_vector(b): " << is_col_vector(b) + << "\n\t is_col_vector(alpha): " << is_col_vector(alpha) + << "\n\t is_col_vector(lower): " << is_col_vector(lower) + << "\n\t is_col_vector(upper): " << is_col_vector(upper) + << "\n\t b.size(): " << b.size() + << "\n\t alpha.size(): " << alpha.size() + << "\n\t lower.size(): " << lower.size() + << "\n\t upper.size(): " << upper.size() + << "\n\t Q.nr(): " << Q.nr() + << "\n\t min(alpha-lower): " << min(alpha-lower) + << "\n\t max(upper-alpha): " << max(upper-alpha) + << "\n\t eps: " << eps + << "\n\t max_iter: " << max_iter + ); + + + // Compute f'(alpha) (i.e. the gradient of f(alpha)) for the current alpha. + matrix df = Q*alpha + b; + matrix QQ = reciprocal_max(diag(Q)); + + // First we use a coordinate descent method to initialize alpha. + double max_df = 0; + for (long iter = 0; iter < alpha.size()*2; ++iter) + { + max_df = 0; + long best_r =0; + // find the best alpha to optimize. + for (long r = 0; r < Q.nr(); ++r) + { + if (alpha(r) <= lower(r) && df(r) > 0) + ;//alpha(r) = lower(r); + else if (alpha(r) >= upper(r) && df(r) < 0) + ;//alpha(r) = upper(r); + else if (std::abs(df(r)) > max_df) + { + best_r = r; + max_df = std::abs(df(r)); + } + } + + // now optimize alpha(best_r) + const long r = best_r; + const T old_alpha = alpha(r); + alpha(r) = -(df(r)-Q(r,r)*alpha(r))*QQ(r); + if (alpha(r) < lower(r)) + alpha(r) = lower(r); + else if (alpha(r) > upper(r)) + alpha(r) = upper(r); + + const T delta = old_alpha-alpha(r); + + // Now update the gradient. We will perform the equivalent of: df = Q*alpha + b; + for(long k = 0; k < df.nr(); ++k) + df(k) -= Q(r,k)*delta; + } + //cout << "max_df: " << max_df << endl; + //cout << "objective value: " << 0.5*trans(alpha)*Q*alpha + trans(b)*alpha << endl; + + + + // Now do the main iteration block of this solver. The coordinate descent method + // we used above can improve the objective rapidly in the beginning. However, + // Nesterov's method has more rapid convergence once it gets going so this is what + // we use for the main iteration. + matrix v, v_old; + v = alpha; + // We need to get an upper bound on the Lipschitz constant for this QP. Since that + // is just the max eigenvalue of Q we can do it using Gershgorin disks. + const T lipschitz_bound = max(diag(Q) + (sum_cols(abs(Q)) - abs(diag(Q)))); + double lambda = 0; + unsigned long iter; + for (iter = 0; iter < max_iter; ++iter) + { + const double next_lambda = (1 + std::sqrt(1+4*lambda*lambda))/2; + const double gamma = (1-lambda)/next_lambda; + lambda = next_lambda; + + v_old = v; + + // now take a projected gradient step using Nesterov's method. + v = clamp(alpha - 1.0/lipschitz_bound * df, lower, upper); + alpha = dlib::clamp((1-gamma)*v + gamma*v_old, lower, upper); + + df = Q*alpha + b; + + // check for convergence every 10 iterations + if (iter%10 == 0) + { + max_df = 0; + double absalpha = 0; + double thealpha = 0; + for (long r = 0; r < Q.nr(); ++r) + { + absalpha += std::abs(alpha(r)); + if (alpha(r) <= lower(r) && df(r) > 0) + ;//alpha(r) = lower(r); + else if (alpha(r) >= upper(r) && df(r) < 0) + ;//alpha(r) = upper(r); + else if (std::abs(df(r)) > max_df) + { + max_df = std::abs(df(r)); + thealpha = std::abs(alpha(r)); + } + } + absalpha /= Q.nr(); + // Stop when the magnitude of the changes we are making to alpha are eps + // smaller than the typical alpha. + if (max_df/lipschitz_bound <= eps*std::min(thealpha,absalpha)) + break; + } + } + + //cout << "max_df: " << max_df << endl; + //cout << "objective value: " << 0.5*trans(alpha)*Q*alpha + trans(b)*alpha << endl; + return iter+1; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + namespace impl + { + // Check if each vector in Q_offdiag is actually a constant times the 1s vector. + template < + typename T, long NR, long NC, typename MM, typename L + > + bool has_uniform_offdiag_vectors( + const std::map, matrix>& Q_offdiag + ) + { + for (auto& x : Q_offdiag) + { + auto ref = x.second(0); + for (auto& y : x.second) + if (ref != y) + return false; + } + return true; + } + + template < + typename T, long NR, long NC, typename MM, typename L + > + matrix compact_offdiag( + const size_t& num_blocks, + const std::map, matrix>& Q_offdiag + ) + { + matrix temp; + // we can only compact the offdiag information if they are uniform vectors + if (!has_uniform_offdiag_vectors(Q_offdiag)) + return temp; + + temp.set_size(num_blocks, num_blocks); + temp = 0; + + for (auto& x : Q_offdiag) + { + long r = x.first.first; + long c = x.first.second; + temp(r,c) = x.second(0); + temp(c,r) = x.second(0); + } + + return temp; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, long NR, long NC, typename MM, typename L + > + unsigned long solve_qp_box_constrained_blockdiag ( + const std::vector>& Q_blocks, + const std::vector>& bs, + const std::map, matrix>& Q_offdiag, + std::vector>& alphas, + const std::vector>& lowers, + const std::vector>& uppers, + T eps = 1e-10, + unsigned long max_iter = 30000 + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(Q_blocks.size() > 0); + DLIB_CASSERT(Q_blocks.size() == bs.size() && + Q_blocks.size() == alphas.size() && + Q_blocks.size() == lowers.size() && + Q_blocks.size() == uppers.size(), + "Q_blocks.size(): "<< Q_blocks.size() << "\n" << + "bs.size(): "<< bs.size() << "\n" << + "alphas.size(): "<< alphas.size() << "\n" << + "lowers.size(): "<< lowers.size() << "\n" << + "uppers.size(): "<< uppers.size() << "\n" + ); + for (auto& Q : Q_blocks) + { + DLIB_CASSERT(Q.nr() == Q.nc(), "All the matrices in Q_blocks have the same dimensions."); + DLIB_CASSERT(Q.size() > 0, "All the matrices in Q_blocks must be non-empty and have the same dimensions."); + DLIB_CASSERT(Q.nr() == Q_blocks[0].nr() && Q.nc() == Q_blocks[0].nc(), "All the matrices in Q_blocks have the same dimensions."); + } +#ifdef ENABLE_ASSERTS + for (size_t i = 0; i < alphas.size(); ++i) + { + DLIB_CASSERT(is_col_vector(bs[i]) && bs[i].size() == Q_blocks[0].nr(), + "is_col_vector(bs["< 0 && max_iter > 0, "eps: " << eps << "\nmax_iter: "<< max_iter); +#endif // ENABLE_ASSERTS + + + const auto offdiag_compact = impl::compact_offdiag(Q_blocks.size(), Q_offdiag); + matrix temp, alphas_compact; + + // Compute f'(alpha) (i.e. the gradient of f(alpha)) for the current alpha. + std::vector> df;// = Q*alpha + b; + auto compute_df = [&]() + { + df.resize(Q_blocks.size()); + for (size_t i = 0; i < df.size(); ++i) + df[i] = Q_blocks[i]*alphas[i] + bs[i]; + + + // Don't forget to include the Q_offdiag terms in the computation. Note that + // we have two options for how we can compute this part. If Q_offdiag is + // uniform and can be compacted into a simple matrix and there are a lot of off + // diagonal entries then it's faster to do it as a matrix multiply. Otherwise + // we do the more general computation. + if (offdiag_compact.size() != 0 && Q_offdiag.size() > Q_blocks.size()*5) + { + // Do it as a matrix multiply (with a bit of data shuffling) + alphas_compact.set_size(alphas[0].size(), offdiag_compact.nr()); + for (long c = 0; c < alphas_compact.nc(); ++c) + set_colm(alphas_compact,c) = alphas[c]; + temp = alphas_compact*offdiag_compact; + for (size_t i = 0; i < df.size(); ++i) + df[i] += colm(temp,i); + } + else + { + // Do the fully general computation that allows for non-uniform values in + // the off diagonal vectors. + for (auto& p : Q_offdiag) + { + long r = p.first.first; + long c = p.first.second; + df[r] += pointwise_multiply(p.second, alphas[c]); + if (r != c) + df[c] += pointwise_multiply(p.second, alphas[r]); + } + } + }; + compute_df(); + + + + std::vector> Q_diag, Q_ggd; + std::vector> QQ;// = reciprocal_max(diag(Q)); + QQ.resize(Q_blocks.size()); + Q_diag.resize(Q_blocks.size()); + Q_ggd.resize(Q_blocks.size()); + + // We need to get an upper bound on the Lipschitz constant for this QP. Since that + // is just the max eigenvalue of Q we can do it using Gershgorin disks. + //const T lipschitz_bound = max(diag(Q) + (sum_cols(abs(Q)) - abs(diag(Q)))); + for (size_t i = 0; i < QQ.size(); ++i) + { + auto f = Q_offdiag.find(make_unordered_pair(i,i)); + if (f != Q_offdiag.end()) + Q_diag[i] = diag(Q_blocks[i]) + f->second; + else + Q_diag[i] = diag(Q_blocks[i]); + QQ[i] = reciprocal_max(Q_diag[i]); + + Q_ggd[i] = Q_diag[i] + (sum_cols(abs(Q_blocks[i]))-abs(diag(Q_blocks[i]))); + } + for (auto& p : Q_offdiag) + { + long r = p.first.first; + long c = p.first.second; + if (r != c) + { + Q_ggd[r] += abs(p.second); + Q_ggd[c] += abs(p.second); + } + } + T lipschitz_bound = -std::numeric_limits::infinity(); + for (auto& x : Q_ggd) + lipschitz_bound = std::max(lipschitz_bound, max(x)); + + + const long num_variables = alphas.size()*alphas[0].size(); + + // First we use a coordinate descent method to initialize alpha. + double max_df = 0; + for (long iter = 0; iter < num_variables*2; ++iter) + { + max_df = 0; + long best_r =0; + size_t best_r2 =0; + // find the best alpha to optimize. + for (size_t r2 = 0; r2 < alphas.size(); ++r2) + { + auto& alpha = alphas[r2]; + auto& df_ = df[r2]; + auto& lower = lowers[r2]; + auto& upper = uppers[r2]; + for (long r = 0; r < alpha.nr(); ++r) + { + if (alpha(r) <= lower(r) && df_(r) > 0) + ;//alpha(r) = lower(r); + else if (alpha(r) >= upper(r) && df_(r) < 0) + ;//alpha(r) = upper(r); + else if (std::abs(df_(r)) > max_df) + { + best_r = r; + best_r2 = r2; + max_df = std::abs(df_(r)); + } + } + } + + // now optimize alphas[best_r2](best_r) + const long r = best_r; + auto& alpha = alphas[best_r2]; + auto& lower = lowers[best_r2]; + auto& upper = uppers[best_r2]; + auto& df_ = df[best_r2]; + const T old_alpha = alpha(r); + alpha(r) = -(df_(r)-Q_diag[best_r2](r)*alpha(r))*QQ[best_r2](r); + if (alpha(r) < lower(r)) + alpha(r) = lower(r); + else if (alpha(r) > upper(r)) + alpha(r) = upper(r); + + const T delta = old_alpha-alpha(r); + + // Now update the gradient. We will perform the equivalent of: df = Q*alpha + + // b; except we only need to compute one column of the matrix multiply because + // only one element of alpha changed. + auto& Q = Q_blocks[best_r2]; + for(long k = 0; k < df_.nr(); ++k) + df_(k) -= Q(r,k)*delta; + for(size_t j = 0; j < Q_blocks.size(); ++j) + { + auto f = Q_offdiag.find(make_unordered_pair(best_r2, j)); + if (f != Q_offdiag.end()) + df[j](r) -= f->second(r)*delta; + } + } + + + + + std::vector> v(alphas), v_old(alphas.size()); + double lambda = 0; + unsigned long iter; + // Now do the main iteration block of this solver. The coordinate descent method + // we used above can improve the objective rapidly in the beginning. However, + // Nesterov's method has more rapid convergence once it gets going so this is what + // we use for the main iteration. + for (iter = 0; iter < max_iter; ++iter) + { + const double next_lambda = (1 + std::sqrt(1+4*lambda*lambda))/2; + const double gamma = (1-lambda)/next_lambda; + lambda = next_lambda; + + v_old.swap(v); + + + // now take a projected gradient step using Nesterov's method. + for (size_t j = 0; j < alphas.size(); ++j) + { + v[j] = clamp(alphas[j] - 1.0/lipschitz_bound * df[j], lowers[j], uppers[j]); + alphas[j] = clamp((1-gamma)*v[j] + gamma*v_old[j], lowers[j], uppers[j]); + } + + //df = Q*alpha + b; + compute_df(); + + // check for convergence every 10 iterations + if (iter%10 == 0) + { + max_df = 0; + double absalpha = 0; + double thealpha = 0; + for (size_t r2 = 0; r2 < alphas.size(); ++r2) + { + auto& alpha = alphas[r2]; + auto& df_ = df[r2]; + auto& lower = lowers[r2]; + auto& upper = uppers[r2]; + for (long r = 0; r < alpha.nr(); ++r) + { + absalpha += std::abs(alpha(r)); + if (alpha(r) <= lower(r) && df_(r) > 0) + ;//alpha(r) = lower(r); + else if (alpha(r) >= upper(r) && df_(r) < 0) + ;//alpha(r) = upper(r); + else if (std::abs(df_(r)) > max_df) + { + max_df = std::abs(df_(r)); + thealpha = std::abs(alpha(r)); + } + } + } + absalpha /= num_variables; + // Stop when the magnitude of the changes we are making to alpha are eps + // smaller than the typical alpha. + if (max_df/lipschitz_bound <= eps*std::min(thealpha,absalpha)) + break; + } + } + + return iter+1; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP1, + typename EXP2, + typename T, long NRa, long NRb + > + unsigned long find_gap_between_convex_hulls ( + const matrix_exp& A, + const matrix_exp& B, + matrix& cA, + matrix& cB, + const double eps, + const unsigned long max_iter = 1000 + ) + { + DLIB_CASSERT(A.size() != 0); + DLIB_CASSERT(B.size() != 0); + DLIB_CASSERT(A.nr() == B.nr(), "The dimensionality of the points in both convex hull sets must match"); + DLIB_CASSERT(eps > 0); + DLIB_CASSERT(max_iter > 0); + + cA.set_size(A.nc()); + cB.set_size(B.nc()); + + // initialize to the centroids of A and B respectively. + cA = 1.0/cA.size(); + cB = 1.0/cB.size(); + + + matrix AA, BB, AB, ABb, ABa; + + AA = trans(A)*A; + BB = trans(B)*B; + AB = trans(A)*B; + + unsigned long iter = 0; + for (iter = 0; iter < max_iter; ++iter) + { + // find the convex combination of A that is nearest to B*cB + ABb = AB*cB; + const auto smo_iter1 = solve_qp_using_smo(AA, ABb, cA, eps, cA.size()); + + // now find the convex combination of B that is nearest to A*cA + ABa = trans(AB)*cA; + const auto smo_iter2 = solve_qp_using_smo(BB, ABa, cB, eps, cB.size()); + + // stop if the QP solvers failed to improve + if (smo_iter1 == 1 && smo_iter2 == 1) + break; + } + + return iter+1; } diff --git a/lib/3rdParty/dlib/include/dlib/optimization/optimization_solve_qp_using_smo_abstract.h b/lib/3rdParty/dlib/include/dlib/optimization/optimization_solve_qp_using_smo_abstract.h index bdb69d0a..55f2e614 100644 --- a/lib/3rdParty/dlib/include/dlib/optimization/optimization_solve_qp_using_smo_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/optimization/optimization_solve_qp_using_smo_abstract.h @@ -4,6 +4,8 @@ #ifdef DLIB_OPTIMIZATION_SOLVE_QP_UsING_SMO_ABSTRACT_Hh_ #include "../matrix.h" +#include +#include "../unordered_pair.h" namespace dlib { @@ -58,51 +60,219 @@ namespace dlib typename EXP1, typename EXP2, typename EXP3, - typename T, long NR, long NC, typename MM, typename L + typename T, long NR, long NC, typename MM, typename L, + long NR2, long NC2 > unsigned long solve_qp4_using_smo ( const matrix_exp& A, const matrix_exp& Q, const matrix_exp& b, + const matrix_exp& d, matrix& alpha, + matrix& lambda, T eps, - unsigned long max_iter + unsigned long max_iter, + T max_lambda = std::numeric_limits::infinity() ); /*! requires - A.nc() == alpha.size() - Q.nr() == Q.nc() - is_col_vector(b) == true + - is_col_vector(d) == true - is_col_vector(alpha) == true - b.size() == alpha.size() == Q.nr() + - d.size() == A.nr() - alpha.size() > 0 - min(alpha) >= 0 - eps > 0 - max_iter > 0 + - max_lambda >= 0 ensures - Let C == sum(alpha) (i.e. C is the sum of the alpha values you supply to this function) - This function solves the following quadratic program: Minimize: f(alpha,lambda) == 0.5*trans(alpha)*Q*alpha - trans(alpha)*b + - 0.5*trans(lambda)*lambda - trans(lambda)*A*alpha + 0.5*trans(lambda)*lambda - trans(lambda)*A*alpha - trans(lambda)*d subject to the following constraints: - sum(alpha) == C (i.e. the sum of alpha values doesn't change) - min(alpha) >= 0 (i.e. all alpha values are nonnegative) - min(lambda) >= 0 (i.e. all lambda values are nonnegative) + - max(lambda) <= max_lambda (i.e. all lambda values are less than max_lambda) Where f is convex. This means that Q should be positive-semidefinite. - - The solution to the above QP will be stored in #alpha. The optimal - lambda is not output since its value is given by the following expression: - lowerbound(A*alpha,0) + - If you don't want an upper limit on lambda then max_lambda can be set to + infinity. + - The solution to the above QP will be stored in #alpha and #lambda. - This function uses a simple implementation of the sequential minimal optimization algorithm. It starts the algorithm with the given alpha and it works on the problem until the duality gap (i.e. how far away we are from the optimum solution) is less than eps. So eps controls how accurate the solution is and smaller values result in better solutions. + The initial value of lambda is ignored since the optimal lambda can be + obtained via a simple closed form expression given alpha. - At most max_iter iterations of optimization will be performed. - returns the number of iterations performed. If this method fails to converge to eps accuracy then the number returned will be max_iter+1. !*/ +// ---------------------------------------------------------------------------------------- + + template < + typename EXP1, + typename EXP2, + typename T, long NR, long NC, typename MM, typename L + > + unsigned long solve_qp_box_constrained ( + const matrix_exp& Q, + const matrix_exp& b, + matrix& alpha, + const matrix& lower, + const matrix& upper, + T eps = 1e-10, + unsigned long max_iter = 30000 + ); + /*! + requires + - Q.nr() == Q.nc() + - alpha.size() == lower.size() == upper.size() + - is_col_vector(b) == true + - is_col_vector(alpha) == true + - is_col_vector(lower) == true + - is_col_vector(upper) == true + - b.size() == alpha.size() == Q.nr() + - alpha.size() > 0 + - 0 <= min(alpha-lower) + - 0 <= max(upper-alpha) + - eps > 0 + - max_iter > 0 + ensures + - This function solves the following quadratic program: + Minimize: f(alpha) == 0.5*trans(alpha)*Q*alpha + trans(b)*alpha + subject to the following box constraints on alpha: + - 0 <= min(alpha-lower) + - 0 <= max(upper-alpha) + Where f is convex. This means that Q should be positive-semidefinite. + - The solution to the above QP will be stored in #alpha. + - This function uses a combination of a SMO algorithm along with Nesterov's + method as the main iteration of the solver. It starts the algorithm with the + given alpha and works on the problem until the magnitude of the changes we + are making to alpha are eps times smaller than the typical values in alpha. + So eps controls how accurate the solution is and smaller values result in + better solutions. + - At most max_iter iterations of optimization will be performed. + - returns the number of iterations performed. If this method fails to + converge to eps accuracy then the number returned will be max_iter+1. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, long NR, long NC, typename MM, typename L + > + unsigned long solve_qp_box_constrained_blockdiag ( + const std::vector>& Q_blocks, + const std::vector>& bs, + const std::map, matrix>& Q_offdiag, + std::vector>& alphas, + const std::vector>& lowers, + const std::vector>& uppers, + T eps = 1e-10, + unsigned long max_iter = 30000 + ); + /*! + requires + - Q_blocks.size() > 0 + - Q_blocks.size() == bs.size() == alphas.size() == lowers.size() == uppers.size() + - All the matrices in Q_blocks have the same dimensions. Moreover, they are + non-empty square matrices. + - All the matrices in bs, Q_offdiag, alphas, lowers, and uppers have the same + dimensions. Moreover, they are all column vectors. + - Q_blocks[0].nr() == alphas[0].size() + (i.e. the dimensionality of the column vectors in alphas must match the + dimensionality of the square matrices in Q_blocks.) + - for all valid i: + - 0 <= min(alphas[i]-lowers[i]) + - 0 <= max(uppers[i]-alphas[i]) + - eps > 0 + - max_iter > 0 + ensures + - This function solves the same QP as solve_qp_box_constrained(), except it is + optimized for the case where the Q matrix has a certain sparsity structure. + To be precise: + - Let Q1 be a block diagonal matrix with the elements of Q_blocks placed + along its diagonal, and in the order contained in Q_blocks. + - Let Q2 be a matrix with the same size as Q1, except instead of being block diagonal, it + is block structured into Q_blocks.nr() by Q_blocks.nc() blocks. If we let (r,c) be the + coordinate of each block then each block contains the matrix + diagm(Q_offdiag[make_unordered_pair(r,c)]) or the zero matrix if Q_offdiag has no entry + for the coordinate (r,c). + - Let Q == Q1+Q2 + - Let b == the concatenation of all the vectors in bs into one big vector. + - Let alpha == the concatenation of all the vectors in alphas into one big vector. + - Let lower == the concatenation of all the vectors in lowers into one big vector. + - Let upper == the concatenation of all the vectors in uppers into one big vector. + - Then this function solves the following quadratic program: + Minimize: f(alpha) == 0.5*trans(alpha)*Q*alpha + trans(b)*alpha + subject to the following box constraints on alpha: + - 0 <= min(alpha-lower) + - 0 <= max(upper-alpha) + Where f is convex. This means that Q should be positive-semidefinite. + - More specifically, this function is identical to + solve_qp_box_constrained(Q, b, alpha, lower, upper, eps, max_iter), + except that it runs faster since it avoids unnecessary computation by + taking advantage of the sparsity structure in the QP. + - The solution to the above QP will be stored in #alphas. + - This function uses a combination of a SMO algorithm along with Nesterov's + method as the main iteration of the solver. It starts the algorithm with the + given alpha and works on the problem until the magnitude of the changes we + are making to alpha are eps times smaller than the typical values in alpha. + So eps controls how accurate the solution is and smaller values result in + better solutions. + - At most max_iter iterations of optimization will be performed. + - returns the number of iterations performed. If this method fails to + converge to eps accuracy then the number returned will be max_iter+1. + !*/ +// ---------------------------------------------------------------------------------------- + + template < + typename EXP1, + typename EXP2, + typename T, long NRa, long NRb + > + unsigned long find_gap_between_convex_hulls ( + const matrix_exp& A, + const matrix_exp& B, + matrix& cA, + matrix& cB, + const double eps, + const unsigned long max_iter = 1000 + ); + /*! + requires + - A.nr() == B.nr() + - A.size() != 0 + - B.size() != 0 + - eps > 0 + - max_iter > 0 + ensures + - If you think of A and B as sets of column vectors, then we can identify the + convex sets hullA and hullB, which are the convex hulls of A and B + respectively. This function finds the pair of points in hullA and hullB that + are nearest to each other. To be precise, this function solves the following + quadratic program: + Minimize: f(cA,cB) == length_squared(A*cA - B*cB) + subject to the following constraints on cA and cB: + - is_col_vector(cA) == true && cA.size() == A.nc() + - is_col_vector(cB) == true && cB.size() == B.nc() + - sum(cA) == 1 && min(cA) >= 0 + - sum(cB) == 1 && min(cB) >= 0 + - This function uses an iterative block coordinate descent algorithm to solve + the QP. It runs until either max_iter iterations have been performed or the + QP is solved to at least eps accuracy. + - returns the number of iterations performed. If this method fails to + converge to eps accuracy then the number returned will be max_iter+1. + !*/ + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/optimization/optimization_trust_region.h b/lib/3rdParty/dlib/include/dlib/optimization/optimization_trust_region.h index 1b68fe02..5f0ad897 100644 --- a/lib/3rdParty/dlib/include/dlib/optimization/optimization_trust_region.h +++ b/lib/3rdParty/dlib/include/dlib/optimization/optimization_trust_region.h @@ -225,6 +225,168 @@ namespace dlib return max_iter+1; } +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template < + typename EXP1, + typename EXP2, + typename EXP3 + > + bool bounds_violated ( + const matrix_exp& v, + const matrix_exp& l, + const matrix_exp& u + ) + { + DLIB_ASSERT(v.nr() == l.nr() && v.nr() == u.nr()); + DLIB_ASSERT(v.nc() == l.nc() && v.nc() == u.nc()); + for (long r = 0; r < v.nr(); ++r) + { + for (long c = 0; c < v.nc(); c++) + { + if (!(l(r,c) <= v(r,c) && v(r,c) <= u(r,c))) + return true; + } + } + return false; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP1, + typename EXP2, + typename T, long NR, long NC, typename MM, typename L, + typename EXP3 + > + void solve_trust_region_subproblem_bounded ( + const matrix_exp& B_, + const matrix_exp& g_, + const typename EXP1::type radius_, + matrix& p_, + double eps, + unsigned long max_iter, + const matrix_exp& lower_, + const matrix_exp& upper_ + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(B_.nr() == B_.nc() && is_col_vector(g_) && g_.size() == B_.nr(), + "\t unsigned long solve_trust_region_subproblem_bounded()" + << "\n\t invalid arguments were given to this function" + << "\n\t B_.nr(): " << B_.nr() + << "\n\t B_.nc(): " << B_.nc() + << "\n\t is_col_vector(g_): " << is_col_vector(g_) + << "\n\t g_.size(): " << g_.size() + ); + DLIB_ASSERT(radius_ > 0 && eps > 0 && max_iter > 0, + "\t unsigned long solve_trust_region_subproblem_bounded()" + << "\n\t invalid arguments were given to this function" + << "\n\t radius_: " << radius_ + << "\n\t eps: " << eps + << "\n\t max_iter: " << max_iter + ); + DLIB_ASSERT(is_col_vector(lower_) && lower_.size() == g_.size()); + DLIB_ASSERT(is_col_vector(upper_) && upper_.size() == g_.size()); + DLIB_ASSERT(max(upper_-lower_) >= 0); + // make sure the problem is feasible. That is, there should be a point inside the + // lower and upper bounds that has a norm <= radius_ + DLIB_ASSERT(length(clamp(zeros_matrix(lower_),lower_,upper_)) <= radius_, + "The lower and upper bounds are incompatible with the radius since there is no point within the bounds with a norm less than the radius."); + + // We are going to solve this by greedily finding the most violated bound constraint, + // locking that variable to its constrained value, removing it from the problem, + // and then resolving. We do that until no more constraint violations are present. + + solve_trust_region_subproblem(B_,g_,radius_,p_,eps,max_iter); + + + // just stop here if all the bounds are satisfied. + if (!impl::bounds_violated(p_, lower_, upper_)) + return; + + matrix B = matrix_cast(B_); + matrix g = matrix_cast(g_); + double radius = radius_; + matrix p = matrix_cast(p_); + matrix lower = matrix_cast(lower_); + matrix upper = matrix_cast(upper_); + + // keep a table that tells us how to map any reduced QP back to the original QP + std::vector idxs(g.size()); + for (size_t i = 0; i < idxs.size(); ++i) + idxs[i] = i; + + + // while we haven't found a p that satisfies the bounds constraints + while(impl::bounds_violated(p, lower, upper) ) + { + // Find the most violated variable and fix its value to a constant (the bound + // value). + long most_violated_idx = 0; + double max_violation = 0; + double bounded_value = 0; + for (long i = 0; i < lower.size(); ++i) + { + if (!(lower(i) <= p(i) && p(i) <= upper(i))) + { + if (lower(i)-p(i) > max_violation) + { + max_violation = lower(i)-p(i); + most_violated_idx = i; + bounded_value = lower(i); + } + else if (p(i)-upper(i) > max_violation) + { + max_violation = p(i)-upper(i); + most_violated_idx = i; + bounded_value = upper(i); + } + } + } + + // assign this variable to its final value. + p_(idxs[most_violated_idx]) = bounded_value; + + + // now reduce the QP by removing the variable p_(idxs[most_violated_idx]). + idxs.erase(idxs.begin()+most_violated_idx); + // we are out of variables to remove since everything is at bounds. + if (idxs.size() == 0) + break; + + lower = remove_row(lower,most_violated_idx); + upper = remove_row(upper,most_violated_idx); + g += colm(B,most_violated_idx)*bounded_value; + g = remove_row(g,most_violated_idx); + p = remove_row(p,most_violated_idx); + B = removerc(B,most_violated_idx, most_violated_idx); + + // Removing a variable changes the radius, so we have to subtract the bounded + // value from the radius so as to not change the effective radius for the whole + // problem. + double squared_radius = radius*radius - bounded_value*bounded_value; + if (squared_radius <= 0) + { + p = 0; + break; + } + radius = std::sqrt(squared_radius); + + + solve_trust_region_subproblem(B,g,radius,p,eps,max_iter); + } + + // assign the non-bound-constrained variables to their final values + for (size_t i = 0; i < idxs.size(); ++i) + p_(idxs[i]) = p(i); + + } + +// ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- template < @@ -294,6 +456,8 @@ namespace dlib const type rho = measured_improvement/std::abs(predicted_improvement); + if (!is_finite(rho)) + break; if (rho < 0.25) { diff --git a/lib/3rdParty/dlib/include/dlib/optimization/optimization_trust_region_abstract.h b/lib/3rdParty/dlib/include/dlib/optimization/optimization_trust_region_abstract.h index c985c6e2..303ee746 100644 --- a/lib/3rdParty/dlib/include/dlib/optimization/optimization_trust_region_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/optimization/optimization_trust_region_abstract.h @@ -40,10 +40,62 @@ namespace dlib Minimize: f(p) == 0.5*trans(p)*B*p + trans(g)*p subject to the following constraint: - length(p) <= radius - - returns the number of iterations performed. If this method fails to - converge to eps accuracy then the number returned will be max_iter+1. - - if this function returns 0 or 1 then we are not hitting the radius bound. - Otherwise, the radius constraint is active and std::abs(length(#p)-radius) <= eps. + - returns the number of iterations performed. If this method fails to converge + to eps accuracy then the number returned will be max_iter+1. + - if (this function didn't terminate due to hitting the max_iter iteration limit) then + - if this function returns 0 or 1 then we are not hitting the radius bound Otherwise, + the radius constraint is active and std::abs(length(#p)-radius)/radius <= eps. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP1, + typename EXP2, + typename T, long NR, long NC, typename MM, typename L, + typename EXP3 + > + void solve_trust_region_subproblem_bounded ( + const matrix_exp& B, + const matrix_exp& g, + const typename EXP1::type radius, + matrix& p, + double eps, + unsigned long max_iter, + const matrix_exp& lower, + const matrix_exp& upper + ); + /*! + requires + - B == trans(B) + (i.e. B should be a symmetric matrix) + - B.nr() == B.nc() + - is_col_vector(g) == true + - is_col_vector(lower) == true + - is_col_vector(upper) == true + - g.size() == B.nr() + - lower.size() == B.nr() + - upper.size() == B.nr() + - p is capable of containing a column vector the size of g + (i.e. p = g; should be a legal expression) + - radius > 0 + - eps > 0 + - max_iter > 0 + - min(upper-lower) >= 0 + - length(clamp(zeros_matrix(lower),lower,upper)) <= radius + (i.e. the lower and upper bounds can't exclude all points with the desired radius.) + ensures + - This function solves the following optimization problem: + Minimize: f(p) == 0.5*trans(p)*B*p + trans(g)*p + subject to the following constraints: + - length(p) <= radius + - lower(i) <= p(i) <= upper(i), for all i + - Solves the problem to eps accuracy. We do this by greedily finding the most + violated bound constraint, locking that variable to its constrained value, removing + it from the problem, and then resolving. We do that until no more constraint + violations are present. Each time we just call solve_trust_region_subproblem() + to get the solution and pass eps and max_iter directly to these calls to + solve_trust_region_subproblem(). !*/ // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/ostream b/lib/3rdParty/dlib/include/dlib/ostream deleted file mode 100644 index eb0e59e4..00000000 --- a/lib/3rdParty/dlib/include/dlib/ostream +++ /dev/null @@ -1 +0,0 @@ -#include "dlib_include_path_tutorial.txt" diff --git a/lib/3rdParty/dlib/include/dlib/pipe/pipe_kernel_1.h b/lib/3rdParty/dlib/include/dlib/pipe/pipe_kernel_1.h index 6a5a8238..54375412 100644 --- a/lib/3rdParty/dlib/include/dlib/pipe/pipe_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/pipe/pipe_kernel_1.h @@ -66,7 +66,7 @@ namespace dlib typedef T type; explicit pipe ( - unsigned long maximum_size + size_t maximum_size ); virtual ~pipe ( @@ -109,16 +109,20 @@ namespace dlib bool is_enabled ( ) const; - unsigned long max_size ( + size_t max_size ( ) const; - unsigned long size ( + size_t size ( ) const; bool enqueue ( T& item ); + bool enqueue ( + T&& item + ) { return enqueue(item); } + bool dequeue ( T& item ); @@ -128,6 +132,11 @@ namespace dlib unsigned long timeout ); + bool enqueue_or_timeout ( + T&& item, + unsigned long timeout + ) { return enqueue_or_timeout(item,timeout); } + bool dequeue_or_timeout ( T& item, unsigned long timeout @@ -135,14 +144,14 @@ namespace dlib private: - unsigned long pipe_size; - const unsigned long pipe_max_size; + size_t pipe_size; + const size_t pipe_max_size; bool enabled; T* const data; - unsigned long first; - unsigned long last; + size_t first; + size_t last; mutex m; signaler dequeue_sig; @@ -172,7 +181,7 @@ namespace dlib > pipe:: pipe ( - unsigned long maximum_size + size_t maximum_size ) : pipe_size(0), pipe_max_size(maximum_size), @@ -304,7 +313,7 @@ namespace dlib template < typename T > - unsigned long pipe:: + size_t pipe:: max_size ( ) const { @@ -317,7 +326,7 @@ namespace dlib template < typename T > - unsigned long pipe:: + size_t pipe:: size ( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/pipe/pipe_kernel_abstract.h b/lib/3rdParty/dlib/include/dlib/pipe/pipe_kernel_abstract.h index c404e56e..91b2205e 100644 --- a/lib/3rdParty/dlib/include/dlib/pipe/pipe_kernel_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/pipe/pipe_kernel_abstract.h @@ -38,7 +38,7 @@ namespace dlib typedef T type; explicit pipe ( - unsigned long maximum_size + size_t maximum_size ); /*! ensures @@ -175,7 +175,7 @@ namespace dlib - #is_dequeue_enabled() == true !*/ - unsigned long max_size ( + size_t max_size ( ) const; /*! ensures @@ -183,7 +183,7 @@ namespace dlib pipe can contain. !*/ - unsigned long size ( + size_t size ( ) const; /*! ensures @@ -219,6 +219,11 @@ namespace dlib - #item == item (i.e. the value of item is unchanged) !*/ + bool enqueue (T&& item) { return enqueue(item); } + /*! + enable enqueueing from rvalues + !*/ + bool enqueue_or_timeout ( T& item, unsigned long timeout @@ -249,6 +254,11 @@ namespace dlib - #item == item (i.e. the value of item is unchanged) !*/ + bool enqueue_or_timeout (T&& item, unsigned long timeout) { return enqueue_or_timeout(item,timeout); } + /*! + enable enqueueing from rvalues + !*/ + bool dequeue ( T& item ); diff --git a/lib/3rdParty/dlib/include/dlib/pixel.h b/lib/3rdParty/dlib/include/dlib/pixel.h index 0082df57..50ead2c3 100644 --- a/lib/3rdParty/dlib/include/dlib/pixel.h +++ b/lib/3rdParty/dlib/include/dlib/pixel.h @@ -9,6 +9,7 @@ #include "algs.h" #include "uintn.h" #include +#include #include "enable_if.h" namespace dlib @@ -35,6 +36,7 @@ namespace dlib - bool rgb - bool rgb_alpha - bool hsi + - bool lab - bool has_alpha @@ -46,7 +48,7 @@ namespace dlib - is_unsigned The above public constants are subject to the following constraints: - - only one of grayscale, rgb, rgb_alpha, or hsi is true + - only one of grayscale, rgb, rgb_alpha, hsi or lab is true - if (rgb == true) then - The type T will be a struct with 3 public members of type unsigned char named "red" "green" and "blue". @@ -80,6 +82,16 @@ namespace dlib - min() == 0 - max() == 255 - is_unsigned == true + - else if (lab == true) then + - The type T will be a struct with 3 public members of type + unsigned char named "l" "a" and "b". + - This type of pixel represents the Lab color space. + - num == 3 + - has_alpha == false + - basic_pixel_type == unsigned char + - min() == 0 + - max() == 255 + - is_unsigned == true - else - grayscale == true - This type of pixel represents a grayscale color space. T @@ -189,6 +201,28 @@ namespace dlib unsigned char s; unsigned char i; }; + // ---------------------------------------------------------------------------------------- + + struct lab_pixel + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a simple struct that represents an Lab colored graphical pixel. + !*/ + + lab_pixel ( + ) {} + + lab_pixel ( + unsigned char l_, + unsigned char a_, + unsigned char b_ + ) : l(l_), a(a_), b(b_) {} + + unsigned char l; + unsigned char a; + unsigned char b; + }; // ---------------------------------------------------------------------------------------- @@ -337,6 +371,17 @@ namespace dlib provides serialization support for the hsi_pixel struct !*/ +// ---------------------------------------------------------------------------------------- + + inline void serialize ( + const lab_pixel& item, + std::ostream& out + ); + /*! + provides serialization support for the lab_pixel struct + !*/ + + // ---------------------------------------------------------------------------------------- inline void deserialize ( @@ -346,22 +391,32 @@ namespace dlib /*! provides deserialization support for the hsi_pixel struct !*/ +// ---------------------------------------------------------------------------------------- + + inline void deserialize ( + lab_pixel& item, + std::istream& in + ); + /*! + provides deserialization support for the lab_pixel struct + !*/ // ---------------------------------------------------------------------------------------- template <> struct pixel_traits { - const static bool rgb = true; - const static bool rgb_alpha = false; - const static bool grayscale = false; - const static bool hsi = false; - const static long num = 3; + constexpr static bool rgb = true; + constexpr static bool rgb_alpha = false; + constexpr static bool grayscale = false; + constexpr static bool hsi = false; + constexpr static bool lab = false; + enum { num = 3}; typedef unsigned char basic_pixel_type; static basic_pixel_type min() { return 0;} static basic_pixel_type max() { return 255;} - const static bool is_unsigned = true; - const static bool has_alpha = false; + constexpr static bool is_unsigned = true; + constexpr static bool has_alpha = false; }; // ---------------------------------------------------------------------------------------- @@ -369,16 +424,17 @@ namespace dlib template <> struct pixel_traits { - const static bool rgb = true; - const static bool rgb_alpha = false; - const static bool grayscale = false; - const static bool hsi = false; - const static long num = 3; + constexpr static bool rgb = true; + constexpr static bool rgb_alpha = false; + constexpr static bool grayscale = false; + constexpr static bool hsi = false; + constexpr static bool lab = false; + constexpr static long num = 3; typedef unsigned char basic_pixel_type; static basic_pixel_type min() { return 0;} static basic_pixel_type max() { return 255;} - const static bool is_unsigned = true; - const static bool has_alpha = false; + constexpr static bool is_unsigned = true; + constexpr static bool has_alpha = false; }; // ---------------------------------------------------------------------------------------- @@ -386,16 +442,17 @@ namespace dlib template <> struct pixel_traits { - const static bool rgb = false; - const static bool rgb_alpha = true; - const static bool grayscale = false; - const static bool hsi = false; - const static long num = 4; + constexpr static bool rgb = false; + constexpr static bool rgb_alpha = true; + constexpr static bool grayscale = false; + constexpr static bool hsi = false; + constexpr static bool lab = false; + constexpr static long num = 4; typedef unsigned char basic_pixel_type; static basic_pixel_type min() { return 0;} static basic_pixel_type max() { return 255;} - const static bool is_unsigned = true; - const static bool has_alpha = true; + constexpr static bool is_unsigned = true; + constexpr static bool has_alpha = true; }; // ---------------------------------------------------------------------------------------- @@ -404,16 +461,36 @@ namespace dlib template <> struct pixel_traits { - const static bool rgb = false; - const static bool rgb_alpha = false; - const static bool grayscale = false; - const static bool hsi = true; - const static long num = 3; + constexpr static bool rgb = false; + constexpr static bool rgb_alpha = false; + constexpr static bool grayscale = false; + constexpr static bool hsi = true; + constexpr static bool lab = false; + constexpr static long num = 3; typedef unsigned char basic_pixel_type; static basic_pixel_type min() { return 0;} static basic_pixel_type max() { return 255;} - const static bool is_unsigned = true; - const static bool has_alpha = false; + constexpr static bool is_unsigned = true; + constexpr static bool has_alpha = false; + }; + +// ---------------------------------------------------------------------------------------- + + + template <> + struct pixel_traits + { + constexpr static bool rgb = false; + constexpr static bool rgb_alpha = false; + constexpr static bool grayscale = false; + constexpr static bool hsi = false; + constexpr static bool lab = true; + constexpr static long num = 3; + typedef unsigned char basic_pixel_type; + static basic_pixel_type min() { return 0;} + static basic_pixel_type max() { return 255;} + constexpr static bool is_unsigned = true; + constexpr static bool has_alpha = false; }; // ---------------------------------------------------------------------------------------- @@ -421,16 +498,17 @@ namespace dlib template struct grayscale_pixel_traits { - const static bool rgb = false; - const static bool rgb_alpha = false; - const static bool grayscale = true; - const static bool hsi = false; - const static long num = 1; - const static bool has_alpha = false; + constexpr static bool rgb = false; + constexpr static bool rgb_alpha = false; + constexpr static bool grayscale = true; + constexpr static bool hsi = false; + constexpr static bool lab = false; + constexpr static long num = 1; + constexpr static bool has_alpha = false; typedef T basic_pixel_type; static basic_pixel_type min() { return std::numeric_limits::min();} static basic_pixel_type max() { return std::numeric_limits::max();} - const static bool is_unsigned = is_unsigned_type::value; + constexpr static bool is_unsigned = is_unsigned_type::value; }; template <> struct pixel_traits : public grayscale_pixel_traits {}; @@ -452,22 +530,29 @@ namespace dlib template struct float_grayscale_pixel_traits { - const static bool rgb = false; - const static bool rgb_alpha = false; - const static bool grayscale = true; - const static bool hsi = false; - const static long num = 1; - const static bool has_alpha = false; + constexpr static bool rgb = false; + constexpr static bool rgb_alpha = false; + constexpr static bool grayscale = true; + constexpr static bool hsi = false; + constexpr static bool lab = false; + constexpr static long num = 1; + constexpr static bool has_alpha = false; typedef T basic_pixel_type; static basic_pixel_type min() { return -std::numeric_limits::max();} static basic_pixel_type max() { return std::numeric_limits::max();} - const static bool is_unsigned = false; + constexpr static bool is_unsigned = false; }; template <> struct pixel_traits : public float_grayscale_pixel_traits {}; template <> struct pixel_traits : public float_grayscale_pixel_traits {}; template <> struct pixel_traits : public float_grayscale_pixel_traits {}; + // These are here mainly so you can easily copy images into complex arrays. This is + // useful when you want to do a FFT on an image or some similar operation. + template <> struct pixel_traits > : public float_grayscale_pixel_traits {}; + template <> struct pixel_traits > : public float_grayscale_pixel_traits {}; + template <> struct pixel_traits > : public float_grayscale_pixel_traits {}; + // ---------------------------------------------------------------------------------------- // The following is a bunch of conversion stuff for the assign_pixel function. @@ -608,6 +693,15 @@ namespace dlib dest.i = src.i; } + template < typename P1, typename P2 > + typename enable_if_c::lab && pixel_traits::lab>::type + assign(P1& dest, const P2& src) + { + dest.l = src.l; + dest.a = src.a; + dest.b = src.b; + } + // ----------------------------- // dest is a grayscale @@ -666,6 +760,13 @@ namespace dlib assign_pixel(dest, src.i); } + template < typename P1, typename P2 > + typename enable_if_c::grayscale && pixel_traits::lab>::type + assign(P1& dest, const P2& src) + { + assign_pixel(dest, src.l); + } + // ----------------------------- @@ -764,6 +865,161 @@ namespace dlib return(c2); } + // ----------------------------- + + struct Lab + { + double l; + double a; + double b; + }; + /* + Calculate Lab from RGB + L is between 0 and 100 + a is between -128 and 127 + b is between -128 and 127 + RGB is between 0.0 and 1.0 + */ + inline Lab RGB2Lab(COLOUR c1) + { + Lab c2; + using namespace std; + + double var_R = c1.r; + double var_G = c1.g; + double var_B = c1.b; + + if (var_R > 0.04045) { + var_R = pow(((var_R + 0.055) / 1.055), 2.4); + } else { + var_R = var_R / 12.92; + } + + if (var_G > 0.04045) { + var_G = pow(((var_G + 0.055) / 1.055), 2.4); + } else { + var_G = var_G / 12.92; + } + + if (var_B > 0.04045) { + var_B = pow(((var_B + 0.055) / 1.055), 2.4); + } else { + var_B = var_B / 12.92; + } + + var_R = var_R * 100; + var_G = var_G * 100; + var_B = var_B * 100; + +//Observer. = 2°, Illuminant = D65 + double X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805; + double Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722; + double Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505; + + double var_X = X / 95.047; + double var_Y = Y / 100.000; + double var_Z = Z / 108.883; + + if (var_X > 0.008856) { + var_X = pow(var_X, (1.0 / 3)); + } + else { + var_X = (7.787 * var_X) + (16.0 / 116); + } + + if (var_Y > 0.008856) { + var_Y = pow(var_Y, (1.0 / 3)); + } + else { + var_Y = (7.787 * var_Y) + (16.0 / 116); + } + + if (var_Z > 0.008856) { + var_Z = pow(var_Z, (1.0 / 3)); + } + else { + var_Z = (7.787 * var_Z) + (16.0 / 116); + } + + //clamping + c2.l = max(0.0, (116.0 * var_Y) - 16); + c2.a = max(-128.0, min(127.0, 500.0 * (var_X - var_Y))); + c2.b = max(-128.0, min(127.0, 200.0 * (var_Y - var_Z))); + + return c2; + } + + /* + Calculate RGB from Lab, reverse of RGB2LAb() + L is between 0 and 100 + a is between -128 and 127 + b is between -128 and 127 + RGB is between 0.0 and 1.0 + */ + inline COLOUR Lab2RGB(Lab c1) { + COLOUR c2; + using namespace std; + + double var_Y = (c1.l + 16) / 116.0; + double var_X = (c1.a / 500.0) + var_Y; + double var_Z = var_Y - (c1.b / 200); + + if (pow(var_Y, 3) > 0.008856) { + var_Y = pow(var_Y, 3); + } else { + var_Y = (var_Y - 16.0 / 116) / 7.787; + } + + if (pow(var_X, 3) > 0.008856) { + var_X = pow(var_X, 3); + } else { + var_X = (var_X - 16.0 / 116) / 7.787; + } + + if (pow(var_Z, 3) > 0.008856) { + var_Z = pow(var_Z, 3); + } else { + var_Z = (var_Z - 16.0 / 116) / 7.787; + } + + double X = var_X * 95.047; + double Y = var_Y * 100.000; + double Z = var_Z * 108.883; + + var_X = X / 100.0; + var_Y = Y / 100.0; + var_Z = Z / 100.0; + + double var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986; + double var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415; + double var_B = var_X * 0.0557 + var_Y * -0.2040 + var_Z * 1.0570; + + if (var_R > 0.0031308) { + var_R = 1.055 * pow(var_R, (1 / 2.4)) - 0.055; + } else { + var_R = 12.92 * var_R; + } + + if (var_G > 0.0031308) { + var_G = 1.055 * pow(var_G, (1 / 2.4)) - 0.055; + } else { + var_G = 12.92 * var_G; + } + + if (var_B > 0.0031308) { + var_B = 1.055 * pow(var_B, (1 / 2.4)) - 0.055; + } else { + var_B = 12.92 * var_B; + } + + // clamping + c2.r = max(0.0, min(1.0, var_R)); + c2.g = max(0.0, min(1.0, var_G)); + c2.b = max(0.0, min(1.0, var_B)); + + return (c2); + } + // ----------------------------- // dest is a color rgb_pixel @@ -846,6 +1102,23 @@ namespace dlib dest.blue = static_cast(c.b*255.0 + 0.5); } + template < typename P1, typename P2 > + typename enable_if_c::rgb && pixel_traits::lab>::type + assign(P1& dest, const P2& src) + { + COLOUR c; + Lab l; + l.l = (src.l/255.0)*100; + l.a = (src.a-128.0); + l.b = (src.b-128.0); + c = Lab2RGB(l); + + dest.red = static_cast(c.r*255.0 + 0.5); + dest.green = static_cast(c.g*255.0 + 0.5); + dest.blue = static_cast(c.b*255.0 + 0.5); + } + + // ----------------------------- // dest is a color rgb_alpha_pixel @@ -901,6 +1174,22 @@ namespace dlib dest.alpha = 255; } + template < typename P1, typename P2 > + typename enable_if_c::rgb_alpha && pixel_traits::lab>::type + assign(P1& dest, const P2& src) + { + COLOUR c; + Lab l; + l.l = (src.l/255.0)*100; + l.a = (src.a-128.0); + l.b = (src.b-128.0); + c = Lab2RGB(l); + + dest.red = static_cast(c.r * 255 + 0.5); + dest.green = static_cast(c.g * 255 + 0.5); + dest.blue = static_cast(c.b * 255 + 0.5); + dest.alpha = 255; + } // ----------------------------- // dest is an hsi pixel @@ -955,6 +1244,84 @@ namespace dlib assign_pixel_helpers::assign(dest,temp); } + template < typename P1, typename P2 > + typename enable_if_c::hsi && pixel_traits::lab>::type + assign(P1& dest, const P2& src) + { + rgb_pixel temp; + // convert lab value to our temp rgb pixel + assign_pixel_helpers::assign(temp,src); + // now we can just go assign the new rgb value to the + // hsi pixel + assign_pixel_helpers::assign(dest,temp); + } + + // ----------------------------- + // dest is an lab pixel + template < typename P1> + typename enable_if_c::lab>::type + assign(P1& dest, const unsigned char& src) + { + dest.a = 128; + dest.b = 128; + dest.l = src; + } + + + template < typename P1, typename P2 > + typename enable_if_c::lab && pixel_traits::grayscale>::type + assign(P1& dest, const P2& src) + { + dest.a = 128; + dest.b = 128; + assign_pixel(dest.l, src); + } + + template < typename P1, typename P2 > + typename enable_if_c::lab && pixel_traits::rgb>::type + assign(P1& dest, const P2& src) + { + COLOUR c1; + Lab c2; + c1.r = src.red / 255.0; + c1.g = src.green / 255.0; + c1.b = src.blue / 255.0; + c2 = RGB2Lab(c1); + + dest.l = static_cast((c2.l / 100) * 255 + 0.5); + dest.a = static_cast(c2.a + 128 + 0.5); + dest.b = static_cast(c2.b + 128 + 0.5); + } + + template < typename P1, typename P2 > + typename enable_if_c::lab && pixel_traits::rgb_alpha>::type + assign(P1& dest, const P2& src) + { + rgb_pixel temp; + // convert target lab pixel to rgb + assign_pixel_helpers::assign(temp,dest); + + // now assign the rgb_alpha value to our temp rgb pixel + assign_pixel_helpers::assign(temp,src); + + // now we can just go assign the new rgb value to the + // lab pixel + assign_pixel_helpers::assign(dest,temp); + } + + template < typename P1, typename P2 > + typename enable_if_c::lab && pixel_traits::hsi>::type + assign(P1& dest, const P2& src) + { + rgb_pixel temp; + + // convert hsi value to our temp rgb pixel + assign_pixel_helpers::assign(temp,src); + + // now we can just go assign the new rgb value to the + // lab pixel + assign_pixel_helpers::assign(dest,temp); + } } // ----------------------------- @@ -983,7 +1350,7 @@ namespace dlib typename P, typename T > - inline typename enable_if_c::grayscale == false&& + inline typename enable_if_c::grayscale == false && pixel_traits

::has_alpha>::type assign_pixel_intensity_helper ( P& dest, const T& new_intensity @@ -1004,7 +1371,7 @@ namespace dlib typename P, typename T > - inline typename enable_if_c::grayscale == false&& + inline typename enable_if_c::grayscale == false && pixel_traits

::has_alpha == false>::type assign_pixel_intensity_helper ( P& dest, const T& new_intensity @@ -1236,6 +1603,44 @@ namespace dlib } } +// ---------------------------------------------------------------------------------------- + + inline void serialize ( + const lab_pixel& item, + std::ostream& out + ) + { + try + { + serialize(item.l,out); + serialize(item.a,out); + serialize(item.b,out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing object of type lab_pixel"); + } + } + +// ---------------------------------------------------------------------------------------- + + inline void deserialize ( + lab_pixel& item, + std::istream& in + ) + { + try + { + deserialize(item.l,in); + deserialize(item.a,in); + deserialize(item.b,in); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing object of type lab_pixel"); + } + } + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/platform.h b/lib/3rdParty/dlib/include/dlib/platform.h index 6aaae61c..f3000a6c 100644 --- a/lib/3rdParty/dlib/include/dlib/platform.h +++ b/lib/3rdParty/dlib/include/dlib/platform.h @@ -1,5 +1,10 @@ // Copyright (C) 2006 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. + +#ifdef DLIB_ALL_SOURCE_END +#include "dlib_basic_cpp_build_tutorial.txt" +#endif + #ifndef DLIB_PLATFORm_ #define DLIB_PLATFORm_ diff --git a/lib/3rdParty/dlib/include/dlib/python.h b/lib/3rdParty/dlib/include/dlib/python.h index 4b2580c4..4898d56c 100644 --- a/lib/3rdParty/dlib/include/dlib/python.h +++ b/lib/3rdParty/dlib/include/dlib/python.h @@ -3,10 +3,9 @@ #ifndef DLIB_PYTHoN_TOP_ #define DLIB_PYTHoN_TOP_ -#include "python/boost_python_utils.h" +#include "python/pybind_utils.h" #include "python/pyassert.h" #include "python/serialize_pickle.h" -#include "python/numpy.h" #include "python/numpy_image.h" #endif // DLIB_PYTHoN_TOP_ diff --git a/lib/3rdParty/dlib/include/dlib/python/boost_python_utils.h b/lib/3rdParty/dlib/include/dlib/python/boost_python_utils.h deleted file mode 100644 index effca7c8..00000000 --- a/lib/3rdParty/dlib/include/dlib/python/boost_python_utils.h +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (C) 2013 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_BOOST_PYTHON_UtILS_Hh_ -#define DLIB_BOOST_PYTHON_UtILS_Hh_ - -#include -#include -#include -#include - -inline bool hasattr( - boost::python::object obj, - const std::string& attr_name -) -/*! - ensures - - if (obj has an attribute named attr_name) then - - returns true - - else - - returns false -!*/ -{ - return PyObject_HasAttrString(obj.ptr(), attr_name.c_str()); -} - -// ---------------------------------------------------------------------------------------- - -template -std::vector python_list_to_vector ( - const boost::python::object& obj -) -/*! - ensures - - converts a python object into a std::vector and returns it. -!*/ -{ - std::vector vect(len(obj)); - for (unsigned long i = 0; i < vect.size(); ++i) - { - vect[i] = boost::python::extract(obj[i]); - } - return vect; -} - -template -boost::python::list vector_to_python_list ( - const std::vector& vect -) -/*! - ensures - - converts a std::vector into a python list object. -!*/ -{ - boost::python::list obj; - for (unsigned long i = 0; i < vect.size(); ++i) - obj.append(vect[i]); - return obj; -} - -// ---------------------------------------------------------------------------------------- - -template -boost::shared_ptr load_object_from_file ( - const std::string& filename -) -/*! - ensures - - deserializes an object of type T from the given file and returns it. -!*/ -{ - std::ifstream fin(filename.c_str(), std::ios::binary); - if (!fin) - throw dlib::error("Unable to open " + filename); - boost::shared_ptr obj(new T()); - deserialize(*obj, fin); - return obj; -} - -// ---------------------------------------------------------------------------------------- - - -#endif // DLIB_BOOST_PYTHON_UtILS_Hh_ - diff --git a/lib/3rdParty/dlib/include/dlib/python/numpy.h b/lib/3rdParty/dlib/include/dlib/python/numpy.h deleted file mode 100644 index 264460a7..00000000 --- a/lib/3rdParty/dlib/include/dlib/python/numpy.h +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (C) 2014 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_PYTHON_NuMPY_Hh_ -#define DLIB_PYTHON_NuMPY_Hh_ - -#include -#include -#include -#include - -// ---------------------------------------------------------------------------------------- - -template -void validate_numpy_array_type ( - boost::python::object& obj -) -{ - using namespace boost::python; - const char ch = extract(obj.attr("dtype").attr("char")); - - if (dlib::is_same_type::value && ch != 'd') - throw dlib::error("Expected numpy.ndarray of float64"); - if (dlib::is_same_type::value && ch != 'f') - throw dlib::error("Expected numpy.ndarray of float32"); - if (dlib::is_same_type::value && ch != 'i') - throw dlib::error("Expected numpy.ndarray of int32"); - if (dlib::is_same_type::value && ch != 'B') - throw dlib::error("Expected numpy.ndarray of uint8"); -} - -// ---------------------------------------------------------------------------------------- - -template -void get_numpy_ndarray_parts ( - boost::python::object& obj, - T*& data, - long (&shape)[dims] -) -/*! - ensures - - extracts the pointer to the data from the given numpy ndarray. Stores the shape - of the array into #shape. -!*/ -{ - Py_buffer pybuf; - if (PyObject_GetBuffer(obj.ptr(), &pybuf, PyBUF_ND | PyBUF_WRITABLE )) - throw dlib::error("Expected contiguous and writable numpy.ndarray."); - - try - { - validate_numpy_array_type(obj); - data = (T*)pybuf.buf; - - if (pybuf.ndim > dims) - throw dlib::error("Expected array with " + dlib::cast_to_string(dims) + " dimensions."); - - for (int i = 0; i < dims; ++i) - { - if (i < pybuf.ndim) - shape[i] = pybuf.shape[i]; - else - shape[i] = 1; - } - } - catch(...) - { - PyBuffer_Release(&pybuf); - throw; - } - PyBuffer_Release(&pybuf); -} - -// ---------------------------------------------------------------------------------------- - -template -void get_numpy_ndarray_parts ( - const boost::python::object& obj, - const T*& data, - long (&shape)[dims] -) -/*! - ensures - - extracts the pointer to the data from the given numpy ndarray. Stores the shape - of the array into #shape. -!*/ -{ - Py_buffer pybuf; - if (PyObject_GetBuffer(obj.ptr(), &pybuf, PyBUF_ND )) - throw dlib::error("Expected contiguous numpy.ndarray."); - - try - { - validate_numpy_array_type(obj); - data = (const T*)pybuf.buf; - - if (pybuf.ndim > dims) - throw dlib::error("Expected array with " + dlib::cast_to_string(dims) + " dimensions."); - - for (int i = 0; i < dims; ++i) - { - if (i < pybuf.ndim) - shape[i] = pybuf.shape[i]; - else - shape[i] = 1; - } - } - catch(...) - { - PyBuffer_Release(&pybuf); - throw; - } - PyBuffer_Release(&pybuf); -} - -// ---------------------------------------------------------------------------------------- - -#endif // DLIB_PYTHON_NuMPY_Hh_ - diff --git a/lib/3rdParty/dlib/include/dlib/python/numpy_image.h b/lib/3rdParty/dlib/include/dlib/python/numpy_image.h index 61e028a1..e2ddcf8b 100644 --- a/lib/3rdParty/dlib/include/dlib/python/numpy_image.h +++ b/lib/3rdParty/dlib/include/dlib/python/numpy_image.h @@ -3,118 +3,415 @@ #ifndef DLIB_PYTHON_NuMPY_IMAGE_Hh_ #define DLIB_PYTHON_NuMPY_IMAGE_Hh_ -#include "numpy.h" -#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +namespace py = pybind11; -// ---------------------------------------------------------------------------------------- - -class numpy_gray_image -{ -public: - - numpy_gray_image() : _data(0), _nr(0), _nc(0) {} - numpy_gray_image (boost::python::object& img) - { - long shape[2]; - get_numpy_ndarray_parts(img, _data, shape); - _nr = shape[0]; - _nc = shape[1]; - } - - friend inline long num_rows(const numpy_gray_image& img) { return img._nr; } - friend inline long num_columns(const numpy_gray_image& img) { return img._nc; } - friend inline void* image_data(numpy_gray_image& img) { return img._data; } - friend inline const void* image_data(const numpy_gray_image& img) { return img._data; } - friend inline long width_step(const numpy_gray_image& img) { return img._nc*sizeof(unsigned char); } - -private: - - unsigned char* _data; - long _nr; - long _nc; -}; namespace dlib { - template <> - struct image_traits + +// ---------------------------------------------------------------------------------------- + + template < + typename pixel_type + > + bool is_image ( + const py::array& img + ) + /*! + ensures + - returns true if and only if the given python numpy array can reasonably be + interpreted as an image containing pixel_type pixels. + !*/ { - typedef unsigned char pixel_type; + using basic_pixel_type = typename pixel_traits::basic_pixel_type; + const size_t expected_channels = pixel_traits::num; + + const bool has_correct_number_of_dims = (img.ndim()==2 && expected_channels==1) || + (img.ndim()==3 && img.shape(2)==expected_channels); + + return img.dtype().kind() == py::dtype::of().kind() && + img.itemsize() == sizeof(basic_pixel_type) && + has_correct_number_of_dims; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename pixel_type + > + void assert_correct_num_channels_in_image ( + const py::array& img + ) + { + const size_t expected_channels = pixel_traits::num; + if (expected_channels == 1) + { + if (!(img.ndim() == 2 || (img.ndim()==3&&img.shape(2)==1))) + throw dlib::error("Expected a 2D numpy array, but instead got one with " + std::to_string(img.ndim()) + " dimensions."); + } + else + { + if (img.ndim() != 3) + { + throw dlib::error("Expected a numpy array with 3 dimensions, but instead got one with " + std::to_string(img.ndim()) + " dimensions."); + } + else if (img.shape(2) != expected_channels) + { + if (pixel_traits::rgb) + throw dlib::error("Expected a RGB image with " + std::to_string(expected_channels) + " channels but got an image with " + std::to_string(img.shape(2)) + " channels."); + else + throw dlib::error("Expected an image with " + std::to_string(expected_channels) + " channels but got an image with " + std::to_string(img.shape(2)) + " channels."); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename pixel_type + > + void assert_is_image ( + const py::array& obj + ) + { + if (!is_image(obj)) + { + assert_correct_num_channels_in_image(obj); + + using basic_pixel_type = typename pixel_traits::basic_pixel_type; + const char expected_type = py::dtype::of().kind(); + const char got_type = obj.dtype().kind(); + + const size_t expected_size = sizeof(basic_pixel_type); + const size_t got_size = obj.itemsize(); + + auto toname = [](char type, size_t size) { + if (type == 'i' && size == 1) return "int8"; + else if (type == 'i' && size == 2) return "int16"; + else if (type == 'i' && size == 4) return "int32"; + else if (type == 'i' && size == 8) return "int64"; + else if (type == 'u' && size == 1) return "uint8"; + else if (type == 'u' && size == 2) return "uint16"; + else if (type == 'u' && size == 4) return "uint32"; + else if (type == 'u' && size == 8) return "uint64"; + else if (type == 'f' && size == 4) return "float32"; + else if (type == 'd' && size == 8) return "float64"; + else DLIB_CASSERT(false, "unknown type"); + }; + + throw dlib::error("Expected numpy array with elements of type " + std::string(toname(expected_type,expected_size)) + " but got " + toname(got_type, got_size) + "."); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename pixel_type + > + class numpy_image : public py::array_t::basic_pixel_type, py::array::c_style> + { + /*! + REQUIREMENTS ON pixel_type + - is a dlib pixel type, this just means that dlib::pixel_traits + is defined. + + WHAT THIS OBJECT REPRESENTS + This is an image object that implements dlib's generic image interface and + is backed by a numpy array. It therefore is easily interchanged with + python since there is no copying. It is functionally just a pybind11 + array_t object with the additional routines needed to conform to dlib's + generic image API. It also includes appropriate runtime checks to make + sure that the numpy array is always typed and sized appropriately relative + to the supplied pixel_type. + !*/ + public: + + numpy_image() = default; + + numpy_image( + const py::array& img + ) : py::array_t::basic_pixel_type, py::array::c_style>(img) + { + assert_is_image(img); + } + + numpy_image ( + const py::object& img + ) + { + py::array_t::basic_pixel_type, py::array::c_style> arr = img.cast(); + assert_is_image(arr); + py::array_t::basic_pixel_type, py::array::c_style>::operator=(arr); + } + + numpy_image( + const numpy_image& img + ) : py::array_t::basic_pixel_type, py::array::c_style>(img) + { + } + + numpy_image& operator= ( + const py::object& rhs + ) + { + py::array arr = rhs.cast(); + assert_is_image(arr); + py::array_t::basic_pixel_type, py::array::c_style>::operator=(arr); + return *this; + } + + numpy_image& operator= ( + const py::array_t::basic_pixel_type, py::array::c_style>& rhs + ) + { + assert_is_image(rhs); + py::array_t::basic_pixel_type, py::array::c_style>::operator=(rhs); + return *this; + } + + numpy_image& operator= ( + const numpy_image& rhs + ) + { + py::array_t::basic_pixel_type, py::array::c_style>::operator=(rhs); + return *this; + } + + numpy_image ( + matrix&& rhs + ) + { + *this = convert_to_numpy(std::move(rhs)); + } + + numpy_image& operator= ( + matrix&& rhs + ) + { + *this = convert_to_numpy(std::move(rhs)); + return *this; + } + + void set_size(size_t rows, size_t cols) + { + using basic_pixel_type = typename pixel_traits::basic_pixel_type; + constexpr size_t channels = pixel_traits::num; + if (channels != 1) + *this = py::array_t({rows, cols, channels}); + else + *this = py::array_t({rows, cols}); + } + + private: + static py::array_t::basic_pixel_type, py::array::c_style> convert_to_numpy(matrix&& img) + { + using basic_pixel_type = typename pixel_traits::basic_pixel_type; + const size_t dtype_size = sizeof(basic_pixel_type); + const auto rows = static_cast(num_rows(img)); + const auto cols = static_cast(num_columns(img)); + const size_t channels = pixel_traits::num; + const size_t image_size = dtype_size * rows * cols * channels; + + std::unique_ptr arr_ptr = img.steal_memory(); + basic_pixel_type* arr = (basic_pixel_type *) arr_ptr.release(); + + if (channels == 1) + { + return pybind11::template array_t( + {rows, cols}, // shape + {dtype_size*cols, dtype_size}, // strides + arr, // pointer + pybind11::capsule{ arr, [](void *arr_p) { delete[] reinterpret_cast(arr_p); } } + ); + } + else + { + return pybind11::template array_t( + {rows, cols, channels}, // shape + {dtype_size * cols * channels, dtype_size * channels, dtype_size}, // strides + arr, // pointer + pybind11::capsule{ arr, [](void *arr_p) { delete[] reinterpret_cast(arr_p); } } + ); + } + } + + }; + +// ---------------------------------------------------------------------------------------- + + template + void assign_image ( + numpy_image& dest, + const py::array& src + ) + { + if (is_image(src)) dest = src; + else if (is_image(src)) assign_image(dest, numpy_image(src)); + else if (is_image(src)) assign_image(dest, numpy_image(src)); + else if (is_image(src)) assign_image(dest, numpy_image(src)); + else if (is_image(src)) assign_image(dest, numpy_image(src)); + else if (is_image(src)) assign_image(dest, numpy_image(src)); + else if (is_image(src)) assign_image(dest, numpy_image(src)); + else if (is_image(src)) assign_image(dest, numpy_image(src)); + else if (is_image(src)) assign_image(dest, numpy_image(src)); + else if (is_image(src)) assign_image(dest, numpy_image(src)); + else if (is_image(src)) assign_image(dest, numpy_image(src)); + else if (is_image(src)) assign_image(dest, numpy_image(src)); + else DLIB_CASSERT(false, "Unsupported pixel type used in assign_image()."); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// BORING IMPLEMENTATION STUFF +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template + long num_rows(const numpy_image& img) + { + if (img.size()==0) + return 0; + + assert_correct_num_channels_in_image(img); + return img.shape(0); + } + + template + long num_columns(const numpy_image& img) + { + if (img.size()==0) + return 0; + + assert_correct_num_channels_in_image(img); + return img.shape(1); + } + + template + void set_image_size(numpy_image& img, size_t rows, size_t cols) + { + img.set_size(rows, cols); + } + + template + void* image_data(numpy_image& img) + { + if (img.size()==0) + return 0; + + assert_is_image(img); + return img.mutable_data(0); + } + + template + const void* image_data (const numpy_image& img) + { + if (img.size()==0) + return 0; + + assert_is_image(img); + return img.data(0); + } + + template + long width_step (const numpy_image& img) + { + if (img.size()==0) + return 0; + + assert_correct_num_channels_in_image(img); + using basic_pixel_type = typename pixel_traits::basic_pixel_type; + if (img.ndim()==3 && img.strides(2) != sizeof(basic_pixel_type)) + throw dlib::error("The stride of the 3rd dimension (the channel dimension) of the numpy array must be " + std::to_string(sizeof(basic_pixel_type))); + if (img.strides(1) != sizeof(pixel_type)) + throw dlib::error("The stride of the 2nd dimension (the columns dimension) of the numpy array must be " + std::to_string(sizeof(pixel_type))); + + return img.strides(0); + } + + template + void swap(numpy_image& a, numpy_image& b) + { + std::swap(a,b); + } + + + template + struct image_traits> + { + typedef T pixel_type; }; } // ---------------------------------------------------------------------------------------- -inline bool is_gray_python_image (boost::python::object& img) +namespace pybind11 { - try + namespace detail { - numpy_gray_image temp(img); - return true; - } - catch (dlib::error&) - { - return false; + template struct handle_type_name> + { + using basic_pixel_type = typename dlib::pixel_traits::basic_pixel_type; + + static PYBIND11_DESCR name() { + constexpr size_t channels = dlib::pixel_traits::num; + if (channels == 1) + return _("numpy.ndarray[(rows,cols),") + npy_format_descriptor::name() + _("]"); + else if (channels == 2) + return _("numpy.ndarray[(rows,cols,2),") + npy_format_descriptor::name() + _("]"); + else if (channels == 3) + return _("numpy.ndarray[(rows,cols,3),") + npy_format_descriptor::name() + _("]"); + else if (channels == 4) + return _("numpy.ndarray[(rows,cols,4),") + npy_format_descriptor::name() + _("]"); + else + DLIB_CASSERT(false,"unsupported pixel type"); + } + }; + + template + struct pyobject_caster> { + using type = dlib::numpy_image; + + bool load(handle src, bool convert) { + // If passed a tuple where the first element of the tuple is a valid + // numpy_image then bind the numpy_image to that element of the tuple. + // We do this because there is a pattern of returning an image and some + // associated metadata. This allows the returned tuple from such functions + // to also be treated as an image without needing to unpack the first + // argument. + if (PyTuple_Check(src.ptr()) && PyTuple_Size(src.ptr()) >= 1) + src = reinterpret_borrow(src)[0]; + + if (!type::check_(src)) + return false; + // stash the output of ensure into a temp variable since assigning it to + // value (the member variable created by the PYBIND11_TYPE_CASTER) + // apparently causes the return bool value to be ignored? + auto temp = type::ensure(src); + if (!dlib::is_image(temp)) + return false; + value = temp; + return static_cast(value); + } + + static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) { + return src.inc_ref(); + } + PYBIND11_TYPE_CASTER(type, handle_type_name::name()); + }; } } -// ---------------------------------------------------------------------------------------- - -class numpy_rgb_image -{ -public: - - numpy_rgb_image() : _data(0), _nr(0), _nc(0) {} - numpy_rgb_image (boost::python::object& img) - { - long shape[3]; - get_numpy_ndarray_parts(img, _data, shape); - _nr = shape[0]; - _nc = shape[1]; - if (shape[2] != 3) - throw dlib::error("Error, python object is not a three band image and therefore can't be a RGB image."); - } - - friend inline long num_rows(const numpy_rgb_image& img) { return img._nr; } - friend inline long num_columns(const numpy_rgb_image& img) { return img._nc; } - friend inline void* image_data(numpy_rgb_image& img) { return img._data; } - friend inline const void* image_data(const numpy_rgb_image& img) { return img._data; } - friend inline long width_step(const numpy_rgb_image& img) { return img._nc*sizeof(dlib::rgb_pixel); } - - -private: - - dlib::rgb_pixel* _data; - long _nr; - long _nc; -}; - -namespace dlib -{ - template <> - struct image_traits - { - typedef rgb_pixel pixel_type; - }; -} - -// ---------------------------------------------------------------------------------------- - - -inline bool is_rgb_python_image (boost::python::object& img) -{ - try - { - numpy_rgb_image temp(img); - return true; - } - catch (dlib::error&) - { - return false; - } -} // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/python/pyassert.h b/lib/3rdParty/dlib/include/dlib/python/pyassert.h index 9de330fa..80939f50 100644 --- a/lib/3rdParty/dlib/include/dlib/python/pyassert.h +++ b/lib/3rdParty/dlib/include/dlib/python/pyassert.h @@ -3,14 +3,15 @@ #ifndef DLIB_PYaSSERT_Hh_ #define DLIB_PYaSSERT_Hh_ -#include +#include #define pyassert(_exp,_message) \ {if ( !(_exp) ) \ { \ + namespace py = pybind11; \ PyErr_SetString( PyExc_ValueError, _message ); \ - boost::python::throw_error_already_set(); \ - }} + throw py::error_already_set(); \ + }} #endif // DLIB_PYaSSERT_Hh_ diff --git a/lib/3rdParty/dlib/include/dlib/python/pybind_utils.h b/lib/3rdParty/dlib/include/dlib/python/pybind_utils.h new file mode 100644 index 00000000..d7608a4a --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/python/pybind_utils.h @@ -0,0 +1,105 @@ +// Copyright (C) 2013 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_PYBIND_UtILS_Hh_ +#define DLIB_PYBIND_UtILS_Hh_ + +#include +#include +#include +#include +#include + +namespace py = pybind11; + +namespace dlib +{ + + template + std::vector python_list_to_vector ( + const py::list& obj + ) + /*! + ensures + - converts a python object into a std::vector and returns it. + !*/ + { + std::vector vect(len(obj)); + for (unsigned long i = 0; i < vect.size(); ++i) + { + vect[i] = obj[i].cast(); + } + return vect; + } + + template + std::array python_list_to_array ( + const py::list& the_list + ) + /*! + ensures + - converts a python object into a std::array and returns it. + !*/ + { + DLIB_CASSERT(len(the_list) == N, "Expected a list of " << N << " things."); + std::array vect; + for (unsigned long i = 0; i < vect.size(); ++i) + { + vect[i] = the_list[i].cast(); + } + return vect; + } + + template + py::list vector_to_python_list ( + const std::vector& vect + ) + /*! + ensures + - converts a std::vector into a python list object. + !*/ + { + py::list obj; + for (unsigned long i = 0; i < vect.size(); ++i) + obj.append(vect[i]); + return obj; + } + + template + void extend_vector_with_python_list ( + std::vector &v, + const py::list &l + ) + /*! + ensures + - appends items from a python list to the end of std::vector. + !*/ + { + for (const auto &item : l) + v.push_back(item.cast()); + } + +// ---------------------------------------------------------------------------------------- + + template + std::shared_ptr load_object_from_file ( + const std::string& filename + ) + /*! + ensures + - deserializes an object of type T from the given file and returns it. + !*/ + { + std::ifstream fin(filename.c_str(), std::ios::binary); + if (!fin) + throw dlib::error("Unable to open " + filename); + auto obj = std::make_shared(); + deserialize(*obj, fin); + return obj; + } +} + +// ---------------------------------------------------------------------------------------- + + +#endif // DLIB_PYBIND_UtILS_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/python/serialize_pickle.h b/lib/3rdParty/dlib/include/dlib/python/serialize_pickle.h index 8352beba..da121efd 100644 --- a/lib/3rdParty/dlib/include/dlib/python/serialize_pickle.h +++ b/lib/3rdParty/dlib/include/dlib/python/serialize_pickle.h @@ -4,44 +4,70 @@ #define DLIB_SERIALIZE_PiCKLE_Hh_ #include -#include +#include #include +#include -template -struct serialize_pickle : boost::python::pickle_suite +namespace py = pybind11; + +namespace dlib { - static boost::python::tuple getstate( - const T& item - ) + + template + py::tuple getstate(const T& item) { using namespace dlib; - std::ostringstream sout; + std::vector buf; + buf.reserve(5000); + vectorstream sout(buf); serialize(item, sout); - return boost::python::make_tuple(sout.str()); + return py::make_tuple(py::handle( + PyBytes_FromStringAndSize(buf.size()?&buf[0]:0, buf.size()))); } - static void setstate( - T& item, - boost::python::tuple state - ) + template + T setstate(py::tuple state) { using namespace dlib; - using namespace boost::python; if (len(state) != 1) { PyErr_SetObject(PyExc_ValueError, - ("expected 1-item tuple in call to __setstate__; got %s" - % state).ptr() + py::str("expected 1-item tuple in call to __setstate__; got {}").format(state).ptr() ); - throw_error_already_set(); + throw py::error_already_set(); } - str data = extract(state[0]); - std::string temp(extract(data), len(data)); - std::istringstream sin(temp); - deserialize(item, sin); + // We used to serialize by converting to a str but the boost.python routines for + // doing this don't work in Python 3. You end up getting an error about invalid + // UTF-8 encodings. So instead we access the python C interface directly and use + // bytes objects. However, we keep the deserialization code that worked with str + // for backwards compatibility with previously pickled files. + T item; + py::object obj = state[0]; + if (py::isinstance(obj)) + { + py::str data = state[0].cast(); + std::string temp = data; + std::istringstream sin(temp); + deserialize(item, sin); + } + else if(PyBytes_Check(py::object(state[0]).ptr())) + { + py::object obj = state[0]; + char* data = PyBytes_AsString(obj.ptr()); + unsigned long num = PyBytes_Size(obj.ptr()); + std::istringstream sin(std::string(data, num)); + deserialize(item, sin); + } + else + { + throw error("Unable to unpickle, error in input file."); + } + + return item; } -}; + +} #endif // DLIB_SERIALIZE_PiCKLE_Hh_ diff --git a/lib/3rdParty/dlib/include/dlib/queue/queue_kernel_1.h b/lib/3rdParty/dlib/include/dlib/queue/queue_kernel_1.h index 2e38e43d..e59bf265 100644 --- a/lib/3rdParty/dlib/include/dlib/queue/queue_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/queue/queue_kernel_1.h @@ -103,7 +103,7 @@ namespace dlib ); // functions from the enumerable interface - inline unsigned long size ( + inline size_t size ( ) const; inline bool at_start ( @@ -402,7 +402,7 @@ namespace dlib typename T, typename mem_manager > - unsigned long queue_kernel_1:: + size_t queue_kernel_1:: size ( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/queue/queue_kernel_2.h b/lib/3rdParty/dlib/include/dlib/queue/queue_kernel_2.h index b28234e5..8e4536ae 100644 --- a/lib/3rdParty/dlib/include/dlib/queue/queue_kernel_2.h +++ b/lib/3rdParty/dlib/include/dlib/queue/queue_kernel_2.h @@ -112,7 +112,7 @@ namespace dlib ); // functions from the enumerable interface - inline unsigned long size ( + inline size_t size ( ) const; inline bool at_start ( @@ -155,13 +155,13 @@ namespace dlib node* in; node* out; - unsigned long queue_size; - unsigned long in_pos; - unsigned long out_pos; + size_t queue_size; + size_t in_pos; + size_t out_pos; mutable node* current_element; - mutable unsigned long current_element_pos; + mutable size_t current_element_pos; mutable bool at_start_; // restricted functions @@ -419,7 +419,7 @@ namespace dlib unsigned long block_size, typename mem_manager > - unsigned long queue_kernel_2:: + size_t queue_kernel_2:: size ( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/rand/rand_kernel_1.h b/lib/3rdParty/dlib/include/dlib/rand/rand_kernel_1.h index bb0ca79b..a1847be2 100644 --- a/lib/3rdParty/dlib/include/dlib/rand/rand_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/rand/rand_kernel_1.h @@ -10,6 +10,7 @@ #include "../is_kind.h" #include #include "../serialize.h" +#include "../string.h" namespace dlib { @@ -39,6 +40,14 @@ namespace dlib init(); } + rand ( + time_t seed_value + ) + { + init(); + set_seed(cast_to_string(seed_value)); + } + rand ( const std::string& seed_value ) @@ -128,6 +137,44 @@ namespace dlib return (a<<32)|b; } + double get_double_in_range ( + double begin, + double end + ) + { + DLIB_ASSERT(begin <= end); + return begin + get_random_double()*(end-begin); + } + + long long get_integer_in_range( + long long begin, + long long end + ) + { + DLIB_ASSERT(begin <= end); + if (begin == end) + return begin; + + auto r = get_random_64bit_number(); + const auto limit = std::numeric_limits::max(); + const auto range = end-begin; + // Use rejection sampling to remove the biased sampling you would get with + // the naive get_random_64bit_number()%range sampling. + while(r >= (limit/range)*range) + r = get_random_64bit_number(); + + return begin + static_cast(r%range); + } + + long long get_integer( + long long end + ) + { + DLIB_ASSERT(end >= 0); + + return get_integer_in_range(0,end); + } + double get_random_double ( ) { @@ -241,7 +288,7 @@ namespace dlib max_val = 0xFFFFFF; max_val *= 0x1000000; max_val += 0xFFFFFF; - max_val += 0.01; + max_val += 0.05; has_gaussian = false; diff --git a/lib/3rdParty/dlib/include/dlib/rand/rand_kernel_abstract.h b/lib/3rdParty/dlib/include/dlib/rand/rand_kernel_abstract.h index cddee5e8..d054fea3 100644 --- a/lib/3rdParty/dlib/include/dlib/rand/rand_kernel_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/rand/rand_kernel_abstract.h @@ -34,6 +34,19 @@ namespace dlib - std::bad_alloc !*/ + rand ( + time_t seed_value + ); + /*! + ensures + - #*this is properly initialized + - #get_seed() == cast_to_string(seed_value) + - This version of the constructor is equivalent to using + the default constructor and then calling set_seed(cast_to_string(seed_value)) + throws + - std::bad_alloc + !*/ + rand ( const std::string& seed_value ); @@ -122,6 +135,43 @@ namespace dlib - returns a random double number N where: 0.0 <= N < 1.0. !*/ + double get_double_in_range ( + double begin, + double end + ); + /*! + requires + - begin <= end + ensures + - if (begin < end) then + - returns a random double number N where: begin <= N < end. + - else + - returns begin + !*/ + + long long get_integer_in_range( + long long begin, + long long end + ); + /*! + requires + - begin <= end + ensures + - returns a random integer N selected from the range: begin <= N < end + The integer is selected uniformly at random. If begin==end then + begin is returned. + !*/ + + long long get_integer( + long long end + ); + /*! + requires + - 0 <= end + ensures + - returns get_integer_in_range(0,end) + !*/ + double get_random_gaussian ( ); /*! diff --git a/lib/3rdParty/dlib/include/dlib/random_forest.h b/lib/3rdParty/dlib/include/dlib/random_forest.h new file mode 100644 index 00000000..082f3670 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/random_forest.h @@ -0,0 +1,10 @@ +// Copyright (C) 2018 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_RANDOM_FOReST_H_ +#define DLIB_RANDOM_FOReST_H_ + +#include "random_forest/random_forest_regression.h" + +#endif // DLIB_RANDOM_FOReST_H_ + + diff --git a/lib/3rdParty/dlib/include/dlib/random_forest/random_forest_regression.h b/lib/3rdParty/dlib/include/dlib/random_forest/random_forest_regression.h new file mode 100644 index 00000000..a61f7a1a --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/random_forest/random_forest_regression.h @@ -0,0 +1,738 @@ +// Copyright (C) 2018 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_RANdOM_FOREST_REGRESSION_H_ +#define DLIB_RANdOM_FOREST_REGRESSION_H_ + +#include "random_forest_regression_abstract.h" +#include +#include "../matrix.h" +#include +#include "../threads.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class dense_feature_extractor + { + + public: + typedef uint32_t feature; + typedef matrix sample_type; + + dense_feature_extractor( + ) = default; + + void setup ( + const std::vector& x, + const std::vector& y + ) + { + DLIB_CASSERT(x.size() > 0); + DLIB_CASSERT(x.size() == y.size()); + for (auto& el : x) + DLIB_CASSERT(el.size() == x[0].size(), "All the vectors in a training set have to have the same dimensionality."); + + DLIB_CASSERT(x[0].size() != 0, "The vectors can't be empty."); + + num_feats = x[0].size(); + } + + + void get_random_features ( + dlib::rand& rnd, + size_t num, + std::vector& feats + ) const + { + DLIB_ASSERT(max_num_feats() != 0); + num = std::min(num, num_feats); + + feats.clear(); + for (size_t i = 0; i < num_feats; ++i) + feats.push_back(i); + + // now pick num features at random + for (size_t i = 0; i < num; ++i) + { + auto idx = rnd.get_integer_in_range(i,num_feats); + std::swap(feats[i], feats[idx]); + } + feats.resize(num); + } + + double extract_feature_value ( + const sample_type& item, + const feature& f + ) const + { + DLIB_ASSERT(max_num_feats() != 0); + return item(f); + } + + size_t max_num_feats ( + ) const + { + return num_feats; + } + + friend void serialize(const dense_feature_extractor& item, std::ostream& out) + { + serialize("dense_feature_extractor", out); + serialize(item.num_feats, out); + } + + friend void deserialize(dense_feature_extractor& item, std::istream& in) + { + check_serialized_version("dense_feature_extractor", in); + deserialize(item.num_feats, in); + } + + private: + size_t num_feats = 0; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename feature_extractor + > + struct internal_tree_node + { + uint32_t left; + uint32_t right; + float split_threshold; + typename feature_extractor::feature split_feature; + }; + + template + void serialize(const internal_tree_node& item, std::ostream& out) + { + serialize(item.left, out); + serialize(item.right, out); + serialize(item.split_threshold, out); + serialize(item.split_feature, out); + } + + template + void deserialize(internal_tree_node& item, std::istream& in) + { + deserialize(item.left, in); + deserialize(item.right, in); + deserialize(item.split_threshold, in); + deserialize(item.split_feature, in); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename feature_extractor = dense_feature_extractor + > + class random_forest_regression_function + { + + public: + + typedef feature_extractor feature_extractor_type; + typedef typename feature_extractor::sample_type sample_type; + + random_forest_regression_function( + ) = default; + + random_forest_regression_function ( + feature_extractor_type&& fe_, + std::vector>>&& trees_, + std::vector>&& leaves_ + ) : + fe(std::move(fe_)), + trees(std::move(trees_)), + leaves(std::move(leaves_)) + { + DLIB_ASSERT(trees.size() > 0); + DLIB_ASSERT(trees.size() == leaves.size(), "Every set of tree nodes has to have leaves"); +#ifdef ENABLE_ASSERTS + for (size_t i = 0; i < trees.size(); ++i) + { + DLIB_ASSERT(trees[i].size() > 0, "A tree can't have 0 leaves."); + for (auto& node : trees[i]) + { + DLIB_ASSERT(trees[i].size()+leaves[i].size() > node.left, "left node index in tree is too big. There is no associated tree node or leaf."); + DLIB_ASSERT(trees[i].size()+leaves[i].size() > node.right, "right node index in tree is too big. There is no associated tree node or leaf."); + } + } +#endif + } + + size_t get_num_trees( + ) const + { + return trees.size(); + } + + const std::vector>>& get_internal_tree_nodes ( + ) const { return trees; } + + const std::vector>& get_tree_leaves ( + ) const { return leaves; } + + const feature_extractor_type& get_feature_extractor ( + ) const { return fe; } + + double operator() ( + const sample_type& x + ) const + { + DLIB_ASSERT(get_num_trees() > 0); + + double accum = 0; + + for (size_t i = 0; i < trees.size(); ++i) + { + auto& tree = trees[i]; + // walk the tree to the leaf + uint32_t idx = 0; + while(idx < tree.size()) + { + auto feature_value = fe.extract_feature_value(x, tree[idx].split_feature); + if (feature_value < tree[idx].split_threshold) + idx = tree[idx].left; + else + idx = tree[idx].right; + } + // compute leaf index + accum += leaves[i][idx-tree.size()]; + } + + return accum/trees.size(); + } + + friend void serialize(const random_forest_regression_function& item, std::ostream& out) + { + serialize("random_forest_regression_function", out); + serialize(item.fe, out); + serialize(item.trees, out); + serialize(item.leaves, out); + } + + friend void deserialize(random_forest_regression_function& item, std::istream& in) + { + check_serialized_version("random_forest_regression_function", in); + deserialize(item.fe, in); + deserialize(item.trees, in); + deserialize(item.leaves, in); + } + + private: + + /*! + CONVENTION + - trees.size() == leaves.size() + - Any .left or .right index in trees that is larger than the number of + nodes in the tree references a leaf. Moreover, the index of the leaf is + computed by subtracting the number of nodes in the tree. + !*/ + + feature_extractor_type fe; + + // internal nodes of trees + std::vector>> trees; + // leaves of trees + std::vector> leaves; + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename feature_extractor = dense_feature_extractor + > + class random_forest_regression_trainer + { + public: + typedef feature_extractor feature_extractor_type; + typedef random_forest_regression_function trained_function_type; + typedef typename feature_extractor::sample_type sample_type; + + + random_forest_regression_trainer ( + ) = default; + + const feature_extractor_type& get_feature_extractor ( + ) const + { + return fe_; + } + + void set_feature_extractor ( + const feature_extractor_type& feat_extractor + ) + { + fe_ = feat_extractor; + } + + void set_seed ( + const std::string& seed + ) + { + random_seed = seed; + } + + const std::string& get_random_seed ( + ) const + { + return random_seed; + } + + size_t get_num_trees ( + ) const + { + return num_trees; + } + + void set_num_trees ( + size_t num + ) + { + DLIB_CASSERT(num > 0); + num_trees = num; + } + + void set_feature_subsampling_fraction ( + double frac + ) + { + DLIB_CASSERT(0 < frac && frac <= 1); + feature_subsampling_frac = frac; + } + + double get_feature_subsampling_frac( + ) const + { + return feature_subsampling_frac; + } + + void set_min_samples_per_leaf ( + size_t num + ) + { + DLIB_ASSERT(num > 0); + min_samples_per_leaf = num; + } + + size_t get_min_samples_per_leaf( + ) const + { + return min_samples_per_leaf; + } + + void be_verbose ( + ) + { + verbose = true; + } + + void be_quiet ( + ) + { + verbose = false; + } + + trained_function_type train ( + const std::vector& x, + const std::vector& y + ) const + { + std::vector junk; + return do_train(x,y,junk,false); + } + + trained_function_type train ( + const std::vector& x, + const std::vector& y, + std::vector& oob_values + ) const + { + return do_train(x,y,oob_values,true); + } + + private: + + trained_function_type do_train ( + const std::vector& x, + const std::vector& y, + std::vector& oob_values, + bool compute_oob_values + ) const + { + DLIB_CASSERT(x.size() == y.size()); + DLIB_CASSERT(x.size() > 0); + + feature_extractor_type fe = fe_; + fe.setup(x,y); + + DLIB_CASSERT(fe.max_num_feats() != 0); + + std::vector>> all_trees(num_trees); + std::vector> all_leaves(num_trees); + + const double sumy = sum(mat(y)); + + const size_t feats_per_node = std::max(1.0,std::round(fe.max_num_feats()*feature_subsampling_frac)); + + // Each tree couldn't have more than this many interior nodes. It might + // end up having less though. We need to know this value because the way + // we mark a left or right pointer in a tree as pointing to a leaf is by + // making its index larger than the number of interior nodes in the tree. + // But we don't know the tree's size before we finish building it. So we + // will use max_num_nodes as a proxy during tree construction and then go + // back and fix it once a tree's size is known. + const uint32_t max_num_nodes = y.size(); + + std::vector oob_hits; + + if (compute_oob_values) + { + oob_values.resize(y.size()); + oob_hits.resize(y.size()); + } + + + std::mutex m; + + // Calling build_tree(i) creates the ith tree and stores the results in + // all_trees and all_leaves. + auto build_tree = [&](long i) + { + dlib::rand rnd(random_seed + std::to_string(i)); + auto& tree = all_trees[i]; + auto& leaves = all_leaves[i]; + + // Check if there are fewer than min_samples_per_leaf and if so then + // don't make any tree. Just average the things and be done. + if (y.size() <= min_samples_per_leaf) + { + leaves.push_back(sumy/y.size()); + return; + } + + + // pick a random bootstrap of the data. + std::vector> idxs(y.size()); + for (auto& idx : idxs) + idx = std::make_pair(0,rnd.get_integer(y.size())); + + // We are going to use ranges_to_process as a stack that tracks which + // range of samples we are going to split next. + std::vector ranges_to_process; + // start with the root of the tree, i.e. the entire range of training + // samples. + ranges_to_process.emplace_back(sumy,0,y.size()); + // push an unpopulated root node into the tree. We will populate it + // when we process its corresponding range. + tree.emplace_back(); + + std::vector feats; + + while(ranges_to_process.size() > 0) + { + // Grab the next range/node to process. + const auto range = ranges_to_process.back(); + ranges_to_process.pop_back(); + + + // Get the split features we will consider at this node. + fe.get_random_features(rnd, feats_per_node, feats); + // Then find the best split + auto best_split = find_best_split_among_feats(fe, range, feats, x, y, idxs); + + range_t left_split(best_split.left_sum, range.begin, best_split.split_idx); + range_t right_split(best_split.right_sum, best_split.split_idx, range.end); + + DLIB_ASSERT(left_split.begin < left_split.end); + DLIB_ASSERT(right_split.begin < right_split.end); + + // Now that we know the split we can populate the parent node we popped + // from ranges_to_process. + tree[range.tree_idx].split_threshold = best_split.split_threshold; + tree[range.tree_idx].split_feature = best_split.split_feature; + + // If the left split is big enough to make a new interior leaf + // node. We also stop splitting if all the samples went into this node. + // This could happen if the features are all uniform so there just + // isn't any way to split them anymore. + if (left_split.size() > min_samples_per_leaf && right_split.size() != 0) + { + // allocate an interior leaf node for it. + left_split.tree_idx = tree.size(); + tree.emplace_back(); + // set the pointer in the parent node to the newly allocated + // node. + tree[range.tree_idx].left = left_split.tree_idx; + + ranges_to_process.emplace_back(left_split); + } + else + { + // Add to leaves. Don't forget to set the pointer in the + // parent node to the newly allocated leaf node. + tree[range.tree_idx].left = leaves.size() + max_num_nodes; + leaves.emplace_back(left_split.avg()); + } + + + // If the right split is big enough to make a new interior leaf + // node. We also stop splitting if all the samples went into this node. + // This could happen if the features are all uniform so there just + // isn't any way to split them anymore. + if (right_split.size() > min_samples_per_leaf && left_split.size() != 0) + { + // allocate an interior leaf node for it. + right_split.tree_idx = tree.size(); + tree.emplace_back(); + // set the pointer in the parent node to the newly allocated + // node. + tree[range.tree_idx].right = right_split.tree_idx; + + ranges_to_process.emplace_back(right_split); + } + else + { + // Add to leaves. Don't forget to set the pointer in the + // parent node to the newly allocated leaf node. + tree[range.tree_idx].right = leaves.size() + max_num_nodes; + leaves.emplace_back(right_split.avg()); + } + } // end while (still building tree) + + // Fix the leaf pointers in the tree now that we know the correct + // tree.size() value. + DLIB_CASSERT(max_num_nodes >= tree.size()); + const auto offset = max_num_nodes - tree.size(); + for (auto& n : tree) + { + if (n.left >= max_num_nodes) + n.left -= offset; + if (n.right >= max_num_nodes) + n.right -= offset; + } + + + if (compute_oob_values) + { + std::sort(idxs.begin(), idxs.end(), + [](const std::pair& a, const std::pair& b) {return a.second lock(m); + + size_t j = 0; + for (size_t i = 0; i < oob_values.size(); ++i) + { + // check if i is in idxs + while(j < idxs.size() && i > idxs[j].second) + ++j; + + // i isn't in idxs so it's an oob sample and we should process it. + if (j == idxs.size() || idxs[j].second != i) + { + oob_hits[i]++; + + // walk the tree to find the leaf value for this oob sample + uint32_t idx = 0; + while(idx < tree.size()) + { + auto feature_value = fe.extract_feature_value(x[i], tree[idx].split_feature); + if (feature_value < tree[idx].split_threshold) + idx = tree[idx].left; + else + idx = tree[idx].right; + } + oob_values[i] += leaves[idx-tree.size()]; + } + } + } + }; + + if (verbose) + parallel_for_verbose(0, num_trees, build_tree); + else + parallel_for(0, num_trees, build_tree); + + + if (compute_oob_values) + { + double meanval = 0; + double cnt = 0; + for (size_t i = 0; i < oob_values.size(); ++i) + { + if (oob_hits[i] != 0) + { + oob_values[i] /= oob_hits[i]; + meanval += oob_values[i]; + ++cnt; + } + } + + // If there are some elements that didn't get hits, we set their oob values + // to the mean oob value. + if (cnt != 0) + { + const double typical_value = meanval/cnt; + for (size_t i = 0; i < oob_values.size(); ++i) + { + if (oob_hits[i] == 0) + oob_values[i] = typical_value; + } + } + } + + return trained_function_type(std::move(fe), std::move(all_trees), std::move(all_leaves)); + } + + struct range_t + { + range_t( + double sumy, + uint32_t begin, + uint32_t end + ) : sumy(sumy), begin(begin), end(end), tree_idx(0) {} + + double sumy; + uint32_t begin; + uint32_t end; + + // Every range object corresponds to an entry in a tree. This tells you the + // tree node that owns the range. + uint32_t tree_idx; + + uint32_t size() const { return end-begin; } + double avg() const { return sumy/size(); } + }; + + struct best_split_details + { + double score = -std::numeric_limits::infinity(); + double left_sum; + double right_sum; + uint32_t split_idx; + double split_threshold; + typename feature_extractor::feature split_feature; + + bool operator < (const best_split_details& rhs) const + { + return score < rhs.score; + } + }; + + static best_split_details find_best_split ( + const range_t& range, + const std::vector& y, + const std::vector>& idxs + ) + /*! + requires + - max(mat(idxs)) < y.size() + - range.sumy == sum of y[idxs[j].second] for all valid j in range [range.begin, range.end). + ensures + - finds a threshold T such that there exists an i satisfying the following: + - y[idxs[j].second] < T for all j <= i + - y[idxs[j].second] > T for all j > i + Therefore, the threshold T partitions the contents of y into two groups, + relative to the ordering established by idxs. Moreover the partitioning + of y values into two groups has the additional requirement that it is + optimal in the sense that the sum of the squared deviations from each + partition's mean is minimized. + !*/ + { + + size_t best_i = range.begin; + double best_score = -1; + double left_sum = 0; + double best_left_sum = y[idxs[range.begin].second]; + const auto size = range.size(); + size_t left_size = 0; + for (size_t i = range.begin; i+1 < range.end; ++i) + { + ++left_size; + left_sum += y[idxs[i].second]; + + // Don't split here because the next element has the same feature value so + // we can't *really* split here. + if (idxs[i].first==idxs[i+1].first) + continue; + + const double right_sum = range.sumy-left_sum; + + const double score = left_sum*left_sum/left_size + right_sum*right_sum/(size-left_size); + + if (score > best_score) + { + best_score = score; + best_i = i; + best_left_sum = left_sum; + } + } + + best_split_details result; + result.score = best_score; + result.left_sum = best_left_sum; + result.right_sum = range.sumy-best_left_sum; + result.split_idx = best_i+1; // one past the end of the left range + result.split_threshold = (idxs[best_i].first+idxs[best_i+1].first)/2; + + return result; + } + + + static best_split_details find_best_split_among_feats( + const feature_extractor& fe, + const range_t& range, + const std::vector& feats, + const std::vector& x, + const std::vector& y, + std::vector>& idxs + ) + { + auto compare_first = [](const std::pair& a, const std::pair& b) { return a.first +#include "../matrix.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class dense_feature_extractor + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a tool for extracting features from objects. In particular, + it is designed to be used with the random forest regression tools discussed + below. + + This particular feature extract does almost nothing since it works on + vectors in R^n and simply selects elements from each vector. However, the + tools below are templated and allow you to design your own feature extractors + that operate on whatever object types you create. So for example, maybe + you want to perform regression on images rather than vectors. Moreover, + your feature extraction could be more complex. Maybe you are selecting + differences between pairs of pixels in an image or doing something + involving geometric transforms during feature extraction. Any of these + kinds of more complex feature extraction patterns can be realized with the + random forest tools by implementing your own feature extractor object and + using it with the random forest objects. + + Therefore, you should consider this dense_feature_extractor as an example + that documents the interface as well as the simple default extractor for + use with dense vectors. + + + THREAD SAFETY + It is safe to call const members of this object from multiple threads. ANY + USER DEFINED FEATURE EXTRACTORS MUST ALSO MEET THIS GUARONTEE AS WELL SINCE + IT IS ASSUMED BY THE RANDOM FOREST TRAINING ROUTINES. + !*/ + + public: + typedef uint32_t feature; + typedef matrix sample_type; + + dense_feature_extractor( + ); + /*! + ensures + - #max_num_feats() == 0 + !*/ + + void setup ( + const std::vector& x, + const std::vector& y + ); + /*! + requires + - x.size() == y.size() + - x.size() > 0 + - x[0].size() > 0 + - all the vectors in x have the same dimensionality. + ensures + - Configures this feature extractor to work on the given training data. + For dense feature extractors all we do is record the dimensionality of + the training vectors. + - #max_num_feats() == x[0].size() + (In general, setup() sets max_num_feats() to some non-zero value so that + the other methods of this object can then be called. The point of setup() + is to allow a feature extractor to gather whatever statistics it needs from + training data. That is, more complex feature extraction strategies my + themselves be trained from data.) + !*/ + + void get_random_features ( + dlib::rand& rnd, + size_t num, + std::vector& feats + ) const; + /*! + requires + - max_num_feats() != 0 + ensures + - #feats.size() == min(num, max_num_feats()) + - This function randomly identifies num features and stores them into feats. + These feature objects can then be used with extract_feature_value() to + obtain a value from any particular sample_type object. This value is the + "feature value" used by a decision tree algorithm to deice how to split + and traverse trees. + - The above two conditions define the behavior of get_random_features() in + general. For this specific implementation of the feature extraction interface + this function selects num integer values from the range [0, max_num_feats()), + without replacement. These values are stored into feats. + !*/ + + double extract_feature_value ( + const sample_type& item, + const feature& f + ) const; + /*! + requires + - #max_num_feats() != 0 + - f was produced from a call to get_random_features(). + ensures + - Extracts the feature value corresponding to f. For this simple dense + feature extractor this simply means returning item(f). But in general + you can design feature extractors that do something more complex. + !*/ + + size_t max_num_feats ( + ) const; + /*! + ensures + - returns the number of distinct features this object might extract. That is, + a feature extractor essentially defines a mapping from sample_type objects to + vectors in R^max_num_feats(). + !*/ + }; + + void serialize(const dense_feature_extractor& item, std::ostream& out); + void deserialize(dense_feature_extractor& item, std::istream& in); + /*! + provides serialization support + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename feature_extractor + > + struct internal_tree_node + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is an internal node in a regression tree. See the code of + random_forest_regression_function to see how it is used to create a tree. + !*/ + + uint32_t left; + uint32_t right; + float split_threshold; + typename feature_extractor::feature split_feature; + }; + + template + void serialize(const internal_tree_node& item, std::ostream& out); + template + void deserialize(internal_tree_node& item, std::istream& in); + /*! + provides serialization support + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename feature_extractor = dense_feature_extractor + > + class random_forest_regression_function + { + /*! + REQUIREMENTS ON feature_extractor + feature_extractor must be dense_feature_extractor or a type with a + compatible interface. + + WHAT THIS OBJECT REPRESENTS + This object represents a regression forest. This is a collection of + decision trees that take an object as input and each vote on a real value + to associate with the object. The final real value output is the average + of all the votes from each of the trees. + !*/ + + public: + + typedef feature_extractor feature_extractor_type; + typedef typename feature_extractor::sample_type sample_type; + + random_forest_regression_function( + ); + /*! + ensures + - #num_trees() == 0 + !*/ + + random_forest_regression_function ( + feature_extractor_type&& fe_, + std::vector>>&& trees_, + std::vector>&& leaves_ + ); + /*! + requires + - trees.size() > 0 + - trees.size() = leaves.size() + - for all valid i: + - leaves[i].size() > 0 + - trees[i].size()+leaves[i].size() > the maximal left or right index values in trees[i]. + (i.e. each left or right value must index to some existing internal tree node or leaf node). + ensures + - #get_internal_tree_nodes() == trees_ + - #get_tree_leaves() == leaves_ + - #get_feature_extractor() == fe_ + !*/ + + size_t get_num_trees( + ) const; + /*! + ensures + - returns the number of trees in this regression forest. + !*/ + + const std::vector>>& get_internal_tree_nodes ( + ) const; + /*! + ensures + - returns the internal tree nodes that define the regression trees. + - get_internal_tree_nodes().size() == get_num_trees() + !*/ + + const std::vector>& get_tree_leaves ( + ) const; + /*! + ensures + - returns the tree leaves that define the regression trees. + - get_tree_leaves().size() == get_num_trees() + !*/ + + const feature_extractor_type& get_feature_extractor ( + ) const; + /*! + ensures + - returns the feature extractor used by the trees. + !*/ + + double operator() ( + const sample_type& x + ) const; + /*! + requires + - get_num_trees() > 0 + ensures + - Maps x to a real value and returns the value. To do this, we find the + get_num_trees() leaf values associated with x and then return the average + of these leaf values. + !*/ + }; + + void serialize(const random_forest_regression_function& item, std::ostream& out); + void deserialize(random_forest_regression_function& item, std::istream& in); + /*! + provides serialization support + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename feature_extractor = dense_feature_extractor + > + class random_forest_regression_trainer + { + /*! + REQUIREMENTS ON feature_extractor + feature_extractor must be dense_feature_extractor or a type with a + compatible interface. + + WHAT THIS OBJECT REPRESENTS + This object implements Breiman's classic random forest regression + algorithm. The algorithm learns to map objects, nominally vectors in R^n, + into the reals. It essentially optimizes the mean squared error by fitting + a bunch of decision trees, each of which vote on the output value of the + regressor. The final prediction is obtained by averaging all the + predictions. + + For more information on the algorithm see: + Breiman, Leo. "Random forests." Machine learning 45.1 (2001): 5-32. + !*/ + + public: + typedef feature_extractor feature_extractor_type; + typedef random_forest_regression_function trained_function_type; + typedef typename feature_extractor::sample_type sample_type; + + + random_forest_regression_trainer ( + ); + /*! + ensures + - #get_min_samples_per_leaf() == 5 + - #get_num_trees() == 1000 + - #get_feature_subsampling_frac() == 1.0/3.0 + - #get_feature_extractor() == a default initialized feature extractor. + - #get_random_seed() == "" + - this object is not verbose. + !*/ + + const feature_extractor_type& get_feature_extractor ( + ) const; + /*! + ensures + - returns the feature extractor used when train() is invoked. + !*/ + + void set_feature_extractor ( + const feature_extractor_type& feat_extractor + ); + /*! + ensures + - #get_feature_extractor() == feat_extractor + !*/ + + void set_seed ( + const std::string& seed + ); + /*! + ensures + - #get_random_seed() == seed + !*/ + + const std::string& get_random_seed ( + ) const; + /*! + ensures + - A central part of this algorithm is random selection of both training + samples and features. This function returns the seed used to initialized + the random number generator used for these random selections. + !*/ + + size_t get_num_trees ( + ) const; + /*! + ensures + - Random forests built by this object will contain get_num_trees() trees. + !*/ + + void set_num_trees ( + size_t num + ); + /*! + requires + - num > 0 + ensures + - #get_num_trees() == num + !*/ + + void set_feature_subsampling_fraction ( + double frac + ); + /*! + requires + - 0 < frac <= 1 + ensures + - #get_feature_subsampling_frac() == frac + !*/ + + double get_feature_subsampling_frac( + ) const; + /*! + ensures + - When we build trees, at each node we don't look at all the available + features. We consider only get_feature_subsampling_frac() fraction of + them, selected at random. + !*/ + + void set_min_samples_per_leaf ( + size_t num + ); + /*! + requires + - num > 0 + ensures + - #get_min_samples_per_leaf() == num + !*/ + + size_t get_min_samples_per_leaf( + ) const; + /*! + ensures + - When building trees, each leaf node in a tree will contain at least + get_min_samples_per_leaf() samples. This means that the output votes of + each tree are averages of at least get_min_samples_per_leaf() y values. + !*/ + + void be_verbose ( + ); + /*! + ensures + - This object will print status messages to standard out so that the + progress of training can be tracked.. + !*/ + + void be_quiet ( + ); + /*! + ensures + - this object will not print anything to standard out + !*/ + + random_forest_regression_function train ( + const std::vector& x, + const std::vector& y, + std::vector& oob_values + ) const; + /*! + requires + - x.size() == y.size() + - x.size() > 0 + - Running following code: + auto fe = get_feature_extractor() + fe.setup(x,y); + Must be valid and result in fe.max_num_feats() != 0 + ensures + - This function fits a regression forest to the given training data. The + goal being to regress x to y in the mean squared sense. It therefore + fits regression trees and returns the resulting random_forest_regression_function + RF, which will have the following properties: + - RF.get_num_trees() == get_num_trees() + - for all valid i: + - RF(x[i]) should output a value close to y[i] + - RF.get_feature_extractor() will be a copy of this->get_feature_extractor() + that has been configured by a call the feature extractor's setup() routine. + To run the algorithm we need to use a feature extractor. We obtain a + valid feature extractor by making a copy of get_feature_extractor(), then + invoking setup(x,y) on it. This feature extractor is what is used to fit + the trees and is also the feature extractor stored in the returned random + forest. + - #oob_values.size() == y.size() + - for all valid i: + - #oob_values[i] == the "out of bag" prediction for y[i]. It is + calculated by computing the average output from trees not trained on + y[i]. This is similar to a leave-one-out cross-validation prediction + of y[i] and can be used to estimate the generalization error of the + regression forest. + - Training uses all the available CPU cores. + !*/ + + random_forest_regression_function train ( + const std::vector& x, + const std::vector& y + ) const; + /*! + requires + - x.size() == y.size() + - x.size() > 0 + - Running following code: + auto fe = get_feature_extractor() + fe.setup(x,y); + Must be valid and result in fe.max_num_feats() != 0 + ensures + - This function is identical to train(x,y,oob_values) except that the + oob_values are not calculated. + !*/ + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_RANdOM_FOREST_REGRESION_ABSTRACT_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/release_build_by_default b/lib/3rdParty/dlib/include/dlib/release_build_by_default deleted file mode 100644 index 1b0e9583..00000000 --- a/lib/3rdParty/dlib/include/dlib/release_build_by_default +++ /dev/null @@ -1,9 +0,0 @@ - -#set default build type to Release -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "Release" CACHE STRING - "Choose the type of build, options are: Debug Release - RelWithDebInfo MinSizeRel." FORCE) -endif() - - diff --git a/lib/3rdParty/dlib/include/dlib/revision.h b/lib/3rdParty/dlib/include/dlib/revision.h index 3ea26481..419e0e8f 100644 --- a/lib/3rdParty/dlib/include/dlib/revision.h +++ b/lib/3rdParty/dlib/include/dlib/revision.h @@ -1,7 +1,6 @@ #ifndef DLIB_REVISION_H -// Version: 18.10 -// Date: Thu Aug 28 19:45:52 EDT 2014 -// Mercurial Revision ID: 5a14394843c0 -#define DLIB_MAJOR_VERSION 18 -#define DLIB_MINOR_VERSION 10 +#define DLIB_MAJOR_VERSION 19 +#define DLIB_MINOR_VERSION 13 +#define DLIB_PATCH_VERSION 0 #endif + diff --git a/lib/3rdParty/dlib/include/dlib/sequence/sequence_kernel_1.h b/lib/3rdParty/dlib/include/dlib/sequence/sequence_kernel_1.h index b8a5da6f..9e1e26f1 100644 --- a/lib/3rdParty/dlib/include/dlib/sequence/sequence_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/sequence/sequence_kernel_1.h @@ -144,7 +144,7 @@ namespace dlib ); // functions from the enumerable interface - inline unsigned long size ( + inline size_t size ( ) const; bool at_start ( @@ -446,7 +446,7 @@ namespace dlib typename T, typename mem_manager > - unsigned long sequence_kernel_1:: + size_t sequence_kernel_1:: size ( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/sequence/sequence_kernel_2.h b/lib/3rdParty/dlib/include/dlib/sequence/sequence_kernel_2.h index 142f1bdf..f15c50e9 100644 --- a/lib/3rdParty/dlib/include/dlib/sequence/sequence_kernel_2.h +++ b/lib/3rdParty/dlib/include/dlib/sequence/sequence_kernel_2.h @@ -103,7 +103,7 @@ namespace dlib ); // functions from the enumerable interface - inline unsigned long size ( + inline size_t size ( ) const; bool at_start ( @@ -430,7 +430,7 @@ namespace dlib typename T, typename mem_manager > - unsigned long sequence_kernel_2:: + size_t sequence_kernel_2:: size ( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/serialize.h b/lib/3rdParty/dlib/include/dlib/serialize.h index a15d4156..f21bdaaf 100644 --- a/lib/3rdParty/dlib/include/dlib/serialize.h +++ b/lib/3rdParty/dlib/include/dlib/serialize.h @@ -62,6 +62,8 @@ - std::string - std::wstring - std::vector + - std::array + - std::deque - std::map - std::set - std::pair @@ -79,6 +81,8 @@ - std::string - std::wstring - std::vector + - std::array + - std::deque - std::map - std::set - std::pair @@ -95,7 +99,7 @@ Note that you can deserialize an integer value to any integral type (except for a char type) if its value will fit into the target integer type. I.e. the types short, int, long, unsigned short, unsigned int, unsigned long, and dlib::uint64 - can all receive serialized data from each other so long as the actual serizlied + can all receive serialized data from each other so long as the actual serialized value fits within the receiving integral type's range. Also note that for any container to be serializable the type of object it contains @@ -143,19 +147,22 @@ #include #include #include +#include +#include #include #include +#include #include #include +#include +#include #include "uintn.h" #include "interfaces/enumerable.h" #include "interfaces/map_pair.h" #include "enable_if.h" #include "unicode.h" -#include "unicode.h" #include "byte_orderer.h" #include "float_details.h" -#include "smart_pointers/shared_ptr.h" namespace dlib { @@ -164,10 +171,81 @@ namespace dlib class serialization_error : public error { + /*! + WHAT THIS OBJECT REPRESENTS + This is the exception object. It is thrown if serialization or + deserialization fails. + !*/ + public: serialization_error(const std::string& e):error(e) {} }; + + void check_serialized_version( + const std::string& expected_version, + std::istream& in + ); + /*! + ensures + - Deserializes a string from in and if it doesn't match expected_version we + throw serialization_error. + !*/ + +// ---------------------------------------------------------------------------------------- + + /*!A ramdump information !*/ + template + struct ramdump_t + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a type decoration used to indicate that serialization should be + done by simply dumping the memory of some object to disk as fast as + possible without any sort of conversions. This means that the data written + will be "non-portable" in the sense that the format output by a RAM dump + may depend on things like the endianness of your CPU or settings of certain + compiler switches. + + You use this object like this: + serialize("yourfile.dat") << ramdump(yourobject); + deserialize("yourfile.dat") >> ramdump(yourobject); + or + serialize(ramdump(yourobject), out); + deserialize(ramdump(yourobject), in); + + Also, not all objects have a ramdump mode. If you try to use ramdump on an + object that does not define a serialization dump for ramdump you will get a + compiler error. + !*/ + ramdump_t(T& item_) : item(item_) {} + T& item; + }; + + // This function just makes a ramdump that wraps an object. + template + ramdump_t::type> ramdump(T&& item) + { + return ramdump_t::type>(item); + } + + + template < + typename T + > + void serialize ( + const ramdump_t& item_, + std::ostream& out + ) + { + // Move the const from inside the ramdump_t template to outside so we can bind + // against a serialize() call that takes just a const ramdump_t. Doing this + // saves you from needing to write multiple overloads of serialize() to handle + // these different const placement cases. + const auto temp = ramdump(const_cast(item_.item)); + serialize(temp, out); + } + // ---------------------------------------------------------------------------------------- namespace ser_helper @@ -272,7 +350,7 @@ namespace dlib size &= 0x0F; // check if the serialized object is too big - if (size > sizeof(T)) + if (size > (unsigned long)tmin::value || size == 0) { return true; } @@ -386,7 +464,7 @@ namespace dlib size &= 0x8F; // check if an error occurred - if (size > sizeof(T)) + if (size > (unsigned long)tmin::value || size == 0) return true; @@ -519,7 +597,7 @@ namespace dlib ) { std::ios::fmtflags oldflags = in.flags(); - in.flags(); + in.flags(static_cast(0)); std::streamsize ss = in.precision(35); if (in.peek() == 'i') { @@ -653,6 +731,18 @@ namespace dlib std::istream& in ); + template + void serialize ( + const std::deque& item, + std::ostream& out + ); + + template + void deserialize ( + std::deque& item, + std::istream& in + ); + inline void serialize ( const std::string& item, std::ostream& out @@ -1036,6 +1126,44 @@ namespace dlib { throw serialization_error(e.info + "\n while deserializing object of type std::vector"); } } +// ---------------------------------------------------------------------------------------- + + template + void serialize ( + const std::deque& item, + std::ostream& out + ) + { + try + { + const unsigned long size = static_cast(item.size()); + + serialize(size,out); + for (unsigned long i = 0; i < item.size(); ++i) + serialize(item[i],out); + } + catch (serialization_error& e) + { throw serialization_error(e.info + "\n while serializing object of type std::deque"); } + } + + template + void deserialize ( + std::deque& item, + std::istream& in + ) + { + try + { + unsigned long size; + deserialize(size,in); + item.resize(size); + for (unsigned long i = 0; i < size; ++i) + deserialize(item[i],in); + } + catch (serialization_error& e) + { throw serialization_error(e.info + "\n while deserializing object of type std::deque"); } + } + // ---------------------------------------------------------------------------------------- inline void serialize ( @@ -1311,6 +1439,64 @@ namespace dlib } } +// ---------------------------------------------------------------------------------------- + + template < + typename T, + size_t N + > + inline void serialize ( + const std::array& array, + std::ostream& out + ) + { + typedef T c_array_type[N]; + serialize(*(const c_array_type*)array.data(), out); + } + + template < + typename T, + size_t N + > + inline void deserialize ( + std::array& array, + std::istream& in + ) + { + typedef T c_array_type[N]; + deserialize(*(c_array_type*)array.data(), in); + } + + template < + typename T + > + inline void serialize ( + const std::array& /*array*/, + std::ostream& out + ) + { + size_t N = 0; + serialize(N, out); + } + + template < + typename T + > + inline void deserialize ( + std::array& /*array*/, + std::istream& in + ) + { + size_t N; + deserialize(N, in); + if (N != 0) + { + std::ostringstream sout; + sout << "Expected std::array of size 0 but found a size of " << N; + throw serialization_error(sout.str()); + } + } + // ---------------------------------------------------------------------------------------- template < @@ -1377,7 +1563,7 @@ namespace dlib } private: - shared_ptr fout; + std::shared_ptr fout; }; class proxy_deserialize @@ -1385,22 +1571,99 @@ namespace dlib public: explicit proxy_deserialize ( const std::string& filename - ) + ) : filename(filename) { fin.reset(new std::ifstream(filename.c_str(), std::ios::binary)); if (!(*fin)) throw serialization_error("Unable to open " + filename + " for reading."); + + // read the file header into a buffer and then seek back to the start of the + // file. + fin->read(file_header,4); + fin->clear(); + fin->seekg(0); } template inline proxy_deserialize& operator>>(T& item) { - deserialize(item, *fin); - return *this; + return doit(item); + } + + template + inline proxy_deserialize& operator>>(ramdump_t&& item) + { + return doit(std::move(item)); } private: - shared_ptr fin; + template + inline proxy_deserialize& doit(T&& item) + { + try + { + if (fin->peek() == EOF) + throw serialization_error("No more objects were in the file!"); + deserialize(std::forward(item), *fin); + } + catch (serialization_error& e) + { + std::string suffix; + if (looks_like_a_compressed_file()) + suffix = "\n *** THIS LOOKS LIKE A COMPRESSED FILE. DID YOU FORGET TO DECOMPRESS IT? *** \n"; + + if (objects_read == 0) + { + throw serialization_error("An error occurred while trying to read the first" + " object from the file " + filename + ".\nERROR: " + e.info + "\n" + suffix); + } + else if (objects_read == 1) + { + throw serialization_error("An error occurred while trying to read the second" + " object from the file " + filename + + ".\nERROR: " + e.info + "\n" + suffix); + } + else if (objects_read == 2) + { + throw serialization_error("An error occurred while trying to read the third" + " object from the file " + filename + + ".\nERROR: " + e.info + "\n" + suffix); + } + else + { + throw serialization_error("An error occurred while trying to read the " + + std::to_string(objects_read+1) + "th object from the file " + filename + + ".\nERROR: " + e.info + "\n" + suffix); + } + } + ++objects_read; + return *this; + } + + int objects_read = 0; + std::string filename; + std::shared_ptr fin; + + // We don't need to look at the file header. However, it's here because people + // keep posting questions to the dlib forums asking why they get file load errors. + // Then it turns out that the problem is they have a compressed file that NEEDS TO + // BE DECOMPRESSED by bzip2 or whatever and the reason they are getting + // deserialization errors is because they didn't decompress the file. So we are + // going to check if this file looks like a compressed file and if so then emit an + // error message telling them to unzip the file. :( + char file_header[4] = {0,0,0,0}; + + bool looks_like_a_compressed_file( + ) const + { + if (file_header[0] == 'B' && file_header[1] == 'Z' && file_header[2] == 'h' && + ('0' <= file_header[3] && file_header[3] <= '9') ) + { + return true; + } + + return false; + } }; inline proxy_serialize serialize(const std::string& filename) @@ -1495,6 +1758,19 @@ namespace dlib } } +// ---------------------------------------------------------------------------------------- + + inline void check_serialized_version(const std::string& expected_version, std::istream& in) + { + std::string version; + deserialize(version, in); + if (version != expected_version) + { + throw serialization_error("Unexpected version '"+version+ + "' found while deserializing object. Expected version to be '"+expected_version+"'."); + } + } + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/server/server_http.cpp b/lib/3rdParty/dlib/include/dlib/server/server_http.cpp deleted file mode 100644 index 9e3051a4..00000000 --- a/lib/3rdParty/dlib/include/dlib/server/server_http.cpp +++ /dev/null @@ -1,409 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_SERVER_HTTP_CPp_ -#define DLIB_SERVER_HTTP_CPp_ - -#include "server_http.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - namespace http_impl - { - inline unsigned char to_hex( unsigned char x ) - { - return x + (x > 9 ? ('A'-10) : '0'); - } - - const std::string urlencode( const std::string& s ) - { - std::ostringstream os; - - for ( std::string::const_iterator ci = s.begin(); ci != s.end(); ++ci ) - { - if ( (*ci >= 'a' && *ci <= 'z') || - (*ci >= 'A' && *ci <= 'Z') || - (*ci >= '0' && *ci <= '9') ) - { // allowed - os << *ci; - } - else if ( *ci == ' ') - { - os << '+'; - } - else - { - os << '%' << to_hex(*ci >> 4) << to_hex(*ci % 16); - } - } - - return os.str(); - } - - inline unsigned char from_hex ( - unsigned char ch - ) - { - if (ch <= '9' && ch >= '0') - ch -= '0'; - else if (ch <= 'f' && ch >= 'a') - ch -= 'a' - 10; - else if (ch <= 'F' && ch >= 'A') - ch -= 'A' - 10; - else - ch = 0; - return ch; - } - - const std::string urldecode ( - const std::string& str - ) - { - using namespace std; - string result; - string::size_type i; - for (i = 0; i < str.size(); ++i) - { - if (str[i] == '+') - { - result += ' '; - } - else if (str[i] == '%' && str.size() > i+2) - { - const unsigned char ch1 = from_hex(str[i+1]); - const unsigned char ch2 = from_hex(str[i+2]); - const unsigned char ch = (ch1 << 4) | ch2; - result += ch; - i += 2; - } - else - { - result += str[i]; - } - } - return result; - } - - void parse_url( - std::string word, - key_value_map& queries - ) - /*! - Parses the query string of a URL. word should be the stuff that comes - after the ? in the query URL. - !*/ - { - std::string::size_type pos; - - for (pos = 0; pos < word.size(); ++pos) - { - if (word[pos] == '&') - word[pos] = ' '; - } - - std::istringstream sin(word); - sin >> word; - while (sin) - { - pos = word.find_first_of("="); - if (pos != std::string::npos) - { - std::string key = urldecode(word.substr(0,pos)); - std::string value = urldecode(word.substr(pos+1)); - - queries[key] = value; - } - sin >> word; - } - } - - void read_with_limit( - std::istream& in, - std::string& buffer, - int delim = '\n' - ) - { - using namespace std; - const size_t max = 64*1024; - buffer.clear(); - buffer.reserve(300); - - while (in.peek() != delim && in.peek() != '\n' && in.peek() != EOF && buffer.size() < max) - { - buffer += (char)in.get(); - } - - // if we quit the loop because the data is longer than expected or we hit EOF - if (in.peek() == EOF) - throw http_parse_error("HTTP field from client terminated incorrectly", 414); - if (buffer.size() == max) - throw http_parse_error("HTTP field from client is too long", 414); - - in.get(); - // eat any remaining whitespace - if (delim == ' ') - { - while (in.peek() == ' ') - in.get(); - } - } - } - -// ---------------------------------------------------------------------------------------- - - unsigned long parse_http_request ( - std::istream& in, - incoming_things& incoming, - unsigned long max_content_length - ) - { - using namespace std; - using namespace http_impl; - read_with_limit(in, incoming.request_type, ' '); - - // get the path - read_with_limit(in, incoming.path, ' '); - - // Get the HTTP/1.1 - Ignore for now... - read_with_limit(in, incoming.protocol); - - key_value_map_ci& incoming_headers = incoming.headers; - key_value_map& cookies = incoming.cookies; - std::string& path = incoming.path; - std::string& content_type = incoming.content_type; - unsigned long content_length = 0; - - string line; - read_with_limit(in, line); - string first_part_of_header; - string::size_type position_of_double_point; - // now loop over all the incoming_headers - while (line != "\r") - { - position_of_double_point = line.find_first_of(':'); - if ( position_of_double_point != string::npos ) - { - first_part_of_header = dlib::trim(line.substr(0, position_of_double_point)); - - if ( !incoming_headers[first_part_of_header].empty() ) - incoming_headers[ first_part_of_header ] += " "; - incoming_headers[first_part_of_header] += dlib::trim(line.substr(position_of_double_point+1)); - - // look for Content-Type: - if (line.size() > 14 && strings_equal_ignore_case(line, "Content-Type:", 13)) - { - content_type = line.substr(14); - if (content_type[content_type.size()-1] == '\r') - content_type.erase(content_type.size()-1); - } - // look for Content-Length: - else if (line.size() > 16 && strings_equal_ignore_case(line, "Content-Length:", 15)) - { - istringstream sin(line.substr(16)); - sin >> content_length; - if (!sin) - { - throw http_parse_error("Invalid Content-Length of '" + line.substr(16) + "'", 411); - } - - if (content_length > max_content_length) - { - std::ostringstream sout; - sout << "Content-Length of post back is too large. It must be less than " << max_content_length; - throw http_parse_error(sout.str(), 413); - } - } - // look for any cookies - else if (line.size() > 6 && strings_equal_ignore_case(line, "Cookie:", 7)) - { - string::size_type pos = 6; - string key, value; - bool seen_key_start = false; - bool seen_equal_sign = false; - while (pos + 1 < line.size()) - { - ++pos; - // ignore whitespace between cookies - if (!seen_key_start && line[pos] == ' ') - continue; - - seen_key_start = true; - if (!seen_equal_sign) - { - if (line[pos] == '=') - { - seen_equal_sign = true; - } - else - { - key += line[pos]; - } - } - else - { - if (line[pos] == ';') - { - cookies[urldecode(key)] = urldecode(value); - seen_equal_sign = false; - seen_key_start = false; - key.clear(); - value.clear(); - } - else - { - value += line[pos]; - } - } - } - if (key.size() > 0) - { - cookies[urldecode(key)] = urldecode(value); - key.clear(); - value.clear(); - } - } - } // no ':' in it! - read_with_limit(in, line); - } // while (line != "\r") - - - // If there is data being posted back to us as a query string then - // pick out the queries using parse_url. - if ((strings_equal_ignore_case(incoming.request_type, "POST") || - strings_equal_ignore_case(incoming.request_type, "PUT")) && - strings_equal_ignore_case(left_substr(content_type,";"), "application/x-www-form-urlencoded")) - { - if (content_length > 0) - { - incoming.body.resize(content_length); - in.read(&incoming.body[0],content_length); - } - parse_url(incoming.body, incoming.queries); - } - - string::size_type pos = path.find_first_of("?"); - if (pos != string::npos) - { - parse_url(path.substr(pos+1), incoming.queries); - } - - - if (!in) - throw http_parse_error("Error parsing HTTP request", 500); - - return content_length; - } - -// ---------------------------------------------------------------------------------------- - - void read_body ( - std::istream& in, - incoming_things& incoming - ) - { - // if the body hasn't already been loaded and there is data to load - if (incoming.body.size() == 0 && - incoming.headers.count("Content-Length") != 0) - { - const unsigned long content_length = string_cast(incoming.headers["Content-Length"]); - - incoming.body.resize(content_length); - if (content_length > 0) - { - in.read(&incoming.body[0],content_length); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void write_http_response ( - std::ostream& out, - outgoing_things outgoing, - const std::string& result - ) - { - using namespace http_impl; - key_value_map& new_cookies = outgoing.cookies; - key_value_map_ci& response_headers = outgoing.headers; - - // only send this header if the user hasn't told us to send another kind - bool has_content_type = false, has_location = false; - for(key_value_map_ci::const_iterator ci = response_headers.begin(); ci != response_headers.end(); ++ci ) - { - if ( !has_content_type && strings_equal_ignore_case(ci->first , "content-type") ) - { - has_content_type = true; - } - else if ( !has_location && strings_equal_ignore_case(ci->first , "location") ) - { - has_location = true; - } - } - - if ( has_location ) - { - outgoing.http_return = 302; - } - - if ( !has_content_type ) - { - response_headers["Content-Type"] = "text/html"; - } - - response_headers["Content-Length"] = cast_to_string(result.size()); - - out << "HTTP/1.0 " << outgoing.http_return << " " << outgoing.http_return_status << "\r\n"; - - // Set any new headers - for(key_value_map_ci::const_iterator ci = response_headers.begin(); ci != response_headers.end(); ++ci ) - { - out << ci->first << ": " << ci->second << "\r\n"; - } - - // set any cookies - for(key_value_map::const_iterator ci = new_cookies.begin(); ci != new_cookies.end(); ++ci ) - { - out << "Set-Cookie: " << urlencode(ci->first) << '=' << urlencode(ci->second) << "\r\n"; - } - out << "\r\n" << result; - } - -// ---------------------------------------------------------------------------------------- - - void write_http_response ( - std::ostream& out, - const http_parse_error& e - ) - { - outgoing_things outgoing; - outgoing.http_return = e.http_error_code; - outgoing.http_return_status = e.what(); - write_http_response(out, outgoing, std::string("Error processing request: ") + e.what()); - } - -// ---------------------------------------------------------------------------------------- - - void write_http_response ( - std::ostream& out, - const std::exception& e - ) - { - outgoing_things outgoing; - outgoing.http_return = 500; - outgoing.http_return_status = e.what(); - write_http_response(out, outgoing, std::string("Error processing request: ") + e.what()); - } - -// ---------------------------------------------------------------------------------------- - - const logger server_http::dlog("dlib.server_http"); - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_SERVER_HTTP_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/server/server_iostream.cpp b/lib/3rdParty/dlib/include/dlib/server/server_iostream.cpp deleted file mode 100644 index 0fd49b67..00000000 --- a/lib/3rdParty/dlib/include/dlib/server/server_iostream.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_SERVER_IOSTREAM_CPp_ -#define DLIB_SERVER_IOSTREAM_CPp_ - -#include "server_iostream.h" - -namespace dlib -{ - const logger server_iostream::_dLog("dlib.server_iostream"); -} - -#endif // DLIB_SERVER_IOSTREAM_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/server/server_iostream.h b/lib/3rdParty/dlib/include/dlib/server/server_iostream.h index 372f7a5d..eed34901 100644 --- a/lib/3rdParty/dlib/include/dlib/server/server_iostream.h +++ b/lib/3rdParty/dlib/include/dlib/server/server_iostream.h @@ -74,7 +74,7 @@ namespace dlib ) { bool my_fault = true; - uint64 this_con_id; + uint64 this_con_id=0; try { sockstreambuf buf(&con); diff --git a/lib/3rdParty/dlib/include/dlib/server/server_kernel.cpp b/lib/3rdParty/dlib/include/dlib/server/server_kernel.cpp deleted file mode 100644 index 9e8130e7..00000000 --- a/lib/3rdParty/dlib/include/dlib/server/server_kernel.cpp +++ /dev/null @@ -1,595 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_SERVER_KERNEL_CPp_ -#define DLIB_SERVER_KERNEL_CPp_ - -#include "server_kernel.h" -#include "../string.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - server:: - server ( - ) : - listening_port(0), - running(false), - shutting_down(false), - running_signaler(running_mutex), - thread_count(0), - thread_count_signaler(thread_count_mutex), - max_connections(1000), - thread_count_zero(thread_count_mutex), - graceful_close_timeout(500) - { - } - -// ---------------------------------------------------------------------------------------- - - server:: - ~server ( - ) - { - clear(); - } - -// ---------------------------------------------------------------------------------------- - - unsigned long server:: - get_graceful_close_timeout ( - ) const - { - auto_mutex lock(max_connections_mutex); - return graceful_close_timeout; - } - -// ---------------------------------------------------------------------------------------- - - void server:: - set_graceful_close_timeout ( - unsigned long timeout - ) - { - auto_mutex lock(max_connections_mutex); - graceful_close_timeout = timeout; - } - -// ---------------------------------------------------------------------------------------- - - - int server:: - get_max_connections ( - ) const - { - max_connections_mutex.lock(); - int temp = max_connections; - max_connections_mutex.unlock(); - return temp; - } - -// ---------------------------------------------------------------------------------------- - - void server:: - set_max_connections ( - int max - ) - { - // make sure requires clause is not broken - DLIB_CASSERT( - max >= 0 , - "\tvoid server::set_max_connections" - << "\n\tmax == " << max - << "\n\tthis: " << this - ); - - max_connections_mutex.lock(); - max_connections = max; - max_connections_mutex.unlock(); - } - -// ---------------------------------------------------------------------------------------- - - void server:: - clear ( - ) - { - // signal that we are shutting down - shutting_down_mutex.lock(); - shutting_down = true; - shutting_down_mutex.unlock(); - - - - max_connections_mutex.lock(); - listening_port_mutex.lock(); - listening_ip_mutex.lock(); - listening_ip = ""; - listening_port = 0; - max_connections = 1000; - graceful_close_timeout = 500; - listening_port_mutex.unlock(); - listening_ip_mutex.unlock(); - max_connections_mutex.unlock(); - - - // tell all the connections to shut down - cons_mutex.lock(); - connection* temp; - while (cons.size() > 0) - { - cons.remove_any(temp); - temp->shutdown(); - } - cons_mutex.unlock(); - - - // wait for all the connections to shut down - thread_count_mutex.lock(); - while (thread_count > 0) - { - thread_count_zero.wait(); - } - thread_count_mutex.unlock(); - - - - - // wait for the listener to close - running_mutex.lock(); - while (running == true) - { - running_signaler.wait(); - } - running_mutex.unlock(); - - - - // signal that the shutdown is complete - shutting_down_mutex.lock(); - shutting_down = false; - shutting_down_mutex.unlock(); - } - -// ---------------------------------------------------------------------------------------- - - void server:: - start_async_helper ( - ) - { - try - { - start_accepting_connections(); - } - catch (std::exception& e) - { - sdlog << LERROR << e.what(); - } - } - -// ---------------------------------------------------------------------------------------- - - void server:: - start_async ( - ) - { - auto_mutex lock(running_mutex); - if (running) - return; - - // Any exceptions likely to be thrown by the server are going to be - // thrown when trying to bind the port. So calling this here rather - // than in the thread we are about to make will cause start_async() - // to report errors back to the user in a very straight forward way. - open_listening_socket(); - - async_start_thread.reset(new thread_function(make_mfp(*this,&server::start_async_helper))); - } - -// ---------------------------------------------------------------------------------------- - - void server:: - open_listening_socket ( - ) - { - if (!sock) - { - int status = create_listener(sock,listening_port,listening_ip); - const int port_used = listening_port; - - // if there was an error then clear this object - if (status < 0) - { - max_connections_mutex.lock(); - listening_port_mutex.lock(); - listening_ip_mutex.lock(); - listening_ip = ""; - listening_port = 0; - max_connections = 1000; - graceful_close_timeout = 500; - listening_port_mutex.unlock(); - listening_ip_mutex.unlock(); - max_connections_mutex.unlock(); - } - - - - // throw an exception for the error - if (status == PORTINUSE) - { - throw dlib::socket_error( - EPORT_IN_USE, - "error occurred in server::start()\nport " + cast_to_string(port_used) + " already in use" - ); - } - else if (status == OTHER_ERROR) - { - throw dlib::socket_error( - "error occurred in server::start()\nunable to create listener" - ); - } - } - - running_mutex.lock(); - running = true; - running_mutex.unlock(); - } - -// ---------------------------------------------------------------------------------------- - - void server:: - start ( - ) - { - // make sure requires clause is not broken - DLIB_CASSERT( - this->is_running() == false, - "\tvoid server::start" - << "\n\tis_running() == " << this->is_running() - << "\n\tthis: " << this - ); - - start_accepting_connections(); - - } - -// ---------------------------------------------------------------------------------------- - - void server:: - start_accepting_connections ( - ) - { - open_listening_socket(); - - // determine the listening port - bool port_assigned = false; - listening_port_mutex.lock(); - if (listening_port == 0) - { - port_assigned = true; - listening_port = sock->get_listening_port(); - } - listening_port_mutex.unlock(); - if (port_assigned) - on_listening_port_assigned(); - - - - int status = 0; - - connection* client; - bool exit = false; - while ( true ) - { - - - // accept the next connection - status = sock->accept(client,1000); - - - // if there was an error then quit the loop - if (status == OTHER_ERROR) - { - break; - } - - shutting_down_mutex.lock(); - // if we are shutting down then signal that we should quit the loop - exit = shutting_down; - shutting_down_mutex.unlock(); - - - // if we should be shutting down - if (exit) - { - // if a connection was opened then close it - if (status == 0) - delete client; - break; - } - - - - // if the accept timed out - if (status == TIMEOUT) - { - continue; - } - - - - - - // add this new connection to cons - cons_mutex.lock(); - connection* client_temp = client; - try{cons.add(client_temp);} - catch(...) - { - sock.reset(); - delete client; - cons_mutex.unlock(); - - // signal that we are not running start() anymore - running_mutex.lock(); - running = false; - running_signaler.broadcast(); - running_mutex.unlock(); - - - clear(); - throw; - } - cons_mutex.unlock(); - - - // make a param structure - param* temp = 0; - try{ - temp = new param ( - *this, - *client, - get_graceful_close_timeout() - ); - } catch (...) - { - sock.reset(); - delete client; - running_mutex.lock(); - running = false; - running_signaler.broadcast(); - running_mutex.unlock(); - clear(); - throw; - } - - - // if create_new_thread failed - if (!create_new_thread(service_connection,temp)) - { - delete temp; - // close the listening socket - sock.reset(); - - // close the new connection and remove it from cons - cons_mutex.lock(); - connection* ctemp; - if (cons.is_member(client)) - { - cons.remove(client,ctemp); - } - delete client; - cons_mutex.unlock(); - - - // signal that the listener has closed - running_mutex.lock(); - running = false; - running_signaler.broadcast(); - running_mutex.unlock(); - - // make sure the object is cleared - clear(); - - // throw the exception - throw dlib::thread_error( - ECREATE_THREAD, - "error occurred in server::start()\nunable to start thread" - ); - } - // if we made the new thread then update thread_count - else - { - // increment the thread count - thread_count_mutex.lock(); - ++thread_count; - if (thread_count == 0) - thread_count_zero.broadcast(); - thread_count_mutex.unlock(); - } - - - - - // check if we have hit the maximum allowed number of connections - max_connections_mutex.lock(); - // if max_connections is zero or the loop is ending then skip this - if (max_connections != 0) - { - // wait for thread_count to be less than max_connections - thread_count_mutex.lock(); - while (thread_count >= max_connections) - { - max_connections_mutex.unlock(); - thread_count_signaler.wait(); - max_connections_mutex.lock(); - - // if we are shutting down the quit the loop - shutting_down_mutex.lock(); - exit = shutting_down; - shutting_down_mutex.unlock(); - if (exit) - break; - } - thread_count_mutex.unlock(); - } - max_connections_mutex.unlock(); - - if (exit) - { - break; - } - } //while ( true ) - - - // close the socket - sock.reset(); - - // signal that the listener has closed - running_mutex.lock(); - running = false; - running_signaler.broadcast(); - running_mutex.unlock(); - - // if there was an error with accept then throw an exception - if (status == OTHER_ERROR) - { - // make sure the object is cleared - clear(); - - // throw the exception - throw dlib::socket_error( - "error occurred in server::start()\nlistening socket returned error" - ); - } - } - -// ---------------------------------------------------------------------------------------- - - bool server:: - is_running ( - ) const - { - running_mutex.lock(); - bool temp = running; - running_mutex.unlock(); - return temp; - } - -// ---------------------------------------------------------------------------------------- - - const std::string server:: - get_listening_ip ( - ) const - { - listening_ip_mutex.lock(); - std::string ip(listening_ip); - listening_ip_mutex.unlock(); - return ip; - } - -// ---------------------------------------------------------------------------------------- - - int server:: - get_listening_port ( - ) const - { - listening_port_mutex.lock(); - int port = listening_port; - listening_port_mutex.unlock(); - return port; - } - -// ---------------------------------------------------------------------------------------- - - void server:: - set_listening_port ( - int port - ) - { - // make sure requires clause is not broken - DLIB_CASSERT( - ( port >= 0 && - this->is_running() == false ), - "\tvoid server::set_listening_port" - << "\n\tport == " << port - << "\n\tis_running() == " << this->is_running() - << "\n\tthis: " << this - ); - - listening_port_mutex.lock(); - listening_port = port; - listening_port_mutex.unlock(); - } - -// ---------------------------------------------------------------------------------------- - - void server:: - set_listening_ip ( - const std::string& ip - ) - { - // make sure requires clause is not broken - DLIB_CASSERT( - ( ( is_ip_address(ip) || ip == "" ) && - this->is_running() == false ), - "\tvoid server::set_listening_ip" - << "\n\tip == " << ip - << "\n\tis_running() == " << this->is_running() - << "\n\tthis: " << this - ); - - listening_ip_mutex.lock(); - listening_ip = ip; - listening_ip_mutex.unlock(); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // static member function definitions -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - const logger server::sdlog("dlib.server"); - - void server:: - service_connection( - void* item - ) - { - param& p = *static_cast(item); - - - p.the_server.on_connect(p.new_connection); - - - // remove this connection from cons and close it - p.the_server.cons_mutex.lock(); - connection* temp; - if (p.the_server.cons.is_member(&p.new_connection)) - p.the_server.cons.remove(&p.new_connection,temp); - p.the_server.cons_mutex.unlock(); - - try{ close_gracefully(&p.new_connection, p.graceful_close_timeout); } - catch (...) { sdlog << LERROR << "close_gracefully() threw"; } - - // decrement the thread count and signal if it is now zero - p.the_server.thread_count_mutex.lock(); - --p.the_server.thread_count; - p.the_server.thread_count_signaler.broadcast(); - if (p.the_server.thread_count == 0) - p.the_server.thread_count_zero.broadcast(); - p.the_server.thread_count_mutex.unlock(); - - delete &p; - - - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_SERVER_KERNEL_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/server/server_kernel.h b/lib/3rdParty/dlib/include/dlib/server/server_kernel.h index 2117e25c..4232ff34 100644 --- a/lib/3rdParty/dlib/include/dlib/server/server_kernel.h +++ b/lib/3rdParty/dlib/include/dlib/server/server_kernel.h @@ -5,13 +5,14 @@ #include "server_kernel_abstract.h" +#include +#include + #include "../threads.h" #include "../sockets.h" -#include #include "../algs.h" #include "../set.h" #include "../logger.h" -#include "../smart_pointers.h" namespace dlib @@ -209,8 +210,8 @@ namespace dlib int max_connections; mutex max_connections_mutex; signaler thread_count_zero; - scoped_ptr async_start_thread; - scoped_ptr sock; + std::unique_ptr async_start_thread; + std::unique_ptr sock; unsigned long graceful_close_timeout; diff --git a/lib/3rdParty/dlib/include/dlib/set/set_kernel_1.h b/lib/3rdParty/dlib/include/dlib/set/set_kernel_1.h index 10690645..9df96e67 100644 --- a/lib/3rdParty/dlib/include/dlib/set/set_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/set/set_kernel_1.h @@ -80,7 +80,7 @@ namespace dlib ); // functions from the enumerable interface - inline unsigned long size ( + inline size_t size ( ) const; inline bool at_start ( @@ -254,7 +254,7 @@ namespace dlib typename bst_base, typename mem_manager > - unsigned long set_kernel_1:: + size_t set_kernel_1:: size ( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/simd/simd4f.h b/lib/3rdParty/dlib/include/dlib/simd/simd4f.h index 83b3d037..2bfadd23 100644 --- a/lib/3rdParty/dlib/include/dlib/simd/simd4f.h +++ b/lib/3rdParty/dlib/include/dlib/simd/simd4f.h @@ -83,6 +83,117 @@ namespace dlib private: __m128 x; }; + +#elif defined(DLIB_HAVE_VSX) + + class simd4f + { + typedef union { + vector float v; + float x[4]; + } v4f; + + v4f x; + + public: + inline simd4f() : x{0,0,0,0} {} + inline simd4f(const simd4f& v) : x(v.x) { } + inline simd4f(const vector float& v) : x{v} { } + + inline simd4f(const simd4i& v) { + x.x[0]=v[0]; x.x[1]=v[1]; x.x[2]=v[2]; x.x[3]=v[3]; + } + + + inline simd4f(float f) : x{f,f,f,f} { } + inline simd4f(float r0, float r1, float r2, float r3) + : x{r0,r1,r2,r3} { } + + inline simd4f& operator=(const simd4f& v) { x = v.x; return *this; } + inline simd4f& operator=(const float& v) { *this = simd4f(v); return *this; } + + inline vector float operator() () const { return x.v; } + inline float operator[](unsigned int idx) const { return x.x[idx]; } + + inline void load_aligned(const float* ptr) { x.v = vec_ld(0, ptr); } + inline void store_aligned(float* ptr) const { vec_st(x.v, 0, ptr); } + inline void load(const float* ptr) { x.v = vec_vsx_ld(0, ptr); } + inline void store(float* ptr) const { vec_vsx_st(x.v, 0, ptr); } + + + // truncate to 32bit integers + inline operator simd4i::rawarray() const + { + simd4i::rawarray temp; + temp.v.x[0] = x.x[0]; + temp.v.x[1] = x.x[1]; + temp.v.x[2] = x.x[2]; + temp.v.x[3] = x.x[3]; + return temp; + } + }; + + typedef simd4i simd4f_bool; + +#elif defined(DLIB_HAVE_NEON) + + class simd4f + { + public: + typedef float type; + + inline simd4f() {} + inline simd4f(float f) { x = vdupq_n_f32(f); } + inline simd4f(float r0, float r1, float r2, float r3) + { + float __attribute__ ((aligned (16))) data[4] = { r0, r1, r2, r3 }; + x = vld1q_f32(data); + } + inline simd4f(const float32x4_t& val):x(val) {} + inline simd4f(const simd4i& val):x(vcvtq_f32_s32(val)) {} + + inline simd4f& operator=(const simd4i& val) + { + x = simd4f(val); + return *this; + } + + inline simd4f& operator=(const float& val) + { + x = simd4f(val); + return *this; + } + + inline simd4f& operator=(const float32x4_t& val) + { + x = val; + return *this; + } + + inline operator float32x4_t() const { return x; } + + // truncate to 32bit integers + inline operator int32x4_t() const { return vcvtq_s32_f32(x); } + + inline void load_aligned(const type* ptr) { x = vld1q_f32(ptr); } + inline void store_aligned(type* ptr) const { vst1q_f32(ptr, x); } + inline void load(const type* ptr) { x = vld1q_f32(ptr); } + inline void store(type* ptr) const { vst1q_f32(ptr, x); } + + inline unsigned int size() const { return 4; } + inline float operator[](unsigned int idx) const + { + float temp[4]; + store(temp); + return temp[idx]; + } + + private: + float32x4_t x; + }; + + + typedef simd4i simd4f_bool; #else class simd4f { @@ -160,6 +271,7 @@ namespace dlib float x[4]; }; + class simd4f_bool { public: @@ -172,6 +284,7 @@ namespace dlib private: bool x[4]; }; + #endif // ---------------------------------------------------------------------------------------- @@ -190,6 +303,10 @@ namespace dlib { #ifdef DLIB_HAVE_SSE2 return _mm_add_ps(lhs, rhs); +#elif defined(DLIB_HAVE_VSX) + return vec_add(lhs(), rhs()); +#elif defined(DLIB_HAVE_NEON) + return vaddq_f32(lhs, rhs); #else return simd4f(lhs[0]+rhs[0], lhs[1]+rhs[1], @@ -198,7 +315,7 @@ namespace dlib #endif } inline simd4f& operator+= (simd4f& lhs, const simd4f& rhs) - { return lhs = lhs + rhs; return lhs;} + { lhs = lhs + rhs; return lhs; } // ---------------------------------------------------------------------------------------- @@ -206,6 +323,10 @@ namespace dlib { #ifdef DLIB_HAVE_SSE2 return _mm_sub_ps(lhs, rhs); +#elif defined(DLIB_HAVE_VSX) + return vec_sub(lhs(), rhs()); +#elif defined(DLIB_HAVE_NEON) + return vsubq_f32(lhs, rhs); #else return simd4f(lhs[0]-rhs[0], lhs[1]-rhs[1], @@ -214,7 +335,7 @@ namespace dlib #endif } inline simd4f& operator-= (simd4f& lhs, const simd4f& rhs) - { return lhs = lhs - rhs; return lhs;} + { lhs = lhs - rhs; return lhs; } // ---------------------------------------------------------------------------------------- @@ -222,6 +343,10 @@ namespace dlib { #ifdef DLIB_HAVE_SSE2 return _mm_mul_ps(lhs, rhs); +#elif defined(DLIB_HAVE_VSX) + return vec_mul(lhs(), rhs()); +#elif defined(DLIB_HAVE_NEON) + return vmulq_f32(lhs, rhs); #else return simd4f(lhs[0]*rhs[0], lhs[1]*rhs[1], @@ -230,7 +355,7 @@ namespace dlib #endif } inline simd4f& operator*= (simd4f& lhs, const simd4f& rhs) - { return lhs = lhs * rhs; return lhs;} + { lhs = lhs * rhs; return lhs; } // ---------------------------------------------------------------------------------------- @@ -238,6 +363,14 @@ namespace dlib { #ifdef DLIB_HAVE_SSE2 return _mm_div_ps(lhs, rhs); +#elif defined(DLIB_HAVE_VSX) + return vec_div(lhs(), rhs()); +#elif defined(DLIB_HAVE_NEON) + float32x4_t reciprocal = vrecpeq_f32(rhs); + reciprocal = vmulq_f32(vrecpsq_f32(rhs, reciprocal), reciprocal); + reciprocal = vmulq_f32(vrecpsq_f32(rhs, reciprocal), reciprocal); + float32x4_t result = vmulq_f32(lhs,reciprocal); + return result; #else return simd4f(lhs[0]/rhs[0], lhs[1]/rhs[1], @@ -245,15 +378,19 @@ namespace dlib lhs[3]/rhs[3]); #endif } - inline simd4f& operator/= (simd4f& lhs, const simd4f& rhs) - { return lhs = lhs / rhs; return lhs;} + inline simd4f& operator/= (simd4f& lhs, const simd4f& rhs) + { lhs = lhs / rhs; return lhs; } // ---------------------------------------------------------------------------------------- - inline simd4f_bool operator== (const simd4f& lhs, const simd4f& rhs) - { + inline simd4f_bool operator== (const simd4f& lhs, const simd4f& rhs) + { #ifdef DLIB_HAVE_SSE2 - return _mm_cmpeq_ps(lhs, rhs); + return _mm_cmpeq_ps(lhs, rhs); +#elif defined(DLIB_HAVE_VSX) + return vec_cmpeq(lhs(), rhs()); +#elif defined(DLIB_HAVE_NEON) + return (int32x4_t)vceqq_f32(lhs, rhs); #else return simd4f_bool(lhs[0]==rhs[0], lhs[1]==rhs[1], @@ -264,10 +401,12 @@ namespace dlib // ---------------------------------------------------------------------------------------- - inline simd4f_bool operator!= (const simd4f& lhs, const simd4f& rhs) - { + inline simd4f_bool operator!= (const simd4f& lhs, const simd4f& rhs) + { #ifdef DLIB_HAVE_SSE2 - return _mm_cmpneq_ps(lhs, rhs); + return _mm_cmpneq_ps(lhs, rhs); +#elif defined(DLIB_HAVE_VSX) || defined(DLIB_HAVE_NEON) + return ~(lhs==rhs); // simd4f_bool is simd4i typedef, can use ~ #else return simd4f_bool(lhs[0]!=rhs[0], lhs[1]!=rhs[1], @@ -278,10 +417,14 @@ namespace dlib // ---------------------------------------------------------------------------------------- - inline simd4f_bool operator< (const simd4f& lhs, const simd4f& rhs) - { + inline simd4f_bool operator< (const simd4f& lhs, const simd4f& rhs) + { #ifdef DLIB_HAVE_SSE2 - return _mm_cmplt_ps(lhs, rhs); + return _mm_cmplt_ps(lhs, rhs); +#elif defined(DLIB_HAVE_VSX) + return vec_cmplt(lhs(), rhs()); +#elif defined(DLIB_HAVE_NEON) + return (int32x4_t)vcltq_f32(lhs, rhs); #else return simd4f_bool(lhs[0]= (const simd4f& lhs, const simd4f& rhs) - { + inline simd4f_bool operator>= (const simd4f& lhs, const simd4f& rhs) + { return rhs <= lhs; } // ---------------------------------------------------------------------------------------- - inline simd4f min (const simd4f& lhs, const simd4f& rhs) - { + inline simd4f min (const simd4f& lhs, const simd4f& rhs) + { #ifdef DLIB_HAVE_SSE2 - return _mm_min_ps(lhs, rhs); + return _mm_min_ps(lhs, rhs); +#elif defined(DLIB_HAVE_VSX) + return vec_min(lhs(), rhs()); +#elif defined(DLIB_HAVE_NEON) + return vminq_f32(lhs, rhs); #else return simd4f(std::min(lhs[0],rhs[0]), std::min(lhs[1],rhs[1]), @@ -334,10 +485,14 @@ namespace dlib // ---------------------------------------------------------------------------------------- - inline simd4f max (const simd4f& lhs, const simd4f& rhs) - { + inline simd4f max (const simd4f& lhs, const simd4f& rhs) + { #ifdef DLIB_HAVE_SSE2 - return _mm_max_ps(lhs, rhs); + return _mm_max_ps(lhs, rhs); +#elif defined(DLIB_HAVE_VSX) + return vec_max(lhs(), rhs()); +#elif defined(DLIB_HAVE_NEON) + return vmaxq_f32(lhs, rhs); #else return simd4f(std::max(lhs[0],rhs[0]), std::max(lhs[1],rhs[1]), @@ -348,10 +503,17 @@ namespace dlib // ---------------------------------------------------------------------------------------- - inline simd4f reciprocal (const simd4f& item) - { + inline simd4f reciprocal (const simd4f& item) + { #ifdef DLIB_HAVE_SSE2 - return _mm_rcp_ps(item); + return _mm_rcp_ps(item); +#elif defined(DLIB_HAVE_VSX) + return vec_re(item()); +#elif defined(DLIB_HAVE_NEON) + float32x4_t estimate = vrecpeq_f32(item); + estimate = vmulq_f32(vrecpsq_f32(estimate , item), estimate ); + estimate = vmulq_f32(vrecpsq_f32(estimate , item), estimate ); + return estimate ; #else return simd4f(1.0f/item[0], 1.0f/item[1], @@ -362,10 +524,17 @@ namespace dlib // ---------------------------------------------------------------------------------------- - inline simd4f reciprocal_sqrt (const simd4f& item) - { + inline simd4f reciprocal_sqrt (const simd4f& item) + { #ifdef DLIB_HAVE_SSE2 - return _mm_rsqrt_ps(item); + return _mm_rsqrt_ps(item); +#elif defined(DLIB_HAVE_VSX) + return vec_rsqrt(item()); +#elif defined(DLIB_HAVE_NEON) + float32x4_t estimate = vrsqrteq_f32(item); + simd4f estimate2 = vmulq_f32(estimate, item); + estimate = vmulq_f32(estimate, vrsqrtsq_f32(estimate2, estimate)); + return estimate; #else return simd4f(1.0f/std::sqrt(item[0]), 1.0f/std::sqrt(item[1]), @@ -388,6 +557,9 @@ namespace dlib simd4f temp = _mm_add_ps(item,_mm_movehl_ps(item,item)); simd4f temp2 = _mm_shuffle_ps(temp,temp,1); return _mm_cvtss_f32(_mm_add_ss(temp,temp2)); +#elif defined(DLIB_HAVE_NEON) + float32x2_t r = vadd_f32(vget_high_f32(item), vget_low_f32(item)); + return vget_lane_f32(vpadd_f32(r, r), 0); #else return item[0]+item[1]+item[2]+item[3]; #endif @@ -403,13 +575,29 @@ namespace dlib return sum(lhs*rhs); #endif } - + // ---------------------------------------------------------------------------------------- inline simd4f sqrt(const simd4f& item) { #ifdef DLIB_HAVE_SSE2 return _mm_sqrt_ps(item); +#elif defined(DLIB_HAVE_VSX) + return vec_sqrt(item()); +#elif defined(DLIB_HAVE_NEON) + float32x4_t q_step_0 = vrsqrteq_f32(item); + float32x4_t q_step_parm0 = vmulq_f32(item, q_step_0); + float32x4_t q_step_result0 = vrsqrtsq_f32(q_step_parm0, q_step_0); + float32x4_t q_step_1 = vmulq_f32(q_step_0, q_step_result0); + float32x4_t q_step_parm1 = vmulq_f32(item, q_step_1); + float32x4_t q_step_result1 = vrsqrtsq_f32(q_step_parm1, q_step_1); + float32x4_t q_step_2 = vmulq_f32(q_step_1, q_step_result1); + float32x4_t res3 = vmulq_f32(item, q_step_2); + + // normalize sqrt(0)=0 + uint32x4_t zcomp = vceqq_f32(vdupq_n_f32(0), item); + float32x4_t rcorr = vbslq_f32(zcomp, item, res3); + return rcorr; #else return simd4f(std::sqrt(item[0]), std::sqrt(item[1]), @@ -424,7 +612,7 @@ namespace dlib { #ifdef DLIB_HAVE_SSE41 return _mm_ceil_ps(item); -#elif defined(DLIB_HAVE_SSE2) +#elif defined(DLIB_HAVE_SSE2) || defined(DLIB_HAVE_NEON) float temp[4]; item.store(temp); temp[0] = std::ceil(temp[0]); @@ -434,6 +622,8 @@ namespace dlib simd4f temp2; temp2.load(temp); return temp2; +#elif defined(DLIB_HAVE_VSX) + return vec_ceil(item()); #else return simd4f(std::ceil(item[0]), std::ceil(item[1]), @@ -448,7 +638,7 @@ namespace dlib { #ifdef DLIB_HAVE_SSE41 return _mm_floor_ps(item); -#elif defined(DLIB_HAVE_SSE2) +#elif defined(DLIB_HAVE_SSE2) || defined(DLIB_HAVE_NEON) float temp[4]; item.store(temp); temp[0] = std::floor(temp[0]); @@ -458,6 +648,8 @@ namespace dlib simd4f temp2; temp2.load(temp); return temp2; +#elif defined(DLIB_HAVE_VSX) + return vec_floor(item()); #else return simd4f(std::floor(item[0]), std::floor(item[1]), @@ -475,6 +667,8 @@ namespace dlib return _mm_blendv_ps(b,a,cmp); #elif defined(DLIB_HAVE_SSE2) return _mm_or_ps(_mm_and_ps(cmp,a) , _mm_andnot_ps(cmp,b)); +#elif defined(DLIB_HAVE_NEON) + return vbslq_f32(cmp, a, b); #else return simd4f(cmp[0]?a[0]:b[0], cmp[1]?a[1]:b[1], diff --git a/lib/3rdParty/dlib/include/dlib/simd/simd4i.h b/lib/3rdParty/dlib/include/dlib/simd/simd4i.h index 3d8e9875..ea33f14a 100644 --- a/lib/3rdParty/dlib/include/dlib/simd/simd4i.h +++ b/lib/3rdParty/dlib/include/dlib/simd/simd4i.h @@ -44,6 +44,94 @@ namespace dlib private: __m128i x; }; + +#elif defined(DLIB_HAVE_VSX) + + class simd4i + { + typedef union { + vector signed int v; + vector bool int b; + signed int x[4]; + } v4i; + + v4i x; + + public: + inline simd4i() : x{0,0,0,0} { } + inline simd4i(const simd4i& v) : x(v.x) { } + inline simd4i(const vector int& v) : x{v} { } + inline simd4i(const vector bool int& b) { x.b=b; } + + inline simd4i(int32 f) : x{f,f,f,f} { } + inline simd4i(int32 r0, int32 r1, int32 r2, int32 r3) + : x{r0,r1,r2,r3} { } + + inline simd4i& operator=(const simd4i& v) { x = v.x; return *this; } + inline simd4i& operator=(const int32& v) { *this = simd4i(v); return *this; } + + inline vector signed int operator() () const { return x.v; } + inline int32 operator[](unsigned int idx) const { return x.x[idx]; } + + inline vector bool int to_bool() const { return x.b; } + + // intrinsics now seem to use xxpermdi automatically now + inline void load_aligned(const int32* ptr) { x.v = vec_ld(0, ptr); } + inline void store_aligned(int32* ptr) const { vec_st(x.v, 0, ptr); } + inline void load(const int32* ptr) { x.v = vec_vsx_ld(0, ptr); } + inline void store(int32* ptr) const { vec_vsx_st(x.v, 0, ptr); } + + + struct rawarray + { + v4i v; + }; + inline simd4i(const rawarray& a) : x{a.v} { } + + }; + +#elif defined(DLIB_HAVE_NEON) + + class simd4i + { + public: + typedef int32 type; + + inline simd4i() {} + inline simd4i(int32 f) { x = vdupq_n_s32(f); } + inline simd4i(int32 r0, int32 r1, int32 r2, int32 r3) + { + int32 __attribute__((aligned(16))) data[4] = { r0, r1, r2, r3 }; + x = vld1q_s32(data); + } + inline simd4i(const int32x4_t& val):x(val) {} + + inline simd4i& operator=(const int32x4_t& val) + { + x = val; + return *this; + } + + inline operator int32x4_t() const { return x; } + inline operator uint32x4_t() const { return (uint32x4_t)x; } + + inline void load_aligned(const type* ptr) { x = vld1q_s32(ptr); } + inline void store_aligned(type* ptr) const { vst1q_s32(ptr, x); } + inline void load(const type* ptr) { x = vld1q_s32(ptr); } + inline void store(type* ptr) const { vst1q_s32(ptr, x); } + + inline unsigned int size() const { return 4; } + inline int32 operator[](unsigned int idx) const + { + int32 temp[4]; + store(temp); + return temp[idx]; + } + + private: + int32x4_t x; + }; + #else class simd4i @@ -117,6 +205,10 @@ namespace dlib { #ifdef DLIB_HAVE_SSE2 return _mm_add_epi32(lhs, rhs); +#elif defined(DLIB_HAVE_VSX) + return vec_add(lhs(), rhs()); +#elif defined(DLIB_HAVE_NEON) + return vaddq_s32(lhs, rhs); #else return simd4i(lhs[0]+rhs[0], lhs[1]+rhs[1], @@ -133,6 +225,10 @@ namespace dlib { #ifdef DLIB_HAVE_SSE2 return _mm_sub_epi32(lhs, rhs); +#elif defined(DLIB_HAVE_VSX) + return vec_sub(lhs(), rhs()); +#elif defined(DLIB_HAVE_NEON) + return vsubq_s32(lhs, rhs); #else return simd4i(lhs[0]-rhs[0], lhs[1]-rhs[1], @@ -156,6 +252,12 @@ namespace dlib _lhs[1]*_rhs[1], _lhs[2]*_rhs[2], _lhs[3]*_rhs[3]); +#elif defined(DLIB_HAVE_VSX) + vector int a = lhs(), b = rhs(); + asm("vmuluwm %0, %0, %1\n\t" : "+&v" (a) : "v" (b) ); + return simd4i(a); +#elif defined(DLIB_HAVE_NEON) + return vmulq_s32(lhs, rhs); #else return simd4i(lhs[0]*rhs[0], lhs[1]*rhs[1], @@ -172,6 +274,10 @@ namespace dlib { #ifdef DLIB_HAVE_SSE2 return _mm_and_si128(lhs, rhs); +#elif defined(DLIB_HAVE_VSX) + return vec_and(lhs(), rhs()); +#elif defined(DLIB_HAVE_NEON) + return vandq_s32(lhs, rhs); #else return simd4i(lhs[0]&rhs[0], lhs[1]&rhs[1], @@ -188,6 +294,10 @@ namespace dlib { #ifdef DLIB_HAVE_SSE2 return _mm_or_si128(lhs, rhs); +#elif defined(DLIB_HAVE_VSX) + return vec_or(lhs(), rhs()); +#elif defined(DLIB_HAVE_NEON) + return vorrq_s32(lhs, rhs); #else return simd4i(lhs[0]|rhs[0], lhs[1]|rhs[1], @@ -204,6 +314,10 @@ namespace dlib { #ifdef DLIB_HAVE_SSE2 return _mm_xor_si128(lhs, rhs); +#elif defined(DLIB_HAVE_VSX) + return vec_xor(lhs(), rhs()); +#elif defined(DLIB_HAVE_NEON) + return veorq_s32(lhs, rhs); #else return simd4i(lhs[0]^rhs[0], lhs[1]^rhs[1], @@ -220,6 +334,10 @@ namespace dlib { #ifdef DLIB_HAVE_SSE2 return _mm_xor_si128(lhs, _mm_set1_epi32(0xFFFFFFFF)); +#elif defined(DLIB_HAVE_VSX) + return vec_xor(lhs(), vec_splats(~0)); +#elif defined(DLIB_HAVE_NEON) + return vmvnq_s32(lhs); #else return simd4i(~lhs[0], ~lhs[1], @@ -234,6 +352,10 @@ namespace dlib { #ifdef DLIB_HAVE_SSE2 return _mm_sll_epi32(lhs,_mm_cvtsi32_si128(rhs)); +#elif defined(DLIB_HAVE_VSX) + return vec_sl(lhs(), vec_splats((uint32_t)rhs)); +#elif defined(DLIB_HAVE_NEON) + return vshlq_s32(lhs, simd4i(rhs)); #else return simd4i(lhs[0]<>rhs, + _lhs[1]>>rhs, + _lhs[2]>>rhs, + _lhs[3]>>rhs); #else return simd4i(lhs[0]>>rhs, lhs[1]>>rhs, @@ -266,6 +396,10 @@ namespace dlib { #ifdef DLIB_HAVE_SSE2 return _mm_cmpeq_epi32(lhs, rhs); +#elif defined(DLIB_HAVE_VSX) + return vec_cmpeq(lhs(), rhs()); +#elif defined(DLIB_HAVE_NEON) + return (int32x4_t)vceqq_s32(lhs,rhs); #else return simd4i(lhs[0]==rhs[0] ? 0xFFFFFFFF : 0, lhs[1]==rhs[1] ? 0xFFFFFFFF : 0, @@ -278,7 +412,7 @@ namespace dlib inline simd4i operator!= (const simd4i& lhs, const simd4i& rhs) { -#ifdef DLIB_HAVE_SSE2 +#if defined(DLIB_HAVE_SSE2) || defined(DLIB_HAVE_VSX) || defined(DLIB_HAVE_NEON) return ~(lhs==rhs); #else return simd4i(lhs[0]!=rhs[0] ? 0xFFFFFFFF : 0, @@ -294,6 +428,10 @@ namespace dlib { #ifdef DLIB_HAVE_SSE2 return _mm_cmplt_epi32(lhs, rhs); +#elif defined(DLIB_HAVE_VSX) + return vec_cmplt(lhs(), rhs()); +#elif defined(DLIB_HAVE_NEON) + return (int32x4_t)vcltq_s32(lhs, rhs); #else return simd4i(lhs[0] rhs); +#elif defined(DLIB_HAVE_NEON) + return (int32x4_t)vcleq_s32(lhs, rhs); #else return simd4i(lhs[0]<=rhs[0] ? 0xFFFFFFFF : 0, lhs[1]<=rhs[1] ? 0xFFFFFFFF : 0, @@ -343,6 +483,10 @@ namespace dlib std::min(_lhs[1],_rhs[1]), std::min(_lhs[2],_rhs[2]), std::min(_lhs[3],_rhs[3])); +#elif defined(DLIB_HAVE_VSX) + return vec_min(lhs(), rhs()); +#elif defined(DLIB_HAVE_NEON) + return (int32x4_t)vminq_s32(lhs, rhs); #else return simd4i(std::min(lhs[0],rhs[0]), std::min(lhs[1],rhs[1]), @@ -364,6 +508,10 @@ namespace dlib std::max(_lhs[1],_rhs[1]), std::max(_lhs[2],_rhs[2]), std::max(_lhs[3],_rhs[3])); +#elif defined(DLIB_HAVE_VSX) + return vec_max(lhs(), rhs()); +#elif defined(DLIB_HAVE_NEON) + return vmaxq_s32(lhs, rhs); #else return simd4i(std::max(lhs[0],rhs[0]), std::max(lhs[1],rhs[1]), @@ -384,6 +532,9 @@ namespace dlib int32 temp[4]; item.store(temp); return temp[0]+temp[1]+temp[2]+temp[3]; +#elif defined(DLIB_HAVE_NEON) + int32x2_t r = vadd_s32(vget_high_s32(item), vget_low_s32(item)); + return vget_lane_s32(vpadd_s32(r, r), 0); #else return item[0]+item[1]+item[2]+item[3]; #endif @@ -398,6 +549,10 @@ namespace dlib return _mm_blendv_epi8(b,a,cmp); #elif defined(DLIB_HAVE_SSE2) return ((cmp&a) | _mm_andnot_si128(cmp,b)); +#elif defined(DLIB_HAVE_VSX) + return vec_sel(b(), a(), cmp.to_bool()); +#elif defined(DLIB_HAVE_NEON) + return vbslq_s32(cmp, a, b); #else return ((cmp&a) | (~cmp&b)); #endif diff --git a/lib/3rdParty/dlib/include/dlib/simd/simd8f.h b/lib/3rdParty/dlib/include/dlib/simd/simd8f.h index 33bd48e5..628ba74e 100644 --- a/lib/3rdParty/dlib/include/dlib/simd/simd8f.h +++ b/lib/3rdParty/dlib/include/dlib/simd/simd8f.h @@ -7,7 +7,6 @@ #include "simd4f.h" #include "simd8i.h" - namespace dlib { #ifdef DLIB_HAVE_AVX @@ -42,6 +41,13 @@ namespace dlib inline void load(const type* ptr) { x = _mm256_loadu_ps(ptr); } inline void store(type* ptr) const { _mm256_storeu_ps(ptr, x); } + inline simd8f& operator=(const simd8i& rhs) { *this = simd8f(rhs); return *this; } + inline simd8f& operator=(const float& val) + { + x = simd8f(val); + return *this; + } + inline unsigned int size() const { return 8; } inline float operator[](unsigned int idx) const { @@ -119,8 +125,8 @@ namespace dlib return _high[idx-4]; } - inline simd4f low() const { return _low; } - inline simd4f high() const { return _high; } + inline const simd4f& low() const { return _low; } + inline const simd4f& high() const { return _high; } private: simd4f _low, _high; @@ -135,8 +141,8 @@ namespace dlib inline simd8f_bool(const simd4f_bool& low_, const simd4f_bool& high_): _low(low_),_high(high_){} - inline simd4f_bool low() const { return _low; } - inline simd4f_bool high() const { return _high; } + inline const simd4f_bool& low() const { return _low; } + inline const simd4f_bool& high() const { return _high; } private: simd4f_bool _low,_high; }; @@ -165,7 +171,7 @@ namespace dlib #endif } inline simd8f& operator+= (simd8f& lhs, const simd8f& rhs) - { return lhs = lhs + rhs; return lhs;} + { lhs = lhs + rhs; return lhs; } // ---------------------------------------------------------------------------------------- @@ -179,7 +185,7 @@ namespace dlib #endif } inline simd8f& operator-= (simd8f& lhs, const simd8f& rhs) - { return lhs = lhs - rhs; return lhs;} + { lhs = lhs - rhs; return lhs; } // ---------------------------------------------------------------------------------------- @@ -193,7 +199,7 @@ namespace dlib #endif } inline simd8f& operator*= (simd8f& lhs, const simd8f& rhs) - { return lhs = lhs * rhs; return lhs;} + { lhs = lhs * rhs; return lhs; } // ---------------------------------------------------------------------------------------- @@ -207,7 +213,7 @@ namespace dlib #endif } inline simd8f& operator/= (simd8f& lhs, const simd8f& rhs) - { return lhs = lhs / rhs; return lhs;} + { lhs = lhs / rhs; return lhs; } // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/simd/simd8i.h b/lib/3rdParty/dlib/include/dlib/simd/simd8i.h index c7c45b4b..18c06ec7 100644 --- a/lib/3rdParty/dlib/include/dlib/simd/simd8i.h +++ b/lib/3rdParty/dlib/include/dlib/simd/simd8i.h @@ -44,7 +44,7 @@ namespace dlib inline simd4i low() const { return _mm256_castsi256_si128(x); } inline simd4i high() const { return _mm256_extractf128_si256(x,1); } - inline unsigned int size() const { return 4; } + inline unsigned int size() const { return 8; } inline int32 operator[](unsigned int idx) const { int32 temp[8]; @@ -91,8 +91,8 @@ namespace dlib return _high[idx-4]; } - inline simd4i low() const { return _low; } - inline simd4i high() const { return _high; } + inline const simd4i& low() const { return _low; } + inline const simd4i& high() const { return _high; } private: simd4i _low, _high; diff --git a/lib/3rdParty/dlib/include/dlib/simd/simd_check.h b/lib/3rdParty/dlib/include/dlib/simd/simd_check.h index 05eb2df1..c4ca0c3b 100644 --- a/lib/3rdParty/dlib/include/dlib/simd/simd_check.h +++ b/lib/3rdParty/dlib/include/dlib/simd/simd_check.h @@ -3,35 +3,76 @@ #ifndef DLIB_SIMd_CHECK_Hh_ #define DLIB_SIMd_CHECK_Hh_ +#include +#include + //#define DLIB_DO_NOT_USE_SIMD // figure out which SIMD instructions we can use. #ifndef DLIB_DO_NOT_USE_SIMD #if defined(_MSC_VER) #ifdef __AVX__ - #define DLIB_HAVE_SSE2 - #define DLIB_HAVE_SSE3 - #define DLIB_HAVE_SSE41 - #define DLIB_HAVE_AVX + #ifndef DLIB_HAVE_SSE2 + #define DLIB_HAVE_SSE2 + #endif + #ifndef DLIB_HAVE_SSE3 + #define DLIB_HAVE_SSE3 + #endif + #ifndef DLIB_HAVE_SSE41 + #define DLIB_HAVE_SSE41 + #endif + #ifndef DLIB_HAVE_AVX + #define DLIB_HAVE_AVX + #endif #endif - #if defined(_M_IX86_FP) && _M_IX86_FP >= 2 && !defined(DLIB_HAVE_SSE2) + #if (defined( _M_X64) || defined(_M_IX86_FP) && _M_IX86_FP >= 2) && !defined(DLIB_HAVE_SSE2) #define DLIB_HAVE_SSE2 #endif #else #ifdef __SSE2__ - #define DLIB_HAVE_SSE2 + #ifndef DLIB_HAVE_SSE2 + #define DLIB_HAVE_SSE2 + #endif #endif #ifdef __SSSE3__ - #define DLIB_HAVE_SSE3 + #ifndef DLIB_HAVE_SSE3 + #define DLIB_HAVE_SSE3 + #endif #endif #ifdef __SSE4_1__ - #define DLIB_HAVE_SSE41 + #ifndef DLIB_HAVE_SSE41 + #define DLIB_HAVE_SSE41 + #endif #endif #ifdef __AVX__ - #define DLIB_HAVE_AVX + #ifndef DLIB_HAVE_AVX + #define DLIB_HAVE_AVX + #endif #endif #ifdef __AVX2__ - #define DLIB_HAVE_AVX2 + #ifndef DLIB_HAVE_AVX2 + #define DLIB_HAVE_AVX2 + #endif + #endif + #ifdef __ALTIVEC__ + #ifndef DLIB_HAVE_ALTIVEC + #define DLIB_HAVE_ALTIVEC + #endif + #endif + #ifdef __VSX__ + #ifndef DLIB_HAVE_VSX + #define DLIB_HAVE_VSX + #endif + #endif + #ifdef __VEC__ // __VEC__ = 10206 + #ifndef DLIB_HAVE_POWER_VEC // vector and vec_ intrinsics + #define DLIB_HAVE_POWER_VEC + #endif + #endif + #ifdef __ARM_NEON + #ifndef DLIB_HAVE_NEON + #define DLIB_HAVE_NEON + #endif #endif #endif #endif @@ -39,6 +80,11 @@ // ---------------------------------------------------------------------------------------- + +#ifdef DLIB_HAVE_ALTIVEC +#include +#endif + #ifdef DLIB_HAVE_SSE2 #include #include @@ -55,8 +101,76 @@ #include // AVX #endif #ifdef DLIB_HAVE_AVX2 - #include + #include // AVX +// #include #endif +#ifdef DLIB_HAVE_NEON + #include // ARM NEON +#endif + +// ---------------------------------------------------------------------------------------- +// Define functions to check, at runtime, what instructions are available + +#if defined(_MSC_VER) && (defined(_M_I86) || defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) ) + #include + + inline std::array cpuid(int function_id) + { + std::array info; + // Load EAX, EBX, ECX, EDX into info + __cpuid((int*)info.data(), function_id); + return info; + } + +#elif (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__i686__) || defined(__amd64__) || defined(__x86_64__)) + #include + + inline std::array cpuid(int function_id) + { + std::array info; + // Load EAX, EBX, ECX, EDX into info + __cpuid(function_id, info[0], info[1], info[2], info[3]); + return info; + } + +#else + + inline std::array cpuid(int) + { + return std::array{}; + } + +#endif + + inline bool cpu_has_sse2_instructions() { return 0!=(cpuid(1)[3]&(1<<26)); } + inline bool cpu_has_sse3_instructions() { return 0!=(cpuid(1)[2]&(1<<0)); } + inline bool cpu_has_sse41_instructions() { return 0!=(cpuid(1)[2]&(1<<19)); } + inline bool cpu_has_sse42_instructions() { return 0!=(cpuid(1)[2]&(1<<20)); } + inline bool cpu_has_avx_instructions() { return 0!=(cpuid(1)[2]&(1<<28)); } + inline bool cpu_has_avx2_instructions() { return 0!=(cpuid(7)[1]&(1<<5)); } + inline bool cpu_has_avx512_instructions() { return 0!=(cpuid(7)[1]&(1<<16)); } + + inline void warn_about_unavailable_but_used_cpu_instructions() + { +#if defined(DLIB_HAVE_AVX2) + if (!cpu_has_avx2_instructions()) + std::cerr << "Dlib was compiled to use AVX2 instructions, but these aren't available on your machine." << std::endl; +#elif defined(DLIB_HAVE_AVX) + if (!cpu_has_avx_instructions()) + std::cerr << "Dlib was compiled to use AVX instructions, but these aren't available on your machine." << std::endl; +#elif defined(DLIB_HAVE_SSE41) + if (!cpu_has_sse41_instructions()) + std::cerr << "Dlib was compiled to use SSE41 instructions, but these aren't available on your machine." << std::endl; +#elif defined(DLIB_HAVE_SSE3) + if (!cpu_has_sse3_instructions()) + std::cerr << "Dlib was compiled to use SSE3 instructions, but these aren't available on your machine." << std::endl; +#elif defined(DLIB_HAVE_SSE2) + if (!cpu_has_sse2_instructions()) + std::cerr << "Dlib was compiled to use SSE2 instructions, but these aren't available on your machine." << std::endl; +#endif + } + +// ---------------------------------------------------------------------------------------- #endif // DLIB_SIMd_CHECK_Hh_ diff --git a/lib/3rdParty/dlib/include/dlib/sliding_buffer/circular_buffer.h b/lib/3rdParty/dlib/include/dlib/sliding_buffer/circular_buffer.h index 9856675c..4fcc922d 100644 --- a/lib/3rdParty/dlib/include/dlib/sliding_buffer/circular_buffer.h +++ b/lib/3rdParty/dlib/include/dlib/sliding_buffer/circular_buffer.h @@ -26,7 +26,11 @@ namespace dlib circular_buffer() { - offset = 0; + } + + explicit circular_buffer(unsigned long s) + { + resize(s); } void clear ( @@ -149,7 +153,7 @@ namespace dlib private: std::vector data; - unsigned long offset; + unsigned long offset = 0; }; // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/sliding_buffer/circular_buffer_abstract.h b/lib/3rdParty/dlib/include/dlib/sliding_buffer/circular_buffer_abstract.h index 03264b93..dc9f35c7 100644 --- a/lib/3rdParty/dlib/include/dlib/sliding_buffer/circular_buffer_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/sliding_buffer/circular_buffer_abstract.h @@ -49,6 +49,15 @@ namespace dlib - this object is properly initialized !*/ + explicit circular_buffer( + unsigned long s + ); + /*! + ensures + - #size() == s + - this object is properly initialized + !*/ + void clear ( ); /*! diff --git a/lib/3rdParty/dlib/include/dlib/sliding_buffer/sliding_buffer_kernel_1.h b/lib/3rdParty/dlib/include/dlib/sliding_buffer/sliding_buffer_kernel_1.h index 9f598c41..d3e6cc4b 100644 --- a/lib/3rdParty/dlib/include/dlib/sliding_buffer/sliding_buffer_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/sliding_buffer/sliding_buffer_kernel_1.h @@ -82,7 +82,7 @@ namespace dlib catch (...) { buffer = 0; buffer_size = 0; throw; } } - unsigned long size ( + size_t size ( ) const { return buffer_size; } void rotate_left ( diff --git a/lib/3rdParty/dlib/include/dlib/smart_pointers.h b/lib/3rdParty/dlib/include/dlib/smart_pointers.h index 3df38a18..905e88b1 100644 --- a/lib/3rdParty/dlib/include/dlib/smart_pointers.h +++ b/lib/3rdParty/dlib/include/dlib/smart_pointers.h @@ -3,9 +3,19 @@ #ifndef DLIB_SMART_POINTERs_H_ #define DLIB_SMART_POINTERs_H_ -#include "smart_pointers/scoped_ptr.h" +// This is legacy smart pointer code that will likely stop working under default compiler +// flags when C++17 becomes the default standard in compilers. Please consider migrating +// your code to new smart pointers from C++ standard library. +#if (defined(__GNUC__) && ((__GNUC__ >= 4 && __GNUC_MINOR__ >= 8) || (__GNUC__ > 4))) || \ + (defined(__clang__) && ((__clang_major__ >= 3 && __clang_minor__ >= 4))) +#pragma GCC warning "smart_pointers.h is included. This code will fail to compile under C++17" +#endif + +#include + #include "smart_pointers/shared_ptr.h" #include "smart_pointers/weak_ptr.h" +#include "smart_pointers/scoped_ptr.h" #endif // DLIB_SMART_POINTERs_H_ diff --git a/lib/3rdParty/dlib/include/dlib/smart_pointers/scoped_ptr.h b/lib/3rdParty/dlib/include/dlib/smart_pointers/scoped_ptr.h index af596405..dd890f33 100644 --- a/lib/3rdParty/dlib/include/dlib/smart_pointers/scoped_ptr.h +++ b/lib/3rdParty/dlib/include/dlib/smart_pointers/scoped_ptr.h @@ -1,217 +1,16 @@ -// Copyright (C) 2007 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_SCOPED_PTr_ -#define DLIB_SCOPED_PTr_ +#ifndef DLIB_SCOPED_PTr_H_ +#define DLIB_SCOPED_PTr_H_ -#include -#include "../noncopyable.h" -#include "../algs.h" -#include "scoped_ptr_abstract.h" +#include -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - template - struct default_deleter - { - void operator() (T* item) const - { - delete item; - } - }; - - template - struct default_deleter - { - void operator() (T* item) const - { - delete [] item; - } - }; - -// ---------------------------------------------------------------------------------------- - - template < - typename T, - typename deleter = default_deleter - > - class scoped_ptr : noncopyable - { - /*! - CONVENTION - - get() == ptr - !*/ - - public: - typedef T element_type; - typedef deleter deleter_type; - - explicit scoped_ptr ( - T* p = 0 - ) : ptr(p) { } - - ~scoped_ptr() - { - if (ptr) - { - deleter del; - del(ptr); - } - } - - void reset ( - T* p = 0 - ) - { - if (ptr) - { - deleter del; - del(ptr); - } - - ptr = p; - } - - T& operator*() const - { - DLIB_ASSERT(get() != 0, - "\tscoped_ptr::operator*()" - << "\n\tget() can't be null if you are going to dereference it" - << "\n\tthis: " << this - ); - - return *ptr; - } - - T* operator->() const - { - DLIB_ASSERT(get() != 0, - "\tscoped_ptr::operator*()" - << "\n\tget() can't be null" - << "\n\tthis: " << this - ); - - return ptr; - } - - T* get() const - { - return ptr; - } - - operator bool() const - { - return (ptr != 0); - } - - void swap( - scoped_ptr& b - ) - { - std::swap(ptr,b.ptr); - } - - private: - - T* ptr; - }; - -// ---------------------------------------------------------------------------------------- - - template < - typename T, - typename deleter - > - class scoped_ptr : noncopyable - { - /*! - CONVENTION - - get() == ptr - !*/ - - public: - typedef T element_type; - - explicit scoped_ptr ( - T* p = 0 - ) : ptr(p) { } - - ~scoped_ptr() - { - if (ptr) - { - deleter del; - del(ptr); - } - } - - void reset ( - T* p = 0 - ) - { - if (ptr) - { - deleter del; - del(ptr); - } - ptr = p; - } - - T& operator[] ( - unsigned long idx - ) const - { - DLIB_ASSERT(get() != 0, - "\tscoped_ptr::operator[]()" - << "\n\tget() can't be null if you are going to dereference it" - << "\n\tthis: " << this - ); - - return ptr[idx]; - } - - T* get() const - { - return ptr; - } - - operator bool() const - { - return (ptr != 0); - } - - void swap( - scoped_ptr& b - ) - { - std::swap(ptr,b.ptr); - } - - private: - - T* ptr; - }; - -// ---------------------------------------------------------------------------------------- - - template < - typename T, - typename deleter - > - void swap( - scoped_ptr& a, - scoped_ptr& b - ) - { - a.swap(b); - } - -// ---------------------------------------------------------------------------------------- +namespace dlib { + // Template alias for compatibility with clients using old dlib::scoped_ptr + // Old scoped_ptr implementation is removed completely + // This alias may fail in some reference deduction cases + + template > + using scoped_ptr = std::unique_ptr; } -#endif // DLIB_SCOPED_PTr_ - - +#endif diff --git a/lib/3rdParty/dlib/include/dlib/smart_pointers/scoped_ptr_abstract.h b/lib/3rdParty/dlib/include/dlib/smart_pointers/scoped_ptr_abstract.h deleted file mode 100644 index 1bc5db64..00000000 --- a/lib/3rdParty/dlib/include/dlib/smart_pointers/scoped_ptr_abstract.h +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (C) 2007 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#undef DLIB_SCOPED_PTr_ABSTRACT_ -#ifdef DLIB_SCOPED_PTr_ABSTRACT_ - -#include "../noncopyable.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - template - struct default_deleter - { - void operator() ( - T* item - ) const; - /*! - ensures - - if (T is an array type (e.g. int[])) then - - performs "delete [] item;" - - else - - performs "delete item;" - !*/ - }; - -// ---------------------------------------------------------------------------------------- - - template < - typename T, - typename deleter = default_deleter - > - class scoped_ptr : noncopyable - { - /*! - REQUIREMENTS ON deleter - Must be a function object that performs deallocation of a pointer - of type T. For example, see the default_deleter type defined above. - It must also not throw when constructed or when performing a delete. - - INITIAL VALUE - defined by constructor - - WHAT THIS OBJECT REPRESENTS - This is a smart pointer class inspired by the implementation of the scoped_ptr - class found in the Boost C++ library. So this is a simple smart pointer - class which guarantees that the pointer contained within it will always be - deleted. - - The class does not permit copying and so does not do any kind of - reference counting. Thus it is very simply and quite fast. - - Note that this class allows you to use pointers to arrays as well as - pointers to single items. To let it know that it is supposed to point - to an array you have to declare it using the bracket syntax. Consider - the following examples: - - // This is how you make a scoped pointer to a single thing - scoped_ptr single_item(new int); - - // This is how you can use a scoped pointer to contain array pointers. - // Note the use of []. This ensures that the proper version of delete - // is called. - scoped_ptr array_of_ints(new int[50]); - !*/ - - public: - typedef T element_type; - typedef deleter deleter_type; - - explicit scoped_ptr ( - T* p = 0 - ); - /*! - ensures - - #get() == p - !*/ - - ~scoped_ptr( - ); - /*! - ensures - - if (get() != 0) then - - calls deleter()(get()) - (i.e. uses the deleter type to delete the pointer that is - contained in this scoped pointer) - !*/ - - void reset ( - T* p = 0 - ); - /*! - ensures - - if (get() != 0) then - - calls deleter()(get()) - (i.e. uses the deleter type to delete the pointer that is - contained in this scoped pointer) - - #get() == p - (i.e. makes this object contain a pointer to p instead of whatever it - used to contain) - !*/ - - T& operator*( - ) const; - /*! - requires - - get() != 0 - - T is NOT an array type (e.g. not int[]) - ensures - - returns a reference to *get() - !*/ - - T* operator->( - ) const; - /*! - requires - - get() != 0 - - T is NOT an array type (e.g. not int[]) - ensures - - returns the pointer contained in this object - !*/ - - T& operator[]( - unsigned long idx - ) const; - /*! - requires - - get() != 0 - - T is an array type (e.g. int[]) - ensures - - returns get()[idx] - !*/ - - T* get( - ) const; - /*! - ensures - - returns the pointer contained in this object - !*/ - - operator bool( - ) const; - /*! - ensures - - returns get() != 0 - !*/ - - void swap( - scoped_ptr& b - ); - /*! - ensures - - swaps *this and item - !*/ - }; - - template < - typename T - > - void swap( - scoped_ptr& a, - scoped_ptr& b - ) { a.swap(b); } - /*! - provides a global swap function - !*/ -} - -#endif // DLIB_SCOPED_PTr_ABSTRACT_ - - diff --git a/lib/3rdParty/dlib/include/dlib/smart_pointers/shared_ptr.h b/lib/3rdParty/dlib/include/dlib/smart_pointers/shared_ptr.h index a9b04b48..15f7a491 100644 --- a/lib/3rdParty/dlib/include/dlib/smart_pointers/shared_ptr.h +++ b/lib/3rdParty/dlib/include/dlib/smart_pointers/shared_ptr.h @@ -10,7 +10,6 @@ #include "../algs.h" #include "shared_ptr_abstract.h" - namespace dlib { @@ -294,21 +293,6 @@ namespace dlib shared_node->ref_count += 1; } - template - explicit shared_ptr( - std::auto_ptr& r - ) - { - DLIB_ASSERT(r.get() != 0, - "\tshared_ptr::shared_ptr(auto_ptr r)" - << "\n\tr.get() can't be null" - << "\n\tthis: " << this - ); - shared_node = new shared_ptr_node; - shared_node->del = new default_deleter; - data = r.release(); - } - shared_ptr& operator= ( const shared_ptr& r ) @@ -326,24 +310,6 @@ namespace dlib return *this; } - template - shared_ptr& operator= ( - std::auto_ptr& r - ) - { - DLIB_ASSERT(r.get() != 0, - "\tshared_ptr::operator=(auto_ptr r)" - << "\n\tr.get() can't be null" - << "\n\tthis: " << this - ); - - reset(); - shared_node = new shared_ptr_node; - shared_node->del = new default_deleter; - data = r.release(); - return *this; - } - void reset() { shared_ptr().swap(*this); @@ -521,5 +487,6 @@ namespace dlib } + #endif // DLIB_SHARED_PTr_ diff --git a/lib/3rdParty/dlib/include/dlib/smart_pointers/shared_ptr_abstract.h b/lib/3rdParty/dlib/include/dlib/smart_pointers/shared_ptr_abstract.h index 4d11490a..9fc12c8e 100644 --- a/lib/3rdParty/dlib/include/dlib/smart_pointers/shared_ptr_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/smart_pointers/shared_ptr_abstract.h @@ -136,24 +136,6 @@ namespace dlib this exception is thrown if r.expired() == true !*/ - template - explicit shared_ptr( - std::auto_ptr& r - ); - /*! - requires - - p.get() != 0 - - p.release() is convertible to a T* type pointer - - p.release() can be deleted by calling "delete p.release();" and doing so will not throw exceptions - ensures - - #get() == p.release() - - #use_count() == 1 - - #r.get() == 0 - - #*this object owns the pointer p.release() - throws - - std::bad_alloc - !*/ - ~shared_ptr( ); /*! @@ -190,20 +172,6 @@ namespace dlib - returns #*this !*/ - template - shared_ptr& operator= ( - std::auto_ptr& r - ); - /*! - requires - - p.get() != 0 - - p.release() is convertible to a T* type pointer - - p.release() can be deleted by calling "delete p.release();" and doing so will not throw exceptions - ensures - - equivalent to shared_ptr(r).swap(*this). - - returns #*this - !*/ - void reset( ); /*! diff --git a/lib/3rdParty/dlib/include/dlib/smart_pointers/shared_ptr_thread_safe.h b/lib/3rdParty/dlib/include/dlib/smart_pointers/shared_ptr_thread_safe.h index 4aaec816..31bda565 100644 --- a/lib/3rdParty/dlib/include/dlib/smart_pointers/shared_ptr_thread_safe.h +++ b/lib/3rdParty/dlib/include/dlib/smart_pointers/shared_ptr_thread_safe.h @@ -257,21 +257,6 @@ namespace dlib } } - - template - explicit shared_ptr_thread_safe( - std::auto_ptr& r - ) - { - DLIB_ASSERT(r.get() != 0, - "\tshared_ptr::shared_ptr_thread_safe(auto_ptr r)" - << "\n\tr.get() can't be null" - << "\n\tthis: " << this - ); - shared_node = new shared_ptr_thread_safe_node; - data = r.release(); - } - shared_ptr_thread_safe& operator= ( const shared_ptr_thread_safe& r ) @@ -289,23 +274,6 @@ namespace dlib return *this; } - template - shared_ptr_thread_safe& operator= ( - std::auto_ptr& r - ) - { - DLIB_ASSERT(r.get() != 0, - "\tshared_ptr::operator=(auto_ptr r)" - << "\n\tr.get() can't be null" - << "\n\tthis: " << this - ); - - reset(); - shared_node = new shared_ptr_thread_safe_node; - data = r.release(); - return *this; - } - void reset() { shared_ptr_thread_safe().swap(*this); @@ -401,10 +369,7 @@ namespace dlib if (shared_node->del) return static_cast(shared_node->del->get_deleter_void(typeid(D))); } - else - { - return 0; - } + return 0; } template diff --git a/lib/3rdParty/dlib/include/dlib/smart_pointers/shared_ptr_thread_safe_abstract.h b/lib/3rdParty/dlib/include/dlib/smart_pointers/shared_ptr_thread_safe_abstract.h index 520ee0aa..472a0046 100644 --- a/lib/3rdParty/dlib/include/dlib/smart_pointers/shared_ptr_thread_safe_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/smart_pointers/shared_ptr_thread_safe_abstract.h @@ -114,24 +114,6 @@ namespace dlib a shared_ptr_thread_safe object that shares ownership with r. !*/ - template - explicit shared_ptr_thread_safe( - std::auto_ptr& r - ); - /*! - requires - - p.get() != 0 - - p.release() is convertible to a T* type pointer - - p.release() can be deleted by calling "delete p.release();" and doing so will not throw exceptions - ensures - - #get() == p.release() - - #use_count() == 1 - - #r.get() == 0 - - #*this object owns the pointer p.release() - throws - - std::bad_alloc - !*/ - ~shared_ptr_thread_safe( ); /*! @@ -168,20 +150,6 @@ namespace dlib - returns #*this !*/ - template - shared_ptr_thread_safe& operator= ( - std::auto_ptr& r - ); - /*! - requires - - p.get() != 0 - - p.release() is convertible to a T* type pointer - - p.release() can be deleted by calling "delete p.release();" and doing so will not throw exceptions - ensures - - equivalent to shared_ptr_thread_safe(r).swap(*this). - - returns #*this - !*/ - void reset( ); /*! diff --git a/lib/3rdParty/dlib/include/dlib/smart_pointers_thread_safe.h b/lib/3rdParty/dlib/include/dlib/smart_pointers_thread_safe.h index 1be31c06..e00141f0 100644 --- a/lib/3rdParty/dlib/include/dlib/smart_pointers_thread_safe.h +++ b/lib/3rdParty/dlib/include/dlib/smart_pointers_thread_safe.h @@ -3,6 +3,16 @@ #ifndef DLIB_SMART_POINTERs_THREAD_SAFE_H_ #define DLIB_SMART_POINTERs_THREAD_SAFE_H_ +// This is legacy smart pointer code that will likely to stop working under default +// compiler flags when C++17 becomes the default standard in the compilers. +// Please consider migrating your code to contemporary smart pointers from C++ +// standard library. The warning below will help to detect if the deprecated code +// was included from library's clients. +#if (defined(__GNUC__) && ((__GNUC__ >= 4 && __GNUC_MINOR__ >= 8) || (__GNUC__ > 4))) || \ + (defined(__clang__) && ((__clang_major__ >= 3 && __clang_minor__ >= 4))) +#pragma GCC warning "smart_pointers_thread_safe.h is included which will fail to compile under C++17" +#endif + #include "smart_pointers/shared_ptr_thread_safe.h" #endif // DLIB_SMART_POINTERs_THREAD_SAFE_H_ diff --git a/lib/3rdParty/dlib/include/dlib/sockets/sockets_extensions.cpp b/lib/3rdParty/dlib/include/dlib/sockets/sockets_extensions.cpp deleted file mode 100644 index 1d794398..00000000 --- a/lib/3rdParty/dlib/include/dlib/sockets/sockets_extensions.cpp +++ /dev/null @@ -1,341 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_SOCKETS_EXTENSIONs_CPP -#define DLIB_SOCKETS_EXTENSIONs_CPP - -#include -#include -#include "../sockets.h" -#include "../error.h" -#include "sockets_extensions.h" -#include "../timer.h" -#include "../algs.h" -#include "../timeout.h" -#include "../misc_api.h" -#include "../serialize.h" -#include "../string.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - network_address:: - network_address( - const std::string& full_address - ) - { - std::istringstream sin(full_address); - sin >> *this; - if (!sin || sin.peek() != EOF) - throw invalid_network_address("invalid network address: " + full_address); - } - -// ---------------------------------------------------------------------------------------- - - void serialize( - const network_address& item, - std::ostream& out - ) - { - serialize(item.host_address, out); - serialize(item.port, out); - } - -// ---------------------------------------------------------------------------------------- - - void deserialize( - network_address& item, - std::istream& in - ) - { - deserialize(item.host_address, in); - deserialize(item.port, in); - } - -// ---------------------------------------------------------------------------------------- - - std::ostream& operator<< ( - std::ostream& out, - const network_address& item - ) - { - out << item.host_address << ":" << item.port; - return out; - } - -// ---------------------------------------------------------------------------------------- - - std::istream& operator>> ( - std::istream& in, - network_address& item - ) - { - std::string temp; - in >> temp; - - std::string::size_type pos = temp.find_last_of(":"); - if (pos == std::string::npos) - { - in.setstate(std::ios::badbit); - return in; - } - - item.host_address = temp.substr(0, pos); - try - { - item.port = sa = temp.substr(pos+1); - } catch (std::exception& ) - { - in.setstate(std::ios::badbit); - return in; - } - - - return in; - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - connection* connect ( - const std::string& host_or_ip, - unsigned short port - ) - { - std::string ip; - connection* con; - if (is_ip_address(host_or_ip)) - { - ip = host_or_ip; - } - else - { - if( hostname_to_ip(host_or_ip,ip)) - throw socket_error(ERESOLVE,"unable to resolve '" + host_or_ip + "' in connect()"); - } - - if(create_connection(con,port,ip)) - { - std::ostringstream sout; - sout << "unable to connect to '" << host_or_ip << ":" << port << "'"; - throw socket_error(sout.str()); - } - - return con; - } - -// ---------------------------------------------------------------------------------------- - - connection* connect ( - const network_address& addr - ) - { - return connect(addr.host_address, addr.port); - } - -// ---------------------------------------------------------------------------------------- - - namespace connect_timeout_helpers - { - mutex connect_mutex; - signaler connect_signaler(connect_mutex); - timestamper ts; - long outstanding_connects = 0; - - struct thread_data - { - std::string host_or_ip; - unsigned short port; - connection* con; - bool connect_ended; - bool error_occurred; - }; - - void thread(void* param) - { - thread_data p = *static_cast(param); - try - { - p.con = connect(p.host_or_ip, p.port); - } - catch (...) - { - p.error_occurred = true; - } - - auto_mutex M(connect_mutex); - // report the results back to the connect() call that spawned this - // thread. - static_cast(param)->con = p.con; - static_cast(param)->error_occurred = p.error_occurred; - connect_signaler.broadcast(); - - // wait for the call to connect() that spawned this thread to terminate - // before we delete the thread_data struct. - while (static_cast(param)->connect_ended == false) - connect_signaler.wait(); - - connect_signaler.broadcast(); - --outstanding_connects; - delete static_cast(param); - } - } - - connection* connect ( - const std::string& host_or_ip, - unsigned short port, - unsigned long timeout - ) - { - using namespace connect_timeout_helpers; - - auto_mutex M(connect_mutex); - - const uint64 end_time = ts.get_timestamp() + timeout*1000; - - - // wait until there are less than 100 outstanding connections - while (outstanding_connects > 100) - { - uint64 cur_time = ts.get_timestamp(); - if (end_time > cur_time) - { - timeout = static_cast((end_time - cur_time)/1000); - } - else - { - throw socket_error("unable to connect to '" + host_or_ip + "' because connect timed out"); - } - - connect_signaler.wait_or_timeout(timeout); - } - - - thread_data* data = new thread_data; - data->host_or_ip = host_or_ip.c_str(); - data->port = port; - data->con = 0; - data->connect_ended = false; - data->error_occurred = false; - - - if (create_new_thread(thread, data) == false) - { - delete data; - throw socket_error("unable to connect to '" + host_or_ip); - } - - ++outstanding_connects; - - // wait until we have a connection object - while (data->con == 0) - { - uint64 cur_time = ts.get_timestamp(); - if (end_time > cur_time && data->error_occurred == false) - { - timeout = static_cast((end_time - cur_time)/1000); - } - else - { - // let the thread know that it should terminate - data->connect_ended = true; - connect_signaler.broadcast(); - if (data->error_occurred) - throw socket_error("unable to connect to '" + host_or_ip); - else - throw socket_error("unable to connect to '" + host_or_ip + "' because connect timed out"); - } - - connect_signaler.wait_or_timeout(timeout); - } - - // let the thread know that it should terminate - data->connect_ended = true; - connect_signaler.broadcast(); - return data->con; - } - -// ---------------------------------------------------------------------------------------- - - bool is_ip_address ( - std::string ip - ) - { - for (std::string::size_type i = 0; i < ip.size(); ++i) - { - if (ip[i] == '.') - ip[i] = ' '; - } - std::istringstream sin(ip); - - bool bad = false; - int num; - for (int i = 0; i < 4; ++i) - { - sin >> num; - if (!sin || num < 0 || num > 255) - { - bad = true; - break; - } - } - - if (sin.get() != EOF) - bad = true; - - return !bad; - } - -// ---------------------------------------------------------------------------------------- - - void close_gracefully ( - connection* con, - unsigned long timeout - ) - { - scoped_ptr ptr(con); - close_gracefully(ptr,timeout); - } - -// ---------------------------------------------------------------------------------------- - - void close_gracefully ( - scoped_ptr& con, - unsigned long timeout - ) - { - if (!con) - return; - - if(con->shutdown_outgoing()) - { - // there was an error so just close it now and return - con.reset(); - return; - } - - try - { - dlib::timeout t(*con,&connection::shutdown,timeout); - - char junk[100]; - // wait for the other end to close their side - while (con->read(junk,sizeof(junk)) > 0) ; - } - catch (...) - { - con.reset(); - throw; - } - - con.reset(); - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_SOCKETS_EXTENSIONs_CPP - - diff --git a/lib/3rdParty/dlib/include/dlib/sockets/sockets_extensions.h b/lib/3rdParty/dlib/include/dlib/sockets/sockets_extensions.h index 3683bac0..9faa34e0 100644 --- a/lib/3rdParty/dlib/include/dlib/sockets/sockets_extensions.h +++ b/lib/3rdParty/dlib/include/dlib/sockets/sockets_extensions.h @@ -3,11 +3,14 @@ #ifndef DLIB_SOCKETS_EXTENSIONs_ #define DLIB_SOCKETS_EXTENSIONs_ -#include -#include "../sockets.h" -#include "sockets_extensions_abstract.h" -#include "../smart_pointers.h" #include +#include +#include + +#include "../sockets.h" +#include "../smart_pointers/scoped_ptr.h" +#include "sockets_extensions_abstract.h" + namespace dlib { @@ -132,7 +135,7 @@ namespace dlib // ---------------------------------------------------------------------------------------- void close_gracefully ( - scoped_ptr& con, + std::unique_ptr& con, unsigned long timeout = 500 ); diff --git a/lib/3rdParty/dlib/include/dlib/sockets/sockets_extensions_abstract.h b/lib/3rdParty/dlib/include/dlib/sockets/sockets_extensions_abstract.h index f40ac705..194c22ab 100644 --- a/lib/3rdParty/dlib/include/dlib/sockets/sockets_extensions_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/sockets/sockets_extensions_abstract.h @@ -3,9 +3,10 @@ #undef DLIB_SOCKETS_EXTENSIONs_ABSTRACT_ #ifdef DLIB_SOCKETS_EXTENSIONs_ABSTRACT_ +#include #include + #include "sockets_kernel_abstract.h" -#include "../smart_pointers.h" #include "../error.h" namespace dlib @@ -265,7 +266,7 @@ namespace dlib // ---------------------------------------------------------------------------------------- void close_gracefully ( - scoped_ptr& con, + std::unique_ptr& con, unsigned long timeout = 500 ); /*! diff --git a/lib/3rdParty/dlib/include/dlib/sockets/sockets_kernel_1.cpp b/lib/3rdParty/dlib/include/dlib/sockets/sockets_kernel_1.cpp deleted file mode 100644 index f3c1e02c..00000000 --- a/lib/3rdParty/dlib/include/dlib/sockets/sockets_kernel_1.cpp +++ /dev/null @@ -1,978 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net), Miguel Grinberg -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_SOCKETS_KERNEL_1_CPp_ -#define DLIB_SOCKETS_KERNEL_1_CPp_ -#include "../platform.h" - -#ifdef WIN32 - -#ifndef _WINSOCKAPI_ -#define _WINSOCKAPI_ /* Prevent inclusion of winsock.h in windows.h */ -#endif - -#include "../windows_magic.h" - -#include "sockets_kernel_1.h" - -#include -#include - -#ifndef NI_MAXHOST -#define NI_MAXHOST 1025 -#endif - - -// tell visual studio to link to the libraries we need if we are -// in fact using visual studio -#ifdef _MSC_VER -#pragma comment (lib, "ws2_32.lib") -#endif - -#include "../assert.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - class SOCKET_container - { - /*! - This object is just a wrapper around the SOCKET type. It exists - so that we can #include the windows.h and Winsock2.h header files - in this cpp file and not at all in the header file. - !*/ - public: - SOCKET_container ( - SOCKET s = INVALID_SOCKET - ) : val(s) {} - - SOCKET val; - operator SOCKET&() { return val; } - - SOCKET_container& operator= ( - const SOCKET& s - ) { val = s; return *this; } - - bool operator== ( - const SOCKET& s - ) const { return s == val; } - }; - -// ---------------------------------------------------------------------------------------- -// stuff to ensure that WSAStartup() is always called before any sockets stuff is needed - - namespace sockets_kernel_1_mutex - { - mutex startup_lock; - } - - class sockets_startupdown - { - public: - sockets_startupdown(); - ~sockets_startupdown() { WSACleanup( ); } - - }; - sockets_startupdown::sockets_startupdown ( - ) - { - WSADATA wsaData; - WSAStartup (MAKEWORD(2,0), &wsaData); - } - - void sockets_startup() - { - // mutex crap to make this function thread-safe - sockets_kernel_1_mutex::startup_lock.lock(); - static sockets_startupdown a; - sockets_kernel_1_mutex::startup_lock.unlock(); - } - -// ---------------------------------------------------------------------------------------- - - // lookup functions - - int - get_local_hostname ( - std::string& hostname - ) - { - // ensure that WSAStartup has been called and WSACleanup will eventually - // be called when program ends - sockets_startup(); - - try - { - - char temp[NI_MAXHOST]; - if (gethostname(temp,NI_MAXHOST) == SOCKET_ERROR ) - { - return OTHER_ERROR; - } - - hostname = temp; - } - catch (...) - { - return OTHER_ERROR; - } - - return 0; - } - -// ----------------- - - int - hostname_to_ip ( - const std::string& hostname, - std::string& ip, - int n - ) - { - // ensure that WSAStartup has been called and WSACleanup will eventually - // be called when program ends - sockets_startup(); - - try - { - // lock this mutex since gethostbyname isn't really thread safe - auto_mutex M(sockets_kernel_1_mutex::startup_lock); - - // if no hostname was given then return error - if ( hostname.empty()) - return OTHER_ERROR; - - hostent* address; - address = gethostbyname(hostname.c_str()); - - if (address == 0) - { - return OTHER_ERROR; - } - - // find the nth address - in_addr* addr = reinterpret_cast(address->h_addr_list[0]); - for (int i = 1; i <= n; ++i) - { - addr = reinterpret_cast(address->h_addr_list[i]); - - // if there is no nth address then return error - if (addr == 0) - return OTHER_ERROR; - } - - char* resolved_ip = inet_ntoa(*addr); - - // check if inet_ntoa returned an error - if (resolved_ip == NULL) - { - return OTHER_ERROR; - } - - ip.assign(resolved_ip); - - } - catch(...) - { - return OTHER_ERROR; - } - - return 0; - } - -// ----------------- - - int - ip_to_hostname ( - const std::string& ip, - std::string& hostname - ) - { - // ensure that WSAStartup has been called and WSACleanup will eventually - // be called when program ends - sockets_startup(); - - try - { - // lock this mutex since gethostbyaddr isn't really thread safe - auto_mutex M(sockets_kernel_1_mutex::startup_lock); - - // if no ip was given then return error - if (ip.empty()) - return OTHER_ERROR; - - hostent* address; - unsigned long ipnum = inet_addr(ip.c_str()); - - // if inet_addr couldn't convert ip then return an error - if (ipnum == INADDR_NONE) - { - return OTHER_ERROR; - } - address = gethostbyaddr(reinterpret_cast(&ipnum),4,AF_INET); - - // check if gethostbyaddr returned an error - if (address == 0) - { - return OTHER_ERROR; - } - hostname.assign(address->h_name); - - } - catch (...) - { - return OTHER_ERROR; - } - return 0; - - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // connection object -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - connection:: - connection( - SOCKET_container sock, - unsigned short foreign_port, - const std::string& foreign_ip, - unsigned short local_port, - const std::string& local_ip - ) : - user_data(0), - connection_socket(*(new SOCKET_container())), - connection_foreign_port(foreign_port), - connection_foreign_ip(foreign_ip), - connection_local_port(local_port), - connection_local_ip(local_ip), - sd(false), - sdo(false), - sdr(0) - { - connection_socket = sock; - } - -// ---------------------------------------------------------------------------------------- - - connection:: - ~connection ( - ) - { - if (connection_socket != INVALID_SOCKET) - closesocket(connection_socket); - delete &connection_socket; - } - -// ---------------------------------------------------------------------------------------- - - int connection:: - disable_nagle() - { - int flag = 1; - int status = setsockopt( connection_socket, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag) ); - - if (status == SOCKET_ERROR) - return OTHER_ERROR; - else - return 0; - } - -// ---------------------------------------------------------------------------------------- - - long connection:: - write ( - const char* buf, - long num - ) - { - const long old_num = num; - long status; - const long max_send_length = 1024*1024*100; - while (num > 0) - { - // Make sure to cap the max value num can take on so that if it is - // really large (it might be big on 64bit platforms) so that the OS - // can't possibly get upset about it being large. - const long length = std::min(max_send_length, num); - if ( (status = send(connection_socket,buf,length,0)) == SOCKET_ERROR) - { - if (sdo_called()) - return SHUTDOWN; - else - return OTHER_ERROR; - } - num -= status; - buf += status; - } - return old_num; - } - -// ---------------------------------------------------------------------------------------- - - long connection:: - read ( - char* buf, - long num - ) - { - const long max_recv_length = 1024*1024*100; - // Make sure to cap the max value num can take on so that if it is - // really large (it might be big on 64bit platforms) so that the OS - // can't possibly get upset about it being large. - const long length = std::min(max_recv_length, num); - long status = recv(connection_socket,buf,length,0); - if (status == SOCKET_ERROR) - { - // if this error is the result of a shutdown call then return SHUTDOWN - if (sd_called()) - return SHUTDOWN; - else - return OTHER_ERROR; - } - else if (status == 0 && sd_called()) - { - return SHUTDOWN; - } - return status; - } - -// ---------------------------------------------------------------------------------------- - - long connection:: - read ( - char* buf, - long num, - unsigned long timeout - ) - { - if (readable(timeout) == false) - return TIMEOUT; - - const long max_recv_length = 1024*1024*100; - // Make sure to cap the max value num can take on so that if it is - // really large (it might be big on 64bit platforms) so that the OS - // can't possibly get upset about it being large. - const long length = std::min(max_recv_length, num); - long status = recv(connection_socket,buf,length,0); - if (status == SOCKET_ERROR) - { - // if this error is the result of a shutdown call then return SHUTDOWN - if (sd_called()) - return SHUTDOWN; - else - return OTHER_ERROR; - } - else if (status == 0 && sd_called()) - { - return SHUTDOWN; - } - return status; - } - -// ---------------------------------------------------------------------------------------- - - bool connection:: - readable ( - unsigned long timeout - ) const - { - fd_set read_set; - // initialize read_set - FD_ZERO(&read_set); - - // add the listening socket to read_set - FD_SET(connection_socket, &read_set); - - // setup a timeval structure - timeval time_to_wait; - time_to_wait.tv_sec = static_cast(timeout/1000); - time_to_wait.tv_usec = static_cast((timeout%1000)*1000); - - // wait on select - int status = select(0,&read_set,0,0,&time_to_wait); - - // if select timed out or there was an error - if (status <= 0) - return false; - - // data is ready to be read - return true; - } - -// ---------------------------------------------------------------------------------------- - - int connection:: - shutdown_outgoing ( - ) - { - sd_mutex.lock(); - if (sdo || sd) - { - sd_mutex.unlock(); - return sdr; - } - sdo = true; - sdr = ::shutdown(connection_socket,SD_SEND); - - // convert -1 error code into the OTHER_ERROR error code - if (sdr == -1) - sdr = OTHER_ERROR; - - int temp = sdr; - - sd_mutex.unlock(); - return temp; - } - -// ---------------------------------------------------------------------------------------- - - int connection:: - shutdown ( - ) - { - sd_mutex.lock(); - if (sd) - { - sd_mutex.unlock(); - return sdr; - } - sd = true; - SOCKET stemp = connection_socket; - connection_socket = INVALID_SOCKET; - sdr = closesocket(stemp); - - // convert SOCKET_ERROR error code into the OTHER_ERROR error code - if (sdr == SOCKET_ERROR) - sdr = OTHER_ERROR; - - int temp = sdr; - - sd_mutex.unlock(); - return temp; - } - -// ---------------------------------------------------------------------------------------- - - connection::socket_descriptor_type connection:: - get_socket_descriptor ( - ) const - { - return connection_socket.val; - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // listener object -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - listener:: - listener( - SOCKET_container sock, - unsigned short port, - const std::string& ip - ) : - listening_socket(*(new SOCKET_container)), - listening_port(port), - listening_ip(ip), - inaddr_any(listening_ip.empty()) - { - listening_socket = sock; - } - -// ---------------------------------------------------------------------------------------- - - listener:: - ~listener ( - ) - { - closesocket(listening_socket); - delete &listening_socket; - } - -// ---------------------------------------------------------------------------------------- - - int listener:: - accept ( - scoped_ptr& new_connection, - unsigned long timeout - ) - { - new_connection.reset(0); - connection* con; - int status = this->accept(con, timeout); - - if (status == 0) - new_connection.reset(con); - - return status; - } - -// ---------------------------------------------------------------------------------------- - - int listener:: - accept ( - connection*& new_connection, - unsigned long timeout - ) - { - SOCKET incoming; - sockaddr_in incomingAddr; - int length = sizeof(sockaddr_in); - - // implement timeout with select if timeout is > 0 - if (timeout > 0) - { - fd_set read_set; - // initialize read_set - FD_ZERO(&read_set); - - // add the listening socket to read_set - FD_SET(listening_socket, &read_set); - - // setup a timeval structure - timeval time_to_wait; - time_to_wait.tv_sec = static_cast(timeout/1000); - time_to_wait.tv_usec = static_cast((timeout%1000)*1000); - - - // wait on select - int status = select(0,&read_set,0,0,&time_to_wait); - - // if select timed out - if (status == 0) - return TIMEOUT; - - // if select returned an error - if (status == SOCKET_ERROR) - return OTHER_ERROR; - - } - - - // call accept to get a new connection - incoming=::accept(listening_socket,reinterpret_cast(&incomingAddr),&length); - - // if there was an error return OTHER_ERROR - if ( incoming == INVALID_SOCKET ) - return OTHER_ERROR; - - - // get the port of the foreign host into foreign_port - int foreign_port = ntohs(incomingAddr.sin_port); - - // get the IP of the foreign host into foreign_ip - std::string foreign_ip; - { - char* foreign_ip_temp = inet_ntoa(incomingAddr.sin_addr); - - // check if inet_ntoa() returned an error - if (foreign_ip_temp == NULL) - { - closesocket(incoming); - return OTHER_ERROR; - } - - foreign_ip.assign(foreign_ip_temp); - } - - - // get the local ip - std::string local_ip; - if (inaddr_any == true) - { - sockaddr_in local_info; - length = sizeof(sockaddr_in); - // get the local sockaddr_in structure associated with this new connection - if ( getsockname ( - incoming, - reinterpret_cast(&local_info), - &length - ) == SOCKET_ERROR - ) - { // an error occurred - closesocket(incoming); - return OTHER_ERROR; - } - char* temp = inet_ntoa(local_info.sin_addr); - - // check if inet_ntoa() returned an error - if (temp == NULL) - { - closesocket(incoming); - return OTHER_ERROR; - } - local_ip.assign(temp); - } - else - { - local_ip = listening_ip; - } - - - // set the SO_OOBINLINE option - int flag_value = 1; - if (setsockopt(incoming,SOL_SOCKET,SO_OOBINLINE,reinterpret_cast(&flag_value),sizeof(int)) == SOCKET_ERROR ) - { - closesocket(incoming); - return OTHER_ERROR; - } - - - // make a new connection object for this new connection - try - { - new_connection = new connection ( - incoming, - foreign_port, - foreign_ip, - listening_port, - local_ip - ); - } - catch (...) { closesocket(incoming); return OTHER_ERROR; } - - return 0; - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // socket creation functions -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - int create_listener ( - scoped_ptr& new_listener, - unsigned short port, - const std::string& ip - ) - { - new_listener.reset(); - listener* temp; - int status = create_listener(temp,port,ip); - - if (status == 0) - new_listener.reset(temp); - - return status; - } - - int create_listener ( - listener*& new_listener, - unsigned short port, - const std::string& ip - ) - { - // ensure that WSAStartup has been called and WSACleanup will eventually - // be called when program ends - sockets_startup(); - - sockaddr_in sa; // local socket structure - ZeroMemory(&sa,sizeof(sockaddr_in)); // initialize sa - - SOCKET sock = socket (AF_INET, SOCK_STREAM, 0); // get a new socket - - // if socket() returned an error then return OTHER_ERROR - if (sock == INVALID_SOCKET ) - { - return OTHER_ERROR; - } - - // set the local socket structure - sa.sin_family = AF_INET; - sa.sin_port = htons(port); - if (ip.empty()) - { - // if the listener should listen on any IP - sa.sin_addr.S_un.S_addr = htons(INADDR_ANY); - } - else - { - // if there is a specific ip to listen on - sa.sin_addr.S_un.S_addr = inet_addr(ip.c_str()); - // if inet_addr couldn't convert the ip then return an error - if ( sa.sin_addr.S_un.S_addr == INADDR_NONE ) - { - closesocket(sock); - return OTHER_ERROR; - } - } - - // set the SO_REUSEADDR option - int flag_value = 1; - setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,reinterpret_cast(&flag_value),sizeof(int)); - - // bind the new socket to the requested port and ip - if (bind(sock,reinterpret_cast(&sa),sizeof(sockaddr_in))==SOCKET_ERROR) - { - const int err = WSAGetLastError(); - // if there was an error - closesocket(sock); - - // if the port is already bound then return PORTINUSE - if (err == WSAEADDRINUSE) - return PORTINUSE; - else - return OTHER_ERROR; - } - - - // tell the new socket to listen - if ( listen(sock,SOMAXCONN) == SOCKET_ERROR) - { - const int err = WSAGetLastError(); - // if there was an error return OTHER_ERROR - closesocket(sock); - - // if the port is already bound then return PORTINUSE - if (err == WSAEADDRINUSE) - return PORTINUSE; - else - return OTHER_ERROR; - } - - // determine the port used if necessary - if (port == 0) - { - sockaddr_in local_info; - int length = sizeof(sockaddr_in); - if ( getsockname ( - sock, - reinterpret_cast(&local_info), - &length - ) == SOCKET_ERROR - ) - { - closesocket(sock); - return OTHER_ERROR; - } - port = ntohs(local_info.sin_port); - } - - - // initialize a listener object on the heap with the new socket - try { new_listener = new listener(sock,port,ip); } - catch(...) { closesocket(sock); return OTHER_ERROR; } - - return 0; - } - -// ---------------------------------------------------------------------------------------- - - int create_connection ( - scoped_ptr& new_connection, - unsigned short foreign_port, - const std::string& foreign_ip, - unsigned short local_port, - const std::string& local_ip - ) - { - new_connection.reset(); - connection* temp; - int status = create_connection(temp,foreign_port, foreign_ip, local_port, local_ip); - - if (status == 0) - new_connection.reset(temp); - - return status; - } - - int create_connection ( - connection*& new_connection, - unsigned short foreign_port, - const std::string& foreign_ip, - unsigned short local_port, - const std::string& local_ip - ) - { - // ensure that WSAStartup has been called and WSACleanup - // will eventually be called when program ends - sockets_startup(); - - - sockaddr_in local_sa; // local socket structure - sockaddr_in foreign_sa; // foreign socket structure - ZeroMemory(&local_sa,sizeof(sockaddr_in)); // initialize local_sa - ZeroMemory(&foreign_sa,sizeof(sockaddr_in)); // initialize foreign_sa - - int length; - - SOCKET sock = socket (AF_INET, SOCK_STREAM, 0); // get a new socket - - // if socket() returned an error then return OTHER_ERROR - if (sock == INVALID_SOCKET ) - { - return OTHER_ERROR; - } - - // set the foreign socket structure - foreign_sa.sin_family = AF_INET; - foreign_sa.sin_port = htons(foreign_port); - foreign_sa.sin_addr.S_un.S_addr = inet_addr(foreign_ip.c_str()); - - // if inet_addr couldn't convert the ip then return an error - if ( foreign_sa.sin_addr.S_un.S_addr == INADDR_NONE ) - { - closesocket(sock); - return OTHER_ERROR; - } - - - // set up the local socket structure - local_sa.sin_family = AF_INET; - - // set the local ip - if (local_ip.empty()) - { - // if the listener should listen on any IP - local_sa.sin_addr.S_un.S_addr = htons(INADDR_ANY); - } - else - { - // if there is a specific ip to listen on - local_sa.sin_addr.S_un.S_addr = inet_addr(local_ip.c_str()); - - // if inet_addr couldn't convert the ip then return an error - if (local_sa.sin_addr.S_un.S_addr == INADDR_NONE) - { - closesocket(sock); - return OTHER_ERROR; - } - } - - // set the local port - local_sa.sin_port = htons(local_port); - - - - // bind the new socket to the requested local port and local ip - if ( bind ( - sock, - reinterpret_cast(&local_sa), - sizeof(sockaddr_in) - ) == SOCKET_ERROR - ) - { - const int err = WSAGetLastError(); - // if there was an error - closesocket(sock); - - // if the port is already bound then return PORTINUSE - if (err == WSAEADDRINUSE) - return PORTINUSE; - else - return OTHER_ERROR; - } - - // connect the socket - if (connect ( - sock, - reinterpret_cast(&foreign_sa), - sizeof(sockaddr_in) - ) == SOCKET_ERROR - ) - { - const int err = WSAGetLastError(); - closesocket(sock); - // if the port is already bound then return PORTINUSE - if (err == WSAEADDRINUSE) - return PORTINUSE; - else - return OTHER_ERROR; - } - - - - // determine the local port and IP and store them in used_local_ip - // and used_local_port - int used_local_port; - std::string used_local_ip; - sockaddr_in local_info; - if (local_port == 0) - { - length = sizeof(sockaddr_in); - if (getsockname ( - sock, - reinterpret_cast(&local_info), - &length - ) == SOCKET_ERROR - ) - { - closesocket(sock); - return OTHER_ERROR; - } - used_local_port = ntohs(local_info.sin_port); - } - else - { - used_local_port = local_port; - } - - // determine real local ip - if (local_ip.empty()) - { - // if local_port is not 0 then we must fill the local_info structure - if (local_port != 0) - { - length = sizeof(sockaddr_in); - if ( getsockname ( - sock, - reinterpret_cast(&local_info), - &length - ) == SOCKET_ERROR - ) - { - closesocket(sock); - return OTHER_ERROR; - } - } - char* temp = inet_ntoa(local_info.sin_addr); - - // check if inet_ntoa returned an error - if (temp == NULL) - { - closesocket(sock); - return OTHER_ERROR; - } - used_local_ip.assign(temp); - } - else - { - used_local_ip = local_ip; - } - - // set the SO_OOBINLINE option - int flag_value = 1; - if (setsockopt(sock,SOL_SOCKET,SO_OOBINLINE,reinterpret_cast(&flag_value),sizeof(int)) == SOCKET_ERROR ) - { - closesocket(sock); - return OTHER_ERROR; - } - - // initialize a connection object on the heap with the new socket - try - { - new_connection = new connection ( - sock, - foreign_port, - foreign_ip, - used_local_port, - used_local_ip - ); - } - catch(...) {closesocket(sock); return OTHER_ERROR; } - - return 0; - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // WIN32 - -#endif // DLIB_SOCKETS_KERNEL_1_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/sockets/sockets_kernel_1.h b/lib/3rdParty/dlib/include/dlib/sockets/sockets_kernel_1.h index 326a3e2b..5fb73ecd 100644 --- a/lib/3rdParty/dlib/include/dlib/sockets/sockets_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/sockets/sockets_kernel_1.h @@ -9,10 +9,11 @@ #include "sockets_kernel_abstract.h" -#include "../algs.h" +#include #include + +#include "../algs.h" #include "../threads.h" -#include "../smart_pointers.h" #include "../uintn.h" @@ -269,7 +270,7 @@ namespace dlib ); int accept ( - scoped_ptr& new_connection, + std::unique_ptr& new_connection, unsigned long timeout = 0 ); @@ -324,13 +325,13 @@ namespace dlib ); int create_listener ( - scoped_ptr& new_listener, + std::unique_ptr& new_listener, unsigned short port, const std::string& ip = "" ); int create_connection ( - scoped_ptr& new_connection, + std::unique_ptr& new_connection, unsigned short foreign_port, const std::string& foreign_ip, unsigned short local_port = 0, diff --git a/lib/3rdParty/dlib/include/dlib/sockets/sockets_kernel_2.cpp b/lib/3rdParty/dlib/include/dlib/sockets/sockets_kernel_2.cpp deleted file mode 100644 index dcd0b5fb..00000000 --- a/lib/3rdParty/dlib/include/dlib/sockets/sockets_kernel_2.cpp +++ /dev/null @@ -1,1109 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net), Miguel Grinberg -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_SOCKETS_KERNEL_2_CPp_ -#define DLIB_SOCKETS_KERNEL_2_CPp_ - -#include "../platform.h" - -#ifdef POSIX - - -#include "sockets_kernel_2.h" -#include -#include "../set.h" -#include - - - -namespace dlib -{ -// ---------------------------------------------------------------------------------------- - -#ifdef HPUX - typedef int dsocklen_t; -#else - typedef socklen_t dsocklen_t; -#endif - -// ---------------------------------------------------------------------------------------- -// stuff to ensure that the signal SIGPIPE is ignored before any connections are made -// so that when a connection object is shutdown the program won't end on a broken pipe - - namespace sockets_kernel_2_mutex - { - mutex startup_lock; - } - - - void sockets_startup() - { - // mutex crap to make this function thread safe - sockets_kernel_2_mutex::startup_lock.lock(); - static bool init = false; - if (init == false) - { - init = true; - signal( SIGPIPE, SIG_IGN); - } - sockets_kernel_2_mutex::startup_lock.unlock(); - } - - -// ---------------------------------------------------------------------------------------- - - // lookup functions - - int - get_local_hostname ( - std::string& hostname - ) - { - try - { - char temp[MAXHOSTNAMELEN]; - - if (gethostname(temp,MAXHOSTNAMELEN) == -1) - { - return OTHER_ERROR; - } - // ensure that NUL is at the end of the string - temp[MAXHOSTNAMELEN-1] = '\0'; - - hostname = temp; - } - catch (...) - { - return OTHER_ERROR; - } - - return 0; - } - -// ----------------- - -// cygwin currently doesn't support the getaddrinfo stuff -#ifndef __CYGWIN__ - - int - hostname_to_ip ( - const std::string& hostname, - std::string& ip, - int n - ) - { - try - { - set::kernel_1a sos; - - if (hostname.empty()) - return OTHER_ERROR; - - addrinfo* result = 0; - if (getaddrinfo(hostname.c_str(),0,0,&result)) - { - return OTHER_ERROR; - } - addrinfo* result_orig = result; - - // loop over all the addrinfo structures and add them to the set. the reason for doing - // this dumb crap is because different platforms return all kinds of weird garbage. many - // return the same ip multiple times, etc. - while (result != 0) - { - char temp[16]; - inet_ntop ( - AF_INET, - &((reinterpret_cast(result->ai_addr))->sin_addr), - temp,16 - ); - - result = result->ai_next; - - ip.assign(temp); - if (sos.is_member(ip) == false) - sos.add(ip); - } - - freeaddrinfo(result_orig); - - // now return the nth unique ip address - int i = 0; - while (sos.move_next()) - { - if (i == n) - { - ip = sos.element(); - return 0; - } - ++i; - } - - return OTHER_ERROR; - } - catch (...) - { - return OTHER_ERROR; - } - return 0; - } - - -// ----------------- - - int - ip_to_hostname ( - const std::string& ip, - std::string& hostname - ) - { - - try - { - - if (ip.empty()) - return OTHER_ERROR; - - sockaddr_in sa; - sa.sin_family = AF_INET; - inet_pton(AF_INET,ip.c_str(),&sa.sin_addr); - - char temp[NI_MAXHOST]; - if ( getnameinfo ( - reinterpret_cast(&sa),sizeof(sockaddr_in), - temp, - NI_MAXHOST, - 0, - 0, - NI_NAMEREQD - ) - ) - { - return OTHER_ERROR; - } - - hostname.assign(temp); - - } - catch (...) - { - return OTHER_ERROR; - } - return 0; - } -#else - int - hostname_to_ip ( - const std::string& hostname, - std::string& ip, - int n - ) - { - try - { - // lock this mutex since gethostbyname isn't really thread safe - auto_mutex M(sockets_kernel_2_mutex::startup_lock); - - // if no hostname was given then return error - if ( hostname.empty()) - return OTHER_ERROR; - - hostent* address; - address = gethostbyname(hostname.c_str()); - - if (address == 0) - { - return OTHER_ERROR; - } - - // find the nth address - in_addr* addr = reinterpret_cast(address->h_addr_list[0]); - for (int i = 1; i <= n; ++i) - { - addr = reinterpret_cast(address->h_addr_list[i]); - - // if there is no nth address then return error - if (addr == 0) - return OTHER_ERROR; - } - - char* resolved_ip = inet_ntoa(*addr); - - // check if inet_ntoa returned an error - if (resolved_ip == NULL) - { - return OTHER_ERROR; - } - - ip.assign(resolved_ip); - - } - catch(...) - { - return OTHER_ERROR; - } - - return 0; - } - -// ----------------- - - int - ip_to_hostname ( - const std::string& ip, - std::string& hostname - ) - { - try - { - // lock this mutex since gethostbyaddr isn't really thread safe - auto_mutex M(sockets_kernel_2_mutex::startup_lock); - - // if no ip was given then return error - if (ip.empty()) - return OTHER_ERROR; - - hostent* address; - unsigned long ipnum = inet_addr(ip.c_str()); - - // if inet_addr couldn't convert ip then return an error - if (ipnum == INADDR_NONE) - { - return OTHER_ERROR; - } - address = gethostbyaddr(reinterpret_cast(&ipnum),4,AF_INET); - - // check if gethostbyaddr returned an error - if (address == 0) - { - return OTHER_ERROR; - } - hostname.assign(address->h_name); - - } - catch (...) - { - return OTHER_ERROR; - } - return 0; - - } - -#endif // __CYGWIN__ - -// ---------------------------------------------------------------------------------------- - - connection:: - connection( - int sock, - int foreign_port, - const std::string& foreign_ip, - int local_port, - const std::string& local_ip - ) : - connection_socket(sock), - connection_foreign_port(foreign_port), - connection_foreign_ip(foreign_ip), - connection_local_port(local_port), - connection_local_ip(local_ip), - sd(false), - sdo(false), - sdr(0) - {} - -// ---------------------------------------------------------------------------------------- - - int connection:: - disable_nagle() - { - int flag = 1; - if(setsockopt( connection_socket, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag) )) - { - return OTHER_ERROR; - } - - return 0; - } - -// ---------------------------------------------------------------------------------------- - - long connection:: - write ( - const char* buf, - long num - ) - { - const long old_num = num; - long status; - const long max_send_length = 1024*1024*100; - while (num > 0) - { - // Make sure to cap the max value num can take on so that if it is - // really large (it might be big on 64bit platforms) so that the OS - // can't possibly get upset about it being large. - const long length = std::min(max_send_length, num); - if ( (status = ::send(connection_socket,buf,length,0)) <=0) - { - // if send was interupted by a signal then restart it - if (errno == EINTR) - { - continue; - } - else - { - // check if shutdown or shutdown_outgoing have been called - if (sdo_called()) - return SHUTDOWN; - else - return OTHER_ERROR; - } - } - num -= status; - buf += status; - } - return old_num; - } - -// ---------------------------------------------------------------------------------------- - - long connection:: - read ( - char* buf, - long num - ) - { - long status; - const long max_recv_length = 1024*1024*100; - while (true) - { - // Make sure to cap the max value num can take on so that if it is - // really large (it might be big on 64bit platforms) so that the OS - // can't possibly get upset about it being large. - const long length = std::min(max_recv_length, num); - status = recv(connection_socket,buf,length,0); - if (status == -1) - { - // if recv was interupted then try again - if (errno == EINTR) - continue; - else - { - if (sd_called()) - return SHUTDOWN; - else - return OTHER_ERROR; - } - } - else if (status == 0 && sd_called()) - { - return SHUTDOWN; - } - - return status; - } // while (true) - } -// ---------------------------------------------------------------------------------------- - - long connection:: - read ( - char* buf, - long num, - unsigned long timeout - ) - { - long status; - const long max_recv_length = 1024*1024*100; - - if (readable(timeout) == false) - return TIMEOUT; - - // Make sure to cap the max value num can take on so that if it is - // really large (it might be big on 64bit platforms) so that the OS - // can't possibly get upset about it being large. - const long length = std::min(max_recv_length, num); - status = recv(connection_socket,buf,length,0); - if (status == -1) - { - // if recv was interupted then call this a timeout - if (errno == EINTR) - { - return TIMEOUT; - } - else - { - if (sd_called()) - return SHUTDOWN; - else - return OTHER_ERROR; - } - } - else if (status == 0 && sd_called()) - { - return SHUTDOWN; - } - - return status; - } - -// ---------------------------------------------------------------------------------------- - - bool connection:: - readable ( - unsigned long timeout - ) const - { - fd_set read_set; - // initialize read_set - FD_ZERO(&read_set); - - // add the listening socket to read_set - FD_SET(connection_socket, &read_set); - - // setup a timeval structure - timeval time_to_wait; - time_to_wait.tv_sec = static_cast(timeout/1000); - time_to_wait.tv_usec = static_cast((timeout%1000)*1000); - - // wait on select - int status = select(connection_socket+1,&read_set,0,0,&time_to_wait); - - // if select timed out or there was an error - if (status <= 0) - return false; - - // socket is ready to be read - return true; - } - -// ---------------------------------------------------------------------------------------- - - connection:: - ~connection ( - ) - { - while (true) - { - int status = ::close(connection_socket); - if (status == -1 && errno == EINTR) - continue; - break; - } - } - - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // listener object -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - listener:: - listener( - int sock, - int port, - const std::string& ip - ) : - listening_socket(sock), - listening_port(port), - listening_ip(ip), - inaddr_any(listening_ip.empty()) - {} - -// ---------------------------------------------------------------------------------------- - - listener:: - ~listener ( - ) - { - while (true) - { - int status = ::close(listening_socket); - if (status == -1 && errno == EINTR) - continue; - break; - } - } - -// ---------------------------------------------------------------------------------------- - - int listener:: - accept ( - scoped_ptr& new_connection, - unsigned long timeout - ) - { - new_connection.reset(0); - connection* con; - int status = this->accept(con, timeout); - - if (status == 0) - new_connection.reset(con); - - return status; - } - -// ---------------------------------------------------------------------------------------- - - int listener:: - accept ( - connection*& new_connection, - unsigned long timeout - ) - { - int incoming; - sockaddr_in incomingAddr; - dsocklen_t length = sizeof(sockaddr_in); - - // implement timeout with select if timeout is > 0 - if (timeout > 0) - { - - fd_set read_set; - // initialize read_set - FD_ZERO(&read_set); - - // add the listening socket to read_set - FD_SET(listening_socket, &read_set); - - timeval time_to_wait; - - - // loop on select so if its interupted then we can start it again - while (true) - { - - // setup a timeval structure - time_to_wait.tv_sec = static_cast(timeout/1000); - time_to_wait.tv_usec = static_cast((timeout%1000)*1000); - - // wait on select - int status = select(listening_socket+1,&read_set,0,0,&time_to_wait); - - // if select timed out - if (status == 0) - return TIMEOUT; - - // if select returned an error - if (status == -1) - { - // if select was interupted or the connection was aborted - // then go back to select - if (errno == EINTR || - errno == ECONNABORTED || -#ifdef EPROTO - errno == EPROTO || -#endif - errno == ECONNRESET - ) - { - continue; - } - else - { - return OTHER_ERROR; - } - } - - // accept the new connection - incoming=::accept ( - listening_socket, - reinterpret_cast(&incomingAddr), - &length - ); - - // if there was an error return OTHER_ERROR - if ( incoming == -1 ) - { - // if accept was interupted then go back to accept - if (errno == EINTR || - errno == ECONNABORTED || -#ifdef EPROTO - errno == EPROTO || -#endif - errno == ECONNRESET - ) - { - continue; - } - else - { - return OTHER_ERROR; - } - } - - // if there were no errors then quit loop - break; - - } - - } - // else if there is no time out then just go into accept - else - { - while (true) - { - // call accept to get a new connection - incoming=::accept ( - listening_socket, - reinterpret_cast(&incomingAddr), - &length - ); - - // if there was an error return OTHER_ERROR - if ( incoming == -1 ) - { - // if accept was interupted then go back to accept - if (errno == EINTR || - errno == ECONNABORTED || -#ifdef EPROTO - errno == EPROTO || -#endif - errno == ECONNRESET - ) - { - continue; - } - else - { - return OTHER_ERROR; - } - } - break; - } - - } - - - // get the port of the foreign host into foreign_port - int foreign_port = ntohs(incomingAddr.sin_port); - - // get the IP of the foreign host into foreign_ip - char foreign_ip[16]; - inet_ntop(AF_INET,&incomingAddr.sin_addr,foreign_ip,16); - - - - // get the local ip for this connection into local_ip - char temp_local_ip[16]; - std::string local_ip; - if (inaddr_any == true) - { - sockaddr_in local_info; - length = sizeof(sockaddr_in); - // get the local sockaddr_in structure associated with this new connection - if ( getsockname ( - incoming, - reinterpret_cast(&local_info), - &length - ) == -1 - ) - { // an error occurred - while (true) - { - int status = ::close(incoming); - if (status == -1 && errno == EINTR) - continue; - break; - } - return OTHER_ERROR; - } - local_ip = const_cast ( - inet_ntop(AF_INET,&local_info.sin_addr,temp_local_ip,16) - ); - } - else - { - local_ip = listening_ip; - } - - - - // set the SO_OOBINLINE option - int flag_value = 1; - if (setsockopt(incoming,SOL_SOCKET,SO_OOBINLINE,reinterpret_cast(&flag_value),sizeof(int))) - { - while (true) - { - int status = ::close(incoming); - if (status == -1 && errno == EINTR) - continue; - break; - } - return OTHER_ERROR; - } - - - - // make a new connection object for this new connection - try - { - new_connection = new connection ( - incoming, - foreign_port, - foreign_ip, - listening_port, - local_ip - ); - } - catch (...) - { - while (true) - { - int status = ::close(incoming); - if (status == -1 && errno == EINTR) - continue; - break; - } - return OTHER_ERROR; - } - - return 0; - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - // socket creation functions -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - static void - close_socket ( - int sock - ) - /*! - requires - - sock == a socket - ensures - - sock has been closed - !*/ - { - while (true) - { - int status = ::close(sock); - if (status == -1 && errno == EINTR) - continue; - break; - } - } - -// ---------------------------------------------------------------------------------------- - - int create_listener ( - scoped_ptr& new_listener, - unsigned short port, - const std::string& ip - ) - { - new_listener.reset(); - listener* temp; - int status = create_listener(temp,port,ip); - - if (status == 0) - new_listener.reset(temp); - - return status; - } - - int create_listener ( - listener*& new_listener, - unsigned short port, - const std::string& ip - ) - { - sockets_startup(); - - - sockaddr_in sa; // local socket structure - memset(&sa,'\0',sizeof(sockaddr_in)); // initialize sa - - - int sock = socket (AF_INET, SOCK_STREAM, 0); // get a new socket - - // if socket() returned an error then return OTHER_ERROR - if (sock == -1) - { - return OTHER_ERROR; - } - - // set the local socket structure - sa.sin_family = AF_INET; - sa.sin_port = htons(port); - if (ip.empty()) - { - // if the listener should listen on any IP - sa.sin_addr.s_addr = htons(INADDR_ANY); - } - else - { - // if there is a specific ip to listen on - sa.sin_addr.s_addr = inet_addr(ip.c_str()); - - // if inet_addr couldn't convert the ip then return an error - if ( sa.sin_addr.s_addr == ( in_addr_t)(-1)) - { - close_socket(sock); - return OTHER_ERROR; - } - } - - // set the SO_REUSEADDR option - int flag_value = 1; - if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,reinterpret_cast(&flag_value),sizeof(int))) - { - close_socket(sock); - return OTHER_ERROR; - } - - - // bind the new socket to the requested port and ip - if (bind(sock,reinterpret_cast(&sa),sizeof(sockaddr_in)) == -1) - { // if there was an error - close_socket(sock); - - // if the port is already bound then return PORTINUSE - if (errno == EADDRINUSE) - return PORTINUSE; - else - return OTHER_ERROR; - } - - - // tell the new socket to listen - if ( listen(sock,SOMAXCONN) == -1) - { - // if there was an error return OTHER_ERROR - close_socket(sock); - - // if the port is already bound then return PORTINUSE - if (errno == EADDRINUSE) - return PORTINUSE; - else - return OTHER_ERROR; - } - - // determine the used local port if necessary - if (port == 0) - { - sockaddr_in local_info; - dsocklen_t length = sizeof(sockaddr_in); - if ( getsockname( - sock, - reinterpret_cast(&local_info), - &length - ) == -1) - { - close_socket(sock); - return OTHER_ERROR; - } - port = ntohs(local_info.sin_port); - } - - // initialize a listener object on the heap with the new socket - try { new_listener = new listener(sock,port,ip); } - catch(...) { close_socket(sock); return OTHER_ERROR; } - - return 0; - } - -// ---------------------------------------------------------------------------------------- - - int create_connection ( - scoped_ptr& new_connection, - unsigned short foreign_port, - const std::string& foreign_ip, - unsigned short local_port, - const std::string& local_ip - ) - { - new_connection.reset(); - connection* temp; - int status = create_connection(temp,foreign_port, foreign_ip, local_port, local_ip); - - if (status == 0) - new_connection.reset(temp); - - return status; - } - - int - create_connection ( - connection*& new_connection, - unsigned short foreign_port, - const std::string& foreign_ip, - unsigned short local_port, - const std::string& local_ip - ) - { - sockets_startup(); - - sockaddr_in local_sa; // local socket structure - sockaddr_in foreign_sa; // foreign socket structure - memset(&local_sa,'\0',sizeof(sockaddr_in)); // initialize local_sa - memset(&foreign_sa,'\0',sizeof(sockaddr_in)); // initialize foreign_sa - - dsocklen_t length; - - int sock = socket (AF_INET, SOCK_STREAM, 0); // get a new socket - - // if socket() returned an error then return OTHER_ERROR - if (sock == -1 ) - { - return OTHER_ERROR; - } - - // set the foreign socket structure - foreign_sa.sin_family = AF_INET; - foreign_sa.sin_port = htons(foreign_port); - foreign_sa.sin_addr.s_addr = inet_addr(foreign_ip.c_str()); - - // if inet_addr couldn't convert the ip then return an error - if ( foreign_sa.sin_addr.s_addr == ( in_addr_t)(-1)) - { - close_socket(sock); - return OTHER_ERROR; - } - - - // set up the local socket structure - local_sa.sin_family = AF_INET; - - // set the local port - local_sa.sin_port = htons(local_port); - - // set the local ip - if (local_ip.empty()) - { - // if the listener should listen on any IP - local_sa.sin_addr.s_addr = htons(INADDR_ANY); - } - else - { - // if there is a specific ip to listen on - local_sa.sin_addr.s_addr = inet_addr(local_ip.c_str()); - - // if inet_addr couldn't convert the ip then return an error - if ( local_sa.sin_addr.s_addr == ( in_addr_t)(-1)) - { - close_socket(sock); - return OTHER_ERROR; - } - } - - - - - - // bind the new socket to the requested local port and local ip - if ( bind(sock,reinterpret_cast(&local_sa),sizeof(sockaddr_in)) == -1) - { // if there was an error - close_socket(sock); - - // if the port is already bound then return PORTINUSE - if (errno == EADDRINUSE) - return PORTINUSE; - else - return OTHER_ERROR; - } - - // connect the socket - if ( connect ( - sock, - reinterpret_cast(&foreign_sa), - sizeof(sockaddr_in) - ) == -1 - ) - { - close_socket(sock); - // if the port is already bound then return PORTINUSE - if (errno == EADDRINUSE) - return PORTINUSE; - else - return OTHER_ERROR; - } - - - // determine the local port and IP and store them in used_local_ip - // and used_local_port - int used_local_port; - char temp_used_local_ip[16]; - std::string used_local_ip; - sockaddr_in local_info; - - // determine the port - if (local_port == 0) - { - length = sizeof(sockaddr_in); - if ( getsockname( - sock, - reinterpret_cast(&local_info), - &length - ) == -1) - { - close_socket(sock); - return OTHER_ERROR; - } - used_local_port = ntohs(local_info.sin_port); - } - else - { - used_local_port = local_port; - } - - // determine the ip - if (local_ip.empty()) - { - // if local_port is not 0 then we must fill the local_info structure - if (local_port != 0) - { - length = sizeof(sockaddr_in); - if ( getsockname ( - sock, - reinterpret_cast(&local_info), - &length - ) == -1 - ) - { - close_socket(sock); - return OTHER_ERROR; - } - } - used_local_ip = inet_ntop(AF_INET,&local_info.sin_addr,temp_used_local_ip,16); - } - else - { - used_local_ip = local_ip; - } - - - // set the SO_OOBINLINE option - int flag_value = 1; - if (setsockopt(sock,SOL_SOCKET,SO_OOBINLINE,reinterpret_cast(&flag_value),sizeof(int))) - { - close_socket(sock); - return OTHER_ERROR; - } - - - // initialize a connection object on the heap with the new socket - try - { - new_connection = new connection ( - sock, - foreign_port, - foreign_ip, - used_local_port, - used_local_ip - ); - } - catch(...) {close_socket(sock); return OTHER_ERROR; } - - return 0; - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // POSIX - -#endif // DLIB_SOCKETS_KERNEL_2_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/sockets/sockets_kernel_2.h b/lib/3rdParty/dlib/include/dlib/sockets/sockets_kernel_2.h index 2ddaa886..f3bc94ec 100644 --- a/lib/3rdParty/dlib/include/dlib/sockets/sockets_kernel_2.h +++ b/lib/3rdParty/dlib/include/dlib/sockets/sockets_kernel_2.h @@ -13,10 +13,14 @@ #define _BSD_SOCKLEN_T_ +#include +#include +#include + #include #include #include -#include + #ifndef HPUX #include #endif @@ -26,13 +30,12 @@ #include #include #include -#include #include #include "../threads.h" #include "../algs.h" -#include "../smart_pointers.h" + @@ -312,7 +315,7 @@ namespace dlib ); int accept ( - scoped_ptr& new_connection, + std::unique_ptr& new_connection, unsigned long timeout = 0 ); @@ -368,13 +371,13 @@ namespace dlib ); int create_listener ( - scoped_ptr& new_listener, + std::unique_ptr& new_listener, unsigned short port, const std::string& ip = "" ); int create_connection ( - scoped_ptr& new_connection, + std::unique_ptr& new_connection, unsigned short foreign_port, const std::string& foreign_ip, unsigned short local_port = 0, diff --git a/lib/3rdParty/dlib/include/dlib/sockets/sockets_kernel_abstract.h b/lib/3rdParty/dlib/include/dlib/sockets/sockets_kernel_abstract.h index 0d721758..d4571aca 100644 --- a/lib/3rdParty/dlib/include/dlib/sockets/sockets_kernel_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/sockets/sockets_kernel_abstract.h @@ -117,13 +117,13 @@ namespace dlib !*/ int create_listener ( - scoped_ptr& new_listener, + std::unique_ptr& new_listener, unsigned short port, const std::string& ip = "" ); /*! This function is just an overload of the above function but it gives you a - scoped_ptr smart pointer instead of a C pointer. + std::unique_ptr smart pointer instead of a C pointer. !*/ int create_connection ( @@ -154,7 +154,7 @@ namespace dlib !*/ int create_connection ( - scoped_ptr& new_connection, + std::unique_ptr& new_connection, unsigned short foreign_port, const std::string& foreign_ip, unsigned short local_port = 0, @@ -162,7 +162,7 @@ namespace dlib ); /*! This function is just an overload of the above function but it gives you a - scoped_ptr smart pointer instead of a C pointer. + std::unique_ptr smart pointer instead of a C pointer. !*/ // ---------------------------------------------------------------------------------------- @@ -242,7 +242,7 @@ namespace dlib - num > 0 - buf points to an array of at least num bytes ensures - - will block until ONE of the following occurrs: + - will block until ONE of the following occurs: - num bytes from buf have been written to the connection - an error has occurred - the outgoing channel of the connection has been shutdown locally @@ -459,12 +459,12 @@ namespace dlib !*/ int accept ( - scoped_ptr& new_connection, + std::unique_ptr& new_connection, unsigned long timeout = 0 ); /*! This function is just an overload of the above function but it gives you a - scoped_ptr smart pointer instead of a C pointer. + std::unique_ptr smart pointer instead of a C pointer. !*/ unsigned short get_listening_port ( diff --git a/lib/3rdParty/dlib/include/dlib/sockstreambuf/sockstreambuf.cpp b/lib/3rdParty/dlib/include/dlib/sockstreambuf/sockstreambuf.cpp deleted file mode 100644 index e328e425..00000000 --- a/lib/3rdParty/dlib/include/dlib/sockstreambuf/sockstreambuf.cpp +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_SOCKStREAMBUF_CPp_ -#define DLIB_SOCKStREAMBUF_CPp_ - -#include "sockstreambuf.h" -#include "../assert.h" - -#include - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - // output functions -// ---------------------------------------------------------------------------------------- - - sockstreambuf::int_type sockstreambuf:: - overflow ( - int_type c - ) - { - if (c != EOF) - { - *pptr() = c; - pbump(1); - } - if (flush_out_buffer() == EOF) - { - // an error occurred - return EOF; - } - return c; - } - -// ---------------------------------------------------------------------------------------- - - std::streamsize sockstreambuf:: - xsputn ( - const char* s, - std::streamsize num - ) - { - // Add a sanity check here - DLIB_ASSERT(num >= 0, - "\tstd::streamsize sockstreambuf::xsputn" - << "\n\tThe number of bytes to write can't be negative" - << "\n\tnum: " << num - << "\n\tthis: " << this - ); - - std::streamsize space_left = static_cast(epptr()-pptr()); - if (num <= space_left) - { - std::memcpy(pptr(),s,static_cast(num)); - pbump(static_cast(num)); - return num; - } - else - { - std::memcpy(pptr(),s,static_cast(space_left)); - s += space_left; - pbump(space_left); - std::streamsize num_left = num - space_left; - - if (flush_out_buffer() == EOF) - { - // the write was not successful so return that 0 bytes were written - return 0; - } - - if (num_left < out_buffer_size) - { - std::memcpy(pptr(),s,static_cast(num_left)); - pbump(num_left); - return num; - } - else - { - if (con.write(s,num_left) != num_left) - { - // the write was not successful so return that 0 bytes were written - return 0; - } - return num; - } - } - } - -// ---------------------------------------------------------------------------------------- - // input functions -// ---------------------------------------------------------------------------------------- - - sockstreambuf::int_type sockstreambuf:: - underflow( - ) - { - if (gptr() < egptr()) - { - return static_cast(*gptr()); - } - - int num_put_back = static_cast(gptr() - eback()); - if (num_put_back > max_putback) - { - num_put_back = max_putback; - } - - // copy the putback characters into the putback end of the in_buffer - std::memmove(in_buffer+(max_putback-num_put_back), gptr()-num_put_back, num_put_back); - - if (flushes_output_on_read()) - { - if (flush_out_buffer() == EOF) - { - // an error occurred - return EOF; - } - } - - int num = con.read(in_buffer+max_putback, in_buffer_size-max_putback); - if (num <= 0) - { - // an error occurred or the connection is over which is EOF - return EOF; - } - - // reset in_buffer pointers - setg (in_buffer+(max_putback-num_put_back), - in_buffer+max_putback, - in_buffer+max_putback+num); - - return static_cast(*gptr()); - } - -// ---------------------------------------------------------------------------------------- - - std::streamsize sockstreambuf:: - xsgetn ( - char_type* s, - std::streamsize n - ) - { - std::streamsize temp = n; - while (n > 0) - { - int num = static_cast(egptr() - gptr()); - if (num >= n) - { - // copy data from our buffer - std::memcpy(s, gptr(), static_cast(n)); - gbump(static_cast(n)); - return temp; - } - - // read more data into our buffer - if (num == 0) - { - if (underflow() == EOF) - break; - continue; - } - - // copy all the data from our buffer - std::memcpy(s, gptr(), num); - n -= num; - gbump(num); - s += num; - } - return temp-n; - } - -// ---------------------------------------------------------------------------------------- - -} -#endif // DLIB_SOCKStREAMBUF_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/sockstreambuf/sockstreambuf.h b/lib/3rdParty/dlib/include/dlib/sockstreambuf/sockstreambuf.h index b0230186..f5b450e7 100644 --- a/lib/3rdParty/dlib/include/dlib/sockstreambuf/sockstreambuf.h +++ b/lib/3rdParty/dlib/include/dlib/sockstreambuf/sockstreambuf.h @@ -47,7 +47,7 @@ namespace dlib } sockstreambuf ( - const scoped_ptr& con_ + const std::unique_ptr& con_ ) : con(*con_), out_buffer(0), diff --git a/lib/3rdParty/dlib/include/dlib/sockstreambuf/sockstreambuf_abstract.h b/lib/3rdParty/dlib/include/dlib/sockstreambuf/sockstreambuf_abstract.h index a59313c9..12be8419 100644 --- a/lib/3rdParty/dlib/include/dlib/sockstreambuf/sockstreambuf_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/sockstreambuf/sockstreambuf_abstract.h @@ -4,7 +4,9 @@ #ifdef DLIB_SOCKSTREAMBUF_ABSTRACT_ #include +#include #include + #include "../sockets/sockets_kernel_abstract.h" namespace dlib @@ -32,16 +34,17 @@ namespace dlib once enough data has arrived. THREADING - generally speaking, this object has the same kind of threading + Generally speaking, this object has the same kind of threading restrictions as a connection object. those being: - - do not try to write to a sockstreambuf from more than one thread - - do not try to read from a sockstreambuf from more than one thread - - you may call shutdown() on the connection object and this will + - Do not try to write to a sockstreambuf from more than one thread. + - Do not try to read from a sockstreambuf from more than one thread. + - You may call shutdown() on the connection object and this will cause any reading or writing calls to end. To the sockstreambuf it will appear the same as hitting EOF. (note that EOF for a sockstreambuf means that the connection has closed) - - it is safe to read from and write to the sockstreambuf at the same time - - it is not safe to try to putback a char and read from the stream from + - It is safe to read from and write to the sockstreambuf at the same time + from different threads so long as flushes_output_on_read()==false. + - It is not safe to try to putback a char and read from the stream from different threads !*/ public: @@ -59,7 +62,7 @@ namespace dlib !*/ sockstreambuf ( - const scoped_ptr& con + const std::unique_ptr& con ); /*! requires @@ -103,6 +106,8 @@ namespace dlib ensures - This function returns true if this object will flush its output buffer to the network socket before performing any network read. + - if (flushes_output_on_read() == true) + - It is not safe to make concurrent read and write calls to this object. !*/ void do_not_flush_output_on_read ( diff --git a/lib/3rdParty/dlib/include/dlib/sockstreambuf/sockstreambuf_unbuffered.cpp b/lib/3rdParty/dlib/include/dlib/sockstreambuf/sockstreambuf_unbuffered.cpp deleted file mode 100644 index 4dcefc17..00000000 --- a/lib/3rdParty/dlib/include/dlib/sockstreambuf/sockstreambuf_unbuffered.cpp +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_SOCKSTrEAMBUF_UNBUFFERED_CPp_ -#define DLIB_SOCKSTrEAMBUF_UNBUFFERED_CPp_ - -#include "sockstreambuf_unbuffered.h" - - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - // output functions -// ---------------------------------------------------------------------------------------- - - sockstreambuf_unbuffered::int_type sockstreambuf_unbuffered:: - overflow ( - int_type c - ) - { - if (c != EOF) - { - char temp = static_cast(c); - if (con.write(&temp,1) != 1) - { - // if the write was not successful - return EOF; - } - } - return c; - } - -// ---------------------------------------------------------------------------------------- - - std::streamsize sockstreambuf_unbuffered:: - xsputn ( - const char* s, - std::streamsize num - ) - { - if (con.write(s,static_cast(num)) != num) - { - // the write was not successful so return that 0 bytes were written - return 0; - } - return num; - } - -// ---------------------------------------------------------------------------------------- - // input functions -// ---------------------------------------------------------------------------------------- - - sockstreambuf_unbuffered::int_type sockstreambuf_unbuffered:: - underflow( - ) - { - if (lastread_next) - { - return lastread; - } - else if (peek != EOF) - { - return peek; - } - else - { - char temp; - if (con.read(&temp,1) != 1) - { - // some error occurred - return EOF; - } - peek = static_cast(temp); - return peek; - } - } - -// ---------------------------------------------------------------------------------------- - - sockstreambuf_unbuffered::int_type sockstreambuf_unbuffered:: - uflow( - ) - { - if (lastread_next) - { - lastread_next = false; - return lastread; - } - else if (peek != EOF) - { - lastread = peek; - peek = EOF; - return lastread; - } - else - { - char temp; - if (con.read(&temp,1) != 1) - { - // some error occurred - return EOF; - } - lastread = static_cast(temp); - return lastread; - } - } - -// ---------------------------------------------------------------------------------------- - - sockstreambuf_unbuffered::int_type sockstreambuf_unbuffered:: - pbackfail( - int_type c - ) - { - // if they are trying to push back a character that they didn't read last - // that is an error - if (c != EOF && c != lastread) - return EOF; - - // if they are trying to push back a second character then thats an error - if (lastread_next) - return EOF; - - lastread_next = true; - return 1; - } - -// ---------------------------------------------------------------------------------------- - - std::streamsize sockstreambuf_unbuffered:: - xsgetn ( - char_type* s, - std::streamsize n - ) - { - std::streamsize temp = n; - if (lastread_next && n > 0) - { - *s = lastread; - lastread_next = false; - ++s; - --n; - } - if (peek != EOF && n > 0) - { - *s = peek; - peek = EOF; - ++s; - --n; - } - - while (n>0) - { - int status = con.read(s,static_cast(n)); - if (status < 1) - break; - n -= status; - s += status; - } - - return temp-n; - } - -// ---------------------------------------------------------------------------------------- - -} -#endif // DLIB_SOCKSTrEAMBUF_UNBUFFERED_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/sockstreambuf/sockstreambuf_unbuffered.h b/lib/3rdParty/dlib/include/dlib/sockstreambuf/sockstreambuf_unbuffered.h index f9aae4c1..8aa5992d 100644 --- a/lib/3rdParty/dlib/include/dlib/sockstreambuf/sockstreambuf_unbuffered.h +++ b/lib/3rdParty/dlib/include/dlib/sockstreambuf/sockstreambuf_unbuffered.h @@ -57,7 +57,7 @@ namespace dlib {} sockstreambuf_unbuffered ( - const scoped_ptr& con_ + const std::unique_ptr& con_ ) : con(*con_), peek(EOF), diff --git a/lib/3rdParty/dlib/include/dlib/sqlite/sqlite.h b/lib/3rdParty/dlib/include/dlib/sqlite/sqlite.h index 5732231a..7eefbb21 100644 --- a/lib/3rdParty/dlib/include/dlib/sqlite/sqlite.h +++ b/lib/3rdParty/dlib/include/dlib/sqlite/sqlite.h @@ -6,12 +6,15 @@ #include "sqlite_abstract.h" #include +#include +#include #include + #include "../algs.h" #include -#include "../smart_pointers.h" #include "../serialize.h" + // -------------------------------------------------------------------------------------------- namespace dlib @@ -104,7 +107,7 @@ namespace dlib friend class statement; std::string filename; - shared_ptr db; + std::shared_ptr db; }; // -------------------------------------------------------------------------------------------- @@ -223,6 +226,32 @@ namespace dlib return sql_string; } + template + typename enable_if_c::is_integer>::type get_column ( + unsigned long idx, + T& item + ) const + { + // unsigned ints won't fit into int all the time so put those into 64bit ints. + if (sizeof(T) < sizeof(int) || (sizeof(T)==sizeof(int) && is_signed_type::value)) + item = get_column_as_int(idx); + else + item = get_column_as_int64(idx); + } + + void get_column(unsigned long idx, std::string& item) const { item = get_column_as_text(idx); } + void get_column(unsigned long idx, float& item ) const { item = get_column_as_double(idx); } + void get_column(unsigned long idx, double& item ) const { item = get_column_as_double(idx); } + void get_column(unsigned long idx, long double& item) const { item = get_column_as_double(idx); } + + template + typename disable_if_c::is_integer>::type get_column ( + unsigned long idx, + T& item + ) const + { + get_column_as_object(idx, item); + } const std::vector get_column_as_blob ( unsigned long idx @@ -354,6 +383,33 @@ namespace dlib return sqlite3_bind_parameter_index(stmt, name.c_str()); } + template + typename enable_if_c::is_integer>::type bind ( + unsigned long idx, + const T& item + ) + { + // unsigned ints won't fit into int all the time so put those into 64bit ints. + if (sizeof(T) < sizeof(int) || (sizeof(T)==sizeof(int) && is_signed_type::value)) + bind_int(idx, item); + else + bind_int64(idx, item); + } + + void bind(unsigned long idx, const std::string& item) { bind_text(idx, item); } + void bind(unsigned long idx, const float& item ) { bind_double(idx, item); } + void bind(unsigned long idx, const double& item ) { bind_double(idx, item); } + void bind(unsigned long idx, const long double& item) { bind_double(idx, item); } + + template + typename disable_if_c::is_integer>::type bind ( + unsigned long idx, + const T& item + ) + { + bind_object(idx, item); + } + void bind_blob ( unsigned long parameter_id, const std::vector& item @@ -539,7 +595,7 @@ namespace dlib int step_status; bool at_first_step; - shared_ptr db; + std::shared_ptr db; sqlite3_stmt* stmt; std::string sql_string; }; diff --git a/lib/3rdParty/dlib/include/dlib/sqlite/sqlite_abstract.h b/lib/3rdParty/dlib/include/dlib/sqlite/sqlite_abstract.h index 58ba2938..7372162d 100644 --- a/lib/3rdParty/dlib/include/dlib/sqlite/sqlite_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/sqlite/sqlite_abstract.h @@ -22,7 +22,7 @@ namespace dlib /*! WHAT THIS OBJECT REPRESENTS This is the exception object used by the SQLite tools to indicate - that an error has occurred. An of the functions defined in this + that an error has occurred. Any of the functions defined in this file might throw this exception. !*/ }; @@ -128,7 +128,7 @@ namespace dlib successful INSERT into the database via this database instance. - If an INSERT has not been performed on the current database instance then the return value is 0. This is true even if the database is not empty. - - See the sqlite documention for the full details on how this function + - See the sqlite documentation for the full details on how this function behaves: http://www.sqlite.org/c3ref/last_insert_rowid.html !*/ }; @@ -244,6 +244,31 @@ namespace dlib routines. !*/ + template < + typename T + > + void get_column ( + unsigned long idx, + T& item + ) const; + /*! + requires + - idx < get_num_columns() + ensures + - This function automatically selects how to extract the column data based + on the type of item given. In particular: + - if (T is a 32bit or smaller built in integer type) then + - #item == get_column_as_int(idx) + - else if (T is a 64bit built in integer type) then + - #item == get_column_as_int64(idx) + - else if (T is float, double, or long double) then + - #item == get_column_as_double(idx) + - else if (T is std::string) then + - #item == get_column_as_text(idx) + - else + - invokes: get_column_as_object(idx, item) + !*/ + const std::vector get_column_as_blob ( unsigned long idx ) const; @@ -349,6 +374,31 @@ namespace dlib - returns 0 !*/ + template < + typename T + > + void bind ( + unsigned long parameter_id, + const T& item + ) const; + /*! + requires + - 1 <= parameter_id <= get_max_parameter_id() + ensures + - This function automatically selects how to bind item to a statement based + on the type of item given. In particular: + - if (T is a 32bit or smaller built in integer type) then + - invokes: bind_int(parameter_id, item) + - else if (T is a 64bit built in integer type) then + - invokes: bind_int64(parameter_id, item) + - else if (T is float, double, or long double) then + - invokes: bind_double(parameter_id, item) + - else if (T is std::string) then + - invokes: bind_text(parameter_id, item) + - else + - invokes: bind_object(parameter_id, item) + !*/ + void bind_blob ( unsigned long parameter_id, const std::vector& item diff --git a/lib/3rdParty/dlib/include/dlib/sqlite/sqlite_tools.h b/lib/3rdParty/dlib/include/dlib/sqlite/sqlite_tools.h index 222312a6..062a6b2c 100644 --- a/lib/3rdParty/dlib/include/dlib/sqlite/sqlite_tools.h +++ b/lib/3rdParty/dlib/include/dlib/sqlite/sqlite_tools.h @@ -33,7 +33,7 @@ namespace dlib } } - ~transaction() + ~transaction() throw (std::exception) { if (!committed) db.exec("rollback"); diff --git a/lib/3rdParty/dlib/include/dlib/sstream b/lib/3rdParty/dlib/include/dlib/sstream deleted file mode 100644 index eb0e59e4..00000000 --- a/lib/3rdParty/dlib/include/dlib/sstream +++ /dev/null @@ -1 +0,0 @@ -#include "dlib_include_path_tutorial.txt" diff --git a/lib/3rdParty/dlib/include/dlib/stack/stack_kernel_1.h b/lib/3rdParty/dlib/include/dlib/stack/stack_kernel_1.h index d68520e2..427d6518 100644 --- a/lib/3rdParty/dlib/include/dlib/stack/stack_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/stack/stack_kernel_1.h @@ -97,7 +97,7 @@ namespace dlib ); // functions from the enumerable interface - inline unsigned long size ( + inline size_t size ( ) const; inline bool at_start ( @@ -365,7 +365,7 @@ namespace dlib typename T, typename mem_manager > - unsigned long stack_kernel_1:: + size_t stack_kernel_1:: size ( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/stack_trace.cpp b/lib/3rdParty/dlib/include/dlib/stack_trace.cpp deleted file mode 100644 index f386b2a9..00000000 --- a/lib/3rdParty/dlib/include/dlib/stack_trace.cpp +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (C) 2008 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_STACK_TRACE_CPp_ -#define DLIB_STACK_TRACE_CPp_ - -#if defined(DLIB_ENABLE_STACK_TRACE) && !defined(NO_MAKEFILE) - -#include -#include -#include "stack_trace.h" -#include "threads.h" -#include "stack.h" -#include "memory_manager.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - namespace - { - struct stack_tracer_data - { - stack_tracer_data( - ) : funct_name(0), - file_name(0), - line_number(0) - {} - const char* funct_name; - const char* file_name; - int line_number; - }; - - thread_specific_data::kernel_2a>::kernel_1a>& get_dlib_stack_trace_stack() - { - static thread_specific_data::kernel_2a>::kernel_1a> a; - return a; - } - } - -// ---------------------------------------------------------------------------------------- - - stack_tracer:: - stack_tracer ( - const char* funct_name, - const char* file_name, - const int line_number - ) - { - stack_tracer_data data; - data.funct_name = funct_name; - data.file_name = file_name; - data.line_number = line_number; - - // pop the info onto the function stack trace - get_dlib_stack_trace_stack().data().push(data); - } - -// ---------------------------------------------------------------------------------------- - - stack_tracer:: - ~stack_tracer() - { - stack_tracer_data temp; - get_dlib_stack_trace_stack().data().pop(temp); - } - -// ---------------------------------------------------------------------------------------- - - const std::string get_stack_trace() - { - std::ostringstream sout; - get_dlib_stack_trace_stack().data().reset(); - while (get_dlib_stack_trace_stack().data().move_next()) - { - stack_tracer_data data = get_dlib_stack_trace_stack().data().element(); - sout << data.file_name << ":" << data.line_number << "\n " << data.funct_name << "\n"; - } - return sout.str(); - } - -// ---------------------------------------------------------------------------------------- - -} -#endif - -#endif // DLIB_STACK_TRACE_CPp_ - - diff --git a/lib/3rdParty/dlib/include/dlib/stack_trace.h b/lib/3rdParty/dlib/include/dlib/stack_trace.h index 230ed374..aacbeb78 100644 --- a/lib/3rdParty/dlib/include/dlib/stack_trace.h +++ b/lib/3rdParty/dlib/include/dlib/stack_trace.h @@ -65,8 +65,8 @@ namespace dlib } // redefine the DLIB_CASSERT macro to include the stack trace -#undef DLIB_CASSERT -#define DLIB_CASSERT(_exp,_message) \ +#undef DLIBM_CASSERT +#define DLIBM_CASSERT(_exp,_message) \ {if ( !(_exp) ) \ { \ std::ostringstream dlib_o_out; \ diff --git a/lib/3rdParty/dlib/include/dlib/static_map/static_map_kernel_1.h b/lib/3rdParty/dlib/include/dlib/static_map/static_map_kernel_1.h index 8f3d7db7..a7b627ae 100644 --- a/lib/3rdParty/dlib/include/dlib/static_map/static_map_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/static_map/static_map_kernel_1.h @@ -157,7 +157,7 @@ namespace dlib ); // functions from the enumerable interface - inline unsigned long size ( + inline size_t size ( ) const; inline bool at_start ( @@ -433,7 +433,7 @@ namespace dlib typename range, typename compare > - unsigned long static_map_kernel_1:: + size_t static_map_kernel_1:: size ( ) const { diff --git a/lib/3rdParty/dlib/include/dlib/static_set/static_set_kernel_1.h b/lib/3rdParty/dlib/include/dlib/static_set/static_set_kernel_1.h index 1b78f03b..7a1f166f 100644 --- a/lib/3rdParty/dlib/include/dlib/static_set/static_set_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/static_set/static_set_kernel_1.h @@ -52,11 +52,11 @@ namespace dlib try { item.clear(); - unsigned long size; + size_t size; deserialize(size,in); item.set_size = size; item.d = new T[size]; - for (unsigned long i = 0; i < size; ++i) + for (size_t i = 0; i < size; ++i) { deserialize(item.d[i],in); } @@ -116,7 +116,7 @@ namespace dlib ); // functions from the enumerable interface - inline unsigned long size ( + inline size_t size ( ) const; inline bool at_start ( @@ -142,7 +142,7 @@ namespace dlib // data members - unsigned long set_size; + size_t set_size; T* d; mutable T* cur; mutable bool at_start_; @@ -231,7 +231,7 @@ namespace dlib set_size = source.size(); - for (unsigned long i = 0; source.size() > 0; ++i) + for (size_t i = 0; source.size() > 0; ++i) source.remove_any(d[i]); compare comp; @@ -261,7 +261,7 @@ namespace dlib set_size = source.size(); - for (unsigned long i = 0; source.size() > 0; ++i) + for (size_t i = 0; source.size() > 0; ++i) source.remove_any(d[i]); } else @@ -282,10 +282,10 @@ namespace dlib const T& item ) const { - unsigned long high = set_size; - unsigned long low = 0; - unsigned long p = set_size; - unsigned long idx; + size_t high = set_size; + size_t low = 0; + size_t p = set_size; + size_t idx; while (p > 0) { p = (high-low)>>1; @@ -306,7 +306,7 @@ namespace dlib typename T, typename compare > - unsigned long static_set_kernel_1:: + size_t static_set_kernel_1:: size ( ) const { @@ -421,7 +421,7 @@ namespace dlib else if (cur != 0) { ++cur; - if (static_cast(cur - d) < set_size) + if (static_cast(cur - d) < set_size) { return true; } diff --git a/lib/3rdParty/dlib/include/dlib/statistics.h b/lib/3rdParty/dlib/include/dlib/statistics.h index afc34206..45785c63 100644 --- a/lib/3rdParty/dlib/include/dlib/statistics.h +++ b/lib/3rdParty/dlib/include/dlib/statistics.h @@ -11,6 +11,7 @@ #include "statistics/cca.h" #include "statistics/average_precision.h" #include "statistics/vector_normalizer_frobmetric.h" +#include "statistics/lda.h" #endif // DLIB_STATISTICs_H_ diff --git a/lib/3rdParty/dlib/include/dlib/statistics/lda.h b/lib/3rdParty/dlib/include/dlib/statistics/lda.h new file mode 100644 index 00000000..38de3fd1 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/statistics/lda.h @@ -0,0 +1,237 @@ +// Copyright (C) 2014 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LDA_Hh_ +#define DLIB_LDA_Hh_ + +#include "lda_abstract.h" +#include "../algs.h" +#include +#include "../matrix.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + + inline std::map make_class_labels( + const std::vector& row_labels + ) + { + std::map class_labels; + for (unsigned long i = 0; i < row_labels.size(); ++i) + { + const unsigned long next = class_labels.size(); + if (class_labels.count(row_labels[i]) == 0) + class_labels[row_labels[i]] = next; + } + return class_labels; + } + + // ------------------------------------------------------------------------------------ + + template < + typename T + > + matrix center_matrix ( + matrix& X + ) + { + matrix mean; + for (long r = 0; r < X.nr(); ++r) + mean += rowm(X,r); + mean /= X.nr(); + + for (long r = 0; r < X.nr(); ++r) + set_rowm(X,r) -= mean; + + return trans(mean); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void compute_lda_transform ( + matrix& X, + matrix& mean, + const std::vector& row_labels, + unsigned long lda_dims = 500, + unsigned long extra_pca_dims = 200 + ) + { + std::map class_labels = impl::make_class_labels(row_labels); + // LDA can only give out at most class_labels.size()-1 dimensions so don't try to + // compute more than that. + lda_dims = std::min(lda_dims, class_labels.size()-1); + + // make sure requires clause is not broken + DLIB_CASSERT(class_labels.size() > 1, + "\t void compute_lda_transform()" + << "\n\t You can't call this function if the number of distinct class labels is less than 2." + ); + DLIB_CASSERT(X.size() != 0 && (long)row_labels.size() == X.nr() && lda_dims != 0, + "\t void compute_lda_transform()" + << "\n\t Invalid inputs were given to this function." + << "\n\t X.size(): " << X.size() + << "\n\t row_labels.size(): " << row_labels.size() + << "\n\t lda_dims: " << lda_dims + ); + + + mean = impl::center_matrix(X); + // Do PCA to reduce dims + matrix pu,pw,pv; + svd_fast(X, pu, pw, pv, lda_dims+extra_pca_dims, 4); + pu.set_size(0,0); // free RAM, we don't need pu. + X = X*pv; + + + matrix class_means(class_labels.size(), X.nc()); + class_means = 0; + matrix class_counts(class_labels.size()); + class_counts = 0; + + // First compute the means of each class + for (unsigned long i = 0; i < row_labels.size(); ++i) + { + const unsigned long class_idx = class_labels[row_labels[i]]; + set_rowm(class_means,class_idx) += rowm(X,i); + class_counts(class_idx)++; + } + class_means = inv(diagm(class_counts))*class_means; + // subtract means from the data + for (unsigned long i = 0; i < row_labels.size(); ++i) + { + const unsigned long class_idx = class_labels[row_labels[i]]; + set_rowm(X,i) -= rowm(class_means,class_idx); + } + + // Note that we are using the formulas from the paper Using Discriminant + // Eigenfeatures for Image Retrieval by Swets and Weng. + matrix Sw = trans(X)*X; + matrix Sb = trans(class_means)*class_means; + matrix A, H; + matrix W; + svd3(Sw, A, W, H); + W = sqrt(W); + W = reciprocal(lowerbound(W,max(W)*1e-5)); + A = trans(H*diagm(W))*Sb*H*diagm(W); + matrix v,s,u; + svd3(A, v, s, u); + matrix tform = H*diagm(W)*u; + // pick out only the number of dimensions we are supposed to for the output, unless + // we should just keep them all, then don't do anything. + if ((long)lda_dims <= tform.nc()) + { + rsort_columns(tform, s); + tform = colm(tform, range(0, lda_dims-1)); + } + + X = trans(pv*tform); + mean = X*mean; + } + +// ---------------------------------------------------------------------------------------- + + inline std::pair equal_error_rate ( + const std::vector& low_vals, + const std::vector& high_vals + ) + { + std::vector > temp; + temp.reserve(low_vals.size()+high_vals.size()); + for (unsigned long i = 0; i < low_vals.size(); ++i) + temp.push_back(std::make_pair(low_vals[i], -1)); + for (unsigned long i = 0; i < high_vals.size(); ++i) + temp.push_back(std::make_pair(high_vals[i], +1)); + + std::sort(temp.begin(), temp.end()); + + if (temp.size() == 0) + return std::make_pair(0,0); + + double thresh = temp[0].first; + + unsigned long num_low_wrong = low_vals.size(); + unsigned long num_high_wrong = 0; + double low_error = num_low_wrong/(double)low_vals.size(); + double high_error = num_high_wrong/(double)high_vals.size(); + for (unsigned long i = 0; i < temp.size() && high_error < low_error; ++i) + { + thresh = temp[i].first; + if (temp[i].second > 0) + { + num_high_wrong++; + high_error = num_high_wrong/(double)high_vals.size(); + } + else + { + num_low_wrong--; + low_error = num_low_wrong/(double)low_vals.size(); + } + } + + return std::make_pair((low_error+high_error)/2, thresh); + } + +// ---------------------------------------------------------------------------------------- + + struct roc_point + { + double true_positive_rate; + double false_positive_rate; + double detection_threshold; + }; + + inline std::vector compute_roc_curve ( + const std::vector& true_detections, + const std::vector& false_detections + ) + { + DLIB_CASSERT(true_detections.size() != 0); + DLIB_CASSERT(false_detections.size() != 0); + + std::vector > temp; + temp.reserve(true_detections.size()+false_detections.size()); + for (unsigned long i = 0; i < true_detections.size(); ++i) + temp.push_back(std::make_pair(true_detections[i], +1)); + for (unsigned long i = 0; i < false_detections.size(); ++i) + temp.push_back(std::make_pair(false_detections[i], -1)); + + std::sort(temp.rbegin(), temp.rend()); + + + std::vector roc_curve; + roc_curve.reserve(temp.size()); + + double num_false_included = 0; + double num_true_included = 0; + for (unsigned long i = 0; i < temp.size(); ++i) + { + if (temp[i].second > 0) + num_true_included++; + else + num_false_included++; + + roc_point p; + p.true_positive_rate = num_true_included/true_detections.size(); + p.false_positive_rate = num_false_included/false_detections.size(); + p.detection_threshold = temp[i].first; + roc_curve.push_back(p); + } + + return roc_curve; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_LDA_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/statistics/lda_abstract.h b/lib/3rdParty/dlib/include/dlib/statistics/lda_abstract.h new file mode 100644 index 00000000..ab9fd7a3 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/statistics/lda_abstract.h @@ -0,0 +1,118 @@ +// Copyright (C) 2014 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_LDA_ABSTRACT_Hh_ +#ifdef DLIB_LDA_ABSTRACT_Hh_ + +#include +#include "../matrix.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void compute_lda_transform ( + matrix& X, + matrix& M, + const std::vector& row_labels, + unsigned long lda_dims = 500, + unsigned long extra_pca_dims = 200 + ); + /*! + requires + - X.size() != 0 + - row_labels.size() == X.nr() + - The number of distinct values in row_labels > 1 + - lda_dims != 0 + ensures + - We interpret X as a collection X.nr() of input vectors, where each row of X + is one of the vectors. + - We interpret row_labels[i] as the label of the vector rowm(X,i). + - This function performs the dimensionality reducing version of linear + discriminant analysis. That is, you give it a set of labeled vectors and it + returns a linear transform that maps the input vectors into a new space that + is good for distinguishing between the different classes. In particular, + this function finds matrices Z and M such that: + - Given an input vector x, Z*x-M, is the transformed version of x. That is, + Z*x-M maps x into a space where x vectors that share the same class label + are near each other. + - Z*x-M results in the transformed vectors having zero expected mean. + - Z.nr() <= lda_dims + (it might be less than lda_dims if there are not enough distinct class + labels to support lda_dims dimensions). + - Z.nc() == X.nc() + - We overwrite the input matrix X and store Z in it. Therefore, the + outputs of this function are in X and M. + - In order to deal with very high dimensional inputs, we perform PCA internally + to map the input vectors into a space of at most lda_dims+extra_pca_dims + prior to performing LDA. + !*/ + +// ---------------------------------------------------------------------------------------- + + std::pair equal_error_rate ( + const std::vector& low_vals, + const std::vector& high_vals + ); + /*! + ensures + - This function finds a threshold T that best separates the elements of + low_vals from high_vals by selecting the threshold with equal error rate. In + particular, we try to pick a threshold T such that: + - for all valid i: + - high_vals[i] >= T + - for all valid i: + - low_vals[i] < T + Where the best T is determined such that the fraction of low_vals >= T is the + same as the fraction of high_vals < T. + - Let ERR == the equal error rate. I.e. the fraction of times low_vals >= T + and high_vals < T. Note that 0 <= ERR <= 1. + - returns make_pair(ERR,T) + !*/ + +// ---------------------------------------------------------------------------------------- + + struct roc_point + { + double true_positive_rate; + double false_positive_rate; + double detection_threshold; + }; + + std::vector compute_roc_curve ( + const std::vector& true_detections, + const std::vector& false_detections + ); + /*! + requires + - true_detections.size() != 0 + - false_detections.size() != 0 + ensures + - This function computes the ROC curve (receiver operating characteristic) + curve of the given data. Therefore, we interpret true_detections as + containing detection scores for a bunch of true detections and + false_detections as detection scores from a bunch of false detections. A + perfect detector would always give higher scores to true detections than to + false detections, resulting in a true positive rate of 1 and a false positive + rate of 0, for some appropriate detection threshold. + - Returns an array, ROC, such that: + - ROC.size() == true_detections.size()+false_detections.size() + - for all valid i: + - If you were to accept all detections with a score >= ROC[i].detection_threshold + then you would obtain a true positive rate of ROC[i].true_positive_rate and a + false positive rate of ROC[i].false_positive_rate. + - ROC is ordered such that low detection rates come first. That is, the + curve is swept from a high detection threshold to a low threshold. + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_LDA_ABSTRACT_Hh_ + + diff --git a/lib/3rdParty/dlib/include/dlib/statistics/random_subset_selector.h b/lib/3rdParty/dlib/include/dlib/statistics/random_subset_selector.h index deb4ec37..17492363 100644 --- a/lib/3rdParty/dlib/include/dlib/statistics/random_subset_selector.h +++ b/lib/3rdParty/dlib/include/dlib/statistics/random_subset_selector.h @@ -67,7 +67,7 @@ namespace dlib const std::vector& to_std_vector( ) const { return items; } - unsigned long size ( + size_t size ( ) const { return items.size(); @@ -170,7 +170,7 @@ namespace dlib random_subset_selector& a ) { - a.swap(a.items); + items.swap(a.items); std::swap(_max_size, a._max_size); std::swap(count, a.count); rnd.swap(a.rnd); diff --git a/lib/3rdParty/dlib/include/dlib/statistics/random_subset_selector_abstract.h b/lib/3rdParty/dlib/include/dlib/statistics/random_subset_selector_abstract.h index fde75373..96f8b545 100644 --- a/lib/3rdParty/dlib/include/dlib/statistics/random_subset_selector_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/statistics/random_subset_selector_abstract.h @@ -101,7 +101,7 @@ namespace dlib - #size() == 0 !*/ - unsigned long size ( + size_t size ( ) const; /*! ensures diff --git a/lib/3rdParty/dlib/include/dlib/statistics/running_gradient.h b/lib/3rdParty/dlib/include/dlib/statistics/running_gradient.h new file mode 100644 index 00000000..d3f1b3dd --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/statistics/running_gradient.h @@ -0,0 +1,370 @@ +// Copyright (C) 2016 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_RuNNING_GRADIENT_Hh_ +#define DLIB_RuNNING_GRADIENT_Hh_ + +#include "running_gradient_abstract.h" +#include "../algs.h" +#include "../serialize.h" +#include +#include "../matrix.h" +#include + + +namespace dlib +{ + class running_gradient + { + public: + + running_gradient ( + ) + { + clear(); + } + + void clear( + ) + { + n = 0; + R = identity_matrix(2)*1e6; + w = 0; + residual_squared = 0; + } + + double current_n ( + ) const + { + return n; + } + + void add( + double y + ) + { + matrix x; + x = n, 1; + + // Do recursive least squares computations + const double temp = 1 + trans(x)*R*x; + matrix tmp = R*x; + R = R - (tmp*trans(tmp))/temp; + // R should always be symmetric. This line improves numeric stability of this algorithm. + R = 0.5*(R + trans(R)); + w = w + R*x*(y - trans(x)*w); + + // Also, recursively keep track of the residual error between the given value + // and what our linear predictor outputs. + residual_squared = residual_squared + std::pow((y - trans(x)*w),2.0)*temp; + + ++n; + } + + double gradient ( + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT(current_n() > 1, + "\t double running_gradient::gradient()" + << "\n\t You must add more values into this object before calling this function." + << "\n\t this: " << this + ); + + return w(0); + } + + double intercept ( + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT(current_n() > 0, + "\t double running_gradient::intercept()" + << "\n\t You must add more values into this object before calling this function." + << "\n\t this: " << this + ); + + return w(1); + } + double standard_error ( + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT(current_n() > 2, + "\t double running_gradient::standard_error()" + << "\n\t You must add more values into this object before calling this function." + << "\n\t this: " << this + ); + + + const double s = residual_squared/(n-2); + const double adjust = 12.0/(std::pow(current_n(),3.0) - current_n()); + return std::sqrt(s*adjust); + } + + double probability_gradient_less_than ( + double thresh + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT(current_n() > 2, + "\t double running_gradient::probability_gradient_less_than()" + << "\n\t You must add more values into this object before calling this function." + << "\n\t this: " << this + ); + + return normal_cdf(thresh, gradient(), standard_error()); + } + + double probability_gradient_greater_than ( + double thresh + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT(current_n() > 2, + "\t double running_gradient::probability_gradient_greater_than()" + << "\n\t You must add more values into this object before calling this function." + << "\n\t this: " << this + ); + + return 1-probability_gradient_less_than(thresh); + } + + friend void serialize (const running_gradient& item, std::ostream& out) + { + int version = 1; + serialize(version, out); + serialize(item.n, out); + serialize(item.R, out); + serialize(item.w, out); + serialize(item.residual_squared, out); + } + + friend void deserialize (running_gradient& item, std::istream& in) + { + int version = 0; + deserialize(version, in); + if (version != 1) + throw serialization_error("Unexpected version found while deserializing dlib::running_gradient."); + deserialize(item.n, in); + deserialize(item.R, in); + deserialize(item.w, in); + deserialize(item.residual_squared, in); + } + + private: + + static double normal_cdf(double value, double mean, double stddev) + { + if (stddev == 0) + { + if (value < mean) + return 0; + else if (value > mean) + return 1; + else + return 0.5; + } + value = (value-mean)/stddev; + return 0.5 * std::erfc(-value / std::sqrt(2.0)); + } + + double n; + matrix R; + matrix w; + double residual_squared; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + double probability_gradient_less_than ( + const T& container, + double thresh + ) + { + running_gradient g; + for(auto&& v : container) + g.add(v); + + // make sure requires clause is not broken + DLIB_ASSERT(g.current_n() > 2, + "\t double probability_gradient_less_than()" + << "\n\t You need more than 2 elements in the given container to call this function." + ); + return g.probability_gradient_less_than(thresh); + } + + template < + typename T + > + double probability_gradient_greater_than ( + const T& container, + double thresh + ) + { + running_gradient g; + for(auto&& v : container) + g.add(v); + + // make sure requires clause is not broken + DLIB_ASSERT(g.current_n() > 2, + "\t double probability_gradient_greater_than()" + << "\n\t You need more than 2 elements in the given container to call this function." + ); + return g.probability_gradient_greater_than(thresh); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + double find_upper_quantile ( + const T& container_, + double quantile + ) + { + DLIB_CASSERT(0 <= quantile && quantile <= 1.0); + + // copy container into a std::vector + std::vector container(container_.begin(), container_.end()); + + DLIB_CASSERT(container.size() > 0); + + size_t idx_upper = std::round((container.size()-1)*(1-quantile)); + + std::nth_element(container.begin(), container.begin()+idx_upper, container.end()); + auto upper_q = *(container.begin()+idx_upper); + return upper_q; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + size_t count_steps_without_decrease ( + const T& container, + double probability_of_decrease = 0.51 + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(0.5 < probability_of_decrease && probability_of_decrease < 1, + "\t size_t count_steps_without_decrease()" + << "\n\t probability_of_decrease: "<< probability_of_decrease + ); + + running_gradient g; + size_t count = 0; + size_t j = 0; + for (auto i = container.rbegin(); i != container.rend(); ++i) + { + ++j; + g.add(*i); + if (g.current_n() > 2) + { + // Note that this only looks backwards because we are looping over the + // container backwards. So here we are really checking if the gradient isn't + // decreasing. + double prob_decreasing = g.probability_gradient_greater_than(0); + // If we aren't confident things are decreasing. + if (prob_decreasing < probability_of_decrease) + count = j; + } + } + return count; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + size_t count_steps_without_decrease_robust ( + const T& container, + double probability_of_decrease = 0.51, + double quantile_discard = 0.10 + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(0 <= quantile_discard && quantile_discard <= 1); + DLIB_ASSERT(0.5 < probability_of_decrease && probability_of_decrease < 1, + "\t size_t count_steps_without_decrease_robust()" + << "\n\t probability_of_decrease: "<< probability_of_decrease + ); + + if (container.size() == 0) + return 0; + + const auto quantile_thresh = find_upper_quantile(container, quantile_discard); + + running_gradient g; + size_t count = 0; + size_t j = 0; + for (auto i = container.rbegin(); i != container.rend(); ++i) + { + ++j; + // ignore values that are too large + if (*i <= quantile_thresh) + g.add(*i); + + if (g.current_n() > 2) + { + // Note that this only looks backwards because we are looping over the + // container backwards. So here we are really checking if the gradient isn't + // decreasing. + double prob_decreasing = g.probability_gradient_greater_than(0); + // If we aren't confident things are decreasing. + if (prob_decreasing < probability_of_decrease) + count = j; + } + } + return count; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + size_t count_steps_without_increase ( + const T& container, + double probability_of_increase = 0.51 + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(0.5 < probability_of_increase && probability_of_increase < 1, + "\t size_t count_steps_without_increase()" + << "\n\t probability_of_increase: "<< probability_of_increase + ); + + running_gradient g; + size_t count = 0; + size_t j = 0; + for (auto i = container.rbegin(); i != container.rend(); ++i) + { + ++j; + g.add(*i); + if (g.current_n() > 2) + { + // Note that this only looks backwards because we are looping over the + // container backwards. So here we are really checking if the gradient isn't + // increasing. + double prob_increasing = g.probability_gradient_less_than(0); + // If we aren't confident things are increasing. + if (prob_increasing < probability_of_increase) + count = j; + } + } + return count; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_RuNNING_GRADIENT_Hh_ + + diff --git a/lib/3rdParty/dlib/include/dlib/statistics/running_gradient_abstract.h b/lib/3rdParty/dlib/include/dlib/statistics/running_gradient_abstract.h new file mode 100644 index 00000000..a42e1c15 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/statistics/running_gradient_abstract.h @@ -0,0 +1,276 @@ +// Copyright (C) 2016 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_RuNNING_GRADIENT_ABSTRACT_Hh_ +#ifdef DLIB_RuNNING_GRADIENT_ABSTRACT_Hh_ + + +namespace dlib +{ + class running_gradient + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a tool for estimating if a noisy sequence of numbers is + trending up or down and by how much. It does this by finding the least + squares fit of a line to the data and then allows you to perform a + statistical test on the slope of that line. + !*/ + + public: + + running_gradient ( + ); + /*! + ensures + - #current_n() == 0 + !*/ + + void clear( + ); + /*! + ensures + - #current_n() == 0 + - this object has its initial value + - clears all memory of any previous data points + !*/ + + double current_n ( + ) const; + /*! + ensures + - returns the number of values given to this object by add(). + !*/ + + void add( + double y + ); + /*! + ensures + - Updates the gradient() and standard_error() estimates in this object + based on the new y value. + - #current_n() == current_n() + 1 + !*/ + + double gradient ( + ) const; + /*! + requires + - current_n() > 1 + ensures + - If we consider the values given to add() as time series data, we can + estimate the rate-of-change of those values. That is, how much, + typically, do those values change from sample to sample? The gradient() + function returns the current estimate. It does this by finding the least + squares fit of a line to the data given to add() and returning the slope + of this line. + !*/ + + double intercept ( + ) const; + /*! + requires + - current_n() > 0 + ensures + - This class fits a line to the time series data given to add(). This + function returns the intercept of that line while gradient() returns the + slope of that line. This means that, for example, the next point that + add() will see, as predicted by this best fit line, is the value + intercept() + current_n()*gradient(). + !*/ + + double standard_error ( + ) const; + /*! + requires + - current_n() > 2 + ensures + - returns the standard deviation of the estimate of gradient(). + !*/ + + double probability_gradient_less_than ( + double thresh + ) const; + /*! + requires + - current_n() > 2 + ensures + - If we can assume the values given to add() are linearly related to each + other and corrupted by Gaussian additive noise then our estimate of + gradient() is a random variable with a mean value of gradient() and a + standard deviation of standard_error(). This lets us compute the + probability that the true gradient of the data is less than thresh, which + is what this function returns. + !*/ + + double probability_gradient_greater_than ( + double thresh + ) const; + /*! + requires + - current_n() > 2 + ensures + - returns 1-probability_gradient_less_than(thresh) + !*/ + + }; + + void serialize ( + const running_gradient& item, + std::ostream& out + ); + /*! + provides serialization support + !*/ + + void deserialize ( + running_gradient& item, + std::istream& in + ); + /*! + provides serialization support + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + double probability_gradient_less_than ( + const T& container, + double thresh + ); + /*! + requires + - container must be a container of double values that can be enumerated with a + range based for loop. + - The container must contain more than 2 elements. + ensures + - Puts all the elements of container into a running_gradient object, R, and + then returns R.probability_gradient_less_than(thresh). + !*/ + + template < + typename T + > + double probability_gradient_greater_than ( + const T& container, + double thresh + ); + /*! + requires + - container must be a container of double values that can be enumerated with a + range based for loop. + - The container must contain more than 2 elements. + ensures + - Puts all the elements of container into a running_gradient object, R, and + then returns R.probability_gradient_greater_than(thresh). + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + size_t count_steps_without_decrease ( + const T& container, + double probability_of_decrease = 0.51 + ); + /*! + requires + - container must be a container of double values that can be enumerated with + .rbegin() and .rend(). + - 0.5 < probability_of_decrease < 1 + ensures + - If you think of the contents of container as a potentially noisy time series, + then this function returns a count of how long the time series has gone + without noticeably decreasing in value. It does this by adding the + elements into a running_gradient object and counting how many elements, + starting with container.back(), that you need to examine before you are + confident that the series has been decreasing in value. Here, "confident of + decrease" means that the probability of decrease is >= probability_of_decrease. + - Setting probability_of_decrease to 0.51 means we count until we see even a + small hint of decrease, whereas a larger value of 0.99 would return a larger + count since it keeps going until it is nearly certain the time series is + decreasing. + - The max possible output from this function is container.size(). + !*/ + + template < + typename T + > + size_t count_steps_without_decrease_robust ( + const T& container, + double probability_of_decrease = 0.51, + double quantile_discard = 0.10 + ); + /*! + requires + - container must be a container of double values that can be enumerated with + .begin() and .end() as well as .rbegin() and .rend(). + - 0.5 < probability_of_decrease < 1 + - 0 <= quantile_discard <= 1 + ensures + - This function behaves just like + count_steps_without_decrease(container,probability_of_decrease) except that + it ignores values in container that are in the upper quantile_discard + quantile. So for example, if the quantile discard is 0.1 then the 10% + largest values in container are ignored. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + size_t count_steps_without_increase ( + const T& container, + double probability_of_increase = 0.51 + ); + /*! + requires + - container must be a container of double values that can be enumerated with + .rbegin() and .rend(). + - 0.5 < probability_of_increase < 1 + ensures + - If you think of the contents of container as a potentially noisy time series, + then this function returns a count of how long the time series has gone + without noticeably increasing in value. It does this by adding the + elements into a running_gradient object and counting how many elements, + starting with container.back(), that you need to examine before you are + confident that the series has been increasing in value. Here, "confident of + increase" means that the probability of increase is >= probability_of_increase. + - Setting probability_of_increase to 0.51 means we count until we see even a + small hint of increase, whereas a larger value of 0.99 would return a larger + count since it keeps going until it is nearly certain the time series is + increasing. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + double find_upper_quantile ( + const T& container, + double quantile + ); + /*! + requires + - container must be a container of double values that can be enumerated with + .begin() and .end(). + - 0 <= quantile <= 1 + - container.size() > 0 + ensures + - Finds and returns the value such that quantile percent of the values in + container are greater than it. For example, 0.5 would find the median value + in container while 0.1 would find the value that lower bounded the 10% + largest values in container. + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_RuNNING_GRADIENT_ABSTRACT_Hh_ + + diff --git a/lib/3rdParty/dlib/include/dlib/statistics/statistics.h b/lib/3rdParty/dlib/include/dlib/statistics/statistics.h index 27c5821c..9dee7006 100644 --- a/lib/3rdParty/dlib/include/dlib/statistics/statistics.h +++ b/lib/3rdParty/dlib/include/dlib/statistics/statistics.h @@ -450,6 +450,331 @@ namespace dlib T n; }; +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + class running_scalar_covariance_decayed + { + public: + + explicit running_scalar_covariance_decayed( + T decay_halflife = 1000 + ) + { + DLIB_ASSERT(decay_halflife > 0); + + sum_xy = 0; + sum_x = 0; + sum_y = 0; + sum_xx = 0; + sum_yy = 0; + forget = std::pow(0.5, 1/decay_halflife); + n = 0; + + COMPILE_TIME_ASSERT (( + is_same_type::value || + is_same_type::value || + is_same_type::value + )); + } + + T forget_factor ( + ) const + { + return forget; + } + + void add ( + const T& x, + const T& y + ) + { + sum_xy = sum_xy*forget + x*y; + + sum_xx = sum_xx*forget + x*x; + sum_yy = sum_yy*forget + y*y; + + sum_x = sum_x*forget + x; + sum_y = sum_y*forget + y; + + n = n*forget + 1; + } + + T current_n ( + ) const + { + return n; + } + + T mean_x ( + ) const + { + if (n != 0) + return sum_x/n; + else + return 0; + } + + T mean_y ( + ) const + { + if (n != 0) + return sum_y/n; + else + return 0; + } + + T covariance ( + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT(current_n() > 1, + "\tT running_scalar_covariance_decayed::covariance()" + << "\n\tyou have to add some numbers to this object first" + << "\n\tthis: " << this + ); + + return 1/(n-1) * (sum_xy - sum_y*sum_x/n); + } + + T correlation ( + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT(current_n() > 1, + "\tT running_scalar_covariance_decayed::correlation()" + << "\n\tyou have to add some numbers to this object first" + << "\n\tthis: " << this + ); + + T temp = std::sqrt(variance_x()*variance_y()); + if (temp != 0) + return covariance() / temp; + else + return 0; // just say it's zero if there isn't any variance in x or y. + } + + T variance_x ( + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT(current_n() > 1, + "\tT running_scalar_covariance_decayed::variance_x()" + << "\n\tyou have to add some numbers to this object first" + << "\n\tthis: " << this + ); + + T temp = 1/(n-1) * (sum_xx - sum_x*sum_x/n); + // make sure the variance is never negative. This might + // happen due to numerical errors. + if (temp >= 0) + return temp; + else + return 0; + } + + T variance_y ( + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT(current_n() > 1, + "\tT running_scalar_covariance_decayed::variance_y()" + << "\n\tyou have to add some numbers to this object first" + << "\n\tthis: " << this + ); + + T temp = 1/(n-1) * (sum_yy - sum_y*sum_y/n); + // make sure the variance is never negative. This might + // happen due to numerical errors. + if (temp >= 0) + return temp; + else + return 0; + } + + T stddev_x ( + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT(current_n() > 1, + "\tT running_scalar_covariance_decayed::stddev_x()" + << "\n\tyou have to add some numbers to this object first" + << "\n\tthis: " << this + ); + + return std::sqrt(variance_x()); + } + + T stddev_y ( + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT(current_n() > 1, + "\tT running_scalar_covariance_decayed::stddev_y()" + << "\n\tyou have to add some numbers to this object first" + << "\n\tthis: " << this + ); + + return std::sqrt(variance_y()); + } + + private: + + T sum_xy; + T sum_x; + T sum_y; + T sum_xx; + T sum_yy; + T n; + T forget; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + class running_stats_decayed + { + public: + + explicit running_stats_decayed( + T decay_halflife = 1000 + ) + { + DLIB_ASSERT(decay_halflife > 0); + + sum_x = 0; + sum_xx = 0; + forget = std::pow(0.5, 1/decay_halflife); + n = 0; + + COMPILE_TIME_ASSERT (( + is_same_type::value || + is_same_type::value || + is_same_type::value + )); + } + + T forget_factor ( + ) const + { + return forget; + } + + void add ( + const T& x + ) + { + + sum_xx = sum_xx*forget + x*x; + + sum_x = sum_x*forget + x; + + n = n*forget + 1; + } + + T current_n ( + ) const + { + return n; + } + + T mean ( + ) const + { + if (n != 0) + return sum_x/n; + else + return 0; + } + + T variance ( + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT(current_n() > 1, + "\tT running_stats_decayed::variance()" + << "\n\tyou have to add some numbers to this object first" + << "\n\tthis: " << this + ); + + T temp = 1/(n-1) * (sum_xx - sum_x*sum_x/n); + // make sure the variance is never negative. This might + // happen due to numerical errors. + if (temp >= 0) + return temp; + else + return 0; + } + + T stddev ( + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT(current_n() > 1, + "\tT running_stats_decayed::stddev()" + << "\n\tyou have to add some numbers to this object first" + << "\n\tthis: " << this + ); + + return std::sqrt(variance()); + } + + template + friend void serialize ( + const running_stats_decayed& item, + std::ostream& out + ); + + template + friend void deserialize ( + running_stats_decayed& item, + std::istream& in + ); + + private: + + T sum_x; + T sum_xx; + T n; + T forget; + }; + + template + void serialize ( + const running_stats_decayed& item, + std::ostream& out + ) + { + int version = 1; + serialize(version, out); + + serialize(item.sum_x, out); + serialize(item.sum_xx, out); + serialize(item.n, out); + serialize(item.forget, out); + } + + template + void deserialize ( + running_stats_decayed& item, + std::istream& in + ) + { + int version = 0; + deserialize(version, in); + if (version != 1) + throw dlib::serialization_error("Unexpected version number found while deserializing dlib::running_stats_decayed object."); + + deserialize(item.sum_x, in); + deserialize(item.sum_xx, in); + deserialize(item.n, in); + deserialize(item.forget, in); + } + // ---------------------------------------------------------------------------------------- template < @@ -1493,6 +1818,70 @@ namespace dlib serialize(item.pca, out); } +// ---------------------------------------------------------------------------------------- + + inline double binomial_random_vars_are_different ( + uint64_t k1, + uint64_t n1, + uint64_t k2, + uint64_t n2 + ) + { + DLIB_ASSERT(k1 <= n1, "k1: "<< k1 << " n1: "<< n1); + DLIB_ASSERT(k2 <= n2, "k2: "<< k2 << " n2: "<< n2); + + const double p1 = k1/(double)n1; + const double p2 = k2/(double)n2; + const double p = (k1+k2)/(double)(n1+n2); + + auto ll = [](double p, uint64_t k, uint64_t n) { + if (p == 0 || p == 1) + return 0.0; + return k*std::log(p) + (n-k)*std::log(1-p); + }; + + auto logll = ll(p1,k1,n1) + ll(p2,k2,n2) - ll(p,k1,n1) - ll(p,k2,n2); + + // The basic statistic only tells you if the random variables are different. But + // it's nice to know which way they are different, i.e., which one is bigger. So + // stuff that information into the sign bit of the return value. + if (p1>=p2) + return logll; + else + return -logll; + } + +// ---------------------------------------------------------------------------------------- + + inline double event_correlation ( + uint64_t A_count, + uint64_t B_count, + uint64_t AB_count, + uint64_t total_num_observations + ) + { + DLIB_ASSERT(AB_count <= A_count && A_count <= total_num_observations, + "AB_count: " << AB_count << ", A_count: "<< A_count << ", total_num_observations: " << total_num_observations); + DLIB_ASSERT(AB_count <= B_count && B_count <= total_num_observations, + "AB_count: " << AB_count << ", B_count: "<< B_count << ", total_num_observations: " << total_num_observations); + + if (total_num_observations == 0) + return 0; + + DLIB_ASSERT(A_count + B_count - AB_count <= total_num_observations, + "AB_count: " << AB_count << " A_count: " << A_count << ", B_count: "<< B_count << ", total_num_observations: " << total_num_observations); + + + const auto AnotB_count = A_count - AB_count; + const auto notB_count = total_num_observations - B_count; + // How likely is it that the odds of A happening is different when conditioned on + // whether or not B happened? + return binomial_random_vars_are_different( + AB_count, B_count, // A conditional on the presence of B + AnotB_count, notB_count // A conditional on the absence of B + ); + } + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/statistics/statistics_abstract.h b/lib/3rdParty/dlib/include/dlib/statistics/statistics_abstract.h index 7b711415..ef8f1380 100644 --- a/lib/3rdParty/dlib/include/dlib/statistics/statistics_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/statistics/statistics_abstract.h @@ -105,6 +105,75 @@ namespace dlib (i.e. mean(squared(mat(a)-mat(b)))) !*/ +// ---------------------------------------------------------------------------------------- + + double binomial_random_vars_are_different ( + uint64_t k1, + uint64_t n1, + uint64_t k2, + uint64_t n2 + ); + /*! + requires + - k1 <= n1 + - k2 <= n2 + ensures + - Given two binomially distributed random variables, X1 and X2, we want to know + if these variables have the same parameter (i.e. the chance of "success"). + So assume that: + - You observed X1 to give k1 successes out of n1 trials. + - You observed X2 to give k2 successes out of n2 trials. + - This function performs a simple likelihood ratio test to determine if X1 and + X2 have the same parameter. The return value of this function will be: + - Close to 0 if they are probably the same. + - Larger than 0 if X1 probably has a higher "success" rate than X2. + - Smaller than 0 if X2 probably has a higher "success" rate than X1. + Moreover, the larger the absolute magnitude of the return value the more + likely it is that X1 and X2 have different distributions. + - For a discussion of the technique and applications see: + Dunning, Ted. "Accurate methods for the statistics of surprise and + coincidence." Computational linguistics 19.1 (1993): 61-74. + !*/ + +// ---------------------------------------------------------------------------------------- + + double event_correlation ( + uint64_t A_count, + uint64_t B_count, + uint64_t AB_count, + uint64_t total_num_observations + ); + /*! + requires + - AB_count <= A_count <= total_num_observations + - AB_count <= B_count <= total_num_observations + - A_count + B_count - AB_count <= total_num_observations + ensures + - This function does a statistical test to determine if two events co-occur in + a statistically significant way. In particular, we assume you performed + total_num_observations measurements and during those measurements you: + - Observed event A to happen A_count times. + - Observed event B to happen B_count times. + - Observed AB_count co-occurrences of the events. That is, AB_count is the + number of times the events happened together during the same measurement. + - This function returns a number, COR, which can take any real value. It has + the following interpretations: + - COR == 0: there is no evidence of correlation between the two events. + They appear to be unrelated. + - COR > 0: There is evidence that A and B co-occur together. That is, + they happen at the same times more often than you would expect if they + were independent events. The larger the magnitude of COR the more + evidence we have for the correlation. + - COR < 0: There is evidence that A and B are anti-correlated. That is, + when A happens B is unlikely to happen and vise versa. The larger the + magnitude of COR the more evidence we have for the anti-correlation. + - This function implements the simple likelihood ratio test discussed in the + following paper: + Dunning, Ted. "Accurate methods for the statistics of surprise and + coincidence." Computational linguistics 19.1 (1993): 61-74. + So for an extended discussion of the method see the above paper. + !*/ + // ---------------------------------------------------------------------------------------- template < @@ -414,6 +483,262 @@ namespace dlib !*/ }; +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + class running_scalar_covariance_decayed + { + /*! + REQUIREMENTS ON T + - T must be a float, double, or long double type + + INITIAL VALUE + - mean_x() == 0 + - mean_y() == 0 + - current_n() == 0 + + WHAT THIS OBJECT REPRESENTS + This object represents something that can compute the running covariance of + a stream of real number pairs. It is essentially the same as + running_scalar_covariance except that it forgets about data it has seen + after a certain period of time. It does this by exponentially decaying old + statistics. + !*/ + + public: + + running_scalar_covariance_decayed( + T decay_halflife = 1000 + ); + /*! + requires + - decay_halflife > 0 + ensures + - #forget_factor() == std::pow(0.5, 1/decay_halflife); + (i.e. after decay_halflife calls to add() the data given to the first add + will be down weighted by 0.5 in the statistics stored in this object). + !*/ + + T forget_factor ( + ) const; + /*! + ensures + - returns the exponential forget factor used to forget old statistics when + add() is called. + !*/ + + void add ( + const T& x, + const T& y + ); + /*! + ensures + - updates the statistics stored in this object so that + the new pair (x,y) is factored into them. + - #current_n() == current_n()*forget_factor() + forget_factor() + - Down weights old statistics by a factor of forget_factor(). + !*/ + + T current_n ( + ) const; + /*! + ensures + - returns the effective number of points given to this object. As add() + is called this value will converge to a constant, the value of which is + based on the decay_halflife supplied to the constructor. + !*/ + + T mean_x ( + ) const; + /*! + ensures + - returns the mean value of all x samples presented to this object + via add(). + !*/ + + T mean_y ( + ) const; + /*! + ensures + - returns the mean value of all y samples presented to this object + via add(). + !*/ + + T covariance ( + ) const; + /*! + requires + - current_n() > 1 + ensures + - returns the covariance between all the x and y samples presented + to this object via add() + !*/ + + T correlation ( + ) const; + /*! + requires + - current_n() > 1 + ensures + - returns the correlation coefficient between all the x and y samples + presented to this object via add() + !*/ + + T variance_x ( + ) const; + /*! + requires + - current_n() > 1 + ensures + - returns the sample variance value of all x samples presented + to this object via add(). + !*/ + + T variance_y ( + ) const; + /*! + requires + - current_n() > 1 + ensures + - returns the sample variance value of all y samples presented + to this object via add(). + !*/ + + T stddev_x ( + ) const; + /*! + requires + - current_n() > 1 + ensures + - returns the sample standard deviation of all x samples + presented to this object via add(). + !*/ + + T stddev_y ( + ) const; + /*! + requires + - current_n() > 1 + ensures + - returns the sample standard deviation of all y samples + presented to this object via add(). + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + class running_stats_decayed + { + /*! + REQUIREMENTS ON T + - T must be a float, double, or long double type + + INITIAL VALUE + - mean() == 0 + - current_n() == 0 + + WHAT THIS OBJECT REPRESENTS + This object represents something that can compute the running mean and + variance of a stream of real numbers. It is similar to running_stats + except that it forgets about data it has seen after a certain period of + time. It does this by exponentially decaying old statistics. + !*/ + + public: + + running_stats_decayed( + T decay_halflife = 1000 + ); + /*! + requires + - decay_halflife > 0 + ensures + - #forget_factor() == std::pow(0.5, 1/decay_halflife); + (i.e. after decay_halflife calls to add() the data given to the first add + will be down weighted by 0.5 in the statistics stored in this object). + !*/ + + T forget_factor ( + ) const; + /*! + ensures + - returns the exponential forget factor used to forget old statistics when + add() is called. + !*/ + + void add ( + const T& x + ); + /*! + ensures + - updates the statistics stored in this object so that x is factored into + them. + - #current_n() == current_n()*forget_factor() + forget_factor() + - Down weights old statistics by a factor of forget_factor(). + !*/ + + T current_n ( + ) const; + /*! + ensures + - returns the effective number of points given to this object. As add() + is called this value will converge to a constant, the value of which is + based on the decay_halflife supplied to the constructor. + !*/ + + T mean ( + ) const; + /*! + ensures + - returns the mean value of all x samples presented to this object + via add(). + !*/ + + T variance ( + ) const; + /*! + requires + - current_n() > 1 + ensures + - returns the sample variance value of all x samples presented to this + object via add(). + !*/ + + T stddev ( + ) const; + /*! + requires + - current_n() > 1 + ensures + - returns the sample standard deviation of all x samples presented to this + object via add(). + !*/ + + }; + + template + void serialize ( + const running_stats_decayed& item, + std::ostream& out + ); + /*! + provides serialization support + !*/ + + template + void deserialize ( + running_stats_decayed& item, + std::istream& in + ); + /*! + provides serialization support + !*/ + // ---------------------------------------------------------------------------------------- template < diff --git a/lib/3rdParty/dlib/include/dlib/statistics/vector_normalizer_frobmetric.h b/lib/3rdParty/dlib/include/dlib/statistics/vector_normalizer_frobmetric.h index ac91685b..690370f8 100644 --- a/lib/3rdParty/dlib/include/dlib/statistics/vector_normalizer_frobmetric.h +++ b/lib/3rdParty/dlib/include/dlib/statistics/vector_normalizer_frobmetric.h @@ -81,8 +81,9 @@ namespace dlib { objective ( const std::vector& samples_, - matrix& Aminus_ - ) : samples(samples_), Aminus(Aminus_) {} + matrix& Aminus_, + const matrix& bias_ + ) : samples(samples_), Aminus(Aminus_), bias(bias_) {} double operator()(const matrix& u) const { @@ -118,12 +119,13 @@ namespace dlib // computation can make Aminus slightly non-symmetric. Aminus = make_symmetric(Aminus); - return sum(u) - 0.5*sum(squared(Aminus)); + return dot(u,bias) - 0.5*sum(squared(Aminus)); } private: const std::vector& samples; matrix& Aminus; + const matrix& bias; }; struct derivative @@ -131,8 +133,9 @@ namespace dlib derivative ( unsigned long num_triples_, const std::vector& samples_, - matrix& Aminus_ - ) : num_triples(num_triples_), samples(samples_), Aminus(Aminus_) {} + matrix& Aminus_, + const matrix& bias_ + ) : num_triples(num_triples_), samples(samples_), Aminus(Aminus_), bias(bias_) {} matrix operator()(const matrix& ) const { @@ -158,7 +161,8 @@ namespace dlib { for (unsigned long k = 0; k < samples[i].far_vects.size(); ++k) { - grad(idx++) = 1 + ufar[k]-unear[j]; + grad(idx) = bias(idx) + ufar[k]-unear[j]; + idx++; } } } @@ -170,6 +174,7 @@ namespace dlib const unsigned long num_triples; const std::vector& samples; matrix& Aminus; + const matrix& bias; }; @@ -245,6 +250,20 @@ namespace dlib eps = 0.1; C = 1; max_iter = 5000; + _use_identity_matrix_prior = false; + } + + bool uses_identity_matrix_prior ( + ) const + { + return _use_identity_matrix_prior; + } + + void set_uses_identity_matrix_prior ( + bool use_prior + ) + { + _use_identity_matrix_prior = use_prior; } void be_verbose( @@ -402,27 +421,50 @@ namespace dlib num_triples += samples[i].near_vects.size()*samples[i].far_vects.size(); matrix u(num_triples); + matrix bias(num_triples); u = 0; + bias = 1; // precompute all the anchor_vect to far_vects/near_vects pairs std::vector data(samples.size()); + unsigned long cnt = 0; + std::vector far_norm, near_norm; for (unsigned long i = 0; i < data.size(); ++i) { + far_norm.clear(); + near_norm.clear(); data[i].far_vects.reserve(samples[i].far_vects.size()); data[i].near_vects.reserve(samples[i].near_vects.size()); for (unsigned long j = 0; j < samples[i].far_vects.size(); ++j) + { data[i].far_vects.push_back(samples[i].anchor_vect - samples[i].far_vects[j]); + if (_use_identity_matrix_prior) + far_norm.push_back(length_squared(data[i].far_vects.back())); + } for (unsigned long j = 0; j < samples[i].near_vects.size(); ++j) + { data[i].near_vects.push_back(samples[i].anchor_vect - samples[i].near_vects[j]); + if (_use_identity_matrix_prior) + near_norm.push_back(length_squared(data[i].near_vects.back())); + } + + // Note that this loop only executes if _use_identity_matrix_prior == true. + for (unsigned long j = 0; j < near_norm.size(); ++j) + { + for (unsigned long k = 0; k < far_norm.size(); ++k) + { + bias(cnt++) = 1 - (far_norm[k] - near_norm[j]); + } + } } // Now run the main part of the algorithm matrix Aminus; find_max_box_constrained(lbfgs_search_strategy(10), custom_stop_strategy(C, eps, verbose, max_iter), - objective(data, Aminus), - derivative(num_triples, data, Aminus), + objective(data, Aminus, bias), + derivative(num_triples, data, Aminus, bias), u, 0, C/num_triples); @@ -437,7 +479,10 @@ namespace dlib if (eigs(i) < tol) eigs(i) = 0; } - tform = matrix_cast(diagm(sqrt(eigs))*trans(ed.get_pseudo_v())); + if (_use_identity_matrix_prior) + tform = matrix_cast(identity_matrix(Aminus) + diagm(sqrt(eigs))*trans(ed.get_pseudo_v())); + else + tform = matrix_cast(diagm(sqrt(eigs))*trans(ed.get_pseudo_v())); // Pre-apply the transform to m so we don't have to do it inside operator() // every time it's called. @@ -509,6 +554,7 @@ namespace dlib double eps; double C; unsigned long max_iter; + bool _use_identity_matrix_prior; // This is just a temporary variable that doesn't contribute to the // state of this object. @@ -525,7 +571,7 @@ namespace dlib std::ostream& out ) { - const int version = 1; + const int version = 2; serialize(version, out); serialize(item.m, out); @@ -534,6 +580,7 @@ namespace dlib serialize(item.eps, out); serialize(item.C, out); serialize(item.max_iter, out); + serialize(item._use_identity_matrix_prior, out); } // ---------------------------------------------------------------------------------------- @@ -548,7 +595,7 @@ namespace dlib { int version = 0; deserialize(version, in); - if (version != 1) + if (version != 1 && version != 2) throw serialization_error("Unsupported version found while deserializing dlib::vector_normalizer_frobmetric."); deserialize(item.m, in); @@ -557,6 +604,10 @@ namespace dlib deserialize(item.eps, in); deserialize(item.C, in); deserialize(item.max_iter, in); + if (version == 2) + deserialize(item._use_identity_matrix_prior, in); + else + item._use_identity_matrix_prior = false; } // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/statistics/vector_normalizer_frobmetric_abstract.h b/lib/3rdParty/dlib/include/dlib/statistics/vector_normalizer_frobmetric_abstract.h index 645db7c5..30262833 100644 --- a/lib/3rdParty/dlib/include/dlib/statistics/vector_normalizer_frobmetric_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/statistics/vector_normalizer_frobmetric_abstract.h @@ -73,6 +73,7 @@ namespace dlib - get_c() == 1 - get_max_iterations() == 5000 - This object is not verbose + - uses_identity_matrix_prior() == false WHAT THIS OBJECT REPRESENTS This object is a tool for performing the FrobMetric distance metric @@ -110,6 +111,27 @@ namespace dlib - this object is properly initialized !*/ + bool uses_identity_matrix_prior ( + ) const; + /*! + ensures + - Normally this object will try and find a matrix transform() that + minimizes sum(squared(transform())) but also fits the training data. + However, if #uses_identity_matrix_prior() == true then it will instead + try to find the transformation matrix that minimizes + sum(squared(identity_matrix()-transform())). That is, it will try to + find the matrix most similar to the identity matrix that best fits the + training data. + !*/ + + void set_uses_identity_matrix_prior ( + bool use_prior + ); + /*! + ensures + - #uses_identity_matrix_prior() == use_prior + !*/ + void be_verbose( ); /*! diff --git a/lib/3rdParty/dlib/include/dlib/string/iomanip b/lib/3rdParty/dlib/include/dlib/string/iomanip deleted file mode 100644 index 6139ba82..00000000 --- a/lib/3rdParty/dlib/include/dlib/string/iomanip +++ /dev/null @@ -1 +0,0 @@ -#include "../dlib_include_path_tutorial.txt" diff --git a/lib/3rdParty/dlib/include/dlib/string/iosfwd b/lib/3rdParty/dlib/include/dlib/string/iosfwd deleted file mode 100644 index 6139ba82..00000000 --- a/lib/3rdParty/dlib/include/dlib/string/iosfwd +++ /dev/null @@ -1 +0,0 @@ -#include "../dlib_include_path_tutorial.txt" diff --git a/lib/3rdParty/dlib/include/dlib/string/iostream b/lib/3rdParty/dlib/include/dlib/string/iostream deleted file mode 100644 index 6139ba82..00000000 --- a/lib/3rdParty/dlib/include/dlib/string/iostream +++ /dev/null @@ -1 +0,0 @@ -#include "../dlib_include_path_tutorial.txt" diff --git a/lib/3rdParty/dlib/include/dlib/string/locale b/lib/3rdParty/dlib/include/dlib/string/locale deleted file mode 100644 index 6139ba82..00000000 --- a/lib/3rdParty/dlib/include/dlib/string/locale +++ /dev/null @@ -1 +0,0 @@ -#include "../dlib_include_path_tutorial.txt" diff --git a/lib/3rdParty/dlib/include/dlib/svm.h b/lib/3rdParty/dlib/include/dlib/svm.h index 62b60ade..4dc7382c 100644 --- a/lib/3rdParty/dlib/include/dlib/svm.h +++ b/lib/3rdParty/dlib/include/dlib/svm.h @@ -1,5 +1,10 @@ // Copyright (C) 2007 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. + +#ifdef DLIB_ALL_SOURCE_END +#include "dlib_basic_cpp_build_tutorial.txt" +#endif + #ifndef DLIB_SVm_HEADER #define DLIB_SVm_HEADER diff --git a/lib/3rdParty/dlib/include/dlib/svm/cross_validate_object_detection_trainer.h b/lib/3rdParty/dlib/include/dlib/svm/cross_validate_object_detection_trainer.h index 2c2d004c..7cb38f0b 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/cross_validate_object_detection_trainer.h +++ b/lib/3rdParty/dlib/include/dlib/svm/cross_validate_object_detection_trainer.h @@ -25,7 +25,8 @@ namespace dlib const std::vector >& boxes, const test_box_overlap& overlap_tester, std::vector >& all_dets, - unsigned long& missing_detections + unsigned long& missing_detections, + const test_box_overlap& overlaps_ignore_tester ) /*! ensures @@ -74,7 +75,7 @@ namespace dlib for (unsigned long i = 0; i < boxes.size(); ++i) { // only out put boxes if they match a truth box or are not ignored. - if (used[i] || !overlaps_any_box(overlap_tester, ignore, boxes[i].second)) + if (used[i] || !overlaps_any_box(overlaps_ignore_tester, ignore, boxes[i].second)) { all_dets.push_back(std::make_pair(boxes[i].first, used[i])); } @@ -83,6 +84,18 @@ namespace dlib return count; } + inline unsigned long number_of_truth_hits ( + const std::vector& truth_boxes, + const std::vector& ignore, + const std::vector >& boxes, + const test_box_overlap& overlap_tester, + std::vector >& all_dets, + unsigned long& missing_detections + ) + { + return number_of_truth_hits(truth_boxes, ignore, boxes, overlap_tester, all_dets, missing_detections, overlap_tester); + } + // ------------------------------------------------------------------------------------ } diff --git a/lib/3rdParty/dlib/include/dlib/svm/cross_validate_object_detection_trainer_abstract.h b/lib/3rdParty/dlib/include/dlib/svm/cross_validate_object_detection_trainer_abstract.h index 15d5972f..575ed77f 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/cross_validate_object_detection_trainer_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/svm/cross_validate_object_detection_trainer_abstract.h @@ -7,6 +7,7 @@ #include "../matrix.h" #include "../geometry.h" #include "../image_processing/full_object_detection_abstract.h" +#include "../dnn/layers_abstract.h" namespace dlib { @@ -130,6 +131,65 @@ namespace dlib given arguments and an empty set of ignore rectangles and returns the results. !*/ +// ---------------------------------------------------------------------------------------- + + template < + typename SUBNET, + typename image_array_type + > + const matrix test_object_detection_function ( + loss_mmod& detector, + const image_array_type& images, + const std::vector>& truth_dets, + const test_box_overlap& overlap_tester = test_box_overlap(), + const double adjust_threshold = 0, + const test_box_overlap& overlaps_ignore_tester = test_box_overlap() + ); + /*! + requires + - is_learning_problem(images,truth_dets) + - image_array_type must be an implementation of dlib/array/array_kernel_abstract.h + and it must contain objects which can be accepted by detector(). + ensures + - This function is just like the test_object_detection_function() for + object_detector's except it runs on CNNs that use loss_mmod. + - Tests the given detector against the supplied object detection problem and + returns the precision, recall, and average precision. Note that the task is + to predict, for each images[i], the set of object locations, and their + corresponding labels, given by truth_dets[i]. Additionally, any detections + on image[i] that match a box in truth_dets[i] that are marked ignore are + ignored. That is, detections matching an ignore box, regardless of the + ignore box's label, do not count as a false alarm and similarly if any + ignored box in truth_dets goes undetected it does not count as a missed + detection. To test if a box overlaps an ignore box, we use overlaps_ignore_tester. + - In particular, returns a matrix M such that: + - M(0) == the precision of the detector object. This is a number + in the range [0,1] which measures the fraction of detector outputs + which correspond to a real target. A value of 1 means the detector + never produces any false alarms while a value of 0 means it only + produces false alarms. + - M(1) == the recall of the detector object. This is a number in the + range [0,1] which measures the fraction of targets found by the detector. + A value of 1 means the detector found all the non-ignore targets in + truth_dets while a value of 0 means the detector didn't locate any of the + targets. + - M(2) == the average precision of the detector object. This is a number + in the range [0,1] which measures the overall quality of the detector. + We compute this by taking all the detections output by the detector and + ordering them in descending order of their detection scores. Then we use + the average_precision() routine to score the ranked listing and store the + output into M(2). + - This function considers a detector output D to match a truth rectangle T if + and only if overlap_tester(T,D) returns true and the labels are identical strings. + - Note that you can use the adjust_threshold argument to raise or lower the + detection threshold. This value is passed into the identically named + argument to the detector object and therefore influences the number of + output detections. It can be useful, for example, to lower the detection + threshold because it results in more detections being output by the + detector, and therefore provides more information in the ranking, + possibly raising the average precision. + !*/ + // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/svm/cross_validate_regression_trainer.h b/lib/3rdParty/dlib/include/dlib/svm/cross_validate_regression_trainer.h index a352781f..a4c6077c 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/cross_validate_regression_trainer.h +++ b/lib/3rdParty/dlib/include/dlib/svm/cross_validate_regression_trainer.h @@ -18,9 +18,9 @@ namespace dlib typename sample_type, typename label_type > - matrix + matrix test_regression_function ( - const reg_funct_type& reg_funct, + reg_funct_type& reg_funct, const std::vector& x_test, const std::vector& y_test ) @@ -33,7 +33,7 @@ namespace dlib << "\n\t is_learning_problem(x_test,y_test): " << is_learning_problem(x_test,y_test)); - running_stats rs; + running_stats rs, rs_mae; running_scalar_covariance rc; for (unsigned long i = 0; i < x_test.size(); ++i) @@ -42,12 +42,13 @@ namespace dlib const double output = reg_funct(x_test[i]); const double temp = output - y_test[i]; + rs_mae.add(std::abs(temp)); rs.add(temp*temp); rc.add(output, y_test[i]); } - matrix result; - result = rs.mean(), std::pow(rc.correlation(),2); + matrix result; + result = rs.mean(), rc.correlation(), rs_mae.mean(), rs_mae.stddev(); return result; } @@ -58,7 +59,7 @@ namespace dlib typename sample_type, typename label_type > - matrix + matrix cross_validate_regression_trainer ( const trainer_type& trainer, const std::vector& x, @@ -82,7 +83,7 @@ namespace dlib const long num_in_test = x.size()/folds; const long num_in_train = x.size() - num_in_test; - running_stats rs; + running_stats rs, rs_mae; running_scalar_covariance rc; std::vector x_test, x_train; @@ -128,6 +129,7 @@ namespace dlib const double output = df(x_test[j]); const double temp = output - y_test[j]; + rs_mae.add(std::abs(temp)); rs.add(temp*temp); rc.add(output, y_test[j]); } @@ -139,8 +141,8 @@ namespace dlib } // for (long i = 0; i < folds; ++i) - matrix result; - result = rs.mean(), std::pow(rc.correlation(),2); + matrix result; + result = rs.mean(), rc.correlation(), rs_mae.mean(), rs_mae.stddev(); return result; } diff --git a/lib/3rdParty/dlib/include/dlib/svm/cross_validate_regression_trainer_abstract.h b/lib/3rdParty/dlib/include/dlib/svm/cross_validate_regression_trainer_abstract.h index f73fdb42..d6298aa7 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/cross_validate_regression_trainer_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/svm/cross_validate_regression_trainer_abstract.h @@ -16,9 +16,9 @@ namespace dlib typename sample_type, typename label_type > - matrix + matrix test_regression_function ( - const reg_funct_type& reg_funct, + reg_funct_type& reg_funct, const std::vector& x_test, const std::vector& y_test ); @@ -32,9 +32,11 @@ namespace dlib y_test and returns a matrix M summarizing the results. Specifically: - M(0) == the mean squared error. The MSE is given by: sum over i: pow(reg_funct(x_test[i]) - y_test[i], 2.0) - - M(1) == the R-squared value (i.e. the squared correlation between - reg_funct(x_test[i]) and y_test[i]). This is a number between 0 - and 1. + - M(1) == the correlation between reg_funct(x_test[i]) and y_test[i]. + This is a number between -1 and 1. + - M(2) == the mean absolute error. + This is given by: sum over i: abs(reg_funct(x_test[i]) - y_test[i]) + - M(3) == the standard deviation of the absolute error. !*/ // ---------------------------------------------------------------------------------------- @@ -44,7 +46,7 @@ namespace dlib typename sample_type, typename label_type > - matrix + matrix cross_validate_regression_trainer ( const trainer_type& trainer, const std::vector& x, @@ -63,9 +65,11 @@ namespace dlib Specifically: - M(0) == the mean squared error. The MSE is given by: sum over i: pow(reg_funct(x[i]) - y[i], 2.0) - - M(1) == the R-squared value (i.e. the squared correlation between - a predicted y value and its true value). This is a number between - 0 and 1. + - M(1) == the correlation between a predicted y value and its true value. + This is a number between -1 and 1. + - M(2) == the mean absolute error. + This is given by: sum over i: abs(reg_funct(x_test[i]) - y_test[i]) + - M(3) == the standard deviation of the absolute error. !*/ } diff --git a/lib/3rdParty/dlib/include/dlib/svm/kernel.h b/lib/3rdParty/dlib/include/dlib/svm/kernel.h index 66f0af5c..90742098 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/kernel.h +++ b/lib/3rdParty/dlib/include/dlib/svm/kernel.h @@ -29,6 +29,9 @@ namespace dlib typedef T sample_type; typedef typename T::mem_manager_type mem_manager_type; + // T must be capable of representing a column vector. + COMPILE_TIME_ASSERT(T::NC == 1 || T::NC == 0); + radial_basis_kernel(const scalar_type g) : gamma(g) {} radial_basis_kernel() : gamma(0.1) {} radial_basis_kernel( @@ -133,6 +136,9 @@ namespace dlib typedef T sample_type; typedef typename T::mem_manager_type mem_manager_type; + // T must be capable of representing a column vector. + COMPILE_TIME_ASSERT(T::NC == 1 || T::NC == 0); + polynomial_kernel(const scalar_type g, const scalar_type c, const scalar_type d) : gamma(g), coef(c), degree(d) {} polynomial_kernel() : gamma(1), coef(0), degree(1) {} polynomial_kernel( @@ -244,6 +250,9 @@ namespace dlib typedef T sample_type; typedef typename T::mem_manager_type mem_manager_type; + // T must be capable of representing a column vector. + COMPILE_TIME_ASSERT(T::NC == 1 || T::NC == 0); + sigmoid_kernel(const scalar_type g, const scalar_type c) : gamma(g), coef(c) {} sigmoid_kernel() : gamma(0.1), coef(-1.0) {} sigmoid_kernel( @@ -349,6 +358,9 @@ namespace dlib typedef T sample_type; typedef typename T::mem_manager_type mem_manager_type; + // T must be capable of representing a column vector. + COMPILE_TIME_ASSERT(T::NC == 1 || T::NC == 0); + scalar_type operator() ( const sample_type& a, const sample_type& b diff --git a/lib/3rdParty/dlib/include/dlib/svm/kernel_matrix.h b/lib/3rdParty/dlib/include/dlib/svm/kernel_matrix.h index 5410a4e5..f6e1e0b9 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/kernel_matrix.h +++ b/lib/3rdParty/dlib/include/dlib/svm/kernel_matrix.h @@ -65,7 +65,7 @@ namespace dlib } template - inline unsigned long size ( + inline size_t size ( const typename kernel_type::sample_type& ) { diff --git a/lib/3rdParty/dlib/include/dlib/svm/kkmeans.h b/lib/3rdParty/dlib/include/dlib/svm/kkmeans.h index 5c3e9471..4c72106d 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/kkmeans.h +++ b/lib/3rdParty/dlib/include/dlib/svm/kkmeans.h @@ -4,6 +4,8 @@ #define DLIB_KKMEANs_ #include +#include + #include "../matrix/matrix_abstract.h" #include "../algs.h" #include "../serialize.h" @@ -12,8 +14,6 @@ #include "kcentroid.h" #include "kkmeans_abstract.h" #include "../noncopyable.h" -#include "../smart_pointers.h" -#include namespace dlib { @@ -176,7 +176,7 @@ namespace dlib item.centers.resize(num); for (unsigned long i = 0; i < item.centers.size(); ++i) { - scoped_ptr > temp(new kcentroid(kernel_type())); + std::unique_ptr > temp(new kcentroid(kernel_type())); deserialize(*temp, in); item.centers[i].swap(temp); } @@ -270,7 +270,7 @@ namespace dlib } - array > > centers; + array > > centers; kcentroid kc; scalar_type min_change; @@ -288,7 +288,7 @@ namespace dlib struct dlib_pick_initial_centers_data { - dlib_pick_initial_centers_data():idx(0), dist(1e200){} + dlib_pick_initial_centers_data():idx(0), dist(std::numeric_limits::infinity()){} long idx; double dist; bool operator< (const dlib_pick_initial_centers_data& d) const { return dist < d.dist; } @@ -331,7 +331,7 @@ namespace dlib // pick the first sample as one of the centers centers.push_back(samples[0]); - const long best_idx = static_cast(samples.size() - samples.size()*percentile - 1); + const long best_idx = static_cast(std::max(0.0,samples.size() - samples.size()*percentile - 1)); // pick the next center for (long i = 0; i < num_centers-1; ++i) @@ -425,10 +425,10 @@ namespace dlib sample_type zero(centers[0]); set_all_elements(zero, 0); - std::vector center_element_count; + std::vector center_element_count; // tells which center a sample belongs to - std::vector assignments(samples.size(), samples.size()); + std::vector assignments(samples.size(), samples.size()); unsigned long iter = 0; @@ -477,6 +477,138 @@ namespace dlib } } + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array_type, + typename sample_type, + typename alloc + > + void find_clusters_using_angular_kmeans ( + const array_type& samples, + std::vector& centers, + unsigned long max_iter = 1000 + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(samples.size() > 0 && centers.size() > 0, + "\tvoid find_clusters_using_angular_kmeans()" + << "\n\tYou passed invalid arguments to this function" + << "\n\t samples.size(): " << samples.size() + << "\n\t centers.size(): " << centers.size() + ); + +#ifdef ENABLE_ASSERTS + { + const long nr = samples[0].nr(); + const long nc = samples[0].nc(); + for (unsigned long i = 0; i < samples.size(); ++i) + { + DLIB_ASSERT(is_vector(samples[i]) && samples[i].nr() == nr && samples[i].nc() == nc, + "\tvoid find_clusters_using_angular_kmeans()" + << "\n\t You passed invalid arguments to this function" + << "\n\t is_vector(samples[i]): " << is_vector(samples[i]) + << "\n\t samples[i].nr(): " << samples[i].nr() + << "\n\t nr: " << nr + << "\n\t samples[i].nc(): " << samples[i].nc() + << "\n\t nc: " << nc + << "\n\t i: " << i + ); + } + } +#endif + + typedef typename sample_type::type scalar_type; + + sample_type zero(centers[0]); + set_all_elements(zero, 0); + + unsigned long seed = 0; + + // tells which center a sample belongs to + std::vector assignments(samples.size(), samples.size()); + std::vector lengths; + for (unsigned long i = 0; i < samples.size(); ++i) + { + lengths.push_back(length(samples[i])); + // If there are zero vectors in samples then just say their length is 1 so we + // can avoid a division by zero check later on. Also, this doesn't matter + // since zero vectors can be assigned to any cluster randomly as there is no + // basis for picking one based on angle. + if (lengths.back() == 0) + lengths.back() = 1; + } + + // We will keep the centers as unit vectors at all times throughout the processing. + for (unsigned long i = 0; i < centers.size(); ++i) + { + double len = length(centers[i]); + // Avoid having length 0 centers. If that is the case then pick another center + // at random. + while(len == 0) + { + centers[i] = matrix_cast(gaussian_randm(centers[i].nr(), centers[i].nc(), seed++)); + len = length(centers[i]); + } + centers[i] /= len; + } + + + unsigned long iter = 0; + bool centers_changed = true; + while (centers_changed && iter < max_iter) + { + ++iter; + centers_changed = false; + + // loop over each sample and see which center it is closest to + for (unsigned long i = 0; i < samples.size(); ++i) + { + // find the best center for sample[i] + scalar_type best_angle = std::numeric_limits::max(); + unsigned long best_center = 0; + for (unsigned long j = 0; j < centers.size(); ++j) + { + scalar_type angle = -dot(centers[j],samples[i])/lengths[i]; + + if (angle < best_angle) + { + best_angle = angle; + best_center = j; + } + } + + if (assignments[i] != best_center) + { + centers_changed = true; + assignments[i] = best_center; + } + } + + // now update all the centers + centers.assign(centers.size(), zero); + for (unsigned long i = 0; i < samples.size(); ++i) + { + centers[assignments[i]] += samples[i]; + } + // Now length normalize all the centers. + for (unsigned long i = 0; i < centers.size(); ++i) + { + double len = length(centers[i]); + // Avoid having length 0 centers. If that is the case then pick another center + // at random. + while(len == 0) + { + centers[i] = matrix_cast(gaussian_randm(centers[i].nr(), centers[i].nc(), seed++)); + len = length(centers[i]); + centers_changed = true; + } + centers[i] /= len; + } + } } // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/svm/kkmeans_abstract.h b/lib/3rdParty/dlib/include/dlib/svm/kkmeans_abstract.h index 5e44ff97..9f9d7ccc 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/kkmeans_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/svm/kkmeans_abstract.h @@ -283,7 +283,7 @@ namespace dlib - centers.size() > 0 - array_type == something with an interface compatible with std::vector and it must contain row or column vectors capable of being stored in - sample_type objects + sample_type objects. - sample_type == a dlib::matrix capable of representing vectors ensures - performs regular old linear kmeans clustering on the samples. The clustering @@ -293,6 +293,46 @@ namespace dlib terminates. !*/ +// ---------------------------------------------------------------------------------------- + + template < + typename array_type, + typename sample_type, + typename alloc + > + void find_clusters_using_angular_kmeans ( + const array_type& samples, + std::vector& centers, + unsigned long max_iter = 1000 + ); + /*! + requires + - samples.size() > 0 + - samples == a bunch of row or column vectors and they all must be of the + same length. + - centers.size() > 0 + - array_type == something with an interface compatible with std::vector + and it must contain row or column vectors capable of being stored in + sample_type objects. + - sample_type == a dlib::matrix capable of representing vectors + ensures + - performs linear kmeans clustering on the samples, except instead of using + Euclidean distance to compare samples to the centers it uses the angle + between a sample and a center (with respect to the origin). So we try to + cluster samples together if they have small angles with respect to each + other. The clustering begins with the initial set of centers given as an + argument to this function. When it finishes #centers will contain the + resulting centers. + - for all valid i: + - length(#centers[i]) == 1 + (i.e. the output centers are scaled to be unit vectors since their + magnitude is irrelevant. Moreover, this makes it so you can use + functions like nearest_center() with #centers to find the cluster + assignments.) + - No more than max_iter iterations will be performed before this function + terminates. + !*/ + // ---------------------------------------------------------------------------------------- template < diff --git a/lib/3rdParty/dlib/include/dlib/svm/linearly_independent_subset_finder.h b/lib/3rdParty/dlib/include/dlib/svm/linearly_independent_subset_finder.h index ef429dff..3bac0df2 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/linearly_independent_subset_finder.h +++ b/lib/3rdParty/dlib/include/dlib/svm/linearly_independent_subset_finder.h @@ -296,7 +296,7 @@ namespace dlib temp.swap(item.temp); } - unsigned long size ( + size_t size ( ) const { return dictionary.size(); } const matrix get_dictionary ( diff --git a/lib/3rdParty/dlib/include/dlib/svm/linearly_independent_subset_finder_abstract.h b/lib/3rdParty/dlib/include/dlib/svm/linearly_independent_subset_finder_abstract.h index 1454794f..3224f9a0 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/linearly_independent_subset_finder_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/svm/linearly_independent_subset_finder_abstract.h @@ -173,7 +173,7 @@ namespace dlib - swaps *this with item !*/ - unsigned long size ( + size_t size ( ) const; /*! ensures diff --git a/lib/3rdParty/dlib/include/dlib/svm/pegasos.h b/lib/3rdParty/dlib/include/dlib/svm/pegasos.h index 6e3834cf..c28093fe 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/pegasos.h +++ b/lib/3rdParty/dlib/include/dlib/svm/pegasos.h @@ -10,7 +10,7 @@ #include "kernel.h" #include "kcentroid.h" #include -#include "../smart_pointers.h" +#include namespace dlib { @@ -355,7 +355,7 @@ namespace dlib //typedef typename K::sample_type sample_type; typedef typename K::mem_manager_type mem_manager_type; - caching_kernel () : samples(0), counter(0), counter_threshold(0) {} + caching_kernel () {} caching_kernel ( const K& kern, @@ -458,12 +458,12 @@ namespace dlib std::vector > frequency_of_use; }; - const sample_vector_type* samples; + const sample_vector_type* samples = 0; - shared_ptr cache; - mutable unsigned long counter; - unsigned long counter_threshold; - long cache_size; + std::shared_ptr cache; + mutable unsigned long counter = 0; + unsigned long counter_threshold = 0; + long cache_size = 0; }; // ------------------------------------------------------------------------------------ diff --git a/lib/3rdParty/dlib/include/dlib/svm/rls.h b/lib/3rdParty/dlib/include/dlib/svm/rls.h index 51609c6c..edee6b06 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/rls.h +++ b/lib/3rdParty/dlib/include/dlib/svm/rls.h @@ -20,7 +20,8 @@ namespace dlib explicit rls( double forget_factor_, - double C_ = 1000 + double C_ = 1000, + bool apply_forget_factor_to_C_ = false ) { // make sure requires clause is not broken @@ -36,6 +37,7 @@ namespace dlib C = C_; forget_factor = forget_factor_; + apply_forget_factor_to_C = apply_forget_factor_to_C_; } rls( @@ -43,6 +45,7 @@ namespace dlib { C = 1000; forget_factor = 1; + apply_forget_factor_to_C = false; } double get_c( @@ -57,6 +60,12 @@ namespace dlib return forget_factor; } + bool should_apply_forget_factor_to_C ( + ) const + { + return apply_forget_factor_to_C; + } + template void train ( const matrix_exp& x, @@ -84,20 +93,25 @@ namespace dlib // multiply by forget factor and incorporate x*trans(x) into R. const double l = 1.0/forget_factor; const double temp = 1 + l*trans(x)*R*x; - matrix tmp = R*x; + tmp = R*x; R = l*R - l*l*(tmp*trans(tmp))/temp; // Since we multiplied by the forget factor, we need to add (1-forget_factor) of the // identity matrix back in to keep the regularization alive. - add_eye_to_inv(R, (1-forget_factor)/C); + if (forget_factor != 1 && !apply_forget_factor_to_C) + add_eye_to_inv(R, (1-forget_factor)/C); // R should always be symmetric. This line improves numeric stability of this algorithm. - R = 0.5*(R + trans(R)); + if (cnt%10 == 0) + R = 0.5*(R + trans(R)); + ++cnt; w = w + R*x*(y - trans(x)*w); } + + const matrix& get_w( ) const { @@ -145,25 +159,37 @@ namespace dlib friend inline void serialize(const rls& item, std::ostream& out) { - int version = 1; + int version = 2; serialize(version, out); serialize(item.w, out); serialize(item.R, out); serialize(item.C, out); serialize(item.forget_factor, out); + serialize(item.cnt, out); + serialize(item.apply_forget_factor_to_C, out); } friend inline void deserialize(rls& item, std::istream& in) { int version = 0; deserialize(version, in); - if (version != 1) + if (!(1 <= version && version <= 2)) throw dlib::serialization_error("Unknown version number found while deserializing rls object."); - deserialize(item.w, in); - deserialize(item.R, in); - deserialize(item.C, in); - deserialize(item.forget_factor, in); + if (version >= 1) + { + deserialize(item.w, in); + deserialize(item.R, in); + deserialize(item.C, in); + deserialize(item.forget_factor, in); + } + item.cnt = 0; + item.apply_forget_factor_to_C = false; + if (version >= 2) + { + deserialize(item.cnt, in); + deserialize(item.apply_forget_factor_to_C, in); + } } private: @@ -189,6 +215,13 @@ namespace dlib matrix R; double C; double forget_factor; + int cnt = 0; + bool apply_forget_factor_to_C; + + + // This object is here only to avoid reallocation during training. It don't + // logically contribute to the state of this object. + matrix tmp; }; // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/svm/rls_abstract.h b/lib/3rdParty/dlib/include/dlib/svm/rls_abstract.h index 2b957649..c593e433 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/rls_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/svm/rls_abstract.h @@ -37,7 +37,8 @@ namespace dlib explicit rls( double forget_factor, - double C = 1000 + double C = 1000, + bool apply_forget_factor_to_C = false ); /*! requires @@ -47,6 +48,7 @@ namespace dlib - #get_w().size() == 0 - #get_c() == C - #get_forget_factor() == forget_factor + - #should_apply_forget_factor_to_C() == apply_forget_factor_to_C !*/ rls( @@ -56,6 +58,7 @@ namespace dlib - #get_w().size() == 0 - #get_c() == 1000 - #get_forget_factor() == 1 + - #should_apply_forget_factor_to_C() == false !*/ double get_c( @@ -80,6 +83,18 @@ namespace dlib zero the faster old examples are forgotten. !*/ + bool should_apply_forget_factor_to_C ( + ) const; + /*! + ensures + - If this function returns false then it means we are optimizing the + objective function discussed in the WHAT THIS OBJECT REPRESENTS section + above. However, if it returns true then we will allow the forget factor + (get_forget_factor()) to be applied to the C value which causes the + algorithm to slowly increase C and convert into a textbook version of RLS + without regularization. The main reason you might want to do this is + because it can make the algorithm run significantly faster. + !*/ template void train ( diff --git a/lib/3rdParty/dlib/include/dlib/svm/structural_assignment_trainer.h b/lib/3rdParty/dlib/include/dlib/svm/structural_assignment_trainer.h index ec9ac6ab..d55b74ff 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/structural_assignment_trainer.h +++ b/lib/3rdParty/dlib/include/dlib/svm/structural_assignment_trainer.h @@ -185,6 +185,19 @@ namespace dlib return loss_per_missed_association; } + bool forces_last_weight_to_1 ( + ) const + { + return last_weight_1; + } + + void force_last_weight_to_1 ( + bool should_last_weight_be_1 + ) + { + last_weight_1 = should_last_weight_be_1; + } + const assignment_function train ( const std::vector& samples, const std::vector& labels @@ -230,7 +243,10 @@ namespace dlib // Take the min here because we want to prevent the user from accidentally // forcing the bias term to be non-negative. const unsigned long num_nonneg = std::min(fe.num_features(),num_nonnegative_weights(fe)); - solver(prob, weights, num_nonneg); + if (last_weight_1) + solver(prob, weights, num_nonneg, fe.num_features()-1); + else + solver(prob, weights, num_nonneg); const double bias = weights(weights.size()-1); return assignment_function(colm(weights,0,weights.size()-1), bias,fe,force_assignment); @@ -249,6 +265,7 @@ namespace dlib unsigned long max_cache_size; double loss_per_false_association; double loss_per_missed_association; + bool last_weight_1; void set_defaults () { @@ -260,6 +277,7 @@ namespace dlib max_cache_size = 5; loss_per_false_association = 1; loss_per_missed_association = 1; + last_weight_1 = false; } feature_extractor fe; diff --git a/lib/3rdParty/dlib/include/dlib/svm/structural_assignment_trainer_abstract.h b/lib/3rdParty/dlib/include/dlib/svm/structural_assignment_trainer_abstract.h index d93062da..ebd402d4 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/structural_assignment_trainer_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/svm/structural_assignment_trainer_abstract.h @@ -54,6 +54,7 @@ namespace dlib - #forces_assignment() == false - #get_loss_per_false_association() == 1 - #get_loss_per_missed_association() == 1 + - #forces_last_weight_to_1() == false !*/ explicit structural_assignment_trainer ( @@ -70,6 +71,7 @@ namespace dlib - #forces_assignment() == false - #get_loss_per_false_association() == 1 - #get_loss_per_missed_association() == 1 + - #forces_last_weight_to_1() == false !*/ const feature_extractor& get_feature_extractor ( @@ -244,6 +246,26 @@ namespace dlib assignment_functions generated by this object. !*/ + bool forces_last_weight_to_1 ( + ) const; + /*! + ensures + - returns true if this trainer has the constraint that the last weight in + the learned parameter vector must be 1. This is the weight corresponding + to the feature in the training vectors with the highest dimension. + - Forcing the last weight to 1 also disables the bias and therefore the + get_bias() field of the learned assignment_function will be 0 when + forces_last_weight_to_1() == true. + !*/ + + void force_last_weight_to_1 ( + bool should_last_weight_be_1 + ); + /*! + ensures + - #forces_last_weight_to_1() == should_last_weight_be_1 + !*/ + const assignment_function train ( const std::vector& samples, const std::vector& labels @@ -262,6 +284,9 @@ namespace dlib new_sample.first match up with the elements of new_sample.second. - F.forces_assignment() == forces_assignment() - F.get_feature_extractor() == get_feature_extractor() + - if (forces_last_weight_to_1()) then + - F.get_bias() == 0 + - F.get_weights()(F.get_weights().size()-1) == 1 !*/ }; diff --git a/lib/3rdParty/dlib/include/dlib/svm/structural_sequence_labeling_trainer.h b/lib/3rdParty/dlib/include/dlib/svm/structural_sequence_labeling_trainer.h index 72795dae..9b61fd6c 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/structural_sequence_labeling_trainer.h +++ b/lib/3rdParty/dlib/include/dlib/svm/structural_sequence_labeling_trainer.h @@ -76,6 +76,16 @@ namespace dlib double get_epsilon ( ) const { return eps; } + unsigned long get_max_iterations ( + ) const { return max_iterations; } + + void set_max_iterations ( + unsigned long max_iter + ) + { + max_iterations = max_iter; + } + void set_max_cache_size ( unsigned long max_size ) @@ -215,6 +225,7 @@ namespace dlib prob.be_verbose(); prob.set_epsilon(eps); + prob.set_max_iterations(max_iterations); prob.set_c(C); prob.set_max_cache_size(max_cache_size); for (unsigned long i = 0; i < loss_values.size(); ++i) @@ -230,6 +241,7 @@ namespace dlib double C; oca solver; double eps; + unsigned long max_iterations; bool verbose; unsigned long num_threads; unsigned long max_cache_size; @@ -240,6 +252,7 @@ namespace dlib C = 100; verbose = false; eps = 0.1; + max_iterations = 10000; num_threads = 2; max_cache_size = 5; loss_values.assign(num_labels(), 1); diff --git a/lib/3rdParty/dlib/include/dlib/svm/structural_sequence_labeling_trainer_abstract.h b/lib/3rdParty/dlib/include/dlib/svm/structural_sequence_labeling_trainer_abstract.h index e53cd9ae..43e5f513 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/structural_sequence_labeling_trainer_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/svm/structural_sequence_labeling_trainer_abstract.h @@ -47,6 +47,7 @@ namespace dlib - #get_c() == 100 - this object isn't verbose - #get_epsilon() == 0.1 + - #get_max_iterations() == 10000 - #get_num_threads() == 2 - #get_max_cache_size() == 5 - #get_feature_extractor() == a default initialized feature_extractor @@ -60,6 +61,7 @@ namespace dlib - #get_c() == 100 - this object isn't verbose - #get_epsilon() == 0.1 + - #get_max_iterations() == 10000 - #get_num_threads() == 2 - #get_max_cache_size() == 5 - #get_feature_extractor() == fe @@ -119,6 +121,22 @@ namespace dlib training sample is within epsilon of its optimal value". !*/ + void set_max_iterations ( + unsigned long max_iter + ); + /*! + ensures + - #get_max_iterations() == max_iter + !*/ + + unsigned long get_max_iterations ( + ); + /*! + ensures + - returns the maximum number of iterations the SVM optimizer is allowed to + run before it is required to stop and return a result. + !*/ + void set_max_cache_size ( unsigned long max_size ); diff --git a/lib/3rdParty/dlib/include/dlib/svm/structural_sequence_segmentation_trainer.h b/lib/3rdParty/dlib/include/dlib/svm/structural_sequence_segmentation_trainer.h index 20d34223..2e021400 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/structural_sequence_segmentation_trainer.h +++ b/lib/3rdParty/dlib/include/dlib/svm/structural_sequence_segmentation_trainer.h @@ -72,6 +72,16 @@ namespace dlib double get_epsilon ( ) const { return trainer.get_epsilon(); } + unsigned long get_max_iterations ( + ) const { return trainer.get_max_iterations(); } + + void set_max_iterations ( + unsigned long max_iter + ) + { + trainer.set_max_iterations(max_iter); + } + void set_max_cache_size ( unsigned long max_size ) diff --git a/lib/3rdParty/dlib/include/dlib/svm/structural_sequence_segmentation_trainer_abstract.h b/lib/3rdParty/dlib/include/dlib/svm/structural_sequence_segmentation_trainer_abstract.h index c650dede..bcd927ca 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/structural_sequence_segmentation_trainer_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/svm/structural_sequence_segmentation_trainer_abstract.h @@ -44,6 +44,7 @@ namespace dlib - #get_c() == 100 - this object isn't verbose - #get_epsilon() == 0.1 + - #get_max_iterations() == 10000 - #get_num_threads() == 2 - #get_max_cache_size() == 40 - #get_feature_extractor() == a default initialized feature_extractor @@ -59,6 +60,7 @@ namespace dlib - #get_c() == 100 - this object isn't verbose - #get_epsilon() == 0.1 + - #get_max_iterations() == 10000 - #get_num_threads() == 2 - #get_max_cache_size() == 40 - #get_feature_extractor() == fe @@ -111,6 +113,22 @@ namespace dlib per training sample is within epsilon of its optimal value". !*/ + void set_max_iterations ( + unsigned long max_iter + ); + /*! + ensures + - #get_max_iterations() == max_iter + !*/ + + unsigned long get_max_iterations ( + ); + /*! + ensures + - returns the maximum number of iterations the SVM optimizer is allowed to + run before it is required to stop and return a result. + !*/ + void set_max_cache_size ( unsigned long max_size ); diff --git a/lib/3rdParty/dlib/include/dlib/svm/structural_svm_distributed.h b/lib/3rdParty/dlib/include/dlib/svm/structural_svm_distributed.h index eebb9c13..a9542c70 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/structural_svm_distributed.h +++ b/lib/3rdParty/dlib/include/dlib/svm/structural_svm_distributed.h @@ -3,20 +3,19 @@ #ifndef DLIB_STRUCTURAL_SVM_DISTRIBUTeD_Hh_ #define DLIB_STRUCTURAL_SVM_DISTRIBUTeD_Hh_ +#include +#include +#include #include "structural_svm_distributed_abstract.h" #include "structural_svm_problem.h" #include "../bridge.h" -#include "../smart_pointers.h" #include "../misc_api.h" #include "../statistics.h" - - #include "../threads.h" #include "../pipe.h" #include "../type_safe_union.h" -#include -#include + namespace dlib { @@ -333,7 +332,7 @@ namespace dlib }; - scoped_ptr the_problem; + std::unique_ptr the_problem; }; // ---------------------------------------------------------------------------------------- @@ -345,6 +344,7 @@ namespace dlib svm_struct_controller_node ( ) : eps(0.001), + max_iterations(10000), cache_based_eps(std::numeric_limits::infinity()), verbose(false), C(1) @@ -389,6 +389,16 @@ namespace dlib double get_epsilon ( ) const { return eps; } + unsigned long get_max_iterations ( + ) const { return max_iterations; } + + void set_max_iterations ( + unsigned long max_iter + ) + { + max_iterations = max_iter; + } + void be_verbose ( ) { @@ -515,6 +525,7 @@ namespace dlib problem_type problem(nodes); problem.set_cache_based_epsilon(cache_based_eps); problem.set_epsilon(eps); + problem.set_max_iterations(max_iterations); if (verbose) problem.be_verbose(); problem.set_c(C); @@ -666,14 +677,15 @@ namespace dlib typedef type_safe_union > tsu_out; typedef type_safe_union, long> tsu_in; - std::vector > > out_pipes; + std::vector > > out_pipes; mutable pipe in; - std::vector > bridges; + std::vector > bridges; long num_dims; }; std::vector nodes; double eps; + unsigned long max_iterations; double cache_based_eps; bool verbose; double C; diff --git a/lib/3rdParty/dlib/include/dlib/svm/structural_svm_distributed_abstract.h b/lib/3rdParty/dlib/include/dlib/svm/structural_svm_distributed_abstract.h index 8847c7e1..175a643c 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/structural_svm_distributed_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/svm/structural_svm_distributed_abstract.h @@ -64,6 +64,7 @@ namespace dlib INITIAL VALUE - get_num_processing_nodes() == 0 - get_epsilon() == 0.001 + - get_max_iterations() == 10000 - get_c() == 1 - This object will not be verbose @@ -182,6 +183,22 @@ namespace dlib - #get_cache_based_epsilon() == eps !*/ + void set_max_iterations ( + unsigned long max_iter + ); + /*! + ensures + - #get_max_iterations() == max_iter + !*/ + + unsigned long get_max_iterations ( + ); + /*! + ensures + - returns the maximum number of iterations the SVM optimizer is allowed to + run before it is required to stop and return a result. + !*/ + void add_nuclear_norm_regularizer ( long first_dimension, long rows, diff --git a/lib/3rdParty/dlib/include/dlib/svm/structural_svm_object_detection_problem.h b/lib/3rdParty/dlib/include/dlib/svm/structural_svm_object_detection_problem.h index 93c905df..1c54a42b 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/structural_svm_object_detection_problem.h +++ b/lib/3rdParty/dlib/include/dlib/svm/structural_svm_object_detection_problem.h @@ -15,14 +15,6 @@ namespace dlib { -// ---------------------------------------------------------------------------------------- - - class impossible_labeling_error : public dlib::error - { - public: - impossible_labeling_error(const std::string& msg) : dlib::error(msg) {}; - }; - // ---------------------------------------------------------------------------------------- template < @@ -244,7 +236,7 @@ namespace dlib sout << "the truth labels for an image contain rectangles which overlap according to the "; sout << "test_box_overlap object supplied for non-max suppression. To resolve this, you "; sout << "either need to relax the test_box_overlap object so it doesn't mark these rectangles as "; - sout << "overlapping or adjust the truth rectangles. "; + sout << "overlapping or adjust the truth rectangles in your training dataset. "; // make sure the above string fits nicely into a command prompt window. string temp = sout.str(); @@ -274,14 +266,15 @@ namespace dlib ostringstream sout; sout << "An impossible set of object labels was detected. This is happening because "; sout << "none of the object locations checked by the supplied image scanner is a close "; - sout << "enough match to one of the truth boxes. To resolve this you need to either lower the match_eps "; - sout << "or adjust the settings of the image scanner so that it hits this truth box. "; - sout << "Or you could adjust the "; - sout << "offending truth rectangle so it can be matched by the current image scanner. Also, if you "; - sout << "are using the scan_image_pyramid object then you could try using a finer image pyramid "; - sout << "or adding more detection templates. E.g. if one of "; - sout << "your existing detection templates has a matching width/height ratio and smaller area "; - sout << "than the offending rectangle then a finer image pyramid would probably help."; + sout << "enough match to one of the truth boxes in your training dataset. To resolve this "; + sout << "you need to either lower the match_eps, adjust the settings of the image scanner "; + sout << "so that it is capable of hitting this truth box, or adjust the offending truth rectangle so it "; + sout << "can be matched by the current image scanner. Also, if you "; + sout << "are using the scan_fhog_pyramid object then you could try using a finer image pyramid. "; + sout << "Additionally, the scan_fhog_pyramid scans a fixed aspect ratio box across the image when it "; + sout << "searches for objects. So if you are getting this error and you are using the scan_fhog_pyramid, "; + sout << "it's very likely the problem is that your training dataset contains truth rectangles of widely "; + sout << "varying aspect ratios. The solution is to make sure your training boxes all have about the same aspect ratio. "; // make sure the above string fits nicely into a command prompt window. @@ -345,7 +338,7 @@ namespace dlib // if hit truth rect if (truth_match > match_eps) { - // if this is the first time we have seen a detect which hit truth_object_detections[truth.second] + // if this is the first time we have seen a detect which hit truth_object_detections[idx][truth.second] const double score = dets[i].first - thresh; if (hit_truth_table[truth.second] == false) { diff --git a/lib/3rdParty/dlib/include/dlib/svm/structural_svm_object_detection_problem_abstract.h b/lib/3rdParty/dlib/include/dlib/svm/structural_svm_object_detection_problem_abstract.h index a990667a..d73c5920 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/structural_svm_object_detection_problem_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/svm/structural_svm_object_detection_problem_abstract.h @@ -12,23 +12,6 @@ namespace dlib { -// ---------------------------------------------------------------------------------------- - - class impossible_labeling_error : public dlib::error - { - /*! - WHAT THIS OBJECT REPRESENTS - This is the exception thrown by the structural_svm_object_detection_problem - when it detects that the image_scanner_type it is working with is incapable - of representing the truth rectangles it has been asked to predict. - - This kind of problem can happen when the test_box_overlap object indicates - that two ground truth rectangles overlap and are therefore not allowed to - both be output at the same time. Or alternatively, if there are not enough - detection templates to cover the variety of truth rectangle shapes. - !*/ - }; - // ---------------------------------------------------------------------------------------- template < @@ -51,30 +34,17 @@ namespace dlib and it must contain objects which can be accepted by image_scanner_type::load(). WHAT THIS OBJECT REPRESENTS - This object is a tool for learning the parameter vector needed to use - a scan_image_pyramid or scan_image_boxes object. + This object is a tool for learning the parameter vector needed to use a + scan_image_pyramid, scan_fhog_pyramid, scan_image_custom, or + scan_image_boxes object. It learns the parameter vector by formulating the problem as a structural - SVM problem. The general approach is similar to the method discussed in - Learning to Localize Objects with Structured Output Regression by - Matthew B. Blaschko and Christoph H. Lampert. However, the method has - been extended to datasets with multiple, potentially overlapping, objects - per image and the measure of loss is different from what is described in - the paper. + SVM problem. The exact details of the method are described in the paper + Max-Margin Object Detection by Davis E. King (http://arxiv.org/abs/1502.00046). - In particular, the loss is measured as follows: - let FA == the number of false alarms produced by a labeling of an image. - let MT == the number of targets missed by a labeling of an image. - Then the loss for a particular labeling is the quantity: - FA*get_loss_per_false_alarm() + MT*get_loss_per_missed_target() - A detection is considered a false alarm if it doesn't match with any - of the ground truth rectangles or if it is a duplicate detection of a - truth rectangle. Finally, for the purposes of calculating loss, a match - is determined using the following formula where rectangles A and B match - if and only if: - A.intersect(B).area()/(A+B).area() > get_match_eps() !*/ + public: structural_svm_object_detection_problem( diff --git a/lib/3rdParty/dlib/include/dlib/svm/structural_svm_problem.h b/lib/3rdParty/dlib/include/dlib/svm/structural_svm_problem.h index 14fb64ef..3a73457b 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/structural_svm_problem.h +++ b/lib/3rdParty/dlib/include/dlib/svm/structural_svm_problem.h @@ -75,6 +75,12 @@ namespace dlib psi = true_psi; else prob->get_truth_joint_feature_vector(sample_idx, psi); + + if (is_matrix::value) + { + DLIB_CASSERT((long)psi.size() == prob->get_num_dimensions(), + "The dimensionality of your PSI vector doesn't match get_num_dimensions()"); + } } void separation_oracle_cached ( @@ -128,6 +134,11 @@ namespace dlib prob->separation_oracle(sample_idx, current_solution, out_loss, out_psi); + if (is_matrix::value) + { + DLIB_CASSERT((long)out_psi.size() == prob->get_num_dimensions(), + "The dimensionality of your PSI vector doesn't match get_num_dimensions()"); + } if (!cache_enabled) return; @@ -228,6 +239,7 @@ namespace dlib CONVENTION - C == get_c() - eps == get_epsilon() + - max_iterations == get_max_iterations() - if (skip_cache) then - we won't use the oracle cache when we need to evaluate the separation oracle. Instead, we will directly call the user supplied separation_oracle(). @@ -248,6 +260,7 @@ namespace dlib ) : saved_current_risk_gap(0), eps(0.001), + max_iterations(10000), verbose(false), skip_cache(true), count_below_eps(0), @@ -297,6 +310,16 @@ namespace dlib const scalar_type get_epsilon ( ) const { return eps; } + unsigned long get_max_iterations ( + ) const { return max_iterations; } + + void set_max_iterations ( + unsigned long max_iter + ) + { + max_iterations = max_iter; + } + void set_max_cache_size ( unsigned long max_size ) @@ -434,6 +457,9 @@ namespace dlib cout << endl; } + if (num_iterations >= max_iterations) + return true; + saved_current_risk_gap = current_risk_gap; if (converged) @@ -600,6 +626,7 @@ namespace dlib mutable scalar_type saved_current_risk_gap; mutable matrix_type psi_true; scalar_type eps; + unsigned long max_iterations; mutable bool verbose; diff --git a/lib/3rdParty/dlib/include/dlib/svm/structural_svm_problem_abstract.h b/lib/3rdParty/dlib/include/dlib/svm/structural_svm_problem_abstract.h index 956a1191..20b3d73a 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/structural_svm_problem_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/svm/structural_svm_problem_abstract.h @@ -29,6 +29,7 @@ namespace dlib INITIAL VALUE - get_epsilon() == 0.001 + - get_max_iterations() == 10000 - get_max_cache_size() == 5 - get_c() == 1 - get_cache_based_epsilon() == std::numeric_limits::infinity() @@ -161,6 +162,22 @@ namespace dlib - #get_cache_based_epsilon() == eps !*/ + void set_max_iterations ( + unsigned long max_iter + ); + /*! + ensures + - #get_max_iterations() == max_iter + !*/ + + unsigned long get_max_iterations ( + ); + /*! + ensures + - returns the maximum number of iterations the SVM optimizer is allowed to + run before it is required to stop and return a result. + !*/ + void set_max_cache_size ( unsigned long max_size ); diff --git a/lib/3rdParty/dlib/include/dlib/svm/svm_c_linear_dcd_trainer.h b/lib/3rdParty/dlib/include/dlib/svm/svm_c_linear_dcd_trainer.h index 7626a86e..039b7099 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/svm_c_linear_dcd_trainer.h +++ b/lib/3rdParty/dlib/include/dlib/svm/svm_c_linear_dcd_trainer.h @@ -9,6 +9,7 @@ #include "../matrix.h" #include "../algs.h" #include "../rand.h" +#include "svm.h" #include "function.h" #include "kernel.h" @@ -47,7 +48,8 @@ namespace dlib verbose(false), have_bias(true), last_weight_1(false), - do_shrinking(true) + do_shrinking(true), + do_svm_l2(false) { } @@ -61,7 +63,8 @@ namespace dlib verbose(false), have_bias(true), last_weight_1(false), - do_shrinking(true) + do_shrinking(true), + do_svm_l2(false) { // make sure requires clause is not broken DLIB_ASSERT(0 < C_, @@ -104,6 +107,13 @@ namespace dlib bool enabled ) { do_shrinking = enabled; } + bool solving_svm_l2_problem ( + ) const { return do_svm_l2; } + + void solve_svm_l2_problem ( + bool enabled + ) { do_svm_l2 = enabled; } + void be_verbose ( ) { @@ -219,12 +229,17 @@ namespace dlib private: template < - typename in_sample_vector_type + typename in_sample_vector_type, + typename in_scalar_vector_type > void init( const in_sample_vector_type& x, + const in_scalar_vector_type& y, bool have_bias_, - bool last_weight_1_ + bool last_weight_1_, + bool do_svm_l2_, + scalar_type Cpos, + scalar_type Cneg ) { const long new_dims = max_index_plus_one(x); @@ -337,6 +352,14 @@ namespace dlib { index.push_back(i); } + + if (do_svm_l2_) + { + if (y(i) > 0) + Q.back() += 1/(2*Cpos); + else + Q.back() += 1/(2*Cneg); + } } if (last_weight_1) @@ -392,6 +415,9 @@ namespace dlib dlib::rand rnd; public: + + const std::vector& get_alpha () const { return alpha; } + friend void serialize(const optimizer_state& item, std::ostream& out) { const int version = 1; @@ -490,18 +516,22 @@ namespace dlib } #endif - state.init(x,have_bias,last_weight_1); + state.init(x,y,have_bias,last_weight_1,do_svm_l2,Cpos,Cneg); std::vector& alpha = state.alpha; scalar_vector_type& w = state.w; std::vector& index = state.index; const long dims = state.dims; + unsigned long active_size = index.size(); scalar_type PG_max_prev = std::numeric_limits::infinity(); scalar_type PG_min_prev = -std::numeric_limits::infinity(); + const scalar_type Dii_pos = 1/(2*Cpos); + const scalar_type Dii_neg = 1/(2*Cneg); + // main loop for (unsigned long iter = 0; iter < max_iterations; ++iter) { @@ -521,8 +551,16 @@ namespace dlib { const long i = index[ii]; - const scalar_type G = y(i)*dot(w, x(i)) - 1; + scalar_type G = y(i)*dot(w, x(i)) - 1; + if (do_svm_l2) + { + if (y(i) > 0) + G += Dii_pos*alpha[i]; + else + G += Dii_neg*alpha[i]; + } const scalar_type C = (y(i) > 0) ? Cpos : Cneg; + const scalar_type U = do_svm_l2 ? std::numeric_limits::infinity() : C; scalar_type PG = 0; if (alpha[i] == 0) @@ -539,7 +577,7 @@ namespace dlib if (G < 0) PG = G; } - else if (alpha[i] == C) + else if (alpha[i] == U) { if (G < PG_min_prev) { @@ -567,7 +605,7 @@ namespace dlib if (std::abs(PG) > 1e-12) { const scalar_type alpha_old = alpha[i]; - alpha[i] = std::min(std::max(alpha[i] - G/state.Q[i], (scalar_type)0.0), C); + alpha[i] = std::min(std::max(alpha[i] - G/state.Q[i], (scalar_type)0.0), U); const scalar_type delta = (alpha[i]-alpha_old)*y(i); add_to(w, x(i), delta); if (have_bias && !last_weight_1) @@ -595,7 +633,7 @@ namespace dlib if (active_size == index.size()) break; - // Turn of shrinking on the next iteration. We will stop if the + // Turn off shrinking on the next iteration. We will stop if the // tolerance is still <= eps when shrinking is off. active_size = index.size(); PG_max_prev = std::numeric_limits::infinity(); @@ -660,6 +698,7 @@ namespace dlib bool have_bias; // having a bias means we pretend all x vectors have an extra element which is always -1. bool last_weight_1; bool do_shrinking; + bool do_svm_l2; }; // end of class svm_c_linear_dcd_trainer diff --git a/lib/3rdParty/dlib/include/dlib/svm/svm_c_linear_dcd_trainer_abstract.h b/lib/3rdParty/dlib/include/dlib/svm/svm_c_linear_dcd_trainer_abstract.h index 549b9e7a..b57c5426 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/svm_c_linear_dcd_trainer_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/svm/svm_c_linear_dcd_trainer_abstract.h @@ -67,6 +67,7 @@ namespace dlib - #forces_last_weight_to_1() == false - #includes_bias() == true - #shrinking_enabled() == true + - #solving_svm_l2_problem() == false !*/ explicit svm_c_linear_dcd_trainer ( @@ -86,6 +87,7 @@ namespace dlib - #forces_last_weight_to_1() == false - #includes_bias() == true - #shrinking_enabled() == true + - #solving_svm_l2_problem() == false !*/ bool includes_bias ( @@ -140,6 +142,23 @@ namespace dlib - #shrinking_enabled() == enabled !*/ + bool solving_svm_l2_problem ( + ) const; + /*! + ensures + - returns true if this solver will solve the L2 version of the SVM + objective function. That is, if solving_svm_l2_problem()==true then this + object, rather than using the hinge loss, uses the squared hinge loss. + !*/ + + void solve_svm_l2_problem ( + bool enabled + ); + /*! + ensures + - #solving_svm_l2_problem() == enabled + !*/ + void be_verbose ( ); /*! @@ -285,10 +304,16 @@ namespace dlib !*/ // optimizer_state is used to record the internal state of the SVM optimizer. It - // can be used with the following train() routine to warm-start the optimizer. - // Note, that optimizer_state objects are serializable but are otherwise completely - // opaque to the user. - class optimizer_state; + // can be used with the following train() routine to warm-start the optimizer or + // access the optimal alpha values (see the Hsieh paper mentioned above). The + // optimizer_state objects are serializable and allow you to get the alphas, but + // are otherwise completely opaque to the user. + class optimizer_state + { + public: + const std::vector& get_alpha ( + ) const; + }; template < typename in_sample_vector_type, @@ -336,6 +361,8 @@ namespace dlib - #state == the internal state of the optimizer at the solution to the SVM problem. Therefore, passing #state to a new call to train() will start the optimizer from the current solution. + - #state.get_alpha().size() == x.size() + - #state.get_alpha() == the optimal alpha/dual values learned by the optimizer. - returns a decision function F with the following properties: - F.alpha.size() == 1 - F.basis_vectors.size() == 1 diff --git a/lib/3rdParty/dlib/include/dlib/svm/svm_c_linear_trainer.h b/lib/3rdParty/dlib/include/dlib/svm/svm_c_linear_trainer.h index 7428f0b2..8d136d71 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/svm_c_linear_trainer.h +++ b/lib/3rdParty/dlib/include/dlib/svm/svm_c_linear_trainer.h @@ -692,7 +692,7 @@ namespace dlib bool learn_nonnegative_weights; bool last_weight_1; matrix prior; - scalar_type prior_b; + scalar_type prior_b = 0; }; // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/svm/svm_multiclass_linear_trainer.h b/lib/3rdParty/dlib/include/dlib/svm/svm_multiclass_linear_trainer.h index d036dbd6..4727f722 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/svm_multiclass_linear_trainer.h +++ b/lib/3rdParty/dlib/include/dlib/svm/svm_multiclass_linear_trainer.h @@ -188,6 +188,7 @@ namespace dlib num_threads(4), C(1), eps(0.001), + max_iterations(10000), verbose(false), learn_nonnegative_weights(false) { @@ -224,6 +225,16 @@ namespace dlib const scalar_type get_epsilon ( ) const { return eps; } + unsigned long get_max_iterations ( + ) const { return max_iterations; } + + void set_max_iterations ( + unsigned long max_iter + ) + { + max_iterations = max_iter; + } + void be_verbose ( ) { @@ -358,6 +369,7 @@ namespace dlib problem.set_max_cache_size(0); problem.set_c(C); problem.set_epsilon(eps); + problem.set_max_iterations(max_iterations); unsigned long num_nonnegative = 0; if (learn_nonnegative_weights) @@ -403,6 +415,7 @@ namespace dlib unsigned long num_threads; scalar_type C; scalar_type eps; + unsigned long max_iterations; bool verbose; oca solver; bool learn_nonnegative_weights; diff --git a/lib/3rdParty/dlib/include/dlib/svm/svm_multiclass_linear_trainer_abstract.h b/lib/3rdParty/dlib/include/dlib/svm/svm_multiclass_linear_trainer_abstract.h index 493a6900..6561ce7b 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/svm_multiclass_linear_trainer_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/svm/svm_multiclass_linear_trainer_abstract.h @@ -34,6 +34,7 @@ namespace dlib - get_num_threads() == 4 - learns_nonnegative_weights() == false - get_epsilon() == 0.001 + - get_max_iterations() == 10000 - get_c() == 1 - this object will not be verbose unless be_verbose() is called - #get_oca() == oca() (i.e. an instance of oca with default parameters) @@ -79,6 +80,22 @@ namespace dlib to execute. !*/ + void set_max_iterations ( + unsigned long max_iter + ); + /*! + ensures + - #get_max_iterations() == max_iter + !*/ + + unsigned long get_max_iterations ( + ); + /*! + ensures + - returns the maximum number of iterations the SVM optimizer is allowed to + run before it is required to stop and return a result. + !*/ + void be_verbose ( ); /*! diff --git a/lib/3rdParty/dlib/include/dlib/svm/svm_threaded.h b/lib/3rdParty/dlib/include/dlib/svm/svm_threaded.h index 5a9f4e21..37927456 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/svm_threaded.h +++ b/lib/3rdParty/dlib/include/dlib/svm/svm_threaded.h @@ -3,21 +3,21 @@ #ifndef DLIB_SVm_THREADED_ #define DLIB_SVm_THREADED_ -#include "svm_threaded_abstract.h" -#include "svm.h" #include +#include #include #include +#include + +#include "svm_threaded_abstract.h" +#include "svm.h" #include "../matrix.h" #include "../algs.h" #include "../serialize.h" #include "function.h" #include "kernel.h" #include "../threads.h" -#include -#include "../smart_pointers.h" #include "../pipe.h" -#include namespace dlib { @@ -47,12 +47,12 @@ namespace dlib { template < typename trainer_type, - typename matrix_type, + typename mem_manager_type, typename in_sample_vector_type > void operator()( job& j, - matrix_type& result + matrix& result ) { try @@ -83,7 +83,7 @@ namespace dlib typename in_sample_vector_type, typename in_scalar_vector_type > - const matrix + const matrix cross_validate_trainer_threaded_impl ( const trainer_type& trainer, const in_sample_vector_type& x, @@ -93,7 +93,6 @@ namespace dlib ) { using namespace dlib::cvtti_helpers; - typedef typename trainer_type::scalar_type scalar_type; typedef typename trainer_type::mem_manager_type mem_manager_type; // make sure requires clause is not broken @@ -137,7 +136,7 @@ namespace dlib std::vector > > jobs(folds); - std::vector > > results(folds); + std::vector > > results(folds); for (long i = 0; i < folds; ++i) @@ -212,7 +211,7 @@ namespace dlib } // for (long i = 0; i < folds; ++i) - matrix res; + matrix res; set_all_elements(res,0); // now compute the total results @@ -221,7 +220,7 @@ namespace dlib res += results[i].get(); } - return res/(scalar_type)folds; + return res/(double)folds; } template < @@ -229,7 +228,7 @@ namespace dlib typename in_sample_vector_type, typename in_scalar_vector_type > - const matrix + const matrix cross_validate_trainer_threaded ( const trainer_type& trainer, const in_sample_vector_type& x, diff --git a/lib/3rdParty/dlib/include/dlib/svm/svm_threaded_abstract.h b/lib/3rdParty/dlib/include/dlib/svm/svm_threaded_abstract.h index 7fad9ba1..f9973fb5 100644 --- a/lib/3rdParty/dlib/include/dlib/svm/svm_threaded_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/svm/svm_threaded_abstract.h @@ -17,7 +17,7 @@ namespace dlib typename in_sample_vector_type, typename in_scalar_vector_type > - const matrix + const matrix cross_validate_trainer_threaded ( const trainer_type& trainer, const in_sample_vector_type& x, diff --git a/lib/3rdParty/dlib/include/dlib/svm_threaded.h b/lib/3rdParty/dlib/include/dlib/svm_threaded.h index ffc9768a..f77fab70 100644 --- a/lib/3rdParty/dlib/include/dlib/svm_threaded.h +++ b/lib/3rdParty/dlib/include/dlib/svm_threaded.h @@ -1,5 +1,10 @@ // Copyright (C) 2008 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. + +#ifdef DLIB_ALL_SOURCE_END +#include "dlib_basic_cpp_build_tutorial.txt" +#endif + #ifndef DLIB_SVm_THREADED_HEADER #define DLIB_SVm_THREADED_HEADER diff --git a/lib/3rdParty/dlib/include/dlib/test/CMakeLists.txt b/lib/3rdParty/dlib/include/dlib/test/CMakeLists.txt deleted file mode 100644 index 2f0f56ed..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/CMakeLists.txt +++ /dev/null @@ -1,169 +0,0 @@ -# -# This is a CMake makefile. You can find the cmake utility and -# information about it at http://www.cmake.org -# - -cmake_minimum_required(VERSION 2.6) - -# This variable contains a list of all the tests we are building -# into the regression test suite. -set (tests - example.cpp - active_learning.cpp - any.cpp - any_function.cpp - array2d.cpp - array.cpp - assignment_learning.cpp - base64.cpp - bayes_nets.cpp - bigint.cpp - binary_search_tree_kernel_1a.cpp - binary_search_tree_kernel_2a.cpp - binary_search_tree_mm1.cpp - binary_search_tree_mm2.cpp - bridge.cpp - bsp.cpp - byte_orderer.cpp - cca.cpp - clustering.cpp - cmd_line_parser.cpp - cmd_line_parser_wchar_t.cpp - compress_stream.cpp - conditioning_class_c.cpp - conditioning_class.cpp - config_reader.cpp - crc32.cpp - create_iris_datafile.cpp - data_io.cpp - directed_graph.cpp - discriminant_pca.cpp - disjoint_subsets.cpp - ekm_and_lisf.cpp - empirical_kernel_map.cpp - entropy_coder.cpp - entropy_encoder_model.cpp - example_args.cpp - face.cpp - fft.cpp - fhog.cpp - filtering.cpp - find_max_factor_graph_nmplp.cpp - find_max_factor_graph_viterbi.cpp - geometry.cpp - graph.cpp - graph_cuts.cpp - graph_labeler.cpp - hash.cpp - hash_map.cpp - hash_set.cpp - hash_table.cpp - hog_image.cpp - image.cpp - iosockstream.cpp - is_same_object.cpp - kcentroid.cpp - kernel_matrix.cpp - kmeans.cpp - learning_to_track.cpp - least_squares.cpp - linear_manifold_regularizer.cpp - lz77_buffer.cpp - map.cpp - matrix2.cpp - matrix3.cpp - matrix4.cpp - matrix_chol.cpp - matrix.cpp - matrix_eig.cpp - matrix_lu.cpp - matrix_qr.cpp - max_cost_assignment.cpp - max_sum_submatrix.cpp - md5.cpp - member_function_pointer.cpp - metaprogramming.cpp - multithreaded_object.cpp - numerical_integration.cpp - object_detector.cpp - oca.cpp - one_vs_all_trainer.cpp - one_vs_one_trainer.cpp - optimization.cpp - optimization_test_functions.cpp - opt_qp_solver.cpp - parallel_for.cpp - parse.cpp - pipe.cpp - pixel.cpp - probabilistic.cpp - pyramid_down.cpp - queue.cpp - rand.cpp - ranking.cpp - read_write_mutex.cpp - reference_counter.cpp - rls.cpp - sammon.cpp - scan_image.cpp - sequence.cpp - sequence_labeler.cpp - sequence_segmenter.cpp - serialize.cpp - set.cpp - sldf.cpp - sliding_buffer.cpp - smart_pointers.cpp - sockets2.cpp - sockets.cpp - sockstreambuf.cpp - sparse_vector.cpp - stack.cpp - static_map.cpp - static_set.cpp - statistics.cpp - std_vector_c.cpp - string.cpp - svm_c_linear.cpp - svm_c_linear_dcd.cpp - svm.cpp - svm_multiclass_linear.cpp - svm_struct.cpp - svr_linear_trainer.cpp - symmetric_matrix_cache.cpp - thread_pool.cpp - threads.cpp - timer.cpp - tokenizer.cpp - trust_region.cpp - tuple.cpp - type_safe_union.cpp - vectorstream.cpp - ) - -# create a variable called target_name and set it to the string "dtest" -set (target_name dtest) - -PROJECT(${target_name}) - -# add all the cpp files we want to compile to this list. This tells -# cmake that they are part of our target (which is the executable named dtest) -ADD_EXECUTABLE(${target_name} main.cpp tester.cpp ${tests}) - -# Turn on all warnings when using gcc. -if (CMAKE_COMPILER_IS_GNUCXX) - add_definitions("-W -Wall") -endif() - - -# Tell cmake to link our target executable to dlib. -include(../cmake) -TARGET_LINK_LIBRARIES(${target_name} dlib ) - - -if (NOT DLIB_NO_GUI_SUPPORT) - add_subdirectory(gui) - add_subdirectory(examples) -endif() - - diff --git a/lib/3rdParty/dlib/include/dlib/test/active_learning.cpp b/lib/3rdParty/dlib/include/dlib/test/active_learning.cpp deleted file mode 100644 index a60f6de4..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/active_learning.cpp +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (C) 2012 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include - -#include "tester.h" - - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.active_learning"); - -// ---------------------------------------------------------------------------------------- - - typedef matrix sample_type; - typedef radial_basis_kernel kernel_type; - -// ---------------------------------------------------------------------------------------- - - void make_dataset ( - std::vector& samples, - std::vector& labels - ) - { - for (int r = -10; r <= 10; ++r) - { - for (int c = -10; c <= 10; ++c) - { - sample_type samp(2); - samp(0) = r; - samp(1) = c; - samples.push_back(samp); - - // if this point is less than 10 from the origin - if (sqrt((double)r*r + c*c) <= 8) - labels.push_back(+1); - else - labels.push_back(-1); - - } - } - - - vector_normalizer normalizer; - normalizer.train(samples); - for (unsigned long i = 0; i < samples.size(); ++i) - samples[i] = normalizer(samples[i]); - - randomize_samples(samples, labels); - - /* - cout << "samples.size(): " << samples.size() << endl; - cout << "num +1 samples: "<< sum(mat(labels) > 0) << endl; - cout << "num -1 samples: "<< sum(mat(labels) < 0) << endl; - */ - - empirical_kernel_map ekm; - ekm.load(kernel_type(0.15), samples); - for (unsigned long i = 0; i < samples.size(); ++i) - samples[i] = ekm.project(samples[i]); - - //cout << "dims: "<< ekm.out_vector_size() << endl; - } - -// ---------------------------------------------------------------------------------------- - - double test_rank_unlabeled_training_samples ( - const std::vector& samples, - const std::vector& labels, - active_learning_mode mode, - int iterations, - bool pick_front - ) - { - matrix s; - s = sum(mat(labels) > 0), sum(mat(labels) < 0); - s /= labels.size(); - - - svm_c_linear_dcd_trainer > trainer; - trainer.set_c(25); - - const unsigned long initial_size = 1; - std::vector tsamples(samples.begin(), samples.begin()+initial_size); - std::vector tlabels(labels.begin(), labels.begin()+initial_size); - - decision_function > df; - - double random_score = 0; - double active_learning_score = 0; - for (int i = 0; i < iterations; ++i) - { - print_spinner(); - random_subset_selector sss = randomly_subsample(samples,50,i); - random_subset_selector ssl = randomly_subsample(labels,50,i); - std::vector results; - - results = rank_unlabeled_training_samples(trainer, tsamples, tlabels, sss, mode); - - const unsigned long idx = pick_front ? results.front() : results.back(); - tsamples.push_back(sss[idx]); - tlabels.push_back(ssl[idx]); - - df = trainer.train(tsamples, tlabels); - //cout << "tsamples.size(): " << tsamples.size() << endl; - const unsigned long num = tsamples.size(); - const double active = test_binary_decision_function(df, samples, labels)*s; - //cout << "test: "<< active; - df = trainer.train(randomly_subsample(samples,num,i), randomly_subsample(labels,num,i)); - const double random = test_binary_decision_function(df, samples, labels)*s; - //cout << "test: "<< random << endl; - - active_learning_score += active; - random_score += random; - - //cout << "\n\n***********\n\n" << flush; - } - - dlog << LINFO << "pick_front: " << pick_front << " mode: "<< mode; - dlog << LINFO << "active_learning_score: "<< active_learning_score; - dlog << LINFO << "random_score: "<< random_score; - return active_learning_score / random_score; - } - -// ---------------------------------------------------------------------------------------- - - class test_active_learning : public tester - { - public: - test_active_learning ( - ) : - tester ("test_active_learning", - "Runs tests on the active learning components.") - {} - - void perform_test ( - ) - { - std::vector samples; - std::vector labels; - print_spinner(); - make_dataset(samples, labels); - dlog << LINFO << "samples.size(): "<< samples.size(); - - // When we pick the best/front ranked element then the active learning method - // shouldn't do much worse than random selection (and often much better). - DLIB_TEST(test_rank_unlabeled_training_samples(samples, labels, max_min_margin, 25, true) >= 0.97); - DLIB_TEST(test_rank_unlabeled_training_samples(samples, labels, ratio_margin, 25, true) >= 0.96); - // However, picking the worst ranked element should do way worse than random - // selection. - DLIB_TEST(test_rank_unlabeled_training_samples(samples, labels, max_min_margin, 25, false) < 0.8); - DLIB_TEST(test_rank_unlabeled_training_samples(samples, labels, ratio_margin, 25, false) < 0.8); - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/any.cpp b/lib/3rdParty/dlib/include/dlib/test/any.cpp deleted file mode 100644 index 355d00b3..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/any.cpp +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (C) 2010 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include "../rand.h" - -#include "tester.h" - - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.any"); - -// ---------------------------------------------------------------------------------------- - - void test_contains_4( - const any a - ) - { - DLIB_TEST(a.is_empty() == false); - DLIB_TEST(a.contains() == true); - DLIB_TEST(a.contains() == false); - DLIB_TEST(any_cast(a) == 4); - } - -// ---------------------------------------------------------------------------------------- - - void run_test() - { - any a, b, c; - - DLIB_TEST(a.is_empty()); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.is_empty()); - - a = b; - - swap(a,b); - a.swap(b); - - a = 4; - DLIB_TEST(a.is_empty() == false); - DLIB_TEST(a.contains() == true); - DLIB_TEST(a.contains() == false); - DLIB_TEST(any_cast(a) == 4); - - test_contains_4(a); - - DLIB_TEST(a.is_empty() == false); - DLIB_TEST(a.contains() == true); - DLIB_TEST(a.contains() == false); - DLIB_TEST(any_cast(a) == 4); - - bool error = false; - try - { - any_cast(a); - } - catch (bad_any_cast&) - { - error = true; - } - DLIB_TEST(error); - - swap(a,b); - - test_contains_4(b); - - DLIB_TEST(a.is_empty()); - - a = b; - - test_contains_4(a); - - c.get() = "test string"; - DLIB_TEST(c.get() == "test string"); - - a = c; - DLIB_TEST(a.cast_to() == "test string"); - - - a.clear(); - DLIB_TEST(a.is_empty()); - error = false; - try - { - any_cast(a); - } - catch (bad_any_cast&) - { - error = true; - } - DLIB_TEST(error); - - - a = 1; - b = 2; - - int* a_ptr = &a.get(); - int* b_ptr = &b.get(); - - swap(a,b); - DLIB_TEST(a_ptr == &b.get()); - DLIB_TEST(b_ptr == &a.get()); - } - -// ---------------------------------------------------------------------------------------- - - class any_tester : public tester - { - public: - any_tester ( - ) : - tester ("test_any", - "Runs tests on the any component.") - {} - - void perform_test ( - ) - { - run_test(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/any_function.cpp b/lib/3rdParty/dlib/include/dlib/test/any_function.cpp deleted file mode 100644 index 8defb598..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/any_function.cpp +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include "../rand.h" - -#include "tester.h" - - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.any_function"); - -// ---------------------------------------------------------------------------------------- - - int add ( int a, int b) { return a + b; } - string cat ( string a, string b) { return a + b; } - -// ---------------------------------------------------------------------------------------- - - void set_vals1( int& a) { a = 1; } - void set_vals2( int& a, int& b) { a = 1; b = 2; } - void set_vals3( int& a, int& b, int& c) { a = 1; b = 2; c = 3; } - void set_vals4( int& a, int& b, int& c, int& d) { a = 1; b = 2; c = 3; d = 4; } - void set_vals5( int& a, int& b, int& c, int& d, int& e) { a = 1; b = 2; c = 3; d = 4; e = 5; } - void set_vals6( int& a, int& b, int& c, int& d, int& e, int& f) { a = 1; b = 2; c = 3; d = 4; e = 5; f = 6; } - void set_vals7( int& a, int& b, int& c, int& d, int& e, int& f, int& g) { a = 1; b = 2; c = 3; d = 4; e = 5; f = 6; g = 7; } - - void set_vals8( int& a, int& b, int& c, int& d, int& e, int& f, int& g, int& h) - { a = 1; b = 2; c = 3; d = 4; e = 5; f = 6; g = 7; h = 8; } - - void set_vals9( int& a, int& b, int& c, int& d, int& e, int& f, int& g, int& h, int& i) - { a = 1; b = 2; c = 3; d = 4; e = 5; f = 6; g = 7; h = 8; i = 9;} - - void set_vals10( int& a, int& b, int& c, int& d, int& e, int& f, int& g, int& h, int& i, int& j) - { a = 1; b = 2; c = 3; d = 4; e = 5; f = 6; g = 7; h = 8; i = 9; j = 10;} - - void zero_vals( int& a, int& b, int& c, int& d, int& e, int& f, int& g, int& h, int& i, int& j) - { a = 0; b = 0; c = 0; d = 0; e = 0; f = 0; g = 0; h = 0; i = 0; j = 0;} - -// ---------------------------------------------------------------------------------------- - - struct test - { - int operator()() const { return 4; } - }; - - struct test2 - { - int v; - - test2() : v(0) {} - test2(int val) : v(val) {} - int operator()() const { return v; } - }; - -// ---------------------------------------------------------------------------------------- - - void test_contains_4( - const any_function a - ) - { - DLIB_TEST(a.is_empty() == false); - DLIB_TEST(a.is_set() == true); - DLIB_TEST(a.contains() == true); - DLIB_TEST(a.contains() == false); - DLIB_TEST(any_cast(a)() == 4); - DLIB_TEST(a() == 4); - } - -// ---------------------------------------------------------------------------------------- - - void run_test() - { - any_function a, b, c; - - DLIB_TEST(a.is_empty()); - DLIB_TEST(a.is_set()==false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.is_empty()); - - a = b; - - swap(a,b); - a.swap(b); - - a = test(); - test_contains_4(a); - - - bool error = false; - try - { - any_cast(a); - } - catch (bad_any_cast&) - { - error = true; - } - DLIB_TEST(error); - - swap(a,b); - - test_contains_4(b); - - DLIB_TEST(a.is_empty()); - - a = b; - - test_contains_4(a); - - c.get() = test2(10); - DLIB_TEST(c.get().v == 10); - - a = c; - DLIB_TEST(a.cast_to().v == 10); - - - a.clear(); - DLIB_TEST(a.is_empty()); - error = false; - try - { - any_cast(a); - } - catch (bad_any_cast&) - { - error = true; - } - DLIB_TEST(error); - - } - -// ---------------------------------------------------------------------------------------- - - void run_test2() - { - any_function f = &add; - - DLIB_TEST(f(1,3) == 4); - - any_function g(&cat); - DLIB_TEST(g("one", "two") == "onetwo"); - } - -// ---------------------------------------------------------------------------------------- - - void run_test3() - { - any_function f1; - any_function f2; - any_function f3; - any_function f4; - any_function f5; - any_function f6; - any_function f7; - any_function f8; - any_function f9; - any_function f10; - - f1 = set_vals1; - f2 = set_vals2; - f3 = set_vals3; - f4 = set_vals4; - f5 = set_vals5; - f6 = set_vals6; - f7 = set_vals7; - f8 = set_vals8; - f9 = set_vals9; - f10 = set_vals10; - - int a,b,c,d,e,f,g,h,i,j; - - zero_vals(a,b,c,d,e,f,g,h,i,j); - - f1(a); - DLIB_TEST(a==1); - zero_vals(a,b,c,d,e,f,g,h,i,j); - - f2(a,b); - DLIB_TEST(a==1 && b==2); - zero_vals(a,b,c,d,e,f,g,h,i,j); - - f3(a,b,c); - DLIB_TEST(a==1 && b==2 && c==3); - zero_vals(a,b,c,d,e,f,g,h,i,j); - - f4(a,b,c,d); - DLIB_TEST(a==1 && b==2 && c==3 && d==4); - zero_vals(a,b,c,d,e,f,g,h,i,j); - - f5(a,b,c,d,e); - DLIB_TEST(a==1 && b==2 && c==3 && d==4 && e==5); - zero_vals(a,b,c,d,e,f,g,h,i,j); - - f6(a,b,c,d,e,f); - DLIB_TEST(a==1 && b==2 && c==3 && d==4 && e==5 && f==6); - zero_vals(a,b,c,d,e,f,g,h,i,j); - - f7(a,b,c,d,e,f,g); - DLIB_TEST(a==1 && b==2 && c==3 && d==4 && e==5 && f==6 && g==7); - zero_vals(a,b,c,d,e,f,g,h,i,j); - - f8(a,b,c,d,e,f,g,h); - DLIB_TEST(a==1 && b==2 && c==3 && d==4 && e==5 && f==6 && g==7 && h==8); - zero_vals(a,b,c,d,e,f,g,h,i,j); - - f9(a,b,c,d,e,f,g,h,i); - DLIB_TEST(a==1 && b==2 && c==3 && d==4 && e==5 && f==6 && g==7 && h==8 && i==9); - zero_vals(a,b,c,d,e,f,g,h,i,j); - - f10(a,b,c,d,e,f,g,h,i,j); - DLIB_TEST(a==1 && b==2 && c==3 && d==4 && e==5 && f==6 && g==7 && h==8 && i==9 && j==10); - zero_vals(a,b,c,d,e,f,g,h,i,j); - } -// ---------------------------------------------------------------------------------------- - - class test_any_function : public tester - { - public: - test_any_function ( - ) : - tester ("test_any_function", - "Runs tests on the any_function component.") - {} - - void perform_test ( - ) - { - print_spinner(); - run_test(); - print_spinner(); - run_test2(); - print_spinner(); - run_test3(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/array.cpp b/lib/3rdParty/dlib/include/dlib/test/array.cpp deleted file mode 100644 index 55ba1a72..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/array.cpp +++ /dev/null @@ -1,669 +0,0 @@ -// Copyright (C) 2005 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include -#include -#include -#include -#include -#include -#include - - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - using dlib::array; - - logger dlog("test.array"); - - template < - typename array - > - void array_expand_test ( - ) - /*! - requires - - array is an implementation of array/array_sort_abstract.h - array is instantiated with unsigned long - ensures - - runs tests on array for compliance with the specs - !*/ - { - dlib::rand rnd; - - DLIB_TEST(dlib::is_array::value == true); - - array a1, a2; - - { - array a4(4); - DLIB_TEST(a4.size() == 4); - } - - { - array a1, a2; - - for (int k = 1; k < 100000; k += 1000) - { - for (int i = 0; i < 10; ++i) - { - a1.clear(); - a1.set_max_size(500+k); - a1.set_size(500+k); - for (unsigned long j = 0; j < a1.size(); ++j) - { - a1[j] = j; - DLIB_TEST(a1[j] == j); - } - } - } - } - - DLIB_TEST(a1.max_size() == 0); - DLIB_TEST(a2.max_size() == 0); - - - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start()); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.size() == 0); - - swap(a1,a2); - DLIB_TEST(a2.size() == 0); - DLIB_TEST(a2.current_element_valid() == false); - DLIB_TEST(a2.at_start() == false); - DLIB_TEST(a2.move_next() == false); - DLIB_TEST(a2.current_element_valid() == false); - DLIB_TEST(a2.size() == 0); - DLIB_TEST(a2.at_start() == false); - DLIB_TEST(a2.size() == 0); - - - - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start()); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.size() == 0); - - a1.reset(); - a2.reset(); - - for (unsigned long k = 0; k < 4; ++k) - { - - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start()); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.size() == 0); - - swap(a1,a2); - DLIB_TEST(a2.size() == 0); - DLIB_TEST(a2.current_element_valid() == false); - DLIB_TEST(a2.at_start() == false); - DLIB_TEST(a2.move_next() == false); - DLIB_TEST(a2.current_element_valid() == false); - DLIB_TEST(a2.size() == 0); - DLIB_TEST(a2.at_start() == false); - DLIB_TEST(a2.size() == 0); - - - - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start()); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.size() == 0); - - a1.clear(); - a2.clear(); - - - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start()); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.size() == 0); - - swap(a1,a2); - DLIB_TEST(a2.size() == 0); - DLIB_TEST(a2.current_element_valid() == false); - DLIB_TEST(a2.at_start() == false); - DLIB_TEST(a2.move_next() == false); - DLIB_TEST(a2.current_element_valid() == false); - DLIB_TEST(a2.size() == 0); - DLIB_TEST(a2.at_start() == false); - DLIB_TEST(a2.size() == 0); - - - - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start()); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.size() == 0); - - a1.clear(); - a2.clear(); - - - - - a1.set_max_size(100000); - a2.set_max_size(100000); - a1.set_size(10000); - DLIB_TEST(a1.size() == 10000); - a2.set_size(10000); - DLIB_TEST(a2.size() == 10000); - for (unsigned long i = 0; i < a1.size(); ++i) - { - unsigned long a = static_cast(rnd.get_random_32bit_number()); - a1[i] = a; - a2[i] = i; - DLIB_TEST(a1[i] == a); - DLIB_TEST(a2[i] == i); - } - - DLIB_TEST(a1.at_start()); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.move_next()); - DLIB_TEST(a1.current_element_valid()); - - DLIB_TEST(a1.at_start() == false); - a1.sort(); - DLIB_TEST(a1.at_start()); - a2.sort(); - DLIB_TEST(a1.size() == 10000); - DLIB_TEST(a2.size() == 10000); - - - for (unsigned long i = 0; i < a1.size(); ++i) - { - if (i+1 < a1.size()) - { - DLIB_TEST_MSG(a1[i] <= a1[i+1], - "a1[i]: " << a1[i] << " a1[i+1]: " << a1[i+1] - << " i: " << i); - } - DLIB_TEST_MSG(a2[i] == i,"i: " << i << " a2[i]: " << a2[i]); - } - - unsigned long last = 0; - unsigned long count = 0; - while (a1.move_next()) - { - DLIB_TEST(last <= a1.element()); - last = a1.element(); - ++count; - } - DLIB_TEST(count == a1.size()); - - last = 0; - count = 0; - while (a2.move_next()) - { - DLIB_TEST(last <= a2.element()); - last = a2.element(); - ++count; - } - DLIB_TEST(count == a2.size()); - - a2.set_size(15000); - - for (unsigned long i = 0; i < a1.size(); ++i) - { - if (i+1 < a1.size()) - { - DLIB_TEST(a1[i] <= a1[i+1]); - } - DLIB_TEST(a2[i] == i); - } - - for (unsigned long i = 10000; i < a2.size(); ++i) - { - a2[i] = i; - DLIB_TEST(a2[i] == i); - } - - for (unsigned long i = 0; i < a2.size(); ++i) - { - DLIB_TEST(a2[i] == i); - } - - a2.reset(); - last = 0; - while (a2.move_next()) - { - DLIB_TEST(last <= a2.element()); - last = a2.element(); - } - - a1.reset(); - last = 0; - while (a1.move_next()) - { - DLIB_TEST(last <= a1.element()); - last = a1.element(); - } - - a1.sort(); - last = 0; - while (a1.move_next()) - { - DLIB_TEST(last <= a1.element()); - last = a1.element(); - } - - swap(a2,a1); - - for (unsigned long i = 0; i < 15000; ++i) - { - DLIB_TEST(a1[i] == i); - } - - - - a1.clear(); - DLIB_TEST(a1.max_size() == 0); - - - - - a1.clear(); - a2.clear(); - - - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a2.size() == 0); - a1.set_max_size(100000); - a2.set_max_size(100000); - - a1.set_size(10000); - DLIB_TEST(a1.size() == 10000); - a2.set_size(10000); - DLIB_TEST(a2.size() == 10000); - for (unsigned long i = 0; i < a1.size(); ++i) - { - unsigned long a = static_cast(rnd.get_random_32bit_number()); - a1[i] = a; - a2[i] = i; - DLIB_TEST(a1[i] == a); - DLIB_TEST(a2[i] == i); - } - - DLIB_TEST(a1.at_start()); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.move_next()); - DLIB_TEST(a1.current_element_valid()); - - DLIB_TEST(a1.at_start() == false); - a1.sort(); - DLIB_TEST(a1.at_start()); - a2.sort(); - DLIB_TEST(a1.size() == 10000); - DLIB_TEST(a2.size() == 10000); - - - for (unsigned long i = 0; i < a1.size(); ++i) - { - if (i+1 < a1.size()) - { - DLIB_TEST(a1[i] <= a1[i+1]); - } - DLIB_TEST(a2[i] == i); - } - - last = 0; - while (a1.move_next()) - { - DLIB_TEST(last <= a1.element()); - last = a1.element(); - } - - last = 0; - while (a2.move_next()) - { - DLIB_TEST(last <= a2.element()); - last = a2.element(); - } - - a2.set_size(15000); - - for (unsigned long i = 0; i < a1.size(); ++i) - { - if (i+1 < a1.size()) - { - DLIB_TEST(a1[i] <= a1[i+1]); - } - DLIB_TEST(a2[i] == i); - } - - for (unsigned long i = 10000; i < a2.size(); ++i) - { - a2[i] = i; - DLIB_TEST(a2[i] == i); - } - - for (unsigned long i = 0; i < a2.size(); ++i) - { - DLIB_TEST(a2[i] == i); - } - - a2.reset(); - last = 0; - while (a2.move_next()) - { - DLIB_TEST(last <= a2.element()); - last = a2.element(); - } - - a1.reset(); - last = 0; - while (a1.move_next()) - { - DLIB_TEST(last <= a1.element()); - last = a1.element(); - } - - a1.sort(); - last = 0; - while (a1.move_next()) - { - DLIB_TEST(last <= a1.element()); - last = a1.element(); - } - - swap(a2,a1); - - for (unsigned long i = 0; i < 15000; ++i) - { - DLIB_TEST(a1[i] == i); - } - - - - a1.clear(); - DLIB_TEST(a1.max_size() == 0); - - a2.clear(); - print_spinner(); - } - - - - a1.set_max_size(2000000); - DLIB_TEST(a1.max_size() == 2000000); - DLIB_TEST(a1.size() == 0); - a1.set_size(2000000); - DLIB_TEST(a1.max_size() == 2000000); - DLIB_TEST(a1.size() == 2000000); - - for (unsigned long i = 0; i < a1.size(); ++i) - { - a1[i] = rnd.get_random_32bit_number(); - } - - print_spinner(); - a1.sort(); - - print_spinner(); - // serialize the state of a1, then clear a1, then - // load the state back into a1. - ostringstream sout; - serialize(a1,sout); - DLIB_TEST(a1.at_start() == true); - istringstream sin(sout.str()); - a1.clear(); - DLIB_TEST(a1.max_size() == 0); - deserialize(a1,sin); - - DLIB_TEST(a1.size() == 2000000); - - for (unsigned long i = 0; i < a1.size()-1; ++i) - { - DLIB_TEST(a1[i] <= a1[i+1]); - } - - DLIB_TEST(a1.max_size() == 2000000); - DLIB_TEST(a1.size() == 2000000); - - - swap(a1,a2); - - print_spinner(); - - DLIB_TEST(a2.size() == 2000000); - - for (unsigned long i = 0; i < a2.size()-1; ++i) - { - DLIB_TEST(a2[i] <= a2[i+1]); - } - - DLIB_TEST(a2.max_size() == 2000000); - DLIB_TEST(a2.size() == 2000000); - - swap(a1,a2); - - - a1.clear(); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.max_size() == 0); - - a1.resize(10); - DLIB_TEST(a1.size() == 10); - DLIB_TEST(a1.max_size() == 10); - - for (unsigned long i = 0; i < a1.size(); ++i) - { - a1[i] = i; - } - - print_spinner(); - a1.resize(100); - DLIB_TEST(a1.size() == 100); - DLIB_TEST(a1.max_size() == 100); - - for (unsigned long i = 0; i < 10; ++i) - { - DLIB_TEST(a1[i] == i); - } - - a1.resize(50); - DLIB_TEST(a1.size() == 50); - DLIB_TEST(a1.max_size() == 100); - - for (unsigned long i = 0; i < 10; ++i) - { - DLIB_TEST(a1[i] == i); - } - - a1.resize(10); - DLIB_TEST(a1.size() == 10); - DLIB_TEST(a1.max_size() == 100); - - for (unsigned long i = 0; i < 10; ++i) - { - DLIB_TEST(a1[i] == i); - } - - a1.resize(20); - DLIB_TEST(a1.size() == 20); - DLIB_TEST(a1.max_size() == 100); - - for (unsigned long i = 0; i < 10; ++i) - { - DLIB_TEST(a1[i] == i); - } - - - a1.resize(100); - DLIB_TEST(a1.size() == 100); - DLIB_TEST(a1.max_size() == 100); - - for (unsigned long i = 0; i < 10; ++i) - { - DLIB_TEST(a1[i] == i); - } - - { - a1.clear(); - DLIB_TEST(a1.size() == 0); - for (unsigned long i = 0; i < 100; ++i) - { - unsigned long a = i; - a1.push_back(a); - DLIB_TEST(a1.size() == i+1); - DLIB_TEST(a1.back() == i); - } - for (unsigned long i = 0; i < 100; ++i) - { - DLIB_TEST(a1[i] == i); - } - for (unsigned long i = 0; i < 100; ++i) - { - unsigned long a = 0; - a1.pop_back(a); - DLIB_TEST(a == 99-i); - } - } - - { - a1.clear(); - DLIB_TEST(a1.size() == 0); - for (unsigned long i = 0; i < 100; ++i) - { - unsigned long a = i; - a1.push_back(a); - DLIB_TEST(a1.size() == i+1); - DLIB_TEST(a1.back() == i); - } - for (unsigned long i = 0; i < 100; ++i) - { - DLIB_TEST(a1[i] == i); - } - for (unsigned long i = 0; i < 100; ++i) - { - a1.pop_back(); - } - DLIB_TEST(a1.size() == 0); - } - - } - - struct stuff - { - int whatever; - }; - void another_array_test() - { - array a; - a.resize(5); - a[0].whatever = 0; - stuff temp; - temp.whatever = 99; - a.push_back(temp); - DLIB_TEST(a.size() == 6); - DLIB_TEST(a[5].whatever == 99); - - DLIB_TEST(dlib::is_array >::value == true); - } - - void test_array_split() - { - array temp(5); - - for (unsigned int i = 0; i < temp.size(); ++i) - temp[i] = i; - - array b; - - split_array(temp, b, 0.5); - DLIB_TEST(temp.size() == 2); - DLIB_TEST(b.size() == 3); - - DLIB_TEST(temp[0] == 0); - DLIB_TEST(temp[1] == 1); - DLIB_TEST(b[0] == 2); - DLIB_TEST(b[1] == 3); - DLIB_TEST(b[2] == 4); - } - - class array_tester : public tester - { - public: - array_tester ( - ) : - tester ("test_array", - "Runs tests on the array component.") - {} - - void perform_test ( - ) - { - print_spinner(); - another_array_test(); - - // test a checking version first for good measure - print_spinner(); - array_expand_test >(); - - DLIB_TEST(dlib::is_array::value == false); - test_array_split(); - } - } a; - - - - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/array2d.cpp b/lib/3rdParty/dlib/include/dlib/test/array2d.cpp deleted file mode 100644 index 12b8b586..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/array2d.cpp +++ /dev/null @@ -1,580 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include "tester.h" -#include -#include - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.array2d"); - - template < - typename array2d - > - void array2d_kernel_test ( - ) - /*! - requires - - array2d is an implementation of array2d/array2d_kernel_abstract.h - is instantiated with unsigned long - ensures - - runs tests on array2d for compliance with the specs - !*/ - { - srand(static_cast(time(0))); - - array2d test,test2; - - long nc, nr; - - - DLIB_TEST(get_rect(test).is_empty()); - - enumerable& e = test; - DLIB_TEST(e.at_start() == true); - - - DLIB_TEST(e.size() == 0); - DLIB_TEST(e.at_start() == true); - DLIB_TEST(e.current_element_valid() == false); - - DLIB_TEST (e.move_next() == false); - DLIB_TEST (e.move_next() == false); - DLIB_TEST (e.move_next() == false); - DLIB_TEST (e.move_next() == false); - DLIB_TEST (e.move_next() == false); - DLIB_TEST (e.move_next() == false); - - - DLIB_TEST(e.size() == 0); - DLIB_TEST(e.at_start() == false); - DLIB_TEST(e.current_element_valid() == false); - - - e.reset(); - - DLIB_TEST(e.size() == 0); - DLIB_TEST(e.at_start() == true); - DLIB_TEST(e.current_element_valid() == false); - - - DLIB_TEST(get_rect(test).is_empty()); - - - - DLIB_TEST(test.at_start() == true); - - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - - DLIB_TEST (test.move_next() == false); - DLIB_TEST (test.move_next() == false); - DLIB_TEST (test.move_next() == false); - DLIB_TEST (test.move_next() == false); - DLIB_TEST (test.move_next() == false); - DLIB_TEST (test.move_next() == false); - - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == false); - - - test.reset(); - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - - test.clear(); - - - DLIB_TEST(test.at_start() == true); - - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - - DLIB_TEST (test.move_next() == false); - DLIB_TEST (test.move_next() == false); - DLIB_TEST (test.move_next() == false); - DLIB_TEST (test.move_next() == false); - DLIB_TEST (test.move_next() == false); - DLIB_TEST (test.move_next() == false); - - - test.set_size(0,0); - - DLIB_TEST(get_rect(test).is_empty()); - - DLIB_TEST(test.at_start() == true); - - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - - DLIB_TEST (test.move_next() == false); - DLIB_TEST (test.move_next() == false); - DLIB_TEST (test.move_next() == false); - DLIB_TEST (test.move_next() == false); - DLIB_TEST (test.move_next() == false); - DLIB_TEST (test.move_next() == false); - - swap(test,test2); - DLIB_TEST (test2.at_start() == false); - DLIB_TEST (test2.current_element_valid() == false); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - swap(test,test2); - DLIB_TEST(test2.at_start() == true); - DLIB_TEST(test2.current_element_valid() == false); - - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == false); - - - test.reset(); - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - - - - - for (int j = 0; j < 30; ++j) - { - test2.clear(); - switch (j) - { - case 0: - nc = 10; - nr = 11; - break; - case 1: - nc = 1; - nr = 1; - break; - case 2: - nc = 100; - nr = 1; - break; - case 3: - nc = 1; - nr = 100; - break; - default: - nc = ::rand()%100 + 1; - nr = ::rand()%100 + 1; - break; - } - - test.set_size(nr,nc); - - DLIB_TEST(get_rect(test).left() == 0); - DLIB_TEST(get_rect(test).top() == 0); - DLIB_TEST(get_rect(test).right() == nc-1); - DLIB_TEST(get_rect(test).bottom() == nr-1); - - DLIB_TEST(test.size() == static_cast(nc*nr)); - DLIB_TEST(test.nr() == nr); - DLIB_TEST(test.nc() == nc); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - - unsigned long i = 0; - while (test.move_next()) - { - DLIB_TEST(test.current_element_valid() == true); - DLIB_TEST(test.at_start() == false); - test.element() = i; - DLIB_TEST(const_cast(test).element() == i); - ++i; - } - DLIB_TEST(i == test.size()); - DLIB_TEST(test.current_element_valid() == false); - - DLIB_TEST(test.nr() == nr); - DLIB_TEST(test.nc() == nc); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.size() == static_cast(nc*nr)); - - i = 0; - for (long row = 0; row < test.nr(); ++row) - { - for (long col = 0; col < test.nc(); ++col) - { - DLIB_TEST_MSG(test[row][col] == i, - "\n\trow: " << row << - "\n\tcol: " << col << - "\n\ti: " << i << - "\n\ttest[row][col]: " << test[row][col]); - DLIB_TEST(test[row].nc() == test.nc()); - DLIB_TEST(test.current_element_valid() == false); - - DLIB_TEST(test.nr() == nr); - DLIB_TEST(test.nc() == nc); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.size() == static_cast(nc*nr)); - ++i; - } - } - - test.reset(); - - i = 0; - while (test.move_next()) - { - DLIB_TEST(test.element() == i); - ++i; - DLIB_TEST(test.current_element_valid() == true); - DLIB_TEST(test.at_start() == false); - } - DLIB_TEST(i == test.size()); - - test.reset(); - - - - - swap(test,test2); - - DLIB_TEST(test2.size() == static_cast(nc*nr)); - DLIB_TEST(test2.nr() == nr); - DLIB_TEST(test2.nc() == nc); - DLIB_TEST(test2.at_start() == true); - DLIB_TEST(test2.current_element_valid() == false); - - i = 0; - while (test2.move_next()) - { - DLIB_TEST(test2.current_element_valid() == true); - DLIB_TEST(test2.at_start() == false); - test2.element() = i; - ++i; - } - DLIB_TEST(i == test2.size()); - DLIB_TEST(test2.current_element_valid() == false); - - DLIB_TEST(test2.nr() == nr); - DLIB_TEST(test2.nr() == test2.nr()); - DLIB_TEST(test2.nc() == nc); - DLIB_TEST(test2.nc() == test2.nc()); - DLIB_TEST(test2.at_start() == false); - DLIB_TEST(test2.size() == static_cast(nc*nr)); - - i = 0; - for (long row = 0; row < test2.nr(); ++row) - { - for (long col = 0; col < test2.nc(); ++col) - { - DLIB_TEST(test2[row][col] == i); - DLIB_TEST(const_cast(test2)[row][col] == i); - DLIB_TEST(test2[row].nc() == test2.nc()); - DLIB_TEST(test2.current_element_valid() == false); - - DLIB_TEST(test2.nr() == nr); - DLIB_TEST(test2.nr() == test2.nr()); - DLIB_TEST(test2.nc() == nc); - DLIB_TEST(test2.nc() == test2.nc()); - DLIB_TEST(test2.at_start() == false); - DLIB_TEST(test2.size() == static_cast(nc*nr)); - ++i; - } - } - - test2.reset(); - - i = 0; - while (test2.move_next()) - { - DLIB_TEST(test2.element() == i); - DLIB_TEST(const_cast(test2).element() == i); - ++i; - DLIB_TEST(test2.current_element_valid() == true); - DLIB_TEST(test2.at_start() == false); - } - DLIB_TEST(i == test2.size()); - - - test2.clear(); - DLIB_TEST(test2.size() == 0); - DLIB_TEST(test2.nr() == 0); - DLIB_TEST(test2.nc() == 0); - DLIB_TEST(test2.current_element_valid() == false); - DLIB_TEST(test2.at_start() == true); - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.nc() == 0); - DLIB_TEST(test.nr() == 0); - - test.set_size(nr,nc); - DLIB_TEST(test.size() == static_cast(nc*nr)); - DLIB_TEST(test.nc() == nc); - DLIB_TEST(test.nr() == nr); - - - - } - - - - - - // test the serialization - istringstream sin; - ostringstream sout; - test.clear(); - test2.clear(); - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.nc() == 0); - DLIB_TEST(test.nr() == 0); - DLIB_TEST(test2.size() == 0); - DLIB_TEST(test2.nc() == 0); - DLIB_TEST(test2.nr() == 0); - - test.set_size(10,10); - - for (long row = 0; row < test.nr(); ++row) - { - for (long col = 0; col < test.nc(); ++col) - { - test[row][col] = row*col; - } - } - - serialize(test,sout); - sin.str(sout.str()); - deserialize(test2,sin); - - DLIB_TEST(test2.size() == test.size()); - DLIB_TEST(test2.nc() == test.nc()); - DLIB_TEST(test2.nr() == test.nr()); - DLIB_TEST(test2.size() == 100); - DLIB_TEST(test2.nc() == 10); - DLIB_TEST(test2.nr() == 10); - - - for (long row = 0; row < test.nr(); ++row) - { - for (long col = 0; col < test.nc(); ++col) - { - DLIB_TEST(test[row][col] == static_cast(row*col)); - DLIB_TEST(test2[row][col] == static_cast(row*col)); - } - } - - - - - - - test.set_size(10,11); - DLIB_TEST(test.nr() == 10); - DLIB_TEST(test.nc() == 11); - test.set_size(0,0); - DLIB_TEST(test.nr() == 0); - DLIB_TEST(test.nc() == 0); - - } - - void test_serialization() - { - // Do these tests because there are overloads of the serialize routines - // specifically for these types of pixel (except for unsigned short, - // we do that because you can never have too many tests). - { - array2d img, img2; - img.set_size(3,2); - assign_all_pixels(img, 5); - img[1][1].red = 9; - img[1][1].green = 8; - img[1][1].blue = 7; - img[1][1].alpha = 3; - ostringstream sout; - serialize(img, sout); - istringstream sin(sout.str()); - deserialize(img2, sin); - - DLIB_TEST(img2.nr() == 3); - DLIB_TEST(img2.nc() == 2); - - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - DLIB_TEST(img[r][c].red == img2[r][c].red); - DLIB_TEST(img[r][c].green == img2[r][c].green); - DLIB_TEST(img[r][c].blue == img2[r][c].blue); - DLIB_TEST(img[r][c].alpha == img2[r][c].alpha); - } - } - } - { - array2d img, img2; - img.set_size(3,2); - assign_all_pixels(img, 5); - img[1][1].h = 9; - img[1][1].s = 2; - img[1][1].i = 3; - ostringstream sout; - serialize(img, sout); - istringstream sin(sout.str()); - deserialize(img2, sin); - - DLIB_TEST(img2.nr() == 3); - DLIB_TEST(img2.nc() == 2); - - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - DLIB_TEST(img[r][c].h == img2[r][c].h); - DLIB_TEST(img[r][c].s == img2[r][c].s); - DLIB_TEST(img[r][c].i == img2[r][c].i); - } - } - } - { - array2d img, img2; - img.set_size(3,2); - assign_all_pixels(img, 5); - img[1][1].red = 1; - img[1][1].green = 2; - img[1][1].blue = 3; - ostringstream sout; - serialize(img, sout); - istringstream sin(sout.str()); - deserialize(img2, sin); - - DLIB_TEST(img2.nr() == 3); - DLIB_TEST(img2.nc() == 2); - - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - DLIB_TEST(img[r][c].red == img2[r][c].red); - DLIB_TEST(img[r][c].green == img2[r][c].green); - DLIB_TEST(img[r][c].blue == img2[r][c].blue); - } - } - } - { - array2d img, img2; - img.set_size(3,2); - assign_all_pixels(img, 5); - img[1][1].red = 1; - img[1][1].green = 2; - img[1][1].blue = 3; - ostringstream sout; - serialize(img, sout); - istringstream sin(sout.str()); - deserialize(img2, sin); - - DLIB_TEST(img2.nr() == 3); - DLIB_TEST(img2.nc() == 2); - - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - DLIB_TEST(img[r][c].red == img2[r][c].red); - DLIB_TEST(img[r][c].green == img2[r][c].green); - DLIB_TEST(img[r][c].blue == img2[r][c].blue); - } - } - } - { - array2d img, img2; - img.set_size(3,2); - assign_all_pixels(img, 5); - img[1][1] = 9; - ostringstream sout; - serialize(img, sout); - istringstream sin(sout.str()); - deserialize(img2, sin); - - DLIB_TEST(img2.nr() == 3); - DLIB_TEST(img2.nc() == 2); - - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - DLIB_TEST(img[r][c] == img2[r][c]); - } - } - } - { - array2d img, img2; - img.set_size(3,2); - assign_all_pixels(img, 5); - img[1][1] = 9; - ostringstream sout; - serialize(img, sout); - istringstream sin(sout.str()); - deserialize(img2, sin); - - DLIB_TEST(img2.nr() == 3); - DLIB_TEST(img2.nc() == 2); - - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - DLIB_TEST(img[r][c] == img2[r][c]); - } - } - - DLIB_TEST((char*)&img[0][0] + img.width_step() == (char*)&img[1][0]); - } - - COMPILE_TIME_ASSERT(is_array2d >::value == true); - COMPILE_TIME_ASSERT(is_array2d >::value == true); - COMPILE_TIME_ASSERT(is_array2d::value == false); - } - - - class array2d_tester : public tester - { - public: - array2d_tester ( - ) : - tester ("test_array2d", - "Runs tests on the array2d component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a"; - array2d_kernel_test >(); - print_spinner(); - test_serialization(); - print_spinner(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/assignment_learning.cpp b/lib/3rdParty/dlib/include/dlib/test/assignment_learning.cpp deleted file mode 100644 index bba47db3..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/assignment_learning.cpp +++ /dev/null @@ -1,379 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include "tester.h" -#include -#include - - -typedef dlib::matrix lhs_element; -typedef dlib::matrix rhs_element; - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.assignment_learning"); - -// ---------------------------------------------------------------------------------------- - - -// ---------------------------------------------------------------------------------------- - - struct feature_extractor_dense - { - typedef matrix feature_vector_type; - - typedef ::lhs_element lhs_element; - typedef ::rhs_element rhs_element; - - unsigned long num_features() const - { - return 3; - } - - void get_features ( - const lhs_element& left, - const rhs_element& right, - feature_vector_type& feats - ) const - { - feats = squared(left - right); - } - - }; - - void serialize (const feature_extractor_dense& , std::ostream& ) {} - void deserialize (feature_extractor_dense& , std::istream& ) {} - -// ---------------------------------------------------------------------------------------- - - struct feature_extractor_sparse - { - typedef std::vector > feature_vector_type; - - typedef ::lhs_element lhs_element; - typedef ::rhs_element rhs_element; - - unsigned long num_features() const - { - return 3; - } - - void get_features ( - const lhs_element& left, - const rhs_element& right, - feature_vector_type& feats - ) const - { - feats.clear(); - feats.push_back(make_pair(0,squared(left-right)(0))); - feats.push_back(make_pair(1,squared(left-right)(1))); - feats.push_back(make_pair(2,squared(left-right)(2))); - } - - }; - - void serialize (const feature_extractor_sparse& , std::ostream& ) {} - void deserialize (feature_extractor_sparse& , std::istream& ) {} - -// ---------------------------------------------------------------------------------------- - - typedef std::pair, std::vector > sample_type; - typedef std::vector label_type; - -// ---------------------------------------------------------------------------------------- - - void make_data ( - std::vector& samples, - std::vector& labels - ) - { - lhs_element a, b, c, d; - a = 1,0,0; - b = 0,1,0; - c = 0,0,1; - d = 0,1,1; - - std::vector lhs; - std::vector rhs; - label_type label; - - lhs.push_back(a); - lhs.push_back(b); - lhs.push_back(c); - - rhs.push_back(b); - rhs.push_back(a); - rhs.push_back(c); - - label.push_back(1); - label.push_back(0); - label.push_back(2); - - samples.push_back(make_pair(lhs,rhs)); - labels.push_back(label); - - - - - lhs.clear(); - rhs.clear(); - label.clear(); - - lhs.push_back(a); - lhs.push_back(b); - lhs.push_back(c); - - rhs.push_back(c); - rhs.push_back(b); - rhs.push_back(a); - rhs.push_back(d); - - label.push_back(2); - label.push_back(1); - label.push_back(0); - - samples.push_back(make_pair(lhs,rhs)); - labels.push_back(label); - - - lhs.clear(); - rhs.clear(); - label.clear(); - - lhs.push_back(a); - lhs.push_back(b); - lhs.push_back(c); - - rhs.push_back(c); - rhs.push_back(a); - rhs.push_back(d); - - label.push_back(1); - label.push_back(-1); - label.push_back(0); - - samples.push_back(make_pair(lhs,rhs)); - labels.push_back(label); - - - - lhs.clear(); - rhs.clear(); - label.clear(); - - lhs.push_back(d); - lhs.push_back(b); - lhs.push_back(c); - - label.push_back(-1); - label.push_back(-1); - label.push_back(-1); - - samples.push_back(make_pair(lhs,rhs)); - labels.push_back(label); - - - - lhs.clear(); - rhs.clear(); - label.clear(); - - samples.push_back(make_pair(lhs,rhs)); - labels.push_back(label); - - } - -// ---------------------------------------------------------------------------------------- - - void make_data_force ( - std::vector& samples, - std::vector& labels - ) - { - lhs_element a, b, c, d; - a = 1,0,0; - b = 0,1,0; - c = 0,0,1; - d = 0,1,1; - - std::vector lhs; - std::vector rhs; - label_type label; - - lhs.push_back(a); - lhs.push_back(b); - lhs.push_back(c); - - rhs.push_back(b); - rhs.push_back(a); - rhs.push_back(c); - - label.push_back(1); - label.push_back(0); - label.push_back(2); - - samples.push_back(make_pair(lhs,rhs)); - labels.push_back(label); - - - - - lhs.clear(); - rhs.clear(); - label.clear(); - - lhs.push_back(a); - lhs.push_back(b); - lhs.push_back(c); - - rhs.push_back(c); - rhs.push_back(b); - rhs.push_back(a); - rhs.push_back(d); - - label.push_back(2); - label.push_back(1); - label.push_back(0); - - samples.push_back(make_pair(lhs,rhs)); - labels.push_back(label); - - - lhs.clear(); - rhs.clear(); - label.clear(); - - lhs.push_back(a); - lhs.push_back(c); - - rhs.push_back(c); - rhs.push_back(a); - - label.push_back(1); - label.push_back(0); - - samples.push_back(make_pair(lhs,rhs)); - labels.push_back(label); - - - - - - lhs.clear(); - rhs.clear(); - label.clear(); - - samples.push_back(make_pair(lhs,rhs)); - labels.push_back(label); - - } - -// ---------------------------------------------------------------------------------------- - - template - void test1(F make_data, bool force_assignment) - { - print_spinner(); - - std::vector samples; - std::vector labels; - - make_data(samples, labels); - make_data(samples, labels); - make_data(samples, labels); - - randomize_samples(samples, labels); - - structural_assignment_trainer trainer; - - DLIB_TEST(trainer.forces_assignment() == false); - DLIB_TEST(trainer.get_c() == 100); - DLIB_TEST(trainer.get_num_threads() == 2); - DLIB_TEST(trainer.get_max_cache_size() == 5); - - - trainer.set_forces_assignment(force_assignment); - trainer.set_num_threads(3); - trainer.set_c(50); - - DLIB_TEST(trainer.get_c() == 50); - DLIB_TEST(trainer.get_num_threads() == 3); - DLIB_TEST(trainer.forces_assignment() == force_assignment); - - assignment_function ass = trainer.train(samples, labels); - - for (unsigned long i = 0; i < samples.size(); ++i) - { - std::vector out = ass(samples[i]); - dlog << LINFO << "true labels: " << trans(mat(labels[i])); - dlog << LINFO << "pred labels: " << trans(mat(out)); - DLIB_TEST(trans(mat(labels[i])) == trans(mat(out))); - } - - double accuracy; - - dlog << LINFO << "samples.size(): "<< samples.size(); - accuracy = test_assignment_function(ass, samples, labels); - dlog << LINFO << "accuracy: "<< accuracy; - DLIB_TEST(accuracy == 1); - - accuracy = cross_validate_assignment_trainer(trainer, samples, labels, 3); - dlog << LINFO << "cv accuracy: "<< accuracy; - DLIB_TEST(accuracy == 1); - - ostringstream sout; - serialize(ass, sout); - istringstream sin(sout.str()); - assignment_function ass2; - deserialize(ass2, sin); - - DLIB_TEST(ass2.forces_assignment() == ass.forces_assignment()); - DLIB_TEST(length(ass2.get_weights() - ass.get_weights()) < 1e-10); - - for (unsigned long i = 0; i < samples.size(); ++i) - { - std::vector out = ass2(samples[i]); - dlog << LINFO << "true labels: " << trans(mat(labels[i])); - dlog << LINFO << "pred labels: " << trans(mat(out)); - DLIB_TEST(trans(mat(labels[i])) == trans(mat(out))); - } - } - -// ---------------------------------------------------------------------------------------- - - class test_assignment_learning : public tester - { - public: - test_assignment_learning ( - ) : - tester ("test_assignment_learning", - "Runs tests on the assignment learning code.") - {} - - void perform_test ( - ) - { - test1(make_data, false); - test1(make_data, false); - - test1(make_data_force, false); - test1(make_data_force, false); - test1(make_data_force, true); - test1(make_data_force, true); - } - } a; - -// ---------------------------------------------------------------------------------------- - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/base64.cpp b/lib/3rdParty/dlib/include/dlib/test/base64.cpp deleted file mode 100644 index f4d47801..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/base64.cpp +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.base64"); - - template < - typename base64 - > - void base64_kernel_test ( - ) - /*! - requires - - base64 is an implementation of base64/base64_kernel_abstract.h - ensures - - runs tests on base64 for compliance with the specs - !*/ - { - - const unsigned int seed = static_cast(time(0)); - try - { - - srand(seed); - - base64 test; - - const string wiki_normal = "\ -Man is distinguished, not only by his reason, but by this singular passion from other \ -animals, which is a lust of the mind, that by a perseverance of delight in the continued \ -and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure."; - - const string wiki_encoded = "\ -TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0\n\ -aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1\n\ -c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0\n\ -aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdl\n\ -LCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="; - - - - string str; - - istringstream sin; - ostringstream sout; - - sin.str(wiki_encoded); - test.decode(sin,sout); - DLIB_TEST_MSG(sout.str() == wiki_normal, - "sout.str(): " << sout.str() << - "\nwiki_normal: " << wiki_normal); - - - sout.str(""); - sin.str(wiki_normal); - sin.clear(); - test.encode(sin,sout); - - string a(sout.str()), b(wiki_encoded); - // we want to strip all the whitespace from a and b now - sin.str(a); - a.clear(); - sin >> str; - while (sin) - { - a += str; - sin >> str; - } - - sin.clear(); - sin.str(b); - b.clear(); - sin >> str; - while (sin) - { - b += str; - sin >> str; - } - sin.clear(); - - DLIB_TEST_MSG(a == b, - "a: \n" << a << - "\n\nb: \n" << b); - - - - sin.clear(); - sin.str(""); - sout.str(""); - test.encode(sin,sout); - sin.str(sout.str()); - sout.str(""); - test.decode(sin,sout); - DLIB_TEST(sout.str() == ""); - - sin.clear(); - sin.str("a"); - sout.str(""); - test.encode(sin,sout); - sin.str(sout.str()); - sout.str(""); - test.decode(sin,sout); - DLIB_TEST(sout.str() == "a"); - - sin.clear(); - sin.str("da"); - sout.str(""); - test.encode(sin,sout); - sin.str(sout.str()); - sout.str(""); - test.decode(sin,sout); - DLIB_TEST(sout.str() == "da"); - - sin.clear(); - sin.str("dav"); - sout.str(""); - test.encode(sin,sout); - sin.str(sout.str()); - sout.str(""); - test.decode(sin,sout); - DLIB_TEST(sout.str() == "dav"); - - sin.clear(); - sin.str("davi"); - sout.str(""); - test.encode(sin,sout); - sin.str(sout.str()); - sout.str(""); - test.decode(sin,sout); - DLIB_TEST(sout.str() == "davi"); - - - for (int i = 0; i < 1000; ++i) - { - str.clear(); - sin.clear(); - sout.str(""); - sin.str(""); - - // fill str with random garbage - const int size = rand()%2000; - for (int j = 0; j < size; ++j) - { - unsigned char ch = rand()&0xFF; - str += ch; - } - - sin.str(str); - test.encode(sin,sout); - sin.clear(); - sin.str(sout.str()); - sout.str(""); - test.decode(sin,sout); - - DLIB_TEST(str == sout.str()); - - - } - - - - - } - catch (typename base64::decode_error& e) - { - DLIB_TEST_MSG(false, - "decode_error thrown when it shouldn't have been (" << seed << "):\n " - << e.info); - } - } - - - class base64_tester : public tester - { - public: - base64_tester ( - ) : - tester ("test_base64", - "Runs tests on the base64 component.") - {} - - void perform_test ( - ) - { - print_spinner(); - base64_kernel_test(); - } - } a; - - - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/bayes_nets.cpp b/lib/3rdParty/dlib/include/dlib/test/bayes_nets.cpp deleted file mode 100644 index acdf6e99..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/bayes_nets.cpp +++ /dev/null @@ -1,411 +0,0 @@ -// Copyright (C) 2007 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include "dlib/graph_utils.h" -#include "dlib/graph.h" -#include "dlib/directed_graph.h" -#include "dlib/bayes_utils.h" -#include "dlib/set.h" -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.bayes_nets"); - enum nodes - { - A, T, S, L, O, B, D, X - }; - - template - void setup_simple_network ( - gtype& bn - ) - { - /* - A - / \ - T S - */ - - using namespace bayes_node_utils; - - bn.set_number_of_nodes(3); - bn.add_edge(A, T); - bn.add_edge(A, S); - - - set_node_num_values(bn, A, 2); - set_node_num_values(bn, T, 2); - set_node_num_values(bn, S, 2); - - assignment parents; - - // set probabilities for node A - set_node_probability(bn, A, 1, parents, 0.1); - set_node_probability(bn, A, 0, parents, 1-0.1); - - // set probabilities for node T - parents.add(A, 1); - set_node_probability(bn, T, 1, parents, 0.5); - set_node_probability(bn, T, 0, parents, 1-0.5); - parents[A] = 0; - set_node_probability(bn, T, 1, parents, 0.5); - set_node_probability(bn, T, 0, parents, 1-0.5); - - // set probabilities for node S - parents[A] = 1; - set_node_probability(bn, S, 1, parents, 0.5); - set_node_probability(bn, S, 0, parents, 1-0.5); - parents[A] = 0; - set_node_probability(bn, S, 1, parents, 0.5); - set_node_probability(bn, S, 0, parents, 1-0.5); - - - // test the serialization code here by pushing this network though it - ostringstream sout; - serialize(bn, sout); - bn.clear(); - DLIB_TEST(bn.number_of_nodes() == 0); - istringstream sin(sout.str()); - deserialize(bn, sin); - DLIB_TEST(bn.number_of_nodes() == 3); - } - - - template - void setup_dyspnea_network ( - gtype& bn, - bool deterministic_o_node = true - ) - { - /* - This is the example network used by David Zaret in his - reasoning under uncertainty class at Johns Hopkins - */ - - using namespace bayes_node_utils; - - bn.set_number_of_nodes(8); - bn.add_edge(A, T); - bn.add_edge(T, O); - - bn.add_edge(O, D); - bn.add_edge(O, X); - - bn.add_edge(S, B); - bn.add_edge(S, L); - - bn.add_edge(L, O); - bn.add_edge(B, D); - - - set_node_num_values(bn, A, 2); - set_node_num_values(bn, T, 2); - set_node_num_values(bn, O, 2); - set_node_num_values(bn, X, 2); - set_node_num_values(bn, L, 2); - set_node_num_values(bn, S, 2); - set_node_num_values(bn, B, 2); - set_node_num_values(bn, D, 2); - - assignment parents; - - // set probabilities for node A - set_node_probability(bn, A, 1, parents, 0.01); - set_node_probability(bn, A, 0, parents, 1-0.01); - - // set probabilities for node S - set_node_probability(bn, S, 1, parents, 0.5); - set_node_probability(bn, S, 0, parents, 1-0.5); - - // set probabilities for node T - parents.add(A, 1); - set_node_probability(bn, T, 1, parents, 0.05); - set_node_probability(bn, T, 0, parents, 1-0.05); - parents[A] = 0; - set_node_probability(bn, T, 1, parents, 0.01); - set_node_probability(bn, T, 0, parents, 1-0.01); - - // set probabilities for node L - parents.clear(); - parents.add(S,1); - set_node_probability(bn, L, 1, parents, 0.1); - set_node_probability(bn, L, 0, parents, 1-0.1); - parents[S] = 0; - set_node_probability(bn, L, 1, parents, 0.01); - set_node_probability(bn, L, 0, parents, 1-0.01); - - - // set probabilities for node B - parents[S] = 1; - set_node_probability(bn, B, 1, parents, 0.6); - set_node_probability(bn, B, 0, parents, 1-0.6); - parents[S] = 0; - set_node_probability(bn, B, 1, parents, 0.3); - set_node_probability(bn, B, 0, parents, 1-0.3); - - - // set probabilities for node O - double v; - if (deterministic_o_node) - v = 1; - else - v = 0.99; - - parents.clear(); - parents.add(T,1); - parents.add(L,1); - set_node_probability(bn, O, 1, parents, v); - set_node_probability(bn, O, 0, parents, 1-v); - parents[T] = 0; parents[L] = 1; - set_node_probability(bn, O, 1, parents, v); - set_node_probability(bn, O, 0, parents, 1-v); - parents[T] = 1; parents[L] = 0; - set_node_probability(bn, O, 1, parents, v); - set_node_probability(bn, O, 0, parents, 1-v); - parents[T] = 0; parents[L] = 0; - set_node_probability(bn, O, 1, parents, 1-v); - set_node_probability(bn, O, 0, parents, v); - - - // set probabilities for node D - parents.clear(); - parents.add(O,1); - parents.add(B,1); - set_node_probability(bn, D, 1, parents, 0.9); - set_node_probability(bn, D, 0, parents, 1-0.9); - parents[O] = 1; parents[B] = 0; - set_node_probability(bn, D, 1, parents, 0.7); - set_node_probability(bn, D, 0, parents, 1-0.7); - parents[O] = 0; parents[B] = 1; - set_node_probability(bn, D, 1, parents, 0.8); - set_node_probability(bn, D, 0, parents, 1-0.8); - parents[O] = 0; parents[B] = 0; - set_node_probability(bn, D, 1, parents, 0.1); - set_node_probability(bn, D, 0, parents, 1-0.1); - - - // set probabilities for node X - parents.clear(); - parents.add(O,1); - set_node_probability(bn, X, 1, parents, 0.98); - set_node_probability(bn, X, 0, parents, 1-0.98); - parents[O] = 0; - set_node_probability(bn, X, 1, parents, 0.05); - set_node_probability(bn, X, 0, parents, 1-0.05); - - - // test the serialization code here by pushing this network though it - ostringstream sout; - serialize(bn, sout); - bn.clear(); - DLIB_TEST(bn.number_of_nodes() == 0); - istringstream sin(sout.str()); - deserialize(bn, sin); - DLIB_TEST(bn.number_of_nodes() == 8); - } - - - void bayes_nets_test ( - ) - /*! - ensures - - runs tests on the bayesian network objects and functions for compliance with the specs - !*/ - { - - print_spinner(); - - directed_graph::kernel_1a_c bn; - setup_dyspnea_network(bn); - - using namespace bayes_node_utils; - - - graph::compare_1b_c, dlib::set::compare_1b_c>::kernel_1a_c join_tree; - - create_moral_graph(bn, join_tree); - create_join_tree(join_tree, join_tree); - - bayesian_network_join_tree solution(bn, join_tree); - - matrix dist; - - dist = solution.probability(A); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 0.01 ) < 1e-5); - - dist = solution.probability(T); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 0.0104) < 1e-5); - - dist = solution.probability(O); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 0.064828) < 1e-5); - - dist = solution.probability(X); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 0.11029004) < 1e-5); - - dist = solution.probability(L); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 0.055) < 1e-5); - - dist = solution.probability(S); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 0.5) < 1e-5); - - dist = solution.probability(B); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 0.4499999) < 1e-5); - - dist = solution.probability(D); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 0.4359706 ) < 1e-5); - - // now lets modify the probabilities of the bayesian network by making O - // not a deterministic node anymore but otherwise leave the network alone - setup_dyspnea_network(bn, false); - - set_node_value(bn, A, 1); - set_node_value(bn, X, 1); - set_node_value(bn, S, 1); - // lets also make some of these nodes evidence nodes - set_node_as_evidence(bn, A); - set_node_as_evidence(bn, X); - set_node_as_evidence(bn, S); - - // reload the solution now that we have changed the probabilities of node O - bayesian_network_join_tree(bn, join_tree).swap(solution); - DLIB_TEST(solution.number_of_nodes() == bn.number_of_nodes()); - - dist = solution.probability(A); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 1.0 ) < 1e-5); - - dist = solution.probability(T); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 0.253508694039 ) < 1e-5); - - dist = solution.probability(O); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 0.77856184024 ) < 1e-5); - - dist = solution.probability(X); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 1.0 ) < 1e-5); - - dist = solution.probability(L); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 0.5070173880 ) < 1e-5); - - dist = solution.probability(S); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 1.0 ) < 1e-5); - - dist = solution.probability(B); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 0.6 ) < 1e-5); - - dist = solution.probability(D); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 0.7535685520 ) < 1e-5); - - - // now lets test the bayesian_network_gibbs_sampler - set_node_value(bn, A, 1); - set_node_value(bn, T, 1); - set_node_value(bn, O, 1); - set_node_value(bn, X, 1); - set_node_value(bn, S, 1); - set_node_value(bn, L, 1); - set_node_value(bn, B, 1); - set_node_value(bn, D, 1); - - bayesian_network_gibbs_sampler sampler; - matrix counts; - set_all_elements(counts, 0); - const unsigned long rounds = 200000; - for (unsigned long i = 0; i < rounds; ++i) - { - sampler.sample_graph(bn); - - for (long c = 0; c < counts.nc(); ++c) - { - if (node_value(bn, c) == 1) - counts(c) += 1; - } - - if ((i&0x3FF) == 0) - { - print_spinner(); - } - } - - counts /= rounds; - - DLIB_TEST(abs(counts(A) - 1.0 ) < 1e-2); - DLIB_TEST(abs(counts(T) - 0.253508694039 ) < 1e-2); - DLIB_TEST_MSG(abs(counts(O) - 0.77856184024 ) < 1e-2,abs(counts(O) - 0.77856184024 ) ); - DLIB_TEST(abs(counts(X) - 1.0 ) < 1e-2); - DLIB_TEST(abs(counts(L) - 0.5070173880 ) < 1e-2); - DLIB_TEST(abs(counts(S) - 1.0 ) < 1e-2); - DLIB_TEST(abs(counts(B) - 0.6 ) < 1e-2); - DLIB_TEST(abs(counts(D) - 0.7535685520 ) < 1e-2); - - - setup_simple_network(bn); - create_moral_graph(bn, join_tree); - create_join_tree(join_tree, join_tree); - bayesian_network_join_tree(bn, join_tree).swap(solution); - DLIB_TEST(solution.number_of_nodes() == bn.number_of_nodes()); - - dist = solution.probability(A); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 0.1 ) < 1e-5); - - dist = solution.probability(T); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 0.5 ) < 1e-5); - - dist = solution.probability(S); - DLIB_TEST(abs(sum(dist) - 1.0) < 1e-5); - DLIB_TEST(abs(dist(1) - 0.5 ) < 1e-5); - - - } - - - - - class bayes_nets_tester : public tester - { - public: - bayes_nets_tester ( - ) : - tester ("test_bayes_nets", - "Runs tests on the bayes_nets objects and functions.") - {} - - void perform_test ( - ) - { - bayes_nets_test(); - } - } a; - -} - - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/bigint.cpp b/lib/3rdParty/dlib/include/dlib/test/bigint.cpp deleted file mode 100644 index 3ddc631b..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/bigint.cpp +++ /dev/null @@ -1,522 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include - -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.bigint"); - - namespace bigint_kernel_test_helpers - { - template < - typename bint - > - bint short_fact (unsigned short value) - /*! - ensures - - returns the factorial of value - !*/ - { - using namespace relational_operators; - - bint a = 1; - for (unsigned short i = 2; i <= value; ++i) - a *= i; - - return a; - } - - template < - typename bint - > - bint short_fact_squared (unsigned short value) - /*! - ensures - - returns the square of the factorial of value - !*/ - { - using namespace relational_operators; - - bint a = 1; - for (unsigned short i = 2; i <= value; ++i) - { - a *= i; - a *= i; - } - - return a; - } - - - template < - typename bint - > - bint big_fact (unsigned short value) - /*! - ensures - - returns the factorial of value - !*/ - { - using namespace relational_operators; - - bint a = 1; - int k = 0; - for (bint i = 2; i <= value; ++i) - { - ++k; - if (k%10 == 0) - print_spinner(); - a *= i; - } - - return a; - } - } - - template < - typename bint - > - void bigint_kernel_test ( - ) - /*! - requires - - bint is an implementation of bigint/bigint_kernel_abstract.h - ensures - - runs tests on bint for compliance with the specs - !*/ - { - using namespace bigint_kernel_test_helpers; - using namespace relational_operators; - istringstream sin; - ostringstream sout; - - bint i = 0; - bint a(5), b, c(0); - - DLIB_TEST(5 - a == 0); - DLIB_TEST(a - 5 == 0); - - DLIB_TEST(0 - c == 0); - DLIB_TEST(c - 0 == 0); - - DLIB_TEST(0 + c == 0); - DLIB_TEST(c + 0 == 0); - - DLIB_TEST(0 + a == 5); - DLIB_TEST(a + 0 == 5); - - DLIB_TEST(0 - b == 0); - DLIB_TEST(b - 0 == 0); - - DLIB_TEST(0 + b == 0); - DLIB_TEST(b + 0 == 0); - - DLIB_TEST(i == 0); - DLIB_TEST(a == 5); - DLIB_TEST(b == 0); - DLIB_TEST(c == 0); - - - - a -= 5; - DLIB_TEST(a == 0); - - - - for (int k = 0; k < 100; ++k) - { - // compute the factorial of k using the O(n) multiplication algorithm - a = short_fact(k); - // compute the factorial of k using the full blown big int - // multiplication algorithm. - b = big_fact(k); - // compute the square of the factorial of k using the full blown - // big int multiplication algorithm. - c = a*b; - // make sure a and b ended up being the same number - DLIB_TEST_MSG(a == b, - "k: " << k << "\n" - "short_fact: " << a << "\n" - "big_fact: " << b - ); - // make sure c really is the square of the factorial of k - DLIB_TEST_MSG(short_fact_squared(k) == c,"k: " << k); - print_spinner(); - } - - // do the same thing as the last loop but do it with way bigger numbers - for (int k = 1000; k < 10000; k += 2000) - { - bint a = short_fact(k); - bint b = big_fact(k); - bint c = a*b; - DLIB_TEST_MSG(a == b, - "k: " << k << "\n" - "short_fact: " << a << "\n" - "big_fact: " << b - ); - DLIB_TEST_MSG(short_fact_squared(k) == c,"k: " << k); - print_spinner(); - } - - - - // test the << and >> operators a little - a = big_fact(20); - sout << a; - DLIB_TEST_MSG( sout.str() == "2432902008176640000","was: " << a); - - sin.str("684626312793279327952039475203945"); - sin >> a; - sout.str(""); - sout << a; - DLIB_TEST(sout.str() == "684626312793279327952039475203945"); - - print_spinner(); - - DLIB_TEST(a > 0); - - - // make sure that when you try to read something that isn't a number - // into a bigint you get an error - DLIB_TEST(sin.fail() == false); - sin.str("the cat ate some cheese"); - sin >> a; - DLIB_TEST(sin.fail() == true); - sin.clear(); - sin.str(""); - - - - sin.str("3628913"); - sin >> i; - DLIB_TEST(short_fact(10) + short_fact(5) - 7 == i); - - sin.str("2432902008173011193"); - sin >> i; - DLIB_TEST(short_fact(20) - short_fact(10) - 7 == i); - - // test the serialization stuff - sout.str(""); - serialize(i,sout); - i = 0; - sin.str(sout.str()); - deserialize(i,sin); - - DLIB_TEST(short_fact(20) - short_fact(10) - 7 == i); - - - - - print_spinner(); - - - - - sin.str("100000"); - sin >> b; - a = b; - ++b; - DLIB_TEST_MSG ( a + 1 == b,"a==" << a << endl << "b==" << b << endl); - - - - - - // compute some stuff and see if you get the right value - a = 0; - b = 0; - sin.str("1000000"); - sin >> b; - int mel = 0; - for (i = a; i <= b; ++i) - { - // switch it up on em - if (i%2 == 0) - a = a + i; - else - a += i; - ++mel; - if ((mel&0xFFF) == 0) - print_spinner(); - } - DLIB_TEST_MSG(a == b*(b+1)/2, "a==" << a << endl << "b*(b+1)/2==" << b*(b+1)/2 << endl); - - - - - - - print_spinner(); - - - // compute some stuff and see if you get the right value - // this time going the other way using operator-- - a = 0; - b = 0; - sin.str("100000"); - sin >> b; - i = b; - DLIB_TEST(i == b); - DLIB_TEST_MSG(i > 0,"i==" << i); - mel = 0; - for (i = b; i > 0; --i) - { - // switch it up on em - if (i%2 == 0) - a = a + i; - else - a += i; - ++mel; - if ((mel&0xFF) == 0) - print_spinner(); - } - DLIB_TEST_MSG(a == b*(b+1)/2, "a==" << a << endl << "b*(b+1)/2==" << b*(b+1)/2 << endl); - - - - - - - - - - - - DLIB_TEST(short_fact(10)/short_fact(5) == 30240); - DLIB_TEST(short_fact(10)/(short_fact(5)+1) == 29990); - - sin.str("221172909834240000"); - sin >> a; - DLIB_TEST(short_fact(20)/(short_fact(5)+1) == a/11); - - sin.str("670442388044"); - sin >> b; - DLIB_TEST(short_fact(20)/(short_fact(10)+1) == b); - - print_spinner(); - - sin.str("1860479"); - sin >> i; - DLIB_TEST_MSG(short_fact(20)/(short_fact(15)+1) == i,short_fact(20)/(short_fact(15)+1)); - - // test the serialization stuff - sout.str(""); - serialize(i,sout); - i = 0; - sin.str(sout.str()); - deserialize(i,sin); - - DLIB_TEST_MSG(short_fact(20)/(short_fact(15)+1) == i,short_fact(20)/(short_fact(15)+1)); - - - print_spinner(); - - // test the serialization stuff - sout.str(""); - i = 0; - serialize(i,sout); - i = 1234; - sin.str(sout.str()); - deserialize(i,sin); - DLIB_TEST(i == 0); - - - DLIB_TEST(short_fact(10000)/short_fact(9999) == 10000); - - - DLIB_TEST(bint(5)%bint(1) == 0); - DLIB_TEST(bint(5)%bint(6) == 5); - DLIB_TEST(bint(25)%bint(6) == 1); - print_spinner(); - DLIB_TEST(bint(354)%bint(123) == 108); - DLIB_TEST(bint(20)%(bint(10)) == 0); - DLIB_TEST(bint(20)%(bint(10)+1) == 9); - - DLIB_TEST(bint(20)%(bint(15)+1) == 4); - - - DLIB_TEST(short_fact(10)%(short_fact(5)+2) == 32); - - sin.str("2908082"); - sin >> i; - DLIB_TEST(short_fact(15)%(short_fact(10)+2) == i); - - - - - - - // same as some of the above stuff but using big_fact - - DLIB_TEST(big_fact(10)%(big_fact(5)+2) == 32); - - sin.str("2908082"); - sin >> i; - DLIB_TEST(big_fact(15)%(big_fact(10)+2) == i); - - - print_spinner(); - - - DLIB_TEST(big_fact(10)/big_fact(5) == 30240); - DLIB_TEST(big_fact(10)/(big_fact(5)+1) == 29990); - - sin.str("221172909834240000"); - sin >> a; - DLIB_TEST(big_fact(20)/(big_fact(5)+1) == a/11); - - - sin.str("670442388044"); - sin >> b; - DLIB_TEST(big_fact(20)/(big_fact(10)+1) == b); - - - sin.str("1860479"); - sin >> i; - DLIB_TEST_MSG(big_fact(20)/(big_fact(15)+1) == i,big_fact(20)/(big_fact(15)+1)); - - DLIB_TEST(big_fact(100)/big_fact(99) == 100); - - - - - sout.str(""); - sout << "148571596448176149730952273362082573788556996128468876694221686370498539309"; - sout << "4065876545992131370884059645617234469978112000000000000000000000"; - sin.str(sout.str()); - sin >> a; - - sout.str(""); - sout << "933262154439441526816992388562667004907159682643816214685929638952175999932"; - sout << "299156089414639761565182862536979208272237582511852109168640000000000000000"; - sout << "000000"; - sin.str(sout.str()); - sin >> b; - - - sout.str(""); - sout << "138656248189732152054159609718432247180282092567575172939636909224427929240"; - sout << "834642263988043338170905744175653189424779336521852536242160190545537133916"; - sout << "649622615351174407746524657461692702500613722228638559932561661493048332720"; - sout << "6050692647868232055316807680000000000000000000000000000000000000000000"; - sin.str(sout.str()); - sin >> c; - - DLIB_TEST_MSG(a*b == c, - "a*b: " << a*b << - "\nc: " << c); - - - print_spinner(); - - i = 0; - mel = 0; - unsigned long j; - for (j = 0; i < bint(100000); ++j) - { - DLIB_TEST(i++ == bint(j)); - ++mel; - if((mel&0xFF) == 0) - print_spinner(); - } - DLIB_TEST(j == 100000); - - i = 1234; - - DLIB_TEST(i == 1234); - DLIB_TEST(i < 2345 ); - DLIB_TEST(i > 0 ); - DLIB_TEST(i > 123 ); - - DLIB_TEST(i != 1334); - DLIB_TEST(i <= 2345); - DLIB_TEST(i >= 0 ); - DLIB_TEST(i >= 123 ); - DLIB_TEST(i >= 1234); - DLIB_TEST(i <= 1234); - - - DLIB_TEST(1234 == i); - DLIB_TEST(2345 > i); - DLIB_TEST(0 < i); - DLIB_TEST(123 < i); - - DLIB_TEST(1334 != i); - DLIB_TEST(2345 >= i); - DLIB_TEST(0 <= i); - DLIB_TEST(123 <= i); - DLIB_TEST(1234 <= i); - DLIB_TEST(1234 >= i); - - - a = big_fact(200); - b = big_fact(100); - - DLIB_TEST(a > b); - DLIB_TEST(a != b); - DLIB_TEST(b < a); - DLIB_TEST(b != a); - DLIB_TEST(b <= a); - DLIB_TEST(a >= b); - - - - a = 10000; - a = a*a*a*a; a = a*a; a = a*a; - b = 2; - DLIB_TEST((a/b)*b == a); - - a = 10000*5; - a = a*a*a*a; a = a*a; a = a*a; - b = 5; - DLIB_TEST((a/b)*b == a); - } - - - - - class bigint_tester : public tester - { - public: - bigint_tester ( - ) : - tester ("test_bigint", - "Runs tests on the bigint component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a"; - bigint_kernel_test(); - print_spinner(); - - dlog << LINFO << "testing kernel_1a_c"; - bigint_kernel_test(); - print_spinner(); - - dlog << LINFO << "testing kernel_2a"; - bigint_kernel_test(); - print_spinner(); - - dlog << LINFO << "testing kernel_2a_c"; - bigint_kernel_test(); - print_spinner(); - - } - } a; - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/binary_search_tree_kernel_1a.cpp b/lib/3rdParty/dlib/include/dlib/test/binary_search_tree_kernel_1a.cpp deleted file mode 100644 index b7e0b3a1..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/binary_search_tree_kernel_1a.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_ -#define DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_ - - -#include -#include -#include -#include - -#include -#include -#include -#include "tester.h" -#include "binary_search_tree.h" - -namespace -{ - - - class binary_search_tree_tester : public tester - { - - public: - binary_search_tree_tester ( - ) : - tester ("test_binary_search_tree_kernel_1a", - "Runs tests on the binary_search_tree_kernel_1a component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a"; - binary_search_tree_kernel_test::kernel_1a>(); - print_spinner(); - - dlog << LINFO << "testing kernel_1a_c"; - binary_search_tree_kernel_test::kernel_1a_c>(); - print_spinner(); - } - } a; - -} - -#endif diff --git a/lib/3rdParty/dlib/include/dlib/test/binary_search_tree_kernel_2a.cpp b/lib/3rdParty/dlib/include/dlib/test/binary_search_tree_kernel_2a.cpp deleted file mode 100644 index e2be4b14..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/binary_search_tree_kernel_2a.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_ -#define DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_ - - -#include -#include -#include -#include - -#include -#include -#include -#include "tester.h" -#include "binary_search_tree.h" - -namespace -{ - - class binary_search_tree_tester : public tester - { - public: - binary_search_tree_tester ( - ) : - tester ("test_binary_search_tree_kernel_2a", - "Runs tests on the binary_search_tree_kernel_2a component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_2a"; - binary_search_tree_kernel_test::kernel_2a>(); - print_spinner(); - - dlog << LINFO << "testing kernel_2a_c"; - binary_search_tree_kernel_test::kernel_2a_c>(); - print_spinner(); - } - } a; - -} - -#endif diff --git a/lib/3rdParty/dlib/include/dlib/test/binary_search_tree_mm1.cpp b/lib/3rdParty/dlib/include/dlib/test/binary_search_tree_mm1.cpp deleted file mode 100644 index a9693bd1..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/binary_search_tree_mm1.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_ -#define DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_ - - -#include -#include -#include -#include - -#include -#include -#include -#include "tester.h" -#include "binary_search_tree.h" - -namespace -{ - - class binary_search_tree_tester : public tester - { - struct factory - { - template - struct return_type { - typedef typename memory_manager::kernel_1c type; - }; - - template - static typename return_type::type* get_instance ( - ) - { - static typename return_type::type instance; - return &instance; - } - - }; - - - public: - binary_search_tree_tester ( - ) : - tester ("test_binary_search_tree_mm1", - "Runs tests on the binary_search_tree component with memory managers.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a /w memory_manager_global"; - binary_search_tree_kernel_test::kernel_1a>::kernel_1a>(); - print_spinner(); - - - dlog << LINFO << "testing kernel_1a /w memory_manager_stateless"; - binary_search_tree_kernel_test::kernel_1a>::kernel_1a>(); - print_spinner(); - } - } a; - -} - -#endif diff --git a/lib/3rdParty/dlib/include/dlib/test/binary_search_tree_mm2.cpp b/lib/3rdParty/dlib/include/dlib/test/binary_search_tree_mm2.cpp deleted file mode 100644 index 354b1f91..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/binary_search_tree_mm2.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_ -#define DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_ - - -#include -#include -#include -#include - -#include -#include -#include -#include "tester.h" -#include "binary_search_tree.h" - -namespace -{ - - class binary_search_tree_tester : public tester - { - - public: - binary_search_tree_tester ( - ) : - tester ("test_binary_search_tree_mm2", - "Runs tests on the binary_search_tree component with memory managers.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a /w memory_manager_stateless_2"; - binary_search_tree_kernel_test::kernel_2_2c>::kernel_1a>(); - print_spinner(); - - dlog << LINFO << "testing kernel_1a /w memory_manager_3"; - binary_search_tree_kernel_test::kernel_3b>::kernel_1a>(); - print_spinner(); - } - } a; - -} - -#endif diff --git a/lib/3rdParty/dlib/include/dlib/test/blas_bindings/CMakeLists.txt b/lib/3rdParty/dlib/include/dlib/test/blas_bindings/CMakeLists.txt deleted file mode 100644 index ff06104d..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/blas_bindings/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -# -# This is a CMake makefile. You can find the cmake utility and -# information about it at http://www.cmake.org -# - -cmake_minimum_required(VERSION 2.6) - -# This variable contains a list of all the tests we are building -# into the regression test suite. -set (tests - blas_bindings_gemm.cpp - blas_bindings_gemv.cpp - blas_bindings_ger.cpp - blas_bindings_dot.cpp - blas_bindings_scal_axpy.cpp - vector.cpp - ) - -# create a variable called target_name and set it to the string "test" -set (target_name test) - -PROJECT(${target_name}) - -# add all the cpp files we want to compile to this list. This tells -# cmake that they are part of our target (which is the executable named test) -ADD_EXECUTABLE(${target_name} ../main.cpp ../tester.cpp ${tests}) - -ADD_DEFINITIONS(-DDLIB_TEST_BLAS_BINDINGS) - -# Tell cmake to link our target executable to dlib -include(../../cmake) -TARGET_LINK_LIBRARIES(${target_name} dlib ) - diff --git a/lib/3rdParty/dlib/include/dlib/test/blas_bindings/blas_bindings_dot.cpp b/lib/3rdParty/dlib/include/dlib/test/blas_bindings/blas_bindings_dot.cpp deleted file mode 100644 index 0571b068..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/blas_bindings/blas_bindings_dot.cpp +++ /dev/null @@ -1,314 +0,0 @@ -// Copyright (C) 2009 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "../tester.h" -#include - -#ifndef DLIB_USE_BLAS -#error "BLAS bindings must be used for this test to make any sense" -#endif - -namespace dlib -{ - namespace blas_bindings - { - // This is a little screwy. This function is used inside the BLAS - // bindings to count how many times each of the BLAS functions get called. -#ifdef DLIB_TEST_BLAS_BINDINGS - int& counter_dot() { static int counter = 0; return counter; } -#endif - - } -} - -namespace -{ - using namespace test; - using namespace std; - // Declare the logger we will use in this test. The name of the logger - // should start with "test." - dlib::logger dlog("test.dot"); - - - class blas_bindings_dot_tester : public tester - { - public: - blas_bindings_dot_tester ( - ) : - tester ( - "test_dot", // the command line argument name for this test - "Run tests for DOT routines.", // the command line argument description - 0 // the number of command line arguments for this test - ) - {} - - void test_mat_bindings() - { - using namespace dlib; - using namespace dlib::blas_bindings; - matrix rv(10); - matrix cv(10); - double val; - - rv = 1; cv = 1; - counter_dot() = 0; - val = rv*cv; - DLIB_TEST(val == 10); - DLIB_TEST(counter_dot() == 1); - - rv = 1; cv = 1; - counter_dot() = 0; - val = rv*mat(&cv(0),cv.size()); - DLIB_TEST(val == 10); - DLIB_TEST(counter_dot() == 1); - - rv = 1; cv = 1; - counter_dot() = 0; - val = trans(mat(&rv(0),rv.size()))*mat(&cv(0),cv.size()); - DLIB_TEST(val == 10); - DLIB_TEST(counter_dot() == 1); - - std::vector sv(10,1); - rv = 1; - counter_dot() = 0; - val = trans(mat(&rv(0),rv.size()))*mat(sv); - DLIB_TEST(val == 10); - DLIB_TEST(counter_dot() == 1); - - - counter_dot() = 0; - val = trans(mat(sv))*mat(sv); - DLIB_TEST(val == 10); - DLIB_TEST(counter_dot() == 1); - - std_vector_c svc(10,1); - counter_dot() = 0; - val = trans(mat(svc))*mat(svc); - DLIB_TEST(val == 10); - DLIB_TEST(counter_dot() == 1); - - - dlib::array arr(10); - for (unsigned int i = 0; i < arr.size(); ++i) - arr[i] = 1; - counter_dot() = 0; - val = trans(mat(arr))*mat(arr); - DLIB_TEST(val == 10); - DLIB_TEST(counter_dot() == 1); - } - - template - void test_dot_stuff( - matrix_type& m, - rv_type& rv, - cv_type& cv - ) const - { - using namespace dlib; - using namespace dlib::blas_bindings; - - rv_type rv2; - cv_type cv2; - matrix_type m2; - typedef typename matrix_type::type scalar_type; - scalar_type val; - - counter_dot() = 0; - m2 = rv*cv; - DLIB_TEST(counter_dot() == 1); - - counter_dot() = 0; - val = rv*cv; - DLIB_TEST(counter_dot() == 1); - - counter_dot() = 0; - val = rv*3*cv; - DLIB_TEST(counter_dot() == 1); - - counter_dot() = 0; - val = rv*trans(rv)*3; - DLIB_TEST(counter_dot() == 1); - - counter_dot() = 0; - val = trans(rv*trans(rv)*3 + trans(cv)*cv); - DLIB_TEST(counter_dot() == 2); - - - counter_dot() = 0; - val = trans(cv)*cv; - DLIB_TEST(counter_dot() == 1); - - counter_dot() = 0; - val = trans(cv)*trans(rv); - DLIB_TEST(counter_dot() == 1); - - counter_dot() = 0; - val = dot(rv,cv); - DLIB_TEST(counter_dot() == 1); - - counter_dot() = 0; - val = dot(rv,colm(cv,0)); - DLIB_TEST(counter_dot() == 1); - - counter_dot() = 0; - val = dot(cv,cv); - DLIB_TEST(counter_dot() == 1); - - counter_dot() = 0; - val = dot(colm(cv,0,cv.size()),colm(cv,0)); - DLIB_TEST(counter_dot() == 1); - - counter_dot() = 0; - val = dot(rv,rv); - DLIB_TEST(counter_dot() == 1); - - counter_dot() = 0; - val = dot(rv,trans(rv)); - DLIB_TEST(counter_dot() == 1); - - counter_dot() = 0; - val = dot(trans(cv),cv); - DLIB_TEST(counter_dot() == 1); - - counter_dot() = 0; - val = dot(trans(cv),trans(rv)); - DLIB_TEST(counter_dot() == 1); - - - // This does one dot and one gemv - counter_dot() = 0; - val = trans(cv)*m*trans(rv); - DLIB_TEST_MSG(counter_dot() == 1, counter_dot()); - - // This does one dot and two gemv - counter_dot() = 0; - val = (trans(cv)*m)*(m*trans(rv)); - DLIB_TEST_MSG(counter_dot() == 1, counter_dot()); - - // This does one dot and two gemv - counter_dot() = 0; - val = trans(cv)*m*trans(m)*trans(rv); - DLIB_TEST_MSG(counter_dot() == 1, counter_dot()); - } - - - template - void test_dot_stuff_conj( - matrix_type& , - rv_type& rv, - cv_type& cv - ) const - { - using namespace dlib; - using namespace dlib::blas_bindings; - - rv_type rv2; - cv_type cv2; - matrix_type m2; - typedef typename matrix_type::type scalar_type; - scalar_type val; - - counter_dot() = 0; - val = conj(rv)*cv; - DLIB_TEST(counter_dot() == 1); - - counter_dot() = 0; - val = trans(conj(cv))*cv; - DLIB_TEST(counter_dot() == 1); - - counter_dot() = 0; - val = trans(conj(cv))*trans(rv); - DLIB_TEST(counter_dot() == 1); - - counter_dot() = 0; - val = trans(conj(cv))*3*trans(rv); - DLIB_TEST(counter_dot() == 1); - } - - void perform_test ( - ) - { - using namespace dlib; - typedef dlib::memory_manager::kernel_1a mm; - - dlog << dlib::LINFO << "test double"; - { - matrix m = randm(4,4); - matrix rv = randm(1,4); - matrix cv = randm(4,1); - test_dot_stuff(m,rv,cv); - } - - dlog << dlib::LINFO << "test float"; - { - matrix m = matrix_cast(randm(4,4)); - matrix rv = matrix_cast(randm(1,4)); - matrix cv = matrix_cast(randm(4,1)); - test_dot_stuff(m,rv,cv); - } - - dlog << dlib::LINFO << "test complex"; - { - matrix > m = complex_matrix(randm(4,4), randm(4,4)); - matrix,1,0> rv = complex_matrix(randm(1,4), randm(1,4)); - matrix,0,1> cv = complex_matrix(randm(4,1), randm(4,1)); - test_dot_stuff(m,rv,cv); - test_dot_stuff_conj(m,rv,cv); - } - - dlog << dlib::LINFO << "test complex"; - { - matrix > m = matrix_cast >(complex_matrix(randm(4,4), randm(4,4))); - matrix,1,0> rv = matrix_cast >(complex_matrix(randm(1,4), randm(1,4))); - matrix,0,1> cv = matrix_cast >(complex_matrix(randm(4,1), randm(4,1))); - test_dot_stuff(m,rv,cv); - test_dot_stuff_conj(m,rv,cv); - } - - - dlog << dlib::LINFO << "test double, column major"; - { - matrix m = randm(4,4); - matrix rv = randm(1,4); - matrix cv = randm(4,1); - test_dot_stuff(m,rv,cv); - } - - dlog << dlib::LINFO << "test float, column major"; - { - matrix m = matrix_cast(randm(4,4)); - matrix rv = matrix_cast(randm(1,4)); - matrix cv = matrix_cast(randm(4,1)); - test_dot_stuff(m,rv,cv); - } - - dlog << dlib::LINFO << "test complex, column major"; - { - matrix,0,0,mm,column_major_layout > m = complex_matrix(randm(4,4), randm(4,4)); - matrix,1,0,mm,column_major_layout> rv = complex_matrix(randm(1,4), randm(1,4)); - matrix,0,1,mm,column_major_layout> cv = complex_matrix(randm(4,1), randm(4,1)); - test_dot_stuff(m,rv,cv); - test_dot_stuff_conj(m,rv,cv); - } - - dlog << dlib::LINFO << "test complex, column major"; - { - matrix,0,0,mm,column_major_layout > m = matrix_cast >(complex_matrix(randm(4,4), randm(4,4))); - matrix,1,0,mm,column_major_layout> rv = matrix_cast >(complex_matrix(randm(1,4), randm(1,4))); - matrix,0,1,mm,column_major_layout> cv = matrix_cast >(complex_matrix(randm(4,1), randm(4,1))); - test_dot_stuff(m,rv,cv); - test_dot_stuff_conj(m,rv,cv); - } - - - test_mat_bindings(); - - print_spinner(); - } - }; - - blas_bindings_dot_tester a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/blas_bindings/blas_bindings_gemm.cpp b/lib/3rdParty/dlib/include/dlib/test/blas_bindings/blas_bindings_gemm.cpp deleted file mode 100644 index 68e01030..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/blas_bindings/blas_bindings_gemm.cpp +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright (C) 2009 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "../tester.h" -#include - -#ifndef DLIB_USE_BLAS -#error "BLAS bindings must be used for this test to make any sense" -#endif - -namespace dlib -{ - namespace blas_bindings - { - // This is a little screwy. This function is used inside the BLAS - // bindings to count how many times each of the BLAS functions get called. -#ifdef DLIB_TEST_BLAS_BINDINGS - int& counter_gemm() { static int counter = 0; return counter; } -#endif - - } -} - -namespace -{ - using namespace test; - using namespace std; - // Declare the logger we will use in this test. The name of the logger - // should start with "test." - dlib::logger dlog("test.gemm"); - - - class blas_bindings_gemm_tester : public tester - { - public: - blas_bindings_gemm_tester ( - ) : - tester ( - "test_gemm", // the command line argument name for this test - "Run tests for GEMM routines.", // the command line argument description - 0 // the number of command line arguments for this test - ) - {} - - template - void test_gemm_stuff( - const matrix_type& c - ) const - { - using namespace dlib; - using namespace dlib::blas_bindings; - - matrix_type b, a; - a = c; - - counter_gemm() = 0; - b = a*a; - DLIB_TEST(counter_gemm() == 1); - - counter_gemm() = 0; - b = a/2*a; - DLIB_TEST(counter_gemm() == 1); - - counter_gemm() = 0; - b = a*trans(a) + a; - DLIB_TEST(counter_gemm() == 1); - - counter_gemm() = 0; - b = (a+a)*(a+a); - DLIB_TEST(counter_gemm() == 1); - - counter_gemm() = 0; - b = a*(a-a); - DLIB_TEST(counter_gemm() == 1); - - counter_gemm() = 0; - b = trans(a)*trans(a) + a; - DLIB_TEST(counter_gemm() == 1); - - counter_gemm() = 0; - b = trans(trans(trans(a)*a + a)); - DLIB_TEST(counter_gemm() == 1); - - counter_gemm() = 0; - b = a*a*a*a; - DLIB_TEST(counter_gemm() == 3); - b = c; - - counter_gemm() = 0; - a = a*a*a*a; - DLIB_TEST(counter_gemm() == 3); - a = c; - - counter_gemm() = 0; - a = (b + a*trans(a)*a*3*a)*trans(b); - DLIB_TEST(counter_gemm() == 4); - a = c; - - counter_gemm() = 0; - a = trans((trans(b) + trans(a)*trans(a)*a*3*a)*trans(b)); - DLIB_TEST(counter_gemm() == 4); - a = c; - - counter_gemm() = 0; - a = trans((trans(b) + trans(a)*(a)*trans(a)*3*a)*trans(b)); - DLIB_TEST(counter_gemm() == 4); - a = c; - - counter_gemm() = 0; - a = trans((trans(b) + trans(a)*(a + b)*trans(a)*3*a)*trans(b)); - DLIB_TEST_MSG(counter_gemm() == 4, counter_gemm()); - a = c; - - counter_gemm() = 0; - a = trans((trans(b) + trans(a)*(a*8 + b+b+b+b)*trans(a)*3*a)*trans(b)); - DLIB_TEST_MSG(counter_gemm() == 4, counter_gemm()); - a = c; - } - - template - void test_gemm_stuff_conj( - const matrix_type& c - ) const - { - using namespace dlib; - using namespace dlib::blas_bindings; - - matrix_type b, a; - a = c; - - counter_gemm() = 0; - b = a*conj(a); - DLIB_TEST(counter_gemm() == 1); - - counter_gemm() = 0; - b = a*trans(conj(a)) + a; - DLIB_TEST(counter_gemm() == 1); - - counter_gemm() = 0; - b = conj(trans(a))*trans(a) + a; - DLIB_TEST(counter_gemm() == 1); - - counter_gemm() = 0; - b = trans(trans(trans(a)*conj(a) + conj(a))); - DLIB_TEST(counter_gemm() == 1); - - counter_gemm() = 0; - b = a*a*conj(a)*a; - DLIB_TEST(counter_gemm() == 3); - b = c; - - counter_gemm() = 0; - a = a*trans(conj(a))*a*a; - DLIB_TEST(counter_gemm() == 3); - a = c; - - counter_gemm() = 0; - a = (b + a*trans(conj(a))*a*3*a)*trans(b); - DLIB_TEST(counter_gemm() == 4); - a = c; - - counter_gemm() = 0; - a = (trans((conj(trans(b)) + trans(a)*conj(trans(a))*a*3*a)*trans(b))); - DLIB_TEST(counter_gemm() == 4); - a = c; - - counter_gemm() = 0; - a = ((trans(b) + trans(a)*(a)*trans(a)*3*a)*trans(conj(b))); - DLIB_TEST(counter_gemm() == 4); - a = c; - - counter_gemm() = 0; - a = trans((trans(b) + trans(a)*conj(a + b)*trans(a)*3*a)*trans(b)); - DLIB_TEST_MSG(counter_gemm() == 4, counter_gemm()); - a = c; - - counter_gemm() = 0; - a = trans((trans(b) + trans(a)*(a*8 + b+b+b+b)*trans(a)*3*conj(a))*trans(b)); - DLIB_TEST_MSG(counter_gemm() == 4, counter_gemm()); - a = c; - } - - void perform_test ( - ) - { - using namespace dlib; - typedef dlib::memory_manager::kernel_1a mm; - - print_spinner(); - - dlog << dlib::LINFO << "test double"; - { - matrix a = randm(4,4); - test_gemm_stuff(a); - } - - print_spinner(); - dlog << dlib::LINFO << "test float"; - { - matrix a = matrix_cast(randm(4,4)); - test_gemm_stuff(a); - } - - print_spinner(); - dlog << dlib::LINFO << "test complex"; - { - matrix a = matrix_cast(randm(4,4)); - matrix b = matrix_cast(randm(4,4)); - matrix > c = complex_matrix(a,b); - test_gemm_stuff(c); - test_gemm_stuff_conj(c); - } - - print_spinner(); - dlog << dlib::LINFO << "test complex"; - { - matrix a = matrix_cast(randm(4,4)); - matrix b = matrix_cast(randm(4,4)); - matrix > c = complex_matrix(a,b); - test_gemm_stuff(c); - test_gemm_stuff_conj(c); - } - - - print_spinner(); - - dlog << dlib::LINFO << "test double, column major"; - { - matrix a = randm(100,100); - test_gemm_stuff(a); - } - - print_spinner(); - dlog << dlib::LINFO << "test float, column major"; - { - matrix a = matrix_cast(randm(100,100)); - test_gemm_stuff(a); - } - - print_spinner(); - dlog << dlib::LINFO << "test complex, column major"; - { - matrix a = matrix_cast(randm(100,100)); - matrix b = matrix_cast(randm(100,100)); - matrix,100,100,mm,column_major_layout > c = complex_matrix(a,b); - test_gemm_stuff(c); - test_gemm_stuff_conj(c); - } - - print_spinner(); - - dlog << dlib::LINFO << "test complex, column major"; - { - matrix a = matrix_cast(randm(100,100)); - matrix b = matrix_cast(randm(100,100)); - matrix,100,100,mm,column_major_layout > c = complex_matrix(a,b); - test_gemm_stuff(c); - test_gemm_stuff_conj(c); - } - - { - using namespace dlib; - using namespace dlib::blas_bindings; - array2d a(100,100); - array2d b(100,100); - matrix c; - - counter_gemm() = 0; - c = mat(a)*mat(b); - DLIB_TEST(counter_gemm() == 1); - - counter_gemm() = 0; - c = trans(2*mat(a)*mat(b)); - DLIB_TEST(counter_gemm() == 1); - } - - print_spinner(); - } - }; - - blas_bindings_gemm_tester a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/blas_bindings/blas_bindings_gemv.cpp b/lib/3rdParty/dlib/include/dlib/test/blas_bindings/blas_bindings_gemv.cpp deleted file mode 100644 index 32243831..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/blas_bindings/blas_bindings_gemv.cpp +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright (C) 2009 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "../tester.h" -#include - -#ifndef DLIB_USE_BLAS -#error "BLAS bindings must be used for this test to make any sense" -#endif - -namespace dlib -{ - namespace blas_bindings - { - // This is a little screwy. This function is used inside the BLAS - // bindings to count how many times each of the BLAS functions get called. -#ifdef DLIB_TEST_BLAS_BINDINGS - int& counter_gemv() { static int counter = 0; return counter; } -#endif - - } -} - -namespace -{ - using namespace test; - using namespace std; - // Declare the logger we will use in this test. The name of the logger - // should start with "test." - dlib::logger dlog("test.gemv"); - - - class blas_bindings_gemv_tester : public tester - { - public: - blas_bindings_gemv_tester ( - ) : - tester ( - "test_gemv", // the command line argument name for this test - "Run tests for GEMV routines.", // the command line argument description - 0 // the number of command line arguments for this test - ) - {} - - template - void test_gemv_stuff( - matrix_type& m, - cv_type& cv, - rv_type& rv - ) const - { - using namespace dlib; - using namespace dlib::blas_bindings; - - cv_type cv2; - rv_type rv2; - typedef typename matrix_type::type scalar_type; - scalar_type val; - - counter_gemv() = 0; - cv2 = m*cv; - DLIB_TEST(counter_gemv() == 1); - - counter_gemv() = 0; - cv2 = m*2*cv; - DLIB_TEST(counter_gemv() == 1); - - counter_gemv() = 0; - cv2 = m*2*trans(rv); - DLIB_TEST(counter_gemv() == 1); - - counter_gemv() = 0; - rv2 = trans(m*2*cv); - DLIB_TEST(counter_gemv() == 1); - - counter_gemv() = 0; - rv2 = rv*m; - DLIB_TEST(counter_gemv() == 1); - - counter_gemv() = 0; - rv2 = (rv + rv)*m; - DLIB_TEST(counter_gemv() == 1); - - counter_gemv() = 0; - rv2 = trans(cv)*m; - DLIB_TEST(counter_gemv() == 1); - dlog << dlib::LTRACE << 1; - - counter_gemv() = 0; - rv2 = trans(cv)*trans(m) + rv*trans(m); - DLIB_TEST(counter_gemv() == 2); - dlog << dlib::LTRACE << 2; - - counter_gemv() = 0; - cv2 = m*trans(trans(cv)*trans(m) + 3*rv*trans(m)); - DLIB_TEST(counter_gemv() == 3); - - // This does one dot and one gemv - counter_gemv() = 0; - val = trans(cv)*m*trans(rv); - DLIB_TEST_MSG(counter_gemv() == 1, counter_gemv()); - - // This does one dot and two gemv - counter_gemv() = 0; - val = (trans(cv)*m)*(m*trans(rv)); - DLIB_TEST_MSG(counter_gemv() == 2, counter_gemv()); - - // This does one dot and two gemv - counter_gemv() = 0; - val = trans(cv)*m*trans(m)*trans(rv); - DLIB_TEST_MSG(counter_gemv() == 2, counter_gemv()); - } - - - template - void test_gemv_stuff_conj( - matrix_type& m, - cv_type& cv, - rv_type& rv - ) const - { - using namespace dlib; - using namespace dlib::blas_bindings; - - cv_type cv2; - rv_type rv2; - - counter_gemv() = 0; - cv2 = trans(cv)*conj(m); - DLIB_TEST(counter_gemv() == 1); - - counter_gemv() = 0; - cv2 = conj(trans(m))*rv; - DLIB_TEST(counter_gemv() == 1); - - counter_gemv() = 0; - cv2 = conj(trans(m))*trans(cv); - DLIB_TEST(counter_gemv() == 1); - - counter_gemv() = 0; - cv2 = trans(trans(cv)*conj(2*m) + conj(3*trans(m))*rv + conj(trans(m)*3)*trans(cv)); - DLIB_TEST(counter_gemv() == 3); - - } - - void perform_test ( - ) - { - using namespace dlib; - typedef dlib::memory_manager::kernel_1a mm; - - dlog << dlib::LINFO << "test double"; - { - matrix m = randm(4,4); - matrix cv = randm(4,1); - matrix rv = randm(1,4); - test_gemv_stuff(m,cv,rv); - } - - dlog << dlib::LINFO << "test float"; - { - matrix m = matrix_cast(randm(4,4)); - matrix cv = matrix_cast(randm(4,1)); - matrix rv = matrix_cast(randm(1,4)); - test_gemv_stuff(m,cv,rv); - } - - dlog << dlib::LINFO << "test complex"; - { - matrix > m = complex_matrix(randm(4,4), randm(4,4)); - matrix,0,1> cv = complex_matrix(randm(4,1), randm(4,1)); - matrix,1,0> rv = complex_matrix(randm(1,4), randm(1,4)); - test_gemv_stuff(m,cv,rv); - } - - dlog << dlib::LINFO << "test complex"; - { - matrix > m = matrix_cast >(complex_matrix(randm(4,4), randm(4,4))); - matrix,0,1> cv = matrix_cast >(complex_matrix(randm(4,1), randm(4,1))); - matrix,1,0> rv = matrix_cast >(complex_matrix(randm(1,4), randm(1,4))); - test_gemv_stuff(m,cv,rv); - } - - - dlog << dlib::LINFO << "test double"; - { - matrix m = randm(4,4); - matrix cv = randm(4,1); - matrix rv = randm(1,4); - test_gemv_stuff(m,cv,rv); - } - - dlog << dlib::LINFO << "test float"; - { - matrix m = matrix_cast(randm(4,4)); - matrix cv = matrix_cast(randm(4,1)); - matrix rv = matrix_cast(randm(1,4)); - test_gemv_stuff(m,cv,rv); - } - - dlog << dlib::LINFO << "test complex"; - { - matrix,0,0,mm,column_major_layout > m = complex_matrix(randm(4,4), randm(4,4)); - matrix,0,1,mm,column_major_layout> cv = complex_matrix(randm(4,1), randm(4,1)); - matrix,1,0,mm,column_major_layout> rv = complex_matrix(randm(1,4), randm(1,4)); - test_gemv_stuff(m,cv,rv); - } - - dlog << dlib::LINFO << "test complex"; - { - matrix,0,0,mm,column_major_layout > m = matrix_cast >(complex_matrix(randm(4,4), randm(4,4))); - matrix,0,1,mm,column_major_layout> cv = matrix_cast >(complex_matrix(randm(4,1), randm(4,1))); - matrix,1,0,mm,column_major_layout> rv = matrix_cast >(complex_matrix(randm(1,4), randm(1,4))); - test_gemv_stuff(m,cv,rv); - } - - - print_spinner(); - } - }; - - blas_bindings_gemv_tester a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/blas_bindings/blas_bindings_ger.cpp b/lib/3rdParty/dlib/include/dlib/test/blas_bindings/blas_bindings_ger.cpp deleted file mode 100644 index 2aac834d..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/blas_bindings/blas_bindings_ger.cpp +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright (C) 2009 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "../tester.h" -#include - -#ifndef DLIB_USE_BLAS -#error "BLAS bindings must be used for this test to make any sense" -#endif - -namespace dlib -{ - namespace blas_bindings - { - // This is a little screwy. This function is used inside the BLAS - // bindings to count how many times each of the BLAS functions get called. -#ifdef DLIB_TEST_BLAS_BINDINGS - int& counter_ger() { static int counter = 0; return counter; } -#endif - - } -} - -namespace -{ - using namespace test; - using namespace std; - // Declare the logger we will use in this test. The name of the logger - // should start with "test." - dlib::logger dlog("test.ger"); - - - class blas_bindings_ger_tester : public tester - { - public: - blas_bindings_ger_tester ( - ) : - tester ( - "test_ger", // the command line argument name for this test - "Run tests for GER routines.", // the command line argument description - 0 // the number of command line arguments for this test - ) - {} - - template - void test_ger_stuff( - matrix_type& m, - rv_type& rv, - cv_type& cv - ) const - { - using namespace dlib; - using namespace dlib::blas_bindings; - - rv_type rv2; - cv_type cv2; - matrix_type m2; - - counter_ger() = 0; - m2 = m + cv*rv; - DLIB_TEST_MSG(counter_ger() == 1, counter_ger()); - - counter_ger() = 0; - m += trans(rv)*rv; - DLIB_TEST(counter_ger() == 1); - - counter_ger() = 0; - m += trans(rv)*trans(cv); - DLIB_TEST(counter_ger() == 1); - - counter_ger() = 0; - m += cv*trans(cv); - DLIB_TEST(counter_ger() == 1); - - counter_ger() = 0; - m += trans(rv)*rv + trans(cv*3*rv); - DLIB_TEST(counter_ger() == 2); - } - - - template - void test_ger_stuff_conj( - matrix_type& m, - rv_type& rv, - cv_type& cv - ) const - { - using namespace dlib; - using namespace dlib::blas_bindings; - - rv_type rv2; - cv_type cv2; - matrix_type m2; - - counter_ger() = 0; - m += cv*conj(rv); - DLIB_TEST_MSG(counter_ger() == 1, counter_ger()); - - counter_ger() = 0; - m += trans(rv)*conj(rv); - DLIB_TEST(counter_ger() == 1); - - counter_ger() = 0; - m += trans(rv)*conj(trans(cv)); - DLIB_TEST(counter_ger() == 1); - - counter_ger() = 0; - m += cv*trans(conj(cv)); - DLIB_TEST(counter_ger() == 1); - - counter_ger() = 0; - m += trans(rv)*rv + trans(cv*3*conj(rv)); - DLIB_TEST(counter_ger() == 2); - } - - void perform_test ( - ) - { - using namespace dlib; - typedef dlib::memory_manager::kernel_1a mm; - - dlog << dlib::LINFO << "test double"; - { - matrix m = randm(4,4); - matrix rv = randm(1,4); - matrix cv = randm(4,1); - test_ger_stuff(m,rv,cv); - } - - dlog << dlib::LINFO << "test float"; - { - matrix m = matrix_cast(randm(4,4)); - matrix rv = matrix_cast(randm(1,4)); - matrix cv = matrix_cast(randm(4,1)); - test_ger_stuff(m,rv,cv); - } - - dlog << dlib::LINFO << "test complex"; - { - matrix > m = complex_matrix(randm(4,4), randm(4,4)); - matrix,1,0> rv = complex_matrix(randm(1,4), randm(1,4)); - matrix,0,1> cv = complex_matrix(randm(4,1), randm(4,1)); - test_ger_stuff(m,rv,cv); - test_ger_stuff_conj(m,rv,cv); - } - - dlog << dlib::LINFO << "test complex"; - { - matrix > m = matrix_cast >(complex_matrix(randm(4,4), randm(4,4))); - matrix,1,0> rv = matrix_cast >(complex_matrix(randm(1,4), randm(1,4))); - matrix,0,1> cv = matrix_cast >(complex_matrix(randm(4,1), randm(4,1))); - test_ger_stuff(m,rv,cv); - test_ger_stuff_conj(m,rv,cv); - } - - - dlog << dlib::LINFO << "test double"; - { - matrix m = randm(4,4); - matrix rv = randm(1,4); - matrix cv = randm(4,1); - test_ger_stuff(m,rv,cv); - } - - dlog << dlib::LINFO << "test float"; - { - matrix m = matrix_cast(randm(4,4)); - matrix rv = matrix_cast(randm(1,4)); - matrix cv = matrix_cast(randm(4,1)); - test_ger_stuff(m,rv,cv); - } - - dlog << dlib::LINFO << "test complex"; - { - matrix,0,0,mm,column_major_layout > m = complex_matrix(randm(4,4), randm(4,4)); - matrix,1,0,mm,column_major_layout> rv = complex_matrix(randm(1,4), randm(1,4)); - matrix,0,1,mm,column_major_layout> cv = complex_matrix(randm(4,1), randm(4,1)); - test_ger_stuff(m,rv,cv); - test_ger_stuff_conj(m,rv,cv); - } - - dlog << dlib::LINFO << "test complex"; - { - matrix,0,0,mm,column_major_layout > m = matrix_cast >(complex_matrix(randm(4,4), randm(4,4))); - matrix,1,0,mm,column_major_layout> rv = matrix_cast >(complex_matrix(randm(1,4), randm(1,4))); - matrix,0,1,mm,column_major_layout> cv = matrix_cast >(complex_matrix(randm(4,1), randm(4,1))); - test_ger_stuff(m,rv,cv); - test_ger_stuff_conj(m,rv,cv); - } - - - print_spinner(); - } - }; - - blas_bindings_ger_tester a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/blas_bindings/blas_bindings_scal_axpy.cpp b/lib/3rdParty/dlib/include/dlib/test/blas_bindings/blas_bindings_scal_axpy.cpp deleted file mode 100644 index b9518b33..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/blas_bindings/blas_bindings_scal_axpy.cpp +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright (C) 2009 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "../tester.h" -#include - -#ifndef DLIB_USE_BLAS -#error "BLAS bindings must be used for this test to make any sense" -#endif - -namespace dlib -{ - namespace blas_bindings - { - // This is a little screwy. This function is used inside the BLAS - // bindings to count how many times each of the BLAS functions get called. -#ifdef DLIB_TEST_BLAS_BINDINGS - int& counter_axpy() { static int counter = 0; return counter; } - int& counter_scal() { static int counter = 0; return counter; } -#endif - - } -} - -namespace -{ - using namespace test; - using namespace std; - // Declare the logger we will use in this test. The name of the logger - // should start with "test." - dlib::logger dlog("test.scal_axpy"); - - - class blas_bindings_scal_axpy_tester : public tester - { - public: - blas_bindings_scal_axpy_tester ( - ) : - tester ( - "test_scal_axpy", // the command line argument name for this test - "Run tests for DOT routines.", // the command line argument description - 0 // the number of command line arguments for this test - ) - {} - - template - void test_scal_axpy_stuff( - matrix_type& m, - rv_type& rv, - cv_type& cv - ) const - { - using namespace dlib; - using namespace dlib::blas_bindings; - - rv_type rv2 = rv; - cv_type cv2 = cv; - matrix_type m2 = m; - typedef typename matrix_type::type scalar_type; - scalar_type val; - - counter_scal() = 0; - m = 5*m; - DLIB_TEST(counter_scal() == 1); - - counter_scal() = 0; - rv = 5*rv; - DLIB_TEST(counter_scal() == 1); - - counter_scal() = 0; - rv = 5*rv; - DLIB_TEST(counter_scal() == 1); - - - counter_axpy() = 0; - m2 += 5*m; - DLIB_TEST(counter_axpy() == 1); - - counter_axpy() = 0; - rv2 += 5*rv; - DLIB_TEST(counter_axpy() == 1); - - counter_axpy() = 0; - rv2 += 5*rv; - DLIB_TEST(counter_axpy() == 1); - - - - counter_scal() = 0; - m = m*5; - DLIB_TEST(counter_scal() == 1); - - counter_scal() = 0; - rv = rv*5; - DLIB_TEST(counter_scal() == 1); - - counter_scal() = 0; - cv = cv*5; - DLIB_TEST(counter_scal() == 1); - - - counter_axpy() = 0; - m2 += m*5; - DLIB_TEST(counter_axpy() == 1); - - counter_axpy() = 0; - rv2 += rv*5; - DLIB_TEST(counter_axpy() == 1); - - counter_axpy() = 0; - cv2 += cv*5; - DLIB_TEST(counter_axpy() == 1); - - - - - counter_axpy() = 0; - m2 = m2 + m*5; - DLIB_TEST(counter_axpy() == 1); - - counter_axpy() = 0; - rv2 = rv2 + rv*5; - DLIB_TEST(counter_axpy() == 1); - - counter_axpy() = 0; - cv2 = cv2 + cv*5; - DLIB_TEST(counter_axpy() == 1); - - - counter_axpy() = 0; - cv2 = 1; - cv = 1; - cv2 = 2*cv2 + cv*5; - DLIB_TEST(counter_axpy() == 1); - DLIB_TEST(max(abs(cv2 - 7)) == 0); - - - counter_axpy() = 0; - rv2 = 1; - rv = 1; - rv2 = 2*rv2 + rv*5; - DLIB_TEST(counter_axpy() == 1); - DLIB_TEST(max(abs(rv2 - 7)) == 0); - - - counter_axpy() = 0; - m2 = 1; - m = 1; - m2 = 2*m2 + m*5; - DLIB_TEST(counter_axpy() == 1); - DLIB_TEST(max(abs(m2 - 7)) == 0); - } - - - - void perform_test ( - ) - { - using namespace dlib; - typedef dlib::memory_manager::kernel_1a mm; - - dlog << dlib::LINFO << "test double"; - { - matrix m = randm(4,4); - matrix rv = randm(1,4); - matrix cv = randm(4,1); - test_scal_axpy_stuff(m,rv,cv); - } - - dlog << dlib::LINFO << "test float"; - { - matrix m = matrix_cast(randm(4,4)); - matrix rv = matrix_cast(randm(1,4)); - matrix cv = matrix_cast(randm(4,1)); - test_scal_axpy_stuff(m,rv,cv); - } - - dlog << dlib::LINFO << "test complex"; - { - matrix > m = complex_matrix(randm(4,4), randm(4,4)); - matrix,1,0> rv = complex_matrix(randm(1,4), randm(1,4)); - matrix,0,1> cv = complex_matrix(randm(4,1), randm(4,1)); - test_scal_axpy_stuff(m,rv,cv); - } - - dlog << dlib::LINFO << "test complex"; - { - matrix > m = matrix_cast >(complex_matrix(randm(4,4), randm(4,4))); - matrix,1,0> rv = matrix_cast >(complex_matrix(randm(1,4), randm(1,4))); - matrix,0,1> cv = matrix_cast >(complex_matrix(randm(4,1), randm(4,1))); - test_scal_axpy_stuff(m,rv,cv); - } - - - dlog << dlib::LINFO << "test double, column major"; - { - matrix m = randm(4,4); - matrix rv = randm(1,4); - matrix cv = randm(4,1); - test_scal_axpy_stuff(m,rv,cv); - } - - dlog << dlib::LINFO << "test float, column major"; - { - matrix m = matrix_cast(randm(4,4)); - matrix rv = matrix_cast(randm(1,4)); - matrix cv = matrix_cast(randm(4,1)); - test_scal_axpy_stuff(m,rv,cv); - } - - dlog << dlib::LINFO << "test complex, column major"; - { - matrix,0,0,mm,column_major_layout > m = complex_matrix(randm(4,4), randm(4,4)); - matrix,1,0,mm,column_major_layout> rv = complex_matrix(randm(1,4), randm(1,4)); - matrix,0,1,mm,column_major_layout> cv = complex_matrix(randm(4,1), randm(4,1)); - test_scal_axpy_stuff(m,rv,cv); - } - - dlog << dlib::LINFO << "test complex, column major"; - { - matrix,0,0,mm,column_major_layout > m = matrix_cast >(complex_matrix(randm(4,4), randm(4,4))); - matrix,1,0,mm,column_major_layout> rv = matrix_cast >(complex_matrix(randm(1,4), randm(1,4))); - matrix,0,1,mm,column_major_layout> cv = matrix_cast >(complex_matrix(randm(4,1), randm(4,1))); - test_scal_axpy_stuff(m,rv,cv); - } - - - print_spinner(); - } - }; - - blas_bindings_scal_axpy_tester a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/blas_bindings/vector.cpp b/lib/3rdParty/dlib/include/dlib/test/blas_bindings/vector.cpp deleted file mode 100644 index 0a6f5f30..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/blas_bindings/vector.cpp +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (C) 2009 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "../tester.h" -#include -#include - -#ifndef DLIB_USE_BLAS -#error "BLAS bindings must be used for this test to make any sense" -#endif - -namespace dlib -{ - namespace blas_bindings - { - -#ifdef DLIB_TEST_BLAS_BINDINGS - extern int& counter_gemm(); - extern int& counter_gemv(); - extern int& counter_ger(); - extern int& counter_dot(); -#endif - - } -} - -namespace -{ - using namespace test; - using namespace std; - // Declare the logger we will use in this test. The name of the logger - // should start with "test." - dlib::logger dlog("test.vector"); - - - class vector_tester : public tester - { - public: - vector_tester ( - ) : - tester ( - "test_vector", // the command line argument name for this test - "Run tests on dlib::vector.", // the command line argument description - 0 // the number of command line arguments for this test - ) - {} - - template - void test_vector( - ) const - { - using namespace dlib; - using namespace dlib::blas_bindings; - - dlib::vector a2, b2, c2; - dlib::vector a3, b3, c3; - - matrix mat2(2,2), mat3(3,3); - mat2 = 0; - mat3 = 0; - - type var = 0; - - // We want to make sure that the BLAS bindings are being called for the 2D and 3D vectors. That would - // be very slow. - counter_gemm() = 0; - counter_gemv() = 0; - counter_ger() = 0; - counter_dot() = 0; - - var = trans(a2)*(a2); - var = dot(a2,a2); - - a2 = mat2*b2; - var = trans(b2)*mat2*b2; - - var = trans(a3)*(a3); - var = dot(a3,a3); - - a3 = mat3*b3; - var = trans(b3)*mat3*b3; - - mat3 = c3*trans(a3); - mat2 = c2*trans(a2); - - DLIB_TEST(counter_gemm() == 0 && counter_gemv() == 0 && counter_ger() == 0 && counter_dot() == 0); - - } - - void perform_test ( - ) - { - using namespace dlib; - - dlog << dlib::LINFO << "test double"; - test_vector(); - - dlog << dlib::LINFO << "test float"; - test_vector(); - - dlog << dlib::LINFO << "test int"; - test_vector(); - - dlog << dlib::LINFO << "test short"; - test_vector(); - - print_spinner(); - } - }; - - vector_tester a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/bridge.cpp b/lib/3rdParty/dlib/include/dlib/test/bridge.cpp deleted file mode 100644 index 36d270c7..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/bridge.cpp +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.bridge"); - - const unsigned short testing_port = 41238; - - void do_test1() - { - dlib::pipe in(0), out(0); - - bridge b1(connect_to_ip_and_port("127.0.0.1",testing_port), receive(in)); - bridge b2(listen_on_port(testing_port), transmit(out)); - - for (int i = 0; i < 100; ++i) - { - int val = i; - out.enqueue(val); - val = 0; - in.dequeue(val); - DLIB_TEST(val == i); - } - } - - void do_test2() - { - dlib::pipe in(0), out(0), echo_pipe(0); - - bridge b2(listen_on_port(testing_port), transmit(out), receive(in)); - bridge echo(connect_to_ip_and_port("127.0.0.1",testing_port), receive(echo_pipe), transmit(echo_pipe)); - - for (int i = 0; i < 100; ++i) - { - int val = i; - out.enqueue(val); - val = 0; - in.dequeue(val); - DLIB_TEST(val == i); - } - } - - void do_test3() - { - dlib::pipe in(10), out(10), echo_pipe(10); - - bridge b2(listen_on_port(testing_port), transmit(out), receive(in)); - bridge echo(connect_to_ip_and_port("127.0.0.1",testing_port), receive(echo_pipe), transmit(echo_pipe)); - - b2.reconfigure(listen_on_port(testing_port), transmit(out), receive(in)); - - for (int i = 0; i < 100; ++i) - { - int val = i; - out.enqueue(val); - val = 0; - in.dequeue(val); - DLIB_TEST(val == i); - } - } - - void do_test4() - { - dlib::pipe in(0), out(0), echo_pipe(0); - - bridge b2, echo; - b2.reconfigure(listen_on_port(testing_port), receive(in), transmit(out)); - echo.reconfigure(connect_to_ip_and_port("127.0.0.1",testing_port), transmit(echo_pipe), receive(echo_pipe)); - - for (int i = 0; i < 100; ++i) - { - int val = i; - out.enqueue(val); - val = 0; - in.dequeue(val); - DLIB_TEST(val == i); - } - } - - void do_test5(int pipe_size) - { - typedef type_safe_union tsu_type; - - dlib::pipe out(pipe_size); - dlib::pipe in(pipe_size); - dlib::pipe out_status(pipe_size); - - bridge b1(connect_to_ip_and_port("127.0.0.1",testing_port), receive(in)); - tsu_type msg; - - msg = b1.get_bridge_status(); - DLIB_TEST(msg.contains() == true); - DLIB_TEST(msg.get().is_connected == false); - DLIB_TEST(msg.get().foreign_ip == ""); - DLIB_TEST(msg.get().foreign_port == 0); - - { - bridge b2(listen_on_port(testing_port), transmit(out), receive(out_status)); - - in.dequeue(msg); - DLIB_TEST(msg.contains() == true); - DLIB_TEST(msg.get().is_connected == true); - DLIB_TEST(msg.get().foreign_ip == "127.0.0.1"); - DLIB_TEST(msg.get().foreign_port == testing_port); - msg = b1.get_bridge_status(); - DLIB_TEST(msg.contains() == true); - DLIB_TEST(msg.get().is_connected == true); - DLIB_TEST(msg.get().foreign_ip == "127.0.0.1"); - DLIB_TEST(msg.get().foreign_port == testing_port); - - bridge_status temp; - out_status.dequeue(temp); - DLIB_TEST(temp.is_connected == true); - DLIB_TEST(temp.foreign_ip == "127.0.0.1"); - - for (int i = 0; i < 100; ++i) - { - msg = i; - out.enqueue(msg); - - msg.get() = 0; - - in.dequeue(msg); - DLIB_TEST(msg.contains() == true); - DLIB_TEST(msg.get() == i); - } - - } - - in.dequeue(msg); - DLIB_TEST(msg.contains() == true); - DLIB_TEST(msg.get().is_connected == false); - DLIB_TEST(msg.get().foreign_ip == "127.0.0.1"); - DLIB_TEST(msg.get().foreign_port == testing_port); - } - - void do_test5_5(int pipe_size) - { - typedef type_safe_union tsu_type; - - dlib::pipe out(pipe_size); - dlib::pipe in(pipe_size); - dlib::pipe out_status(pipe_size); - - bridge b1(connect_to_ip_and_port("127.0.0.1",testing_port), receive(in)); - tsu_type msg; - - bridge b2(listen_on_port(testing_port), transmit(out), receive(out_status)); - - in.dequeue(msg); - DLIB_TEST(msg.contains() == true); - DLIB_TEST(msg.get().is_connected == true); - DLIB_TEST(msg.get().foreign_ip == "127.0.0.1"); - DLIB_TEST(msg.get().foreign_port == testing_port); - - bridge_status temp; - out_status.dequeue(temp); - DLIB_TEST(temp.is_connected == true); - DLIB_TEST(temp.foreign_ip == "127.0.0.1"); - - for (int i = 0; i < 100; ++i) - { - msg = i; - out.enqueue(msg); - - msg.get() = 0; - - in.dequeue(msg); - DLIB_TEST(msg.contains() == true); - DLIB_TEST(msg.get() == i); - } - - b2.clear(); - msg = b2.get_bridge_status(); - DLIB_TEST(msg.contains() == true); - DLIB_TEST(msg.get().is_connected == false); - DLIB_TEST(msg.get().foreign_ip == ""); - DLIB_TEST(msg.get().foreign_port == 0); - - in.dequeue(msg); - DLIB_TEST(msg.contains() == true); - DLIB_TEST(msg.get().is_connected == false); - DLIB_TEST(msg.get().foreign_ip == "127.0.0.1"); - DLIB_TEST(msg.get().foreign_port == testing_port); - } - - void do_test6() - { - dlib::pipe in(0), out(300); - - bridge b1(connect_to_ip_and_port("127.0.0.1",testing_port), receive(in)); - bridge b2(listen_on_port(testing_port), transmit(out)); - - for (int i = 0; i < 100; ++i) - { - int val = i; - out.enqueue(val); - } - - int val = 10; - in.dequeue(val); - DLIB_TEST(val == 0); - dlib::sleep(100); - in.dequeue(val); - DLIB_TEST(val == 1); - dlib::sleep(100); - } - - class test_bridge : public tester - { - public: - test_bridge ( - ) : - tester ("test_bridge", - "Runs tests on the bridge component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing bridge, using local port number of " << testing_port; - - print_spinner(); - do_test1(); - print_spinner(); - do_test2(); - print_spinner(); - do_test3(); - print_spinner(); - do_test4(); - print_spinner(); - for (int i = 0; i < 5; ++i) - do_test5(i); - do_test5_5(1); - print_spinner(); - do_test6(); - } - } a; - - - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/bsp.cpp b/lib/3rdParty/dlib/include/dlib/test/bsp.cpp deleted file mode 100644 index 04367c1d..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/bsp.cpp +++ /dev/null @@ -1,566 +0,0 @@ -// Copyright (C) 2012 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.bsp"); - - - template - struct callfunct_helper - { - callfunct_helper ( - funct f_, - int port_, - bool& error_occurred_ - ) :f(f_), port(port_), error_occurred(error_occurred_) {} - - funct f; - int port; - bool& error_occurred; - - void operator() ( - ) const - { - try - { - bsp_listen(port, f); - } - catch (exception& e) - { - dlog << LERROR << "error calling bsp_listen(): " << e.what(); - error_occurred = true; - } - } - }; - - template - callfunct_helper callfunct(funct f, int port, bool& error_occurred) - { - return callfunct_helper(f,port,error_occurred); - - } - -// ---------------------------------------------------------------------------------------- - - template - struct callfunct_helper_pn - { - callfunct_helper_pn ( - funct f_, - int port_, - bool& error_occurred_, - dlib::pipe& port_pipe_ - ) :f(f_), port(port_), error_occurred(error_occurred_), port_pipe(port_pipe_) {} - - funct f; - int port; - bool& error_occurred; - dlib::pipe& port_pipe; - - struct helper - { - helper ( - dlib::pipe& port_pipe_ - ) : port_pipe(port_pipe_) {} - - dlib::pipe& port_pipe; - - void operator() (unsigned short p) { port_pipe.enqueue(p); } - }; - - void operator() ( - ) const - { - try - { - bsp_listen_dynamic_port(port, helper(port_pipe), f); - } - catch (exception& e) - { - dlog << LERROR << "error calling bsp_listen_dynamic_port(): " << e.what(); - error_occurred = true; - } - } - }; - - template - callfunct_helper_pn callfunct(funct f, int port, bool& error_occurred, dlib::pipe& port_pipe) - { - return callfunct_helper_pn(f,port,error_occurred,port_pipe); - } - -// ---------------------------------------------------------------------------------------- - - void sum_array_driver ( - bsp_context& obj, - const std::vector& v, - int& result - ) - { - obj.broadcast(v); - - result = 0; - int val; - while(obj.try_receive(val)) - result += val; - } - - void sum_array_other ( - bsp_context& obj - ) - { - std::vector v; - obj.receive(v); - - int sum = 0; - for (unsigned long i = 0; i < v.size(); ++i) - sum += v[i]; - - obj.send(sum, 0); - - - } - - - void dotest1() - { - dlog << LINFO << "start dotest1()"; - print_spinner(); - bool error_occurred = false; - { - thread_function t1(callfunct(sum_array_other, 12345, error_occurred)); - thread_function t2(callfunct(sum_array_other, 12346, error_occurred)); - thread_function t3(callfunct(sum_array_other, 12347, error_occurred)); - std::vector v; - int true_value = 0; - for (int i = 0; i < 10; ++i) - { - v.push_back(i); - true_value += i; - } - - // wait a little bit for the threads to start up - dlib::sleep(200); - - try - { - int result; - std::vector hosts; - hosts.push_back("127.0.0.1:12345"); - hosts.push_back("localhost:12346"); - hosts.push_back("127.0.0.1:12347"); - bsp_connect(hosts, sum_array_driver, dlib::ref(v), dlib::ref(result)); - - dlog << LINFO << "result: "<< result; - dlog << LINFO << "should be: "<< 3*true_value; - DLIB_TEST(result == 3*true_value); - } - catch (std::exception& e) - { - dlog << LERROR << "error during bsp_context: " << e.what(); - DLIB_TEST(false); - } - } - DLIB_TEST(error_occurred == false); - } - -// ---------------------------------------------------------------------------------------- - - template - void test2_job(bsp_context& obj) - { - if (obj.node_id() == id) - dlib::sleep(100); - } - - template - void dotest2() - { - dlog << LINFO << "start dotest2()"; - print_spinner(); - bool error_occurred = false; - { - thread_function t1(callfunct(test2_job, 12345, error_occurred)); - thread_function t2(callfunct(test2_job, 12346, error_occurred)); - thread_function t3(callfunct(test2_job, 12347, error_occurred)); - - // wait a little bit for the threads to start up - dlib::sleep(200); - - try - { - std::vector hosts; - hosts.push_back("127.0.0.1:12345"); - hosts.push_back("127.0.0.1:12346"); - hosts.push_back("127.0.0.1:12347"); - bsp_connect(hosts, test2_job); - } - catch (std::exception& e) - { - dlog << LERROR << "error during bsp_context: " << e.what(); - DLIB_TEST(false); - } - - } - DLIB_TEST(error_occurred == false); - } - -// ---------------------------------------------------------------------------------------- - - void test3_job_driver(bsp_context& obj, int& result) - { - - obj.broadcast(obj.node_id()); - - int accum = 0; - int temp = 0; - while(obj.try_receive(temp)) - accum += temp; - - // send to node 1 so it can sum everything - if (obj.node_id() != 1) - obj.send(accum, 1); - - while(obj.try_receive(temp)) - accum += temp; - - // Now hop the accum values along the nodes until the value from node 1 gets to - // node 0. - obj.send(accum, (obj.node_id()+1)%obj.number_of_nodes()); - obj.receive(accum); - obj.send(accum, (obj.node_id()+1)%obj.number_of_nodes()); - obj.receive(accum); - obj.send(accum, (obj.node_id()+1)%obj.number_of_nodes()); - obj.receive(accum); - - // this whole block is a noop since it doesn't end up doing anything. - for (int k = 0; k < 100; ++k) - { - dlog << LINFO << "k: " << k; - for (int i = 0; i < 4; ++i) - { - obj.send(accum, (obj.node_id()+1)%obj.number_of_nodes()); - obj.receive(accum); - } - } - - - dlog << LINFO << "TERMINATE"; - if (obj.node_id() == 0) - result = accum; - } - - - void test3_job(bsp_context& obj) - { - int junk; - test3_job_driver(obj, junk); - } - - - void dotest3() - { - dlog << LINFO << "start dotest3()"; - print_spinner(); - bool error_occurred = false; - { - dlib::pipe ports(5); - thread_function t1(callfunct(test3_job, 12345, error_occurred, ports)); - thread_function t2(callfunct(test3_job, 0, error_occurred, ports)); - thread_function t3(callfunct(test3_job, 12347, error_occurred, ports)); - - - try - { - std::vector hosts; - unsigned short port; - ports.dequeue(port); hosts.push_back(network_address("127.0.0.1",port)); dlog << LINFO << "PORT: " << port; - ports.dequeue(port); hosts.push_back(network_address("127.0.0.1",port)); dlog << LINFO << "PORT: " << port; - ports.dequeue(port); hosts.push_back(network_address("127.0.0.1",port)); dlog << LINFO << "PORT: " << port; - int result = 0; - const int expected = 1+2+3 + 0+2+3 + 0+1+3 + 0+1+2; - bsp_connect(hosts, test3_job_driver, dlib::ref(result)); - - dlog << LINFO << "result: " << result; - dlog << LINFO << "should be: " << expected; - DLIB_TEST(result == expected); - } - catch (std::exception& e) - { - dlog << LERROR << "error during bsp_context: " << e.what(); - DLIB_TEST(false); - } - - } - DLIB_TEST(error_occurred == false); - } - -// ---------------------------------------------------------------------------------------- - - void test4_job_driver(bsp_context& obj, int& result) - { - - obj.broadcast(obj.node_id()); - - int accum = 0; - int temp = 0; - while(obj.try_receive(temp)) - accum += temp; - - // send to node 1 so it can sum everything - if (obj.node_id() != 1) - obj.send(accum, 1); - - while(obj.try_receive(temp)) - accum += temp; - - // Now hop the accum values along the nodes until the value from node 1 gets to - // node 0. - obj.send(accum, (obj.node_id()+1)%obj.number_of_nodes()); - obj.receive(accum); - obj.send(accum, (obj.node_id()+1)%obj.number_of_nodes()); - obj.receive(accum); - obj.send(accum, (obj.node_id()+1)%obj.number_of_nodes()); - obj.receive(accum); - - // this whole block is a noop since it doesn't end up doing anything. - for (int k = 0; k < 40; ++k) - { - dlog << LINFO << "k: " << k; - for (int i = 0; i < 4; ++i) - { - obj.send(accum, (obj.node_id()+1)%obj.number_of_nodes()); - obj.receive(accum); - - obj.receive(); - } - } - - - dlog << LINFO << "TERMINATE"; - if (obj.node_id() == 0) - result = accum; - } - - - void test4_job(bsp_context& obj) - { - int junk; - test4_job_driver(obj, junk); - } - - - void dotest4() - { - dlog << LINFO << "start dotest4()"; - print_spinner(); - bool error_occurred = false; - { - dlib::pipe ports(5); - thread_function t1(callfunct(test4_job, 0, error_occurred, ports)); - thread_function t2(callfunct(test4_job, 0, error_occurred, ports)); - thread_function t3(callfunct(test4_job, 0, error_occurred, ports)); - - - try - { - std::vector hosts; - unsigned short port; - ports.dequeue(port); hosts.push_back(network_address("127.0.0.1",port)); dlog << LINFO << "PORT: " << port; - ports.dequeue(port); hosts.push_back(network_address("127.0.0.1",port)); dlog << LINFO << "PORT: " << port; - ports.dequeue(port); hosts.push_back(network_address("127.0.0.1",port)); dlog << LINFO << "PORT: " << port; - int result = 0; - const int expected = 1+2+3 + 0+2+3 + 0+1+3 + 0+1+2; - bsp_connect(hosts, test4_job_driver, dlib::ref(result)); - - dlog << LINFO << "result: " << result; - dlog << LINFO << "should be: " << expected; - DLIB_TEST(result == expected); - } - catch (std::exception& e) - { - dlog << LERROR << "error during bsp_context: " << e.what(); - DLIB_TEST(false); - } - - } - DLIB_TEST(error_occurred == false); - } - -// ---------------------------------------------------------------------------------------- - - void test5_job( - bsp_context& , - int& val - ) - { - val = 25; - } - - void dotest5() - { - dlog << LINFO << "start dotest5()"; - print_spinner(); - std::vector hosts; - int val = 0; - bsp_connect(hosts, test5_job, dlib::ref(val)); - DLIB_TEST(val == 25); - } - -// ---------------------------------------------------------------------------------------- - - double f ( double x) - { - return std::pow(x-2.0, 2.0); - } - - - void bsp_job_node_0 ( - bsp_context& context, - double& min_value, - double& optimal_x - ) - { - double left = -100; - double right = 100; - - min_value = std::numeric_limits::infinity(); - double interval_width = std::abs(right-left); - - // This is doing a BSP based grid search for the minimum of f(). Here we - // do 100 iterations where we keep shrinking the grid size. - for (int i = 0; i < 100; ++i) - { - context.broadcast(left); - context.broadcast(right); - - for (unsigned int k = 1; k < context.number_of_nodes(); ++k) - { - std::pair val; - context.receive(val); - if (val.second < min_value) - { - min_value = val.second; - optimal_x = val.first; - } - } - - interval_width *= 0.5; - left = optimal_x - interval_width/2; - right = optimal_x + interval_width/2; - } - } - - - void bsp_job_other_nodes ( - bsp_context& context - ) - { - double left, right; - while (context.try_receive(left)) - { - context.receive(right); - - const double l = (context.node_id()-1)/(context.number_of_nodes()-1.0); - const double r = context.node_id() /(context.number_of_nodes()-1.0); - - const double width = right-left; - matrix values_to_check = linspace(left +l*width, left + r*width, 100); - - double best_x = 0; - double best_val = std::numeric_limits::infinity(); - for (long j = 0; j < values_to_check.size(); ++j) - { - double temp = f(values_to_check(j)); - if (temp < best_val) - { - best_val = temp; - best_x = values_to_check(j); - } - } - - context.send(make_pair(best_x, best_val), 0); - } - } - - void dotest6() - { - dlog << LINFO << "start dotest6()"; - print_spinner(); - bool error_occurred = false; - { - dlib::pipe ports(5); - thread_function t1(callfunct(bsp_job_other_nodes, 0, error_occurred, ports)); - thread_function t2(callfunct(bsp_job_other_nodes, 0, error_occurred, ports)); - thread_function t3(callfunct(bsp_job_other_nodes, 0, error_occurred, ports)); - - - try - { - std::vector hosts; - unsigned short port; - ports.dequeue(port); hosts.push_back(network_address("127.0.0.1",port)); dlog << LINFO << "PORT: " << port; - ports.dequeue(port); hosts.push_back(network_address("127.0.0.1",port)); dlog << LINFO << "PORT: " << port; - ports.dequeue(port); hosts.push_back(network_address("127.0.0.1",port)); dlog << LINFO << "PORT: " << port; - double min_value = 10, optimal_x = 0; - bsp_connect(hosts, bsp_job_node_0, dlib::ref(min_value), dlib::ref(optimal_x)); - - dlog << LINFO << "min_value: " << min_value; - dlog << LINFO << "optimal_x: " << optimal_x; - DLIB_TEST(std::abs(min_value - 0) < 1e-14); - DLIB_TEST(std::abs(optimal_x - 2) < 1e-14); - } - catch (std::exception& e) - { - dlog << LERROR << "error during bsp_context: " << e.what(); - DLIB_TEST(false); - } - - } - DLIB_TEST(error_occurred == false); - } -// ---------------------------------------------------------------------------------------- - - class bsp_tester : public tester - { - - public: - bsp_tester ( - ) : - tester ("test_bsp", - "Runs tests on the BSP components.") - {} - - void perform_test ( - ) - { - for (int i = 0; i < 3; ++i) - { - dotest1(); - dotest2<0>(); - dotest2<1>(); - dotest2<2>(); - dotest3(); - dotest4(); - dotest5(); - dotest6(); - } - } - } a; - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/byte_orderer.cpp b/lib/3rdParty/dlib/include/dlib/test/byte_orderer.cpp deleted file mode 100644 index 7200c1b4..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/byte_orderer.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.byte_orderer"); - - - class byte_orderer_tester : public tester - { - public: - byte_orderer_tester ( - ) : - tester ("test_byte_orderer", - "Runs tests on the byte_orderer component.") - {} - - void perform_test ( - ) - { - byte_orderer bo; - - union data - { - unsigned char b[4]; - dlib::uint32 val; - }; - - data a; - - a.val = 1; - - if (bo.host_is_little_endian()) - { - DLIB_TEST(a.b[0] == 1); - DLIB_TEST(a.b[1] == 0); - DLIB_TEST(a.b[2] == 0); - DLIB_TEST(a.b[3] == 0); - - bo.host_to_big(a.val); - - DLIB_TEST(a.b[0] == 0); - DLIB_TEST(a.b[1] == 0); - DLIB_TEST(a.b[2] == 0); - DLIB_TEST(a.b[3] == 1); - - bo.big_to_host(a.val); - - DLIB_TEST(a.b[0] == 1); - DLIB_TEST(a.b[1] == 0); - DLIB_TEST(a.b[2] == 0); - DLIB_TEST(a.b[3] == 0); - - DLIB_TEST(a.val == 1); - bo.host_to_network(a.val); - DLIB_TEST(a.val == 0x01000000); - bo.network_to_host(a.val); - DLIB_TEST(a.val == 1); - } - else - { - DLIB_TEST(a.b[0] == 0); - DLIB_TEST(a.b[1] == 0); - DLIB_TEST(a.b[2] == 0); - DLIB_TEST(a.b[3] == 1); - - bo.host_to_little(a.val); - - DLIB_TEST(a.b[0] == 1); - DLIB_TEST(a.b[1] == 0); - DLIB_TEST(a.b[2] == 0); - DLIB_TEST(a.b[3] == 0); - - bo.little_to_host(a.val); - - DLIB_TEST(a.b[0] == 0); - DLIB_TEST(a.b[1] == 0); - DLIB_TEST(a.b[2] == 0); - DLIB_TEST(a.b[3] == 1); - - - DLIB_TEST(a.val == 1); - bo.network_to_host(a.val); - DLIB_TEST(a.val == 1); - bo.host_to_network(a.val); - DLIB_TEST(a.val == 1); - - } - - - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/cca.cpp b/lib/3rdParty/dlib/include/dlib/test/cca.cpp deleted file mode 100644 index aa795a5e..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/cca.cpp +++ /dev/null @@ -1,401 +0,0 @@ -// Copyright (C) 2013 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.cca"); - - dlib::rand rnd; -// ---------------------------------------------------------------------------------------- - - std::vector > make_really_big_test_matrix ( - ) - { - std::vector > temp(30000); - for (unsigned long i = 0; i < temp.size(); ++i) - { - for (int k = 0; k < 30; ++k) - temp[i][rnd.get_random_32bit_number()%10000] = 1; - } - return temp; - } - - template - std::vector > mat_to_sparse ( - const matrix& A - ) - { - std::vector > temp(A.nr()); - for (long r = 0; r < A.nr(); ++r) - { - for (long c = 0; c < A.nc(); ++c) - { - temp[r][c] = A(r,c); - } - } - return temp; - } - -// ---------------------------------------------------------------------------------------- - - template - matrix rm_zeros ( - const matrix_exp& m - ) - { - // Do this to avoid trying to correlate super small numbers that are really just - // zero. Doing this avoids some potential false alarms in the unit tests below. - return round_zeros(m, max(abs(m))*1e-14); - } - -// ---------------------------------------------------------------------------------------- - - void check_correlation ( - matrix L, - matrix R, - const matrix& Ltrans, - const matrix& Rtrans, - const matrix& correlations - ) - { - // apply the transforms - L = L*Ltrans; - R = R*Rtrans; - - // compute the real correlation values. Store them in A. - matrix A = compute_correlations(L, R); - - for (long i = 0; i < correlations.size(); ++i) - { - // compare what the measured correlation values are (in A) to the - // predicted values. - cout << "error: "<< A(i) - correlations(i); - } - } - -// ---------------------------------------------------------------------------------------- - - void test_cca3() - { - print_spinner(); - const unsigned long rank = rnd.get_random_32bit_number()%10 + 1; - const unsigned long m = rank + rnd.get_random_32bit_number()%15; - const unsigned long n = rank + rnd.get_random_32bit_number()%15; - const unsigned long n2 = rank + rnd.get_random_32bit_number()%15; - const unsigned long rank2 = rank + rnd.get_random_32bit_number()%5; - - dlog << LINFO << "m: " << m; - dlog << LINFO << "n: " << n; - dlog << LINFO << "n2: " << n2; - dlog << LINFO << "rank: " << rank; - dlog << LINFO << "rank2: " << rank2; - - - matrix L = randm(m,rank, rnd)*randm(rank,n, rnd); - //matrix R = randm(m,rank, rnd)*randm(rank,n2, rnd); - matrix R = L*randm(n,n2); - //matrix L = randm(m,n, rnd); - //matrix R = randm(m,n2, rnd); - - matrix Ltrans, Rtrans; - matrix correlations; - - { - correlations = cca(L, R, Ltrans, Rtrans, min(m,n), max(n,n2)); - DLIB_TEST(Ltrans.nc() == Rtrans.nc()); - dlog << LINFO << "correlations: "<< trans(correlations); - - const double corr_error = max(abs(compute_correlations(rm_zeros(L*Ltrans), rm_zeros(R*Rtrans)) - correlations)); - dlog << LINFO << "correlation error: "<< corr_error; - DLIB_TEST_MSG(corr_error < 1e-13, Ltrans << "\n\n" << Rtrans); - - const double trans_error = max(abs(L*Ltrans - R*Rtrans)); - dlog << LINFO << "trans_error: "<< trans_error; - DLIB_TEST(trans_error < 1e-10); - } - { - correlations = cca(mat_to_sparse(L), mat_to_sparse(R), Ltrans, Rtrans, min(m,n), max(n,n2)+6, 4); - DLIB_TEST(Ltrans.nc() == Rtrans.nc()); - dlog << LINFO << "correlations: "<< trans(correlations); - dlog << LINFO << "computed cors: " << trans(compute_correlations(rm_zeros(L*Ltrans), rm_zeros(R*Rtrans))); - - const double trans_error = max(abs(L*Ltrans - R*Rtrans)); - dlog << LINFO << "trans_error: "<< trans_error; - const double corr_error = max(abs(compute_correlations(rm_zeros(L*Ltrans), rm_zeros(R*Rtrans)) - correlations)); - dlog << LINFO << "correlation error: "<< corr_error; - DLIB_TEST_MSG(corr_error < 1e-13, Ltrans << "\n\n" << Rtrans); - - DLIB_TEST(trans_error < 1e-10); - } - - dlog << LINFO << "*****************************************************"; - } - - void test_cca2() - { - print_spinner(); - const unsigned long rank = rnd.get_random_32bit_number()%10 + 1; - const unsigned long m = rank + rnd.get_random_32bit_number()%15; - const unsigned long n = rank + rnd.get_random_32bit_number()%15; - const unsigned long n2 = rank + rnd.get_random_32bit_number()%15; - - dlog << LINFO << "m: " << m; - dlog << LINFO << "n: " << n; - dlog << LINFO << "n2: " << n2; - dlog << LINFO << "rank: " << rank; - - - matrix L = randm(m,n, rnd); - matrix R = randm(m,n2, rnd); - - matrix Ltrans, Rtrans; - matrix correlations; - - { - correlations = cca(L, R, Ltrans, Rtrans, min(n,n2), max(n,n2)-min(n,n2)); - DLIB_TEST(Ltrans.nc() == Rtrans.nc()); - dlog << LINFO << "correlations: "<< trans(correlations); - - if (Ltrans.nc() > 1) - { - // The CCA projection directions are supposed to be uncorrelated for - // non-matching pairs of projections. - const double corr_rot1_error = max(abs(compute_correlations(rm_zeros(L*rotate<0,1>(Ltrans)), rm_zeros(R*Rtrans)))); - dlog << LINFO << "corr_rot1_error: "<< corr_rot1_error; - DLIB_TEST(std::abs(corr_rot1_error) < 1e-10); - } - // Matching projection directions should be correlated with the amount of - // correlation indicated by the return value of cca(). - const double corr_error = max(abs(compute_correlations(rm_zeros(L*Ltrans), rm_zeros(R*Rtrans)) - correlations)); - dlog << LINFO << "correlation error: "<< corr_error; - DLIB_TEST(corr_error < 1e-13); - } - { - correlations = cca(mat_to_sparse(L), mat_to_sparse(R), Ltrans, Rtrans, min(n,n2), max(n,n2)-min(n,n2)); - DLIB_TEST(Ltrans.nc() == Rtrans.nc()); - dlog << LINFO << "correlations: "<< trans(correlations); - - if (Ltrans.nc() > 1) - { - // The CCA projection directions are supposed to be uncorrelated for - // non-matching pairs of projections. - const double corr_rot1_error = max(abs(compute_correlations(rm_zeros(L*rotate<0,1>(Ltrans)), rm_zeros(R*Rtrans)))); - dlog << LINFO << "corr_rot1_error: "<< corr_rot1_error; - DLIB_TEST(std::abs(corr_rot1_error) < 1e-10); - } - // Matching projection directions should be correlated with the amount of - // correlation indicated by the return value of cca(). - const double corr_error = max(abs(compute_correlations(rm_zeros(L*Ltrans), rm_zeros(R*Rtrans)) - correlations)); - dlog << LINFO << "correlation error: "<< corr_error; - DLIB_TEST(corr_error < 1e-13); - } - - dlog << LINFO << "*****************************************************"; - } - - void test_cca1() - { - print_spinner(); - const unsigned long rank = rnd.get_random_32bit_number()%10 + 1; - const unsigned long m = rank + rnd.get_random_32bit_number()%15; - const unsigned long n = rank + rnd.get_random_32bit_number()%15; - - dlog << LINFO << "m: " << m; - dlog << LINFO << "n: " << n; - dlog << LINFO << "rank: " << rank; - - matrix T = randm(n,n, rnd); - - matrix L = randm(m,rank, rnd)*randm(rank,n, rnd); - //matrix L = randm(m,n, rnd); - matrix R = L*T; - - matrix Ltrans, Rtrans; - matrix correlations; - - { - correlations = cca(L, R, Ltrans, Rtrans, rank); - DLIB_TEST(Ltrans.nc() == Rtrans.nc()); - if (Ltrans.nc() > 1) - { - // The CCA projection directions are supposed to be uncorrelated for - // non-matching pairs of projections. - const double corr_rot1_error = max(abs(compute_correlations(rm_zeros(L*rotate<0,1>(Ltrans)), rm_zeros(R*Rtrans)))); - dlog << LINFO << "corr_rot1_error: "<< corr_rot1_error; - DLIB_TEST(std::abs(corr_rot1_error) < 1e-10); - } - // Matching projection directions should be correlated with the amount of - // correlation indicated by the return value of cca(). - const double corr_error = max(abs(compute_correlations(rm_zeros(L*Ltrans), rm_zeros(R*Rtrans)) - correlations)); - dlog << LINFO << "correlation error: "<< corr_error; - DLIB_TEST(corr_error < 1e-13); - - const double trans_error = max(abs(L*Ltrans - R*Rtrans)); - dlog << LINFO << "trans_error: "<< trans_error; - DLIB_TEST(trans_error < 1e-10); - - dlog << LINFO << "correlations: "<< trans(correlations); - } - { - correlations = cca(mat_to_sparse(L), mat_to_sparse(R), Ltrans, Rtrans, rank); - DLIB_TEST(Ltrans.nc() == Rtrans.nc()); - if (Ltrans.nc() > 1) - { - // The CCA projection directions are supposed to be uncorrelated for - // non-matching pairs of projections. - const double corr_rot1_error = max(abs(compute_correlations(rm_zeros(L*rotate<0,1>(Ltrans)), rm_zeros(R*Rtrans)))); - dlog << LINFO << "corr_rot1_error: "<< corr_rot1_error; - DLIB_TEST(std::abs(corr_rot1_error) < 1e-10); - } - // Matching projection directions should be correlated with the amount of - // correlation indicated by the return value of cca(). - const double corr_error = max(abs(compute_correlations(rm_zeros(L*Ltrans), rm_zeros(R*Rtrans)) - correlations)); - dlog << LINFO << "correlation error: "<< corr_error; - DLIB_TEST(corr_error < 1e-13); - - const double trans_error = max(abs(L*Ltrans - R*Rtrans)); - dlog << LINFO << "trans_error: "<< trans_error; - DLIB_TEST(trans_error < 1e-9); - - dlog << LINFO << "correlations: "<< trans(correlations); - } - - dlog << LINFO << "*****************************************************"; - } - -// ---------------------------------------------------------------------------------------- - - void test_svd_fast( - long rank, - long m, - long n - ) - { - print_spinner(); - matrix A = randm(m,rank,rnd)*randm(rank,n,rnd); - matrix u,v; - matrix w; - - dlog << LINFO << "rank: "<< rank; - dlog << LINFO << "m: "<< m; - dlog << LINFO << "n: "<< n; - - svd_fast(A, u, w, v, rank, 2); - DLIB_TEST(u.nr() == m); - DLIB_TEST(u.nc() == rank); - DLIB_TEST(w.nr() == rank); - DLIB_TEST(w.nc() == 1); - DLIB_TEST(v.nr() == n); - DLIB_TEST(v.nc() == rank); - DLIB_TEST(max(abs(trans(u)*u - identity_matrix(u.nc()))) < 1e-13); - DLIB_TEST(max(abs(trans(v)*v - identity_matrix(u.nc()))) < 1e-13); - - DLIB_TEST(max(abs(tmp(A - u*diagm(w)*trans(v)))) < 1e-13); - svd_fast(mat_to_sparse(A), u, w, v, rank, 2); - DLIB_TEST(u.nr() == m); - DLIB_TEST(u.nc() == rank); - DLIB_TEST(w.nr() == rank); - DLIB_TEST(w.nc() == 1); - DLIB_TEST(v.nr() == n); - DLIB_TEST(v.nc() == rank); - DLIB_TEST(max(abs(trans(u)*u - identity_matrix(u.nc()))) < 1e-13); - DLIB_TEST(max(abs(trans(v)*v - identity_matrix(u.nc()))) < 1e-13); - DLIB_TEST(max(abs(tmp(A - u*diagm(w)*trans(v)))) < 1e-13); - - svd_fast(A, u, w, v, rank, 0); - DLIB_TEST(u.nr() == m); - DLIB_TEST(u.nc() == rank); - DLIB_TEST(w.nr() == rank); - DLIB_TEST(w.nc() == 1); - DLIB_TEST(v.nr() == n); - DLIB_TEST(v.nc() == rank); - DLIB_TEST(max(abs(trans(u)*u - identity_matrix(u.nc()))) < 1e-13); - DLIB_TEST(max(abs(trans(v)*v - identity_matrix(u.nc()))) < 1e-13); - DLIB_TEST_MSG(max(abs(tmp(A - u*diagm(w)*trans(v)))) < 1e-9,max(abs(tmp(A - u*diagm(w)*trans(v))))); - svd_fast(mat_to_sparse(A), u, w, v, rank, 0); - DLIB_TEST(u.nr() == m); - DLIB_TEST(u.nc() == rank); - DLIB_TEST(w.nr() == rank); - DLIB_TEST(w.nc() == 1); - DLIB_TEST(v.nr() == n); - DLIB_TEST(v.nc() == rank); - DLIB_TEST(max(abs(trans(u)*u - identity_matrix(u.nc()))) < 1e-13); - DLIB_TEST(max(abs(trans(v)*v - identity_matrix(u.nc()))) < 1e-13); - DLIB_TEST(max(abs(tmp(A - u*diagm(w)*trans(v)))) < 1e-10); - - svd_fast(A, u, w, v, rank+5, 0); - DLIB_TEST(max(abs(trans(u)*u - identity_matrix(u.nc()))) < 1e-13); - DLIB_TEST(max(abs(trans(v)*v - identity_matrix(u.nc()))) < 1e-13); - DLIB_TEST(max(abs(tmp(A - u*diagm(w)*trans(v)))) < 1e-11); - svd_fast(mat_to_sparse(A), u, w, v, rank+5, 0); - DLIB_TEST(max(abs(trans(u)*u - identity_matrix(u.nc()))) < 1e-13); - DLIB_TEST(max(abs(trans(v)*v - identity_matrix(u.nc()))) < 1e-13); - DLIB_TEST(max(abs(tmp(A - u*diagm(w)*trans(v)))) < 1e-11); - svd_fast(A, u, w, v, rank+5, 1); - DLIB_TEST(max(abs(trans(u)*u - identity_matrix(u.nc()))) < 1e-13); - DLIB_TEST(max(abs(trans(v)*v - identity_matrix(u.nc()))) < 1e-13); - DLIB_TEST(max(abs(tmp(A - u*diagm(w)*trans(v)))) < 1e-12); - svd_fast(mat_to_sparse(A), u, w, v, rank+5, 1); - DLIB_TEST(max(abs(trans(u)*u - identity_matrix(u.nc()))) < 1e-13); - DLIB_TEST(max(abs(trans(v)*v - identity_matrix(u.nc()))) < 1e-13); - DLIB_TEST(max(abs(tmp(A - u*diagm(w)*trans(v)))) < 1e-12); - } - - void test_svd_fast() - { - for (int iter = 0; iter < 1000; ++iter) - { - const unsigned long rank = rnd.get_random_32bit_number()%10 + 1; - const unsigned long m = rank + rnd.get_random_32bit_number()%10; - const unsigned long n = rank + rnd.get_random_32bit_number()%10; - - test_svd_fast(rank, m, n); - - } - test_svd_fast(1, 1, 1); - test_svd_fast(1, 2, 2); - test_svd_fast(1, 1, 2); - test_svd_fast(1, 2, 1); - } - -// ---------------------------------------------------------------------------------------- - - class test_cca : public tester - { - public: - test_cca ( - ) : - tester ("test_cca", - "Runs tests on the cca() and svd_fast() routines.") - {} - - void perform_test ( - ) - { - for (int i = 0; i < 200; ++i) - { - test_cca1(); - test_cca2(); - test_cca3(); - } - test_svd_fast(); - } - } a; - - - -} - - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/clustering.cpp b/lib/3rdParty/dlib/include/dlib/test/clustering.cpp deleted file mode 100644 index aa852b0d..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/clustering.cpp +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright (C) 2012 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.clustering"); - -// ---------------------------------------------------------------------------------------- - - void make_test_graph( - dlib::rand& rnd, - std::vector& edges, - std::vector& labels, - const int groups, - const int group_size, - const int noise_level, - const double missed_edges - ) - { - labels.resize(groups*group_size); - - for (unsigned long i = 0; i < labels.size(); ++i) - { - labels[i] = i/group_size; - } - - edges.clear(); - for (int i = 0; i < groups; ++i) - { - for (int j = 0; j < group_size; ++j) - { - for (int k = 0; k < group_size; ++k) - { - if (j == k) - continue; - - if (rnd.get_random_double() < missed_edges) - continue; - - edges.push_back(sample_pair(j+group_size*i, k+group_size*i, 1)); - } - } - } - - for (int k = 0; k < groups*noise_level; ++k) - { - const int i = rnd.get_random_32bit_number()%labels.size(); - const int j = rnd.get_random_32bit_number()%labels.size(); - edges.push_back(sample_pair(i,j,1)); - } - - } - -// ---------------------------------------------------------------------------------------- - - void make_modularity_matrices ( - const std::vector& edges, - matrix& A, - matrix& P, - double& m - ) - { - const unsigned long num_nodes = max_index_plus_one(edges); - A.set_size(num_nodes, num_nodes); - P.set_size(num_nodes, num_nodes); - A = 0; - P = 0; - std::vector k(num_nodes,0); - - for (unsigned long i = 0; i < edges.size(); ++i) - { - const unsigned long n1 = edges[i].index1(); - const unsigned long n2 = edges[i].index2(); - k[n1] += edges[i].distance(); - if (n1 != n2) - { - k[n2] += edges[i].distance(); - A(n2,n1) += edges[i].distance(); - } - - A(n1,n2) += edges[i].distance(); - } - - m = sum(A)/2; - - for (long r = 0; r < P.nr(); ++r) - { - for (long c = 0; c < P.nc(); ++c) - { - P(r,c) = k[r]*k[c]/(2*m); - } - } - - } - - double compute_modularity_simple ( - const std::vector& edges, - std::vector labels - ) - { - double m; - matrix A,P; - make_modularity_matrices(edges, A, P, m); - matrix B = A - P; - - double Q = 0; - for (long r = 0; r < B.nr(); ++r) - { - for (long c = 0; c < B.nc(); ++c) - { - if (labels[r] == labels[c]) - { - Q += B(r,c); - } - } - } - return 1.0/(2*m) * Q; - } - -// ---------------------------------------------------------------------------------------- - - void test_modularity(dlib::rand& rnd) - { - print_spinner(); - std::vector edges; - std::vector oedges; - std::vector labels; - - make_test_graph(rnd, edges, labels, 10, 30, 3, 0.10); - if (rnd.get_random_double() < 0.5) - remove_duplicate_edges(edges); - convert_unordered_to_ordered(edges, oedges); - - - const double m1 = modularity(edges, labels); - const double m2 = compute_modularity_simple(edges, labels); - const double m3 = modularity(oedges, labels); - - DLIB_TEST(std::abs(m1-m2) < 1e-12); - DLIB_TEST(std::abs(m2-m3) < 1e-12); - DLIB_TEST(std::abs(m3-m1) < 1e-12); - } - - void test_newman_clustering(dlib::rand& rnd) - { - print_spinner(); - std::vector edges; - std::vector labels; - - make_test_graph(rnd, edges, labels, 5, 30, 3, 0.10); - if (rnd.get_random_double() < 0.5) - remove_duplicate_edges(edges); - - - std::vector labels2; - - unsigned long num_clusters = newman_cluster(edges, labels2); - DLIB_TEST(labels.size() == labels2.size()); - DLIB_TEST(num_clusters == 5); - - for (unsigned long i = 0; i < labels.size(); ++i) - { - for (unsigned long j = 0; j < labels.size(); ++j) - { - if (labels[i] == labels[j]) - { - DLIB_TEST(labels2[i] == labels2[j]); - } - else - { - DLIB_TEST(labels2[i] != labels2[j]); - } - } - } - } - - void test_chinese_whispers(dlib::rand& rnd) - { - print_spinner(); - std::vector edges; - std::vector labels; - - make_test_graph(rnd, edges, labels, 5, 30, 3, 0.10); - if (rnd.get_random_double() < 0.5) - remove_duplicate_edges(edges); - - - std::vector labels2; - - unsigned long num_clusters; - if (rnd.get_random_double() < 0.5) - num_clusters = chinese_whispers(edges, labels2, 200, rnd); - else - num_clusters = chinese_whispers(edges, labels2); - - DLIB_TEST(labels.size() == labels2.size()); - DLIB_TEST(num_clusters == 5); - - for (unsigned long i = 0; i < labels.size(); ++i) - { - for (unsigned long j = 0; j < labels.size(); ++j) - { - if (labels[i] == labels[j]) - { - DLIB_TEST(labels2[i] == labels2[j]); - } - else - { - DLIB_TEST(labels2[i] != labels2[j]); - } - } - } - } - - class test_clustering : public tester - { - public: - test_clustering ( - ) : - tester ("test_clustering", - "Runs tests on the clustering routines.") - {} - - void perform_test ( - ) - { - dlib::rand rnd; - - std::vector edges; - std::vector labels; - DLIB_TEST(newman_cluster(edges, labels) == 0); - DLIB_TEST(chinese_whispers(edges, labels) == 0); - - edges.push_back(sample_pair(0,1,1)); - DLIB_TEST(newman_cluster(edges, labels) == 1); - DLIB_TEST(labels.size() == 2); - DLIB_TEST(chinese_whispers(edges, labels) == 1); - DLIB_TEST(labels.size() == 2); - - edges.clear(); - edges.push_back(sample_pair(0,0,1)); - DLIB_TEST(newman_cluster(edges, labels) == 1); - DLIB_TEST(labels.size() == 1); - DLIB_TEST(chinese_whispers(edges, labels) == 1); - DLIB_TEST(labels.size() == 1); - - edges.clear(); - edges.push_back(sample_pair(1,1,1)); - DLIB_TEST(newman_cluster(edges, labels) == 1); - DLIB_TEST(labels.size() == 2); - DLIB_TEST(chinese_whispers(edges, labels) == 2); - DLIB_TEST(labels.size() == 2); - - edges.push_back(sample_pair(0,0,1)); - DLIB_TEST(newman_cluster(edges, labels) == 2); - DLIB_TEST(labels.size() == 2); - DLIB_TEST(chinese_whispers(edges, labels) == 2); - DLIB_TEST(labels.size() == 2); - - - for (int i = 0; i < 10; ++i) - test_modularity(rnd); - - for (int i = 0; i < 10; ++i) - test_newman_clustering(rnd); - - for (int i = 0; i < 10; ++i) - test_chinese_whispers(rnd); - - - } - } a; - - - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/cmd_line_parser.cpp b/lib/3rdParty/dlib/include/dlib/test/cmd_line_parser.cpp deleted file mode 100644 index 9216a76c..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/cmd_line_parser.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include - -#include - -#include "tester.h" - -#include "cmd_line_parser.h" -namespace -{ - - class cmd_line_parser_tester : public tester - { - public: - cmd_line_parser_tester ( - ) : - tester ("test_cmd_line_parser_char", - "Runs tests on the cmd_line_parser component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a with char"; - cmd_line_parser_kernel_test::kernel_1a>(); - print_spinner(); - - dlog << LINFO << "testing kernel_1a_c with char"; - cmd_line_parser_kernel_test::kernel_1a_c>(); - print_spinner(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/cmd_line_parser_wchar_t.cpp b/lib/3rdParty/dlib/include/dlib/test/cmd_line_parser_wchar_t.cpp deleted file mode 100644 index f771eeed..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/cmd_line_parser_wchar_t.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include - -#include - -#include "tester.h" - -#include "cmd_line_parser.h" -namespace -{ - - class cmd_line_parser_tester : public tester - { - public: - cmd_line_parser_tester ( - ) : - tester ("test_cmd_line_parser_wchar_t", - "Runs tests on the cmd_line_parser component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a with wchar_t"; - cmd_line_parser_kernel_test::kernel_1a>(); - print_spinner(); - - dlog << LINFO << "testing kernel_1a_c with wchar_t"; - cmd_line_parser_kernel_test::kernel_1a_c>(); - print_spinner(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/compress_stream.cpp b/lib/3rdParty/dlib/include/dlib/test/compress_stream.cpp deleted file mode 100644 index fbc57dd4..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/compress_stream.cpp +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include - -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace std; - using namespace dlib; - - logger dlog("test.compress_stream"); - - template < - typename cs - > - void compress_stream_kernel_test ( - unsigned long seed - ) - /*! - requires - - cs is an implementation of compress_stream/compress_stream_kernel_abstract.h - the alphabet_size for cc is 256 - ensures - - runs tests on cs for compliance with the specs - !*/ - { - - - srand(seed); - - cs test; - - - dlog << LTRACE << 1; - - int count = 0; - while (count < 2) - { - print_spinner(); - istringstream sin; - ostringstream sout; - string buffer; - buffer.reserve(10000); - // fill sin with a bunch of random data in the range 0 to 63 - for (int i = 0; i < 10000; ++i) - { - char temp = static_cast(::rand()&0x3f); - buffer.push_back(temp); - } - - print_spinner(); - sin.str(buffer); - string old_buffer = buffer; - - test.compress(sin,sout); - buffer = sout.str(); - - print_spinner(); - // corrput the data in buffer - buffer[buffer.size()/2]++; - - sin.str(buffer); - sout.str(""); - - bool detected_error = false; - try { - test.decompress(sin,sout); - } catch ( typename cs::decompression_error e ) - { - detected_error = true; - ++count; - } - - - DLIB_TEST_MSG(detected_error || sout.str() == old_buffer,(unsigned int)sout.str().size()); - - - - } /**/ - - - dlog << LTRACE << 2; - - for (int j = 0; j < 2; ++j) - { - - print_spinner(); - istringstream sin; - ostringstream sout; - - string buffer; - - buffer.reserve(10); - - // make sure a single char can be compressed and decompressed - for (int i = 0; i < 256; ++i) - { - sin.str(""); - sout.str(""); - char ch = static_cast(i); - buffer = ch; - sin.str(buffer); - - test.compress(sin,sout); - - sin.str(sout.str()); - sout.str(""); - test.decompress(sin,sout); - DLIB_TEST(sout.str() == buffer); - } - - print_spinner(); - - // make sure you can compress a single char, then append a new - // compressed single char. and make sure you can decode the - // two streams. Just to make sure the decoder doesn't leave - // extra bytes behind or eat more than it should. - for (int i = 0; i < 500; ++i) - { - sin.str(""); - sin.clear(); - sout.str(""); - sout.clear(); - char ch = static_cast(::rand()%256); - char ch2 = static_cast(::rand()%256); - - buffer = ch; - sin.str(buffer); - - - - test.compress(sin,sout); - - - - - buffer = ch2; - sin.str(buffer); - test.compress(sin,sout); - - sin.str(sout.str()); - - sout.str(""); - test.decompress(sin,sout); - buffer = ch; - DLIB_TEST(sout.str() == buffer); - - - - - sout.str(""); - test.decompress(sin,sout); - buffer = ch2; - DLIB_TEST(sout.str() == buffer); - - - } - print_spinner(); - - - // make sure you can compress and decompress the empty string - sout.str(""); - sin.str(""); - test.compress(sin,sout); - sin.str(sout.str()); - sout.str(""); - test.decompress(sin,sout); - DLIB_TEST_MSG(sout.str() == "",sout.str()); - - - - - - print_spinner(); - - sin.str(""); - sout.str(""); - buffer = ""; - - buffer.reserve(20000); - // fill buffer with a bunch of random data in the range 0 to 63 - for (int i = 0; i < 20000; ++i) - { - char temp = static_cast(::rand()&0x3f); - buffer.push_back(temp); - } - - sin.str(buffer); - - print_spinner(); - test.compress(sin,sout); - - sin.str(sout.str()); - sout.str(""); - - print_spinner(); - test.decompress(sin,sout); - - DLIB_TEST(sout.str() == buffer); - - print_spinner(); - } - - dlog << LTRACE << 3; - - // this block will try to compress a bunch of 'a' chars - { - - istringstream sin; - ostringstream sout; - - string buffer; - - - print_spinner(); - - sin.str(""); - sout.str(""); - buffer = ""; - - buffer.reserve(50000); - // fill buffer with a bunch of 'a' chars - for (int i = 0; i < 50000; ++i) - { - char temp = 'a'; - buffer.push_back(temp); - } - - sin.str(buffer); - - print_spinner(); - test.compress(sin,sout); - - sin.str(sout.str()); - sout.str(""); - - print_spinner(); - test.decompress(sin,sout); - - DLIB_TEST(sout.str() == buffer); - - print_spinner(); - - } - - dlog << LTRACE << 4; - - } - - - - - - - class compress_stream_tester : public tester - { - public: - compress_stream_tester ( - ) : - tester ("test_compress_stream", - "Runs tests on the compress_stream component.") - {} - - void perform_test ( - ) - { - const unsigned int seed = static_cast(time(0)); - dlog << LINFO << "using seed: " << seed; - - dlog << LINFO << "testing kernel_1a"; - compress_stream_kernel_test(seed); - dlog << LINFO << "testing kernel_1b"; - compress_stream_kernel_test(seed); - dlog << LINFO << "testing kernel_1c"; - compress_stream_kernel_test(seed); - dlog << LINFO << "testing kernel_1da"; - compress_stream_kernel_test(seed); - dlog << LINFO << "testing kernel_1db"; - compress_stream_kernel_test(seed); - dlog << LINFO << "testing kernel_1ea"; - compress_stream_kernel_test(seed); - dlog << LINFO << "testing kernel_1eb"; - compress_stream_kernel_test(seed); - dlog << LINFO << "testing kernel_1ec"; - compress_stream_kernel_test(seed); - dlog << LINFO << "testing kernel_2a"; - compress_stream_kernel_test(seed); - dlog << LINFO << "testing kernel_3a"; - compress_stream_kernel_test(seed); - dlog << LINFO << "testing kernel_3b"; - compress_stream_kernel_test(seed); - } - } a; - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/conditioning_class.cpp b/lib/3rdParty/dlib/include/dlib/test/conditioning_class.cpp deleted file mode 100644 index b4415eaf..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/conditioning_class.cpp +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include - -#include - -#include "tester.h" -#include "conditioning_class.h" - -namespace -{ - - - class conditioning_class_tester : public tester - { - public: - conditioning_class_tester ( - ) : - tester ("test_conditioning_class", - "Runs tests on the conditioning_class component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a"; - conditioning_class_kernel_test< - conditioning_class<256>::kernel_1a, - conditioning_class<2>::kernel_1a - >(); - print_spinner(); - - dlog << LINFO << "testing kernel_2a"; - conditioning_class_kernel_test< - conditioning_class<256>::kernel_2a, - conditioning_class<2>::kernel_2a - >(); - print_spinner(); - - dlog << LINFO << "testing kernel_3a"; - conditioning_class_kernel_test< - conditioning_class<256>::kernel_3a, - conditioning_class<2>::kernel_3a - >(); - print_spinner(); - - dlog << LINFO << "testing kernel_4a"; - conditioning_class_kernel_test< - conditioning_class<256>::kernel_4a, - conditioning_class<2>::kernel_4a - >(); - print_spinner(); - - dlog << LINFO << "testing kernel_4b"; - conditioning_class_kernel_test< - conditioning_class<256>::kernel_4b, - conditioning_class<2>::kernel_4b - >(); - print_spinner(); - - dlog << LINFO << "testing kernel_4c"; - conditioning_class_kernel_test< - conditioning_class<256>::kernel_4c, - conditioning_class<2>::kernel_4c - >(); - print_spinner(); - - dlog << LINFO << "testing kernel_4d"; - conditioning_class_kernel_test< - conditioning_class<256>::kernel_4d, - conditioning_class<2>::kernel_4d - >(); - print_spinner(); - - - } - } a; - - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/conditioning_class_c.cpp b/lib/3rdParty/dlib/include/dlib/test/conditioning_class_c.cpp deleted file mode 100644 index 4bfd9f32..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/conditioning_class_c.cpp +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include - -#include - -#include "tester.h" -#include "conditioning_class.h" - -namespace -{ - - - class conditioning_class_tester : public tester - { - public: - conditioning_class_tester ( - ) : - tester ("test_conditioning_class_c", - "Runs tests on the conditioning_class checked components.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a_c"; - conditioning_class_kernel_test< - conditioning_class<256>::kernel_1a_c, - conditioning_class<2>::kernel_1a_c - >(); - print_spinner(); - - dlog << LINFO << "testing kernel_2a_c"; - conditioning_class_kernel_test< - conditioning_class<256>::kernel_2a_c, - conditioning_class<2>::kernel_2a_c - >(); - print_spinner(); - - dlog << LINFO << "testing kernel_3a_c"; - conditioning_class_kernel_test< - conditioning_class<256>::kernel_3a_c, - conditioning_class<2>::kernel_3a_c - >(); - print_spinner(); - - dlog << LINFO << "testing kernel_4a_c"; - conditioning_class_kernel_test< - conditioning_class<256>::kernel_4a_c, - conditioning_class<2>::kernel_4a_c - >(); - print_spinner(); - - dlog << LINFO << "testing kernel_4b_c"; - conditioning_class_kernel_test< - conditioning_class<256>::kernel_4b_c, - conditioning_class<2>::kernel_4b_c - >(); - print_spinner(); - - - dlog << LINFO << "testing kernel_4c_c"; - conditioning_class_kernel_test< - conditioning_class<256>::kernel_4c_c, - conditioning_class<2>::kernel_4c_c - >(); - print_spinner(); - - dlog << LINFO << "testing kernel_4d_c"; - conditioning_class_kernel_test< - conditioning_class<256>::kernel_4d_c, - conditioning_class<2>::kernel_4d_c - >(); - print_spinner(); - - - } - } a; - - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/config_reader.cpp b/lib/3rdParty/dlib/include/dlib/test/config_reader.cpp deleted file mode 100644 index 20b5215f..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/config_reader.cpp +++ /dev/null @@ -1,509 +0,0 @@ -// Copyright (C) 2007 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -// This is called an unnamed-namespace and it has the effect of making everything inside this file "private" -// so that everything you declare will have static linkage. Thus we won't have any multiply -// defined symbol errors coming out of the linker when we try to compile the test suite. -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - // Declare the logger we will use in this test. The name of the tester - // should start with "test." - logger dlog("test.config_reader"); - - template < - typename config_reader - > - void do_the_tests ( - config_reader& cr - ) - { - DLIB_TEST(cr.is_key_defined("global")); - DLIB_TEST(cr.is_block_defined("all")); - DLIB_TEST(cr.is_key_defined("globalasfd") == false); - DLIB_TEST(cr.is_block_defined("all!") == false); - DLIB_TEST(cr["global"] == "hmm"); - DLIB_TEST(cr["global2"] == "hmm2"); - - std_vector_c blocks; - cr.block("all").get_blocks(blocks); - DLIB_TEST(blocks.size() == 4); - cr.block("all").block("block1").get_blocks(blocks); DLIB_TEST(blocks.size() == 0); - cr.block("all").block("block2").get_blocks(blocks); DLIB_TEST(blocks.size() == 0); - cr.block("all").block("block3").get_blocks(blocks); DLIB_TEST(blocks.size() == 0); - cr.block("all").block("block4").get_blocks(blocks); DLIB_TEST(blocks.size() == 0); - - DLIB_TEST(cr.block("all").block("block1").is_key_defined("name")); - DLIB_TEST(cr.block("all").block("block2").is_key_defined("name")); - DLIB_TEST(cr.block("all").block("block3").is_key_defined("name")); - DLIB_TEST(cr.block("all").block("block4").is_key_defined("name")); - DLIB_TEST(cr.block("all").block("block1").is_key_defined("age")); - DLIB_TEST(cr.block("all").block("block2").is_key_defined("age")); - DLIB_TEST(cr.block("all").block("block3").is_key_defined("age")); - DLIB_TEST(cr.block("all").block("block4").is_key_defined("age")); - - DLIB_TEST(cr.block("all").block("block1")["name"] == "davis king"); - DLIB_TEST(cr.block("all").block("block2")["name"] == "joel"); - DLIB_TEST(cr.block("all").block("block3")["name"] == "john"); - DLIB_TEST(cr.block("all").block("block4")["name"] == "dude"); - DLIB_TEST(cr.block("all").block("block1")["age"] == "24"); - DLIB_TEST(cr.block("all").block("block2")["age"] == "24"); - DLIB_TEST(cr.block("all").block("block3")["age"] == "24"); - DLIB_TEST(cr.block("all").block("block4")["age"] == "53"); - - - int count2 = 0; - cr.get_blocks(blocks); - DLIB_TEST(blocks.size() == 1); - DLIB_TEST(blocks[0] == "all"); - - - DLIB_TEST(cr.block("all").is_key_defined("global") == false); - DLIB_TEST(cr.block("all").is_key_defined("global2") == false); - DLIB_TEST(cr.block("all").is_key_defined("name") == false); - DLIB_TEST(cr.block("all").is_key_defined("age") == false); - - cr.block("all").get_blocks(blocks); - DLIB_TEST(blocks.size() == 4); - std::vector temp_blocks; - for (unsigned long i = 0; i < blocks.size(); ++i) - { - ++count2; - ostringstream sout; - sout << "block" << count2; - DLIB_TEST(blocks[i] == sout.str()); - - cr.block("all").block(blocks[i]).get_blocks(temp_blocks); - DLIB_TEST(temp_blocks.size() == 0); - - DLIB_TEST(cr.block("all").block(blocks[i]).is_key_defined("name")); - DLIB_TEST(cr.block("all").block(blocks[i]).is_key_defined("age")); - } - - - - bool found_error = false; - try - { - cr.block("bogus_block"); - } - catch (typename config_reader::config_reader_access_error& e) - { - DLIB_TEST(e.block_name == "bogus_block"); - DLIB_TEST(e.key_name == ""); - found_error = true; - } - DLIB_TEST(found_error); - - found_error = false; - try - { - cr["bogus_key"]; - } - catch (typename config_reader::config_reader_access_error& e) - { - DLIB_TEST(e.block_name == ""); - DLIB_TEST(e.key_name == "bogus_key"); - found_error = true; - } - DLIB_TEST(found_error); - - - found_error = false; - try - { - cr.block("all").block("block10"); - } - catch (typename config_reader::config_reader_access_error& e) - { - DLIB_TEST(e.block_name == "block10"); - DLIB_TEST(e.key_name == ""); - found_error = true; - } - DLIB_TEST(found_error); - - found_error = false; - try - { - cr.block("all")["msdofg"]; - } - catch (typename config_reader::config_reader_access_error& e) - { - DLIB_TEST(e.block_name == ""); - DLIB_TEST(e.key_name == "msdofg"); - found_error = true; - } - DLIB_TEST(found_error); - - } - - - - template < - typename config_reader - > - void config_reader_test ( - ) - /*! - requires - - config_reader is an implementation of config_reader/config_reader_kernel_abstract.h - is instantiated with int - ensures - - runs tests on config_reader for compliance with the specs - !*/ - { - - - - ostringstream sout; - - sout << "all#comment { { } \n"; - sout << "{ \n"; - sout << " block1 \n"; - sout << " { \n"; - sout << " name = davis king \n"; - sout << " age = 24 \n"; - sout << " } \n"; - sout << " \n"; - sout << " block2 \n"; - sout << " { \n"; - sout << " name= joel \n"; - sout << " age =24 \n"; - sout << " } \n"; - sout << " \n"; - sout << " block3 \n"; - sout << " { \n"; - sout << " name = john \n"; - sout << " age = 24 \n"; - sout << " } \n"; - sout << " #comment \n"; - sout << "#comment \n"; - sout << " block4{ # comment"; - sout << " \n"; - sout << " name = dude \n"; - sout << " age = 53}\n"; - sout << " \n"; - sout << "} \n"; - sout << " \n"; - sout << " \n"; - sout << "global=hmm#comment \n"; - sout << "global2=hmm2 \n"; - sout << " # comment \n"; - - string data = sout.str(); - - config_reader cr2; - for (int i = 0; i < 3; ++i) - { - istringstream sin; - - sin.clear(); - sin.str(data); - - config_reader cr(sin); - sin.clear(); - sin.str(data); - - cr2.load_from(sin); - - do_the_tests(cr); - do_the_tests(cr2); - - cr.clear(); - DLIB_TEST(cr.is_key_defined("global") == false); - } - - - sout.clear(); - sout.str(""); - - { - sout << "all#comment { { } \n"; - sout << "{ \n"; - sout << " block1 \n"; - sout << " { \n"; - sout << " name = davis king \n"; - sout << " age = 24 \n"; - sout << " } \n"; - sout << " \n"; - sout << " block2 \n"; - sout << " { \n"; - sout << " name= joel \n"; - sout << " age =24 \n"; - sout << " } \n"; - sout << " \n"; - sout << " block3 \n"; - sout << " {{ \n"; // error on this line - sout << " name = john \n"; - sout << " age = 24 \n"; - sout << " } \n"; - sout << " #comment \n"; - sout << "#comment \n"; - sout << " block4{ # comment"; - sout << " \n"; - sout << " name = dude \n"; - sout << " age = 53}\n"; - sout << " \n"; - sout << "} \n"; - sout << " \n"; - sout << " \n"; - sout << "global=hmm#comment \n"; - sout << "global2=hmm2 \n"; - sout << " # comment \n"; - - istringstream sin(sout.str()); - - bool error_found = false; - try - { - cr2.load_from(sin); - } - catch (typename config_reader::config_reader_error& e) - { - error_found = true; - DLIB_TEST(e.line_number == 16); - DLIB_TEST(e.redefinition == false); - } - DLIB_TEST(error_found); - } - - { - sout.str(""); - sout.clear(); - sout << "all#comment { { } \n"; - sout << "{ \n"; - sout << " block1 \n"; - sout << " { \n"; - sout << " name = davis king \n"; - sout << " age = 24 \n"; - sout << " } \n"; - sout << " \n"; - sout << " block2 \n"; - sout << " { \n"; - sout << " name= joel \n"; - sout << " age =24 \n"; - sout << " } \n"; - sout << " \n"; - sout << " block3 \n"; - sout << " { \n"; - sout << " name = john \n"; - sout << " age = 24 \n"; - sout << " } \n"; - sout << " #comment \n"; - sout << "#comment \n"; - sout << " block4{ # comment"; - sout << " \n"; - sout << " name = dude \n"; - sout << " age = 53}\n"; - sout << " \n"; - sout << "} \n"; - sout << " \n"; - sout << " \n"; - sout << "global=hmm#comment \n"; - sout << " \n"; - sout << "global=hmm2 \n"; // error on this line - sout << " # comment \n"; - - istringstream sin(sout.str()); - - bool error_found = false; - try - { - cr2.load_from(sin); - } - catch (typename config_reader::config_reader_error& e) - { - error_found = true; - DLIB_TEST_MSG(e.line_number == 31,e.line_number); - DLIB_TEST(e.redefinition == true); - } - DLIB_TEST(error_found); - } - - - { - sout.str(""); - sout.clear(); - sout << "all#comment { { } \n"; - sout << "{ \n"; - sout << " block1 \n"; - sout << " { \n"; - sout << " name = davis king \n"; - sout << " age = 24 \n"; - sout << " } \n"; - sout << " \n"; - sout << " block2 \n"; - sout << " { \n"; - sout << " name= joel \n"; - sout << " age =24 \n"; - sout << " } block2{} \n"; // error on this line - sout << " \n"; - sout << " block3 \n"; - sout << " { \n"; - sout << " name = john \n"; - sout << " age = 24 \n"; - sout << " } \n"; - sout << " #comment \n"; - sout << "#comment \n"; - sout << " block4{ # comment"; - sout << " \n"; - sout << " name = dude \n"; - sout << " age = 53}\n"; - sout << " \n"; - sout << "} \n"; - sout << " \n"; - sout << " \n"; - sout << "global=hmm#comment \n"; - sout << " \n"; - sout << " # comment \n"; - - istringstream sin(sout.str()); - - bool error_found = false; - try - { - cr2.load_from(sin); - } - catch (typename config_reader::config_reader_error& e) - { - error_found = true; - DLIB_TEST_MSG(e.line_number == 13,e.line_number); - DLIB_TEST(e.redefinition == true); - } - DLIB_TEST(error_found); - } - - - - } - - - void test_get_option() - { - const char* argv[100]; - int argc; - - // program --opt 4 -d dude - argv[0] = "program"; - argv[1] = "--opt"; - argv[2] = "4"; - argv[3] = "-d"; - argv[4] = "dude"; - argc = 5; - - std::ostringstream sout; - sout << "block#comment { { } \n"; - sout << "{ \n"; - sout << " opt = 5 \n"; - sout << " a = 6 \n"; - sout << " d = joel \n"; - sout << " subblock {} \n"; - sout << "} \n"; - sout << " \n"; - sout << " \n"; - sout << "opt = 8 \n"; - sout << "d = davis \n"; - sout << "a = 50 \n"; - sout << " # comment \n"; - - std::istringstream sin(sout.str()); - - config_reader cr(sin); - - dlib::cmd_line_parser::kernel_1a_c parser; - - parser.add_option("opt","",1); - parser.add_option("d","",1); - parser.add_option("a","",1); - parser.add_option("b","",1); - parser.parse(argc, argv); - - DLIB_TEST(get_option(cr, "d", "default") == "davis"); - DLIB_TEST(get_option(cr, "opt", "default") == "8"); - DLIB_TEST(get_option(cr, "opt", 1) == 8); - DLIB_TEST(get_option(cr, "optasdf", 1) == 1); - DLIB_TEST(get_option(cr, "optasdf", 1.1) == 1.1); - DLIB_TEST(get_option(cr.block("block"), "d", "default") == "joel"); - DLIB_TEST(get_option(cr.block("block"), "opt", "default") == "5"); - DLIB_TEST(get_option(cr.block("block"), "opt", 1) == 5); - DLIB_TEST(get_option(cr.block("block").block("subblock"), "d", "default") == "default"); - DLIB_TEST(get_option(cr.block("block").block("subblock"), "opt", "default") == "default"); - DLIB_TEST(get_option(cr.block("block").block("subblock"), "opt", 1) == 1); - DLIB_TEST(get_option(cr, "block.d", "default") == "joel"); - DLIB_TEST(get_option(cr, "block.opt", "default") == "5"); - DLIB_TEST(get_option(cr, "block.opt", 1) == 5); - DLIB_TEST(get_option(cr, "block.asdf.d", "default") == "default"); - DLIB_TEST(get_option(cr, "block.asdf.opt", "default") == "default"); - DLIB_TEST(get_option(cr, "block.asdf.opt", 2) == 2); - DLIB_TEST(get_option(cr, "block.subblock.d", "default") == "default"); - DLIB_TEST(get_option(cr, "block.subblock.opt", "default") == "default"); - DLIB_TEST(get_option(cr, "block.subblock.opt", 2) == 2); - - DLIB_TEST(get_option(parser, "opt", 99) == 4); - DLIB_TEST(get_option(parser, "d", "stuff") == "dude"); - DLIB_TEST(get_option(parser, "a", "stuff") == "stuff"); - DLIB_TEST(get_option(parser, "a", 99) == 99); - - DLIB_TEST(get_option(parser, cr, "d", "default") == "dude"); - DLIB_TEST(get_option(cr, parser, "d", "default") == "dude"); - DLIB_TEST(get_option(parser, cr, "a", 2) == 50); - DLIB_TEST(get_option(cr, parser, "a", 2) == 50); - DLIB_TEST(get_option(parser, cr, "opt", 2) == 4); - DLIB_TEST(get_option(cr, parser, "opt", 2) == 4); - DLIB_TEST(get_option(parser, cr, "b", 2) == 2); - DLIB_TEST(get_option(cr, parser, "b", 2) == 2); - - DLIB_TEST(get_option(parser, cr.block("block"), "a", 2) == 6); - DLIB_TEST(get_option(cr.block("block"), parser, "a", 2) == 6); - } - - - class config_reader_tester : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a test for the config_reader object. When it is constructed - it adds itself into the testing framework. The command line switch is - specified as test_config_reader by passing that string to the tester constructor. - !*/ - public: - config_reader_tester ( - ) : - tester ("test_config_reader", - "Runs tests on the config_reader component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing config_reader"; - print_spinner(); - config_reader_test(); - - dlog << LINFO << "testing config_reader_thread_safe"; - print_spinner(); - config_reader_test(); - - dlog << LINFO << "testing get_option()"; - print_spinner(); - test_get_option(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/crc32.cpp b/lib/3rdParty/dlib/include/dlib/test/crc32.cpp deleted file mode 100644 index 83cfbad2..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/crc32.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.crc32"); - - - class crc32_tester : public tester - { - public: - crc32_tester ( - ) : - tester ("test_crc32", - "Runs tests on the crc32 component.") - {} - - void perform_test ( - ) - { - DLIB_TEST(crc32("davis").get_checksum() == 0x0445527C); - - crc32 c, c2; - DLIB_TEST(c.get_checksum() == 0); - c.add("davis"); - DLIB_TEST(c.get_checksum() == 0x0445527C); - DLIB_TEST(c2.get_checksum() == 0); - c2 = c; - DLIB_TEST(c2.get_checksum() == 0x0445527C); - crc32 c3(c); - DLIB_TEST(c3.get_checksum() == 0x0445527C); - c.add('a'); - c2.add('a'); - c3.add('a'); - DLIB_TEST(c.get_checksum() == 0xB100C606); - DLIB_TEST(c2.get_checksum() == 0xB100C606); - DLIB_TEST(c3.get_checksum() == 0xB100C606); - - - crc32::kernel_1a cold; - DLIB_TEST(cold.get_checksum() == 0); - cold.add("davis"); - DLIB_TEST(cold.get_checksum() == 0x0445527C); - - c.clear(); - DLIB_TEST(c.get_checksum() == 0); - c.add("davis"); - DLIB_TEST(c.get_checksum() == 0x0445527C); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/create_iris_datafile.cpp b/lib/3rdParty/dlib/include/dlib/test/create_iris_datafile.cpp deleted file mode 100644 index 1e19d2aa..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/create_iris_datafile.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include -#include -#include -#include - -namespace -{ - // This function returns the contents of the file 'iris.scale' - const std::string get_decoded_string() - { - dlib::base64::kernel_1a base64_coder; - dlib::compress_stream::kernel_1ea compressor; - std::ostringstream sout; - std::istringstream sin; - - // The base64 encoded data from the file 'iris.scale' we want to decode and return. - sout << "MU66cCmT9lCXWJXwhdfOGELwlyExClbHEF1s9XoqxNDV7o8AdVVHws/C9oIKO5EShH1lI/QFTWk3"; - sout << "8EUdVpSw/NpZCUa7O9nq5uO6SE0gfRAyryH+pfIVL9jPiQi8rBdagDf4kUd4eggz9glwYnKEE+US"; - sout << "K4GUBnW33YDf/jMF2GIBLNvz69yGJj8RC5rOUeJxR4mlHrDmnEfgRSdFIfXk4OQ4V/XbOsE1bnhG"; - sout << "fmACcu7nYv6M/043Z6o8oaBeoJ2XK/9UqOWGFOwfVpQ46fz1a0oTlOzyDbbzMiniLr8z5P/VYwYd"; - sout << "iAE70MwxHXs6Ga3zMmD/h1WxB/uRRph39B1lPN1UXC7U6SIatmtGWY+JYpwBk6raAnR3sblTFBNs"; - sout << "UdPW+1a7AxinR0NZO6YEiCFy8lbpfPRZNAr5ENqPbD2DZtkHk3L8ARxSoFBgqPa8aO3fFow7rVxF"; - sout << "xIJ2TxcHS84+BtH7KvtWfH7kUPOZLQ+Ohqghn9I57IeMl7E3aoTRTiVv3P2twAbP5Y+ZaAUoU7CK"; - sout << "c9FptjKgMClUkuWxA7tGUEp069PqGT8NbI+yxorh/iVhkVhuGAzgjjXYS/D26OGj4bzF6mtRbnms"; - sout << "Y2OYlF7QqhawZaHLtmZ6xLhR2F8p/0nrbpAz2brQLNKgQAMvU9rTZ0XYpuJNbRSsARkRDorPopDO"; - sout << "kKNUORfkh2zfIytVToQ9tZ9W2LkfGZdWjJu/wEKjPDAU55q3bCfKOUk12tjq0sq/7qjUWJRcLSCu"; - sout << "bqo8EzaKJj3cTXVgXXLHP6WEOPZ9vShuxQUu1JWkh8YEinjwFSyA6UnAKqPtN/HsBgv8YbnfnY/q"; - sout << "e5JvUYWbs3Lk9enlhcI0vEVTV5f0GMjdkW87l3cWgmXJqiljJDREWEdKZJQ0rGBU/gW5kO3SAS1W"; - sout << "OETVJG2kJD8Ib7hT15Mu2lOVNQYFri6O3yWtp5/NLHsYXoDKIYrxoJtM9+GkprVwRuhDcwxE+eQa"; - sout << "pp5nC8qj38ameQHaJR2hJCuW2nvr4Wwm0ploF00ZP9cS9YznCO52cueUQX0+zil7bU++jghqSGP5"; - sout << "+JyRzWUWWbDhnCyanej2Y3sqfZ3o2kuUjaAgZFz5pLqK64uACjztp4bQFsaMRdc+OCV2uItqoaRg"; - sout << "a6u7/VrvS+ZigwcGWDjXSKev334f8ZqQQIR5hljdeseGuw7/5XySzUrgc8lCOvMa0pKNn9Nl8W/W"; - sout << "vbKz1VwA"; - - // Put the data into the istream sin - sin.str(sout.str()); - sout.str(""); - - // Decode the base64 text into its compressed binary form - base64_coder.decode(sin,sout); - sin.clear(); - sin.str(sout.str()); - sout.str(""); - - // Decompress the data into its original form - compressor.decompress(sin,sout); - - // Return the decoded and decompressed data - return sout.str(); - } -} - -namespace dlib -{ - void create_iris_datafile ( - ) - { - std::ofstream fout("iris.scale"); - fout << get_decoded_string(); - } -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/data_io.cpp b/lib/3rdParty/dlib/include/dlib/test/data_io.cpp deleted file mode 100644 index 8ced8800..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/data_io.cpp +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "tester.h" -#include -#include -#include -#include "create_iris_datafile.h" -#include -#include - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - dlib::logger dlog("test.data_io"); - - - class test_data_io : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a unit test. When it is constructed - it adds itself into the testing framework. - !*/ - public: - test_data_io ( - ) : - tester ( - "test_data_io", // the command line argument name for this test - "Run tests on the data_io stuff.", // the command line argument description - 0 // the number of command line arguments for this test - ) - { - } - - - template - void run_test() - { - print_spinner(); - - typedef typename sample_type::value_type::second_type scalar_type; - - std::vector samples; - std::vector labels; - - load_libsvm_formatted_data("iris.scale",samples, labels); - save_libsvm_formatted_data("iris.scale2", samples, labels); - - DLIB_TEST(samples.size() == 150); - DLIB_TEST(labels.size() == 150); - DLIB_TEST(max_index_plus_one(samples) == 5); - fix_nonzero_indexing(samples); - DLIB_TEST(max_index_plus_one(samples) == 4); - - load_libsvm_formatted_data("iris.scale2",samples, labels); - - DLIB_TEST(samples.size() == 150); - DLIB_TEST(labels.size() == 150); - - DLIB_TEST(max_index_plus_one(samples) == 5); - fix_nonzero_indexing(samples); - DLIB_TEST(max_index_plus_one(samples) == 4); - - one_vs_one_trainer,scalar_type> trainer; - - typedef sparse_linear_kernel kernel_type; - trainer.set_trainer(krr_trainer()); - - randomize_samples(samples, labels); - matrix cv = cross_validate_multiclass_trainer(trainer, samples, labels, 4); - - dlog << LINFO << "confusion matrix: \n" << cv; - const scalar_type cv_accuracy = sum(diag(cv))/sum(cv); - dlog << LINFO << "cv accuracy: " << cv_accuracy; - DLIB_TEST(cv_accuracy > 0.97); - - - - - { - print_spinner(); - typedef matrix dsample_type; - std::vector dsamples = sparse_to_dense(samples); - DLIB_TEST(dsamples.size() == 150); - DLIB_TEST(dsamples[0].size() == 4); - DLIB_TEST(max_index_plus_one(dsamples) == 4); - - one_vs_one_trainer,scalar_type> trainer; - - typedef linear_kernel kernel_type; - trainer.set_trainer(rr_trainer()); - - cv = cross_validate_multiclass_trainer(trainer, dsamples, labels, 4); - - dlog << LINFO << "dense confusion matrix: \n" << cv; - const scalar_type cv_accuracy = sum(diag(cv))/sum(cv); - dlog << LINFO << "dense cv accuracy: " << cv_accuracy; - DLIB_TEST(cv_accuracy > 0.97); - } - - } - - - void test_sparse_to_dense() - { - { - std::map temp; - - matrix m, m2; - - m = sparse_to_dense(m); - DLIB_TEST(m.size() == 0); - m.set_size(2,1); - m = 1, 2; - m2 = sparse_to_dense(m); - DLIB_TEST(m == m2); - m2 = sparse_to_dense(m,1); - DLIB_TEST(m2.size() == 1); - DLIB_TEST(m2(0,0) == 1); - m2 = sparse_to_dense(m,0); - DLIB_TEST(m2.size() == 0); - - temp[3] = 2; - temp[5] = 4; - m2 = sparse_to_dense(temp); - m.set_size(6); - m = 0,0,0,2,0,4; - DLIB_TEST(m2 == m); - - m2 = sparse_to_dense(temp, 5); - m.set_size(5); - m = 0,0,0,2,0; - DLIB_TEST(m2 == m); - - m2 = sparse_to_dense(temp, 7); - m.set_size(7); - m = 0,0,0,2,0,4,0; - DLIB_TEST(m2 == m); - - std::vector > > vects; - - std::vector > v; - v.push_back(make_pair(5,2)); - v.push_back(make_pair(3,1)); - v.push_back(make_pair(5,2)); - v.push_back(make_pair(3,1)); - v = make_sparse_vector(v); - vects.push_back(v); - vects.push_back(v); - vects.push_back(v); - vects.push_back(v); - DLIB_TEST(max_index_plus_one(v) == 6); - m2 = sparse_to_dense(v); - m.set_size(6); - m = 0,0,0,2,0,4; - DLIB_TEST_MSG(m2 == m, m2 << "\n\n" << m ); - - m2 = sparse_to_dense(v,7); - m.set_size(7); - m = 0,0,0,2,0,4,0; - DLIB_TEST(m2 == m); - - m2 = sparse_to_dense(v,5); - m.set_size(5); - m = 0,0,0,2,0; - DLIB_TEST(m2 == m); - - v.clear(); - m2 = sparse_to_dense(v); - DLIB_TEST(m2.size() == 0); - - - std::vector > mvects = sparse_to_dense(vects); - DLIB_TEST(mvects.size() == 4); - m.set_size(6); - m = 0,0,0,2,0,4; - DLIB_TEST(mvects[0] == m); - DLIB_TEST(mvects[1] == m); - DLIB_TEST(mvects[2] == m); - DLIB_TEST(mvects[3] == m); - - - mvects = sparse_to_dense(vects, 7); - DLIB_TEST(mvects.size() == 4); - m.set_size(7); - m = 0,0,0,2,0,4,0; - DLIB_TEST(mvects[0] == m); - DLIB_TEST(mvects[1] == m); - DLIB_TEST(mvects[2] == m); - DLIB_TEST(mvects[3] == m); - - mvects = sparse_to_dense(vects, 5); - DLIB_TEST(mvects.size() == 4); - m.set_size(5); - m = 0,0,0,2,0; - DLIB_TEST(mvects[0] == m); - DLIB_TEST(mvects[1] == m); - DLIB_TEST(mvects[2] == m); - DLIB_TEST(mvects[3] == m); - - } - } - - - void perform_test ( - ) - { - print_spinner(); - create_iris_datafile(); - - test_sparse_to_dense(); - - run_test >(); - run_test >(); - run_test > >(); - run_test > >(); - } - }; - - test_data_io a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/directed_graph.cpp b/lib/3rdParty/dlib/include/dlib/test/directed_graph.cpp deleted file mode 100644 index bf5a6b53..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/directed_graph.cpp +++ /dev/null @@ -1,541 +0,0 @@ -// Copyright (C) 2007 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -// This is called an unnamed-namespace and it has the effect of making everything inside this file "private" -// so that everything you declare will have static linkage. Thus we won't have any multiply -// defined symbol errors coming out of the linker when we try to compile the test suite. -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - // Declare the logger we will use in this test. The name of the tester - // should start with "test." - logger dlog("test.directed_graph"); - - template < - typename directed_graph - > - void directed_graph_test ( - ) - /*! - requires - - directed_graph is an implementation of directed_graph/directed_graph_kernel_abstract.h - is instantiated with int - ensures - - runs tests on directed_graph for compliance with the specs - !*/ - { - print_spinner(); - - COMPILE_TIME_ASSERT(is_directed_graph::value == true); - directed_graph a, b; - dlib::set::compare_1b_c s; - - DLIB_TEST(graph_contains_directed_cycle(a) == false); - DLIB_TEST(graph_contains_undirected_cycle(a) == false); - - DLIB_TEST(a.number_of_nodes() == 0); - - DLIB_TEST(graph_contains_length_one_cycle(a) == false); - - a.set_number_of_nodes(5); - DLIB_TEST(graph_contains_length_one_cycle(a) == false); - DLIB_TEST(graph_is_connected(a) == false); - DLIB_TEST(graph_contains_directed_cycle(a) == false); - DLIB_TEST(graph_contains_undirected_cycle(a) == false); - DLIB_TEST(a.number_of_nodes() == 5); - - for (int i = 0; i < 5; ++i) - { - a.node(i).data = i; - DLIB_TEST(a.node(i).index() == (unsigned int)i); - } - - a.remove_node(1); - - DLIB_TEST(a.number_of_nodes() == 4); - - - // make sure that only the number with data == 1 was remove - int count = 0; - for (int i = 0; i < 4; ++i) - { - count += a.node(i).data; - DLIB_TEST(a.node(i).number_of_children() == 0); - DLIB_TEST(a.node(i).number_of_parents() == 0); - DLIB_TEST(a.node(i).index() == (unsigned int)i); - } - - DLIB_TEST(count == 9); - - DLIB_TEST(graph_contains_directed_cycle(a) == false); - - a.add_edge(1,1); - DLIB_TEST(graph_contains_length_one_cycle(a) == true); - DLIB_TEST(graph_contains_undirected_cycle(a) == true); - - DLIB_TEST(graph_contains_directed_cycle(a) == true); - - a.add_edge(1,2); - - DLIB_TEST(graph_contains_directed_cycle(a) == true); - - DLIB_TEST(a.node(1).number_of_children() == 2); - DLIB_TEST(a.node(1).number_of_parents() == 1); - DLIB_TEST_MSG(a.node(1).parent(0).index() == 1,"") - - DLIB_TEST_MSG(a.node(1).child(0).index() + a.node(1).child(1).index() == 3,"") - DLIB_TEST(a.node(2).number_of_children() == 0); - DLIB_TEST(a.node(2).number_of_parents() == 1); - DLIB_TEST(a.node(2).index() == 2); - - int val = a.node(1).data; - a.remove_node(1); - DLIB_TEST(graph_contains_length_one_cycle(a) == false); - - DLIB_TEST(graph_contains_directed_cycle(a) == false); - DLIB_TEST(graph_contains_undirected_cycle(a) == false); - - - DLIB_TEST(a.number_of_nodes() == 3); - - count = 0; - for (int i = 0; i < 3; ++i) - { - count += a.node(i).data; - DLIB_TEST(a.node(i).number_of_children() == 0); - DLIB_TEST(a.node(i).number_of_parents() == 0); - DLIB_TEST(a.node(i).index() == (unsigned int)i); - } - DLIB_TEST(count == 9-val); - - - val = a.add_node(); - DLIB_TEST(val == 3); - DLIB_TEST(a.number_of_nodes() == 4); - - for (int i = 0; i < 4; ++i) - { - a.node(i).data = i; - DLIB_TEST(a.node(i).index() == (unsigned int)i); - } - - for (int i = 0; i < 4; ++i) - { - DLIB_TEST(a.node(i).data == i); - DLIB_TEST(a.node(i).index() == (unsigned int)i); - } - - a.add_edge(0, 1); - a.add_edge(0, 2); - DLIB_TEST(graph_is_connected(a) == false); - a.add_edge(1, 3); - DLIB_TEST(graph_is_connected(a) == true); - a.add_edge(2, 3); - DLIB_TEST(graph_is_connected(a) == true); - DLIB_TEST(graph_contains_length_one_cycle(a) == false); - - DLIB_TEST(a.has_edge(0, 1)); - DLIB_TEST(a.has_edge(0, 2)); - DLIB_TEST(a.has_edge(1, 3)); - DLIB_TEST(a.has_edge(2, 3)); - - DLIB_TEST(!a.has_edge(1, 0)); - DLIB_TEST(!a.has_edge(2, 0)); - DLIB_TEST(!a.has_edge(3, 1)); - DLIB_TEST(!a.has_edge(3, 2)); - - DLIB_TEST(a.node(0).number_of_parents() == 0); - DLIB_TEST(a.node(0).number_of_children() == 2); - - DLIB_TEST(a.node(1).number_of_parents() == 1); - DLIB_TEST(a.node(1).number_of_children() == 1); - DLIB_TEST(a.node(1).child(0).index() == 3); - DLIB_TEST(a.node(1).parent(0).index() == 0); - - DLIB_TEST(a.node(2).number_of_parents() == 1); - DLIB_TEST(a.node(2).number_of_children() == 1); - DLIB_TEST(a.node(2).child(0).index() == 3); - DLIB_TEST(a.node(2).parent(0).index() == 0); - - DLIB_TEST(a.node(3).number_of_parents() == 2); - DLIB_TEST(a.node(3).number_of_children() == 0); - - DLIB_TEST(graph_contains_directed_cycle(a) == false); - DLIB_TEST(graph_contains_undirected_cycle(a) == true); - - a.remove_edge(0,1); - - DLIB_TEST(graph_contains_directed_cycle(a) == false); - - DLIB_TEST(!a.has_edge(0, 1)); - DLIB_TEST(a.has_edge(0, 2)); - DLIB_TEST(a.has_edge(1, 3)); - DLIB_TEST(a.has_edge(2, 3)); - - DLIB_TEST(!a.has_edge(1, 0)); - DLIB_TEST(!a.has_edge(2, 0)); - DLIB_TEST(!a.has_edge(3, 1)); - DLIB_TEST(!a.has_edge(3, 2)); - - - DLIB_TEST(a.node(0).number_of_parents() == 0); - DLIB_TEST(a.node(0).number_of_children() == 1); - - DLIB_TEST(a.node(1).number_of_parents() == 0); - DLIB_TEST(a.node(1).number_of_children() == 1); - DLIB_TEST(a.node(1).child(0).index() == 3); - - DLIB_TEST(a.node(2).number_of_parents() == 1); - DLIB_TEST(a.node(2).number_of_children() == 1); - DLIB_TEST(a.node(2).child(0).index() == 3); - DLIB_TEST(a.node(2).parent(0).index() == 0); - - DLIB_TEST(a.node(3).number_of_parents() == 2); - DLIB_TEST(a.node(3).number_of_children() == 0); - - for (int i = 0; i < 4; ++i) - { - DLIB_TEST(a.node(i).data == i); - DLIB_TEST(a.node(i).index() == (unsigned int)i); - } - - - - swap(a,b); - - DLIB_TEST(a.number_of_nodes() == 0); - DLIB_TEST(b.number_of_nodes() == 4); - DLIB_TEST(b.node(0).number_of_parents() == 0); - DLIB_TEST(b.node(0).number_of_children() == 1); - - DLIB_TEST(b.node(1).number_of_parents() == 0); - DLIB_TEST(b.node(1).number_of_children() == 1); - DLIB_TEST(b.node(1).child(0).index() == 3); - - DLIB_TEST(b.node(2).number_of_parents() == 1); - DLIB_TEST(b.node(2).number_of_children() == 1); - DLIB_TEST(b.node(2).child(0).index() == 3); - DLIB_TEST(b.node(2).parent(0).index() == 0); - - DLIB_TEST(b.node(3).number_of_parents() == 2); - DLIB_TEST(b.node(3).number_of_children() == 0); - b.node(0).child_edge(0) = static_cast(b.node(0).child(0).index()+1); - b.node(1).child_edge(0) = static_cast(b.node(1).child(0).index()+1); - b.node(2).child_edge(0) = static_cast(b.node(2).child(0).index()+1); - - DLIB_TEST_MSG(b.node(0).child_edge(0) == b.node(0).child(0).index()+1, - b.node(0).child_edge(0) << " " << b.node(0).child(0).index()+1); - DLIB_TEST_MSG(b.node(1).child_edge(0) == b.node(1).child(0).index()+1, - b.node(1).child_edge(0) << " " << b.node(1).child(0).index()+1); - DLIB_TEST_MSG(b.node(2).child_edge(0) == b.node(2).child(0).index()+1, - b.node(2).child_edge(0) << " " << b.node(2).child(0).index()+1); - - DLIB_TEST_MSG(b.node(2).parent_edge(0) == 2+1, - b.node(2).parent_edge(0) << " " << 2+1); - DLIB_TEST_MSG(b.node(3).parent_edge(0) == 3+1, - b.node(3).parent_edge(0) << " " << 3+1); - DLIB_TEST_MSG(b.node(3).parent_edge(1) == 3+1, - b.node(3).parent_edge(1) << " " << 3+1); - - ostringstream sout; - - serialize(b, sout); - - istringstream sin(sout.str()); - - a.set_number_of_nodes(20); - DLIB_TEST(a.number_of_nodes() == 20); - deserialize(a, sin); - DLIB_TEST(a.number_of_nodes() == 4); - - DLIB_TEST(!a.has_edge(0, 1)); - DLIB_TEST(a.has_edge(0, 2)); - DLIB_TEST(a.has_edge(1, 3)); - DLIB_TEST(a.has_edge(2, 3)); - - DLIB_TEST(!a.has_edge(1, 0)); - DLIB_TEST(!a.has_edge(2, 0)); - DLIB_TEST(!a.has_edge(3, 1)); - DLIB_TEST(!a.has_edge(3, 2)); - - DLIB_TEST_MSG(a.node(0).child_edge(0) == a.node(0).child(0).index()+1, - a.node(0).child_edge(0) << " " << a.node(0).child(0).index()+1); - DLIB_TEST_MSG(a.node(1).child_edge(0) == a.node(1).child(0).index()+1, - a.node(1).child_edge(0) << " " << a.node(1).child(0).index()+1); - DLIB_TEST_MSG(a.node(2).child_edge(0) == a.node(2).child(0).index()+1, - a.node(2).child_edge(0) << " " << a.node(2).child(0).index()+1); - DLIB_TEST_MSG(a.node(2).parent_edge(0) == 2+1, - a.node(2).parent_edge(0) << " " << 2+1); - DLIB_TEST_MSG(a.node(3).parent_edge(0) == 3+1, - a.node(3).parent_edge(0) << " " << 3+1); - DLIB_TEST_MSG(a.node(3).parent_edge(1) == 3+1, - a.node(3).parent_edge(1) << " " << 3+1); - - - - for (int i = 0; i < 4; ++i) - { - DLIB_TEST(a.node(i).data == i); - DLIB_TEST(a.node(i).index() == (unsigned int)i); - } - - - DLIB_TEST(graph_contains_undirected_cycle(a) == false); - - DLIB_TEST(b.number_of_nodes() == 4); - DLIB_TEST(b.node(0).number_of_parents() == 0); - DLIB_TEST(b.node(0).number_of_children() == 1); - - DLIB_TEST(b.node(1).number_of_parents() == 0); - DLIB_TEST(b.node(1).number_of_children() == 1); - DLIB_TEST(b.node(1).child(0).index() == 3); - - DLIB_TEST(b.node(2).number_of_parents() == 1); - DLIB_TEST(b.node(2).number_of_children() == 1); - DLIB_TEST(b.node(2).child(0).index() == 3); - DLIB_TEST(b.node(2).parent(0).index() == 0); - - DLIB_TEST(b.node(3).number_of_parents() == 2); - DLIB_TEST(b.node(3).number_of_children() == 0); - - - DLIB_TEST(a.number_of_nodes() == 4); - DLIB_TEST(a.node(0).number_of_parents() == 0); - DLIB_TEST(a.node(0).number_of_children() == 1); - - DLIB_TEST(a.node(1).number_of_parents() == 0); - DLIB_TEST(a.node(1).number_of_children() == 1); - DLIB_TEST(a.node(1).child(0).index() == 3); - - DLIB_TEST(a.node(2).number_of_parents() == 1); - DLIB_TEST(a.node(2).number_of_children() == 1); - DLIB_TEST(a.node(2).child(0).index() == 3); - DLIB_TEST(a.node(2).parent(0).index() == 0); - - DLIB_TEST(a.node(3).number_of_parents() == 2); - DLIB_TEST(a.node(3).number_of_children() == 0); - - DLIB_TEST(a.number_of_nodes() == 4); - a.clear(); - DLIB_TEST(a.number_of_nodes() == 0); - - - DLIB_TEST(graph_contains_directed_cycle(a) == false); - - a.set_number_of_nodes(10); - - DLIB_TEST(graph_contains_directed_cycle(a) == false); - - a.add_edge(0,1); - a.add_edge(1,2); - a.add_edge(1,3); - a.add_edge(2,4); - a.add_edge(3,4); - a.add_edge(4,5); - a.add_edge(5,1); - - DLIB_TEST(graph_contains_directed_cycle(a) == true); - DLIB_TEST(graph_contains_undirected_cycle(a) == true); - - a.remove_edge(5,1); - - DLIB_TEST(graph_contains_undirected_cycle(a) == true); - DLIB_TEST(graph_contains_directed_cycle(a) == false); - a.add_edge(7,8); - DLIB_TEST(graph_contains_directed_cycle(a) == false); - a.add_edge(8,7); - DLIB_TEST(graph_contains_directed_cycle(a) == true); - DLIB_TEST(graph_contains_undirected_cycle(a) == true); - - - a.clear(); - /* - Make a graph that looks like: - 0 1 - \ / - 2 - | - 3 - */ - a.set_number_of_nodes(4); - a.add_edge(0,2); - a.add_edge(1,2); - a.add_edge(2,3); - for (unsigned long i = 0; i < 4; ++i) - a.node(i).data = i; - - graph::kernel_1a_c g; - create_moral_graph(a,g); - - graph::compare_1b_c, dlib::set::compare_1a_c>::kernel_1a_c join_tree; - dlib::set::compare_1b_c>::kernel_1b_c sos; - - create_join_tree(g, join_tree); - DLIB_TEST(is_join_tree(g, join_tree)); - DLIB_TEST(join_tree.number_of_nodes() == 2); - DLIB_TEST(graph_contains_undirected_cycle(join_tree) == false); - DLIB_TEST(graph_is_connected(join_tree) == true); - - unsigned long temp; - triangulate_graph_and_find_cliques(g,sos); - - temp = 2; s.add(temp); - temp = 3; s.add(temp); - DLIB_TEST(sos.is_member(s)); - s.clear(); - temp = 0; s.add(temp); - temp = 1; s.add(temp); - temp = 2; s.add(temp); - DLIB_TEST(sos.is_member(s)); - DLIB_TEST(sos.size() == 2); - DLIB_TEST(sos.is_member(join_tree.node(0).data)); - DLIB_TEST(sos.is_member(join_tree.node(1).data)); - - - s.clear(); - temp = 0; s.add(temp); - DLIB_TEST(is_clique(g,s) == true); - DLIB_TEST(is_maximal_clique(g,s) == false); - temp = 3; s.add(temp); - DLIB_TEST(is_clique(g,s) == false); - s.destroy(3); - DLIB_TEST(is_clique(g,s) == true); - temp = 2; s.add(temp); - DLIB_TEST(is_clique(g,s) == true); - DLIB_TEST(is_maximal_clique(g,s) == false); - temp = 1; s.add(temp); - DLIB_TEST(is_clique(g,s) == true); - DLIB_TEST(is_maximal_clique(g,s) == true); - s.clear(); - DLIB_TEST(is_clique(g,s) == true); - temp = 3; s.add(temp); - DLIB_TEST(is_clique(g,s) == true); - temp = 2; s.add(temp); - DLIB_TEST(is_clique(g,s) == true); - DLIB_TEST(is_maximal_clique(g,s) == true); - - - DLIB_TEST(a.number_of_nodes() == 4); - DLIB_TEST(g.number_of_nodes() == 4); - for (unsigned long i = 0; i < 4; ++i) - DLIB_TEST( a.node(i).data == (int)i); - DLIB_TEST(g.has_edge(0,1)); - DLIB_TEST(g.has_edge(0,2)); - DLIB_TEST(g.has_edge(1,2)); - DLIB_TEST(g.has_edge(3,2)); - DLIB_TEST(g.has_edge(0,3) == false); - DLIB_TEST(g.has_edge(1,3) == false); - - } - - - void test_copy() - { - { - directed_graph::kernel_1a_c a,b; - - a.set_number_of_nodes(3); - a.node(0).data = 1; - a.node(1).data = 2; - a.node(2).data = 3; - a.add_edge(0,1); - a.add_edge(1,0); - a.add_edge(0,2); - edge(a,0,1) = 4; - edge(a,1,0) = 3; - edge(a,0,2) = 5; - - a.add_edge(0,0); - edge(a,0,0) = 9; - copy_graph(a, b); - - DLIB_TEST(b.number_of_nodes() == 3); - DLIB_TEST(b.node(0).data == 1); - DLIB_TEST(b.node(1).data == 2); - DLIB_TEST(b.node(2).data == 3); - DLIB_TEST(edge(b,0,1) == 4); - DLIB_TEST(edge(b,1,0) == 3); - DLIB_TEST(edge(b,0,2) == 5); - DLIB_TEST(edge(b,0,0) == 9); - } - { - directed_graph::kernel_1a_c a,b; - - a.set_number_of_nodes(4); - a.node(0).data = 1; - a.node(1).data = 2; - a.node(2).data = 3; - a.node(3).data = 8; - a.add_edge(0,1); - a.add_edge(0,2); - a.add_edge(2,3); - a.add_edge(3,2); - edge(a,0,1) = 4; - edge(a,0,2) = 5; - edge(a,2,3) = 6; - edge(a,3,2) = 3; - - copy_graph(a, b); - - DLIB_TEST(b.number_of_nodes() == 4); - DLIB_TEST(b.node(0).data == 1); - DLIB_TEST(b.node(1).data == 2); - DLIB_TEST(b.node(2).data == 3); - DLIB_TEST(b.node(3).data == 8); - DLIB_TEST(edge(b,0,1) == 4); - DLIB_TEST(edge(b,0,2) == 5); - DLIB_TEST(edge(b,2,3) == 6); - DLIB_TEST(edge(b,3,2) == 3); - } - } - - - - class directed_graph_tester : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a test for the directed_graph object. When it is constructed - it adds itself into the testing framework. The command line switch is - specified as test_directed_graph by passing that string to the tester constructor. - !*/ - public: - directed_graph_tester ( - ) : - tester ("test_directed_graph", - "Runs tests on the directed_graph component.") - {} - - void perform_test ( - ) - { - test_copy(); - - dlog << LINFO << "testing kernel_1a_c"; - directed_graph_test::kernel_1a_c>(); - - dlog << LINFO << "testing kernel_1a"; - directed_graph_test::kernel_1a>(); - } - } a; - - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/discriminant_pca.cpp b/lib/3rdParty/dlib/include/dlib/test/discriminant_pca.cpp deleted file mode 100644 index a28e5d69..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/discriminant_pca.cpp +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright (C) 2009 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "tester.h" -#include -#include -#include -#include -#include -#include - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - dlib::logger dlog("test.discriminant_pca"); - - using dlib::equal; - - class discriminant_pca_tester : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a unit test. When it is constructed - it adds itself into the testing framework. - !*/ - public: - discriminant_pca_tester ( - ) : - tester ( - "test_discriminant_pca", // the command line argument name for this test - "Run tests on the discriminant_pca object.", // the command line argument description - 0 // the number of command line arguments for this test - ) - { - thetime = time(0); - } - - time_t thetime; - dlib::rand rnd; - - template - void test1() - { - - dpca_type dpca, dpca2, dpca3; - - DLIB_TEST(dpca.in_vector_size() == 0); - DLIB_TEST(dpca.between_class_weight() == 1); - DLIB_TEST(dpca.within_class_weight() == 1); - - // generate a bunch of 4 dimensional vectors and compute the normal PCA transformation matrix - // and just make sure it is a unitary matrix as it should be. - for (int i = 0; i < 5000; ++i) - { - dpca.add_to_total_variance(randm(4,1,rnd)); - DLIB_TEST(dpca.in_vector_size() == 4); - } - - - matrix mat = dpca.dpca_matrix(1); - - DLIB_TEST(equal(mat*trans(mat), identity_matrix(4))); - - mat = dpca.dpca_matrix(0.9); - DLIB_TEST(equal(mat*trans(mat), identity_matrix(mat.nr()))); - - matrix eig; - dpca.dpca_matrix(mat, eig, 1); - DLIB_TEST(equal(mat*trans(mat), identity_matrix(4))); - // check that all eigen values are grater than 0 - DLIB_TEST(min(eig > 0) == 1); - DLIB_TEST(eig.size() == mat.nr()); - DLIB_TEST(is_col_vector(eig)); - // check that the eigenvalues are sorted - double last = eig(0); - for (long i = 1; i < eig.size(); ++i) - { - DLIB_TEST(last >= eig(i)); - } - - { - matrix mat = dpca.dpca_matrix_of_size(4); - DLIB_TEST(equal(mat*trans(mat), identity_matrix(4))); - } - { - matrix mat = dpca.dpca_matrix_of_size(3); - DLIB_TEST(equal(mat*trans(mat), identity_matrix(3))); - } - - - dpca.set_within_class_weight(5); - dpca.set_between_class_weight(6); - - DLIB_TEST(dpca.in_vector_size() == 4); - DLIB_TEST(dpca.within_class_weight() == 5); - DLIB_TEST(dpca.between_class_weight() == 6); - - - ostringstream sout; - serialize(dpca, sout); - istringstream sin(sout.str()); - deserialize(dpca2, sin); - - // now make sure the serialization worked - DLIB_TEST(dpca.in_vector_size() == 4); - DLIB_TEST(dpca.within_class_weight() == 5); - DLIB_TEST(dpca.between_class_weight() == 6); - DLIB_TEST(dpca2.in_vector_size() == 4); - DLIB_TEST(dpca2.within_class_weight() == 5); - DLIB_TEST(dpca2.between_class_weight() == 6); - DLIB_TEST(equal(dpca.dpca_matrix(), dpca2.dpca_matrix(), 1e-10)); - DLIB_TEST(equal(mat, dpca2.dpca_matrix(1), 1e-10)); - DLIB_TEST(equal(dpca.dpca_matrix(1), mat, 1e-10)); - - // now test swap - dpca2.swap(dpca3); - DLIB_TEST(dpca2.in_vector_size() == 0); - DLIB_TEST(dpca2.between_class_weight() == 1); - DLIB_TEST(dpca2.within_class_weight() == 1); - - DLIB_TEST(dpca3.in_vector_size() == 4); - DLIB_TEST(dpca3.within_class_weight() == 5); - DLIB_TEST(dpca3.between_class_weight() == 6); - DLIB_TEST(equal(mat, dpca3.dpca_matrix(1), 1e-10)); - DLIB_TEST((dpca3 + dpca3).in_vector_size() == 4); - DLIB_TEST((dpca3 + dpca3).within_class_weight() == 5); - DLIB_TEST((dpca3 + dpca3).between_class_weight() == 6); - - dpca.clear(); - - DLIB_TEST(dpca.in_vector_size() == 0); - DLIB_TEST(dpca.between_class_weight() == 1); - DLIB_TEST(dpca.within_class_weight() == 1); - } - - template - void test2() - { - dpca_type dpca, dpca2, dpca3; - - typename dpca_type::column_matrix samp1(4), samp2(4); - - for (int i = 0; i < 5000; ++i) - { - dpca.add_to_total_variance(randm(4,1,rnd)); - DLIB_TEST(dpca.in_vector_size() == 4); - - // do this to subtract out the variance along the 3rd axis - samp1 = 0,0,0,0; - samp2 = 0,0,1,0; - dpca.add_to_within_class_variance(samp1, samp2); - } - - matrix mat; - - dpca.set_within_class_weight(0); - mat = dpca.dpca_matrix(1); - DLIB_TEST(equal(mat*trans(mat), identity_matrix(4))); - DLIB_TEST(dpca.dpca_matrix(1).nr() == 4); - dpca.set_within_class_weight(1000); - DLIB_TEST(dpca.dpca_matrix(1).nr() == 3); - - // the 3rd column of the transformation matrix should be all zero since - // we killed all the variation long the 3rd axis - DLIB_TEST(sum(abs(colm(dpca.dpca_matrix(1),2))) < 1e-5); - - mat = dpca.dpca_matrix(1); - DLIB_TEST(equal(mat*trans(mat), identity_matrix(3))); - - - } - - template - void test3() - { - dpca_type dpca, dpca2, dpca3; - - typename dpca_type::column_matrix samp1(4), samp2(4); - - for (int i = 0; i < 5000; ++i) - { - dpca.add_to_total_variance(randm(4,1,rnd)); - DLIB_TEST(dpca.in_vector_size() == 4); - - // do this to subtract out the variance along the 3rd axis - samp1 = 0,0,0,0; - samp2 = 0,0,1,0; - dpca.add_to_within_class_variance(samp1, samp2); - - // do this to subtract out the variance along the 1st axis - samp1 = 0,0,0,0; - samp2 = 1,0,0,0; - dpca.add_to_within_class_variance(samp1, samp2); - } - - matrix mat; - - dpca.set_within_class_weight(0); - mat = dpca.dpca_matrix(1); - DLIB_TEST(equal(mat*trans(mat), identity_matrix(4))); - DLIB_TEST(dpca.dpca_matrix(1).nr() == 4); - dpca.set_within_class_weight(10000); - DLIB_TEST(dpca.dpca_matrix(1).nr() == 2); - - // the 1st and 3rd columns of the transformation matrix should be all zero since - // we killed all the variation long the 1st and 3rd axes - DLIB_TEST(sum(abs(colm(dpca.dpca_matrix(1),2))) < 1e-5); - DLIB_TEST(sum(abs(colm(dpca.dpca_matrix(1),0))) < 1e-5); - - mat = dpca.dpca_matrix(1); - DLIB_TEST(equal(mat*trans(mat), identity_matrix(2))); - - - } - - template - void test4() - { - dpca_type dpca, dpca2, dpca3; - - dpca_type add_dpca1, add_dpca2, add_dpca3, add_dpca4, sum_dpca; - - typename dpca_type::column_matrix samp1(4), samp2(4), samp; - - for (int i = 0; i < 5000; ++i) - { - samp = randm(4,1,rnd); - dpca.add_to_total_variance(samp); - add_dpca4.add_to_total_variance(samp); - DLIB_TEST(dpca.in_vector_size() == 4); - - // do this to subtract out the variance along the 3rd axis - samp1 = 0,0,0,0; - samp2 = 0,0,1,0; - dpca.add_to_within_class_variance(samp1, samp2); - add_dpca1.add_to_within_class_variance(samp1, samp2); - - // do this to subtract out the variance along the 1st axis - samp1 = 0,0,0,0; - samp2 = 1,0,0,0; - dpca.add_to_within_class_variance(samp1, samp2); - add_dpca2.add_to_within_class_variance(samp1, samp2); - - // do this to add the variance along the 3rd axis back in - samp1 = 0,0,0,0; - samp2 = 0,0,1,0; - dpca.add_to_between_class_variance(samp1, samp2); - add_dpca3.add_to_between_class_variance(samp1, samp2); - } - - matrix mat, mat2; - - sum_dpca += dpca_type() + dpca_type() + add_dpca1 + dpca_type() + add_dpca2 + add_dpca3 + add_dpca4; - dpca.set_within_class_weight(0); - dpca.set_between_class_weight(0); - sum_dpca.set_within_class_weight(0); - sum_dpca.set_between_class_weight(0); - mat = dpca.dpca_matrix(1); - DLIB_TEST(equal(mat, sum_dpca.dpca_matrix(1), 1e-10)); - DLIB_TEST(equal(mat*trans(mat), identity_matrix(4))); - DLIB_TEST(dpca.dpca_matrix(1).nr() == 4); - dpca.set_within_class_weight(10000); - sum_dpca.set_within_class_weight(10000); - DLIB_TEST(dpca.dpca_matrix(1).nr() == 2); - - // the 1st and 3rd columns of the transformation matrix should be all zero since - // we killed all the variation long the 1st and 3rd axes - DLIB_TEST(sum(abs(colm(dpca.dpca_matrix(1),2))) < 1e-4); - DLIB_TEST(sum(abs(colm(dpca.dpca_matrix(1),0))) < 1e-4); - - mat = dpca.dpca_matrix(1); - DLIB_TEST(equal(mat*trans(mat), identity_matrix(2))); - DLIB_TEST_MSG(equal(mat, mat2=sum_dpca.dpca_matrix(1), 1e-9), max(abs(mat - mat2))); - - - // now add the variance back in using the between class weight - dpca.set_within_class_weight(0); - dpca.set_between_class_weight(1); - mat = dpca.dpca_matrix(1); - DLIB_TEST(equal(mat*trans(mat), identity_matrix(4))); - DLIB_TEST(dpca.dpca_matrix(1).nr() == 4); - dpca.set_within_class_weight (10000); - dpca.set_between_class_weight(100000); - sum_dpca.set_within_class_weight (10000); - sum_dpca.set_between_class_weight(100000); - DLIB_TEST(dpca.dpca_matrix(1).nr() == 3); - - // the first column should be all zeros - DLIB_TEST(sum(abs(colm(dpca.dpca_matrix(1),0))) < 1e-5); - - mat = dpca.dpca_matrix(1); - DLIB_TEST(equal(mat*trans(mat), identity_matrix(3))); - DLIB_TEST(equal(mat, sum_dpca.dpca_matrix(1))); - - - } - - template - void test5() - { - dpca_type dpca, dpca2; - typename dpca_type::column_matrix samp1(4), samp2(4); - - samp1 = 0,0,0,0; - samp2 = 0,0,1,0; - - for (int i = 0; i < 5000; ++i) - { - dpca.add_to_between_class_variance(samp1, samp2); - dpca2.add_to_total_variance(samp1); - dpca2.add_to_total_variance(samp2); - } - - matrix mat, eig; - dpca.dpca_matrix(mat, eig, 1); - - // make sure the eigenvalues come out the way they should for this simple data set - DLIB_TEST(eig.size() == 1); - DLIB_TEST_MSG(abs(eig(0) - 1) < 1e-10, abs(eig(0) - 1)); - - dpca2.dpca_matrix(mat, eig, 1); - - // make sure the eigenvalues come out the way they should for this simple data set - DLIB_TEST(eig.size() == 1); - DLIB_TEST(abs(eig(0) - 0.25) < 1e-10); - - } - - void perform_test ( - ) - { - ++thetime; - typedef matrix sample_type; - typedef discriminant_pca dpca_type; - - dlog << LINFO << "time seed: " << thetime; - rnd.set_seed(cast_to_string(thetime)); - - test5(); - - for (int i = 0; i < 10; ++i) - { - print_spinner(); - test1(); - print_spinner(); - test2(); - print_spinner(); - test3(); - print_spinner(); - test4(); - } - } - }; - - // Create an instance of this object. Doing this causes this test - // to be automatically inserted into the testing framework whenever this cpp file - // is linked into the project. Note that since we are inside an unnamed-namespace - // we won't get any linker errors about the symbol a being defined multiple times. - discriminant_pca_tester a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/disjoint_subsets.cpp b/lib/3rdParty/dlib/include/dlib/test/disjoint_subsets.cpp deleted file mode 100644 index da265849..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/disjoint_subsets.cpp +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.disjoint_subsets"); - - void test_disjoint_subset() - { - print_spinner(); - disjoint_subsets s; - - DLIB_TEST(s.size() == 0); - - s.set_size(5); - DLIB_TEST(s.size() == 5); - - DLIB_TEST(s.find_set(0) == 0); - DLIB_TEST(s.find_set(1) == 1); - DLIB_TEST(s.find_set(2) == 2); - DLIB_TEST(s.find_set(3) == 3); - DLIB_TEST(s.find_set(4) == 4); - - - unsigned long id = s.merge_sets(1,3); - DLIB_TEST(s.find_set(0) == 0); - DLIB_TEST(s.find_set(1) == id); - DLIB_TEST(s.find_set(2) == 2); - DLIB_TEST(s.find_set(3) == id); - DLIB_TEST(s.find_set(4) == 4); - - id = s.merge_sets(s.find_set(1),4); - DLIB_TEST(s.find_set(0) == 0); - DLIB_TEST(s.find_set(1) == id); - DLIB_TEST(s.find_set(2) == 2); - DLIB_TEST(s.find_set(3) == id); - DLIB_TEST(s.find_set(4) == id); - - unsigned long id2 = s.merge_sets(0,2); - DLIB_TEST(s.find_set(0) == id2); - DLIB_TEST(s.find_set(1) == id); - DLIB_TEST(s.find_set(2) == id2); - DLIB_TEST(s.find_set(3) == id); - DLIB_TEST(s.find_set(4) == id); - - id = s.merge_sets(s.find_set(1),s.find_set(0)); - DLIB_TEST(s.find_set(0) == id); - DLIB_TEST(s.find_set(1) == id); - DLIB_TEST(s.find_set(2) == id); - DLIB_TEST(s.find_set(3) == id); - DLIB_TEST(s.find_set(4) == id); - - DLIB_TEST(s.size() == 5); - s.set_size(1); - DLIB_TEST(s.size() == 1); - DLIB_TEST(s.find_set(0) == 0); - s.set_size(2); - DLIB_TEST(s.size() == 2); - DLIB_TEST(s.find_set(0) == 0); - DLIB_TEST(s.find_set(1) == 1); - id = s.merge_sets(0,1); - DLIB_TEST(s.size() == 2); - DLIB_TEST(id == s.find_set(0)); - DLIB_TEST(id == s.find_set(1)); - DLIB_TEST(s.size() == 2); - s.clear(); - DLIB_TEST(s.size() == 0); - - } - - - class tester_disjoint_subsets : public tester - { - public: - tester_disjoint_subsets ( - ) : - tester ("test_disjoint_subsets", - "Runs tests on the disjoint_subsets component.") - {} - - void perform_test ( - ) - { - test_disjoint_subset(); - } - } a; - - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/ekm_and_lisf.cpp b/lib/3rdParty/dlib/include/dlib/test/ekm_and_lisf.cpp deleted file mode 100644 index b6f41017..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/ekm_and_lisf.cpp +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright (C) 2009 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "tester.h" -#include -#include -#include -#include -#include -#include - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - dlib::logger dlog("test.ekm_and_lisf"); - - - class empirical_kernel_map_tester : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a unit test. When it is constructed - it adds itself into the testing framework. - !*/ - public: - empirical_kernel_map_tester ( - ) : - tester ( - "test_ekm_and_lisf", // the command line argument name for this test - "Run tests on the empirical_kernel_map and linearly_independent_subset_finder objects.", // the command line argument description - 0 // the number of command line arguments for this test - ) - { - thetime = time(0); - } - - time_t thetime; - dlib::rand rnd; - - template - void validate ( - const T& ekm_small, - const T& ekm_big - ) - { - matrix tmat; - projection_function proj; - - ekm_small.get_transformation_to(ekm_big, tmat, proj); - DLIB_TEST(tmat.nr() == ekm_big.out_vector_size()); - DLIB_TEST(tmat.nc() == ekm_small.out_vector_size()); - DLIB_TEST((unsigned long)proj.basis_vectors.size() == ekm_big.basis_size() - ekm_small.basis_size()); - for (unsigned long i = 0; i < 6; ++i) - { - const typename T::sample_type temp = randm(4,1,rnd); - DLIB_TEST(length(ekm_big.project(temp) - (tmat*ekm_small.project(temp) + proj(temp))) < 1e-10); - } - } - - - void test_transformation_stuff() - { - typedef matrix sample_type; - typedef radial_basis_kernel kernel_type; - const kernel_type kern(1); - - - for (unsigned long n = 1; n < 6; ++n) - { - print_spinner(); - for (unsigned long extra = 1; extra < 10; ++extra) - { - std::vector samps_small, samps_big; - linearly_independent_subset_finder lisf_small(kern, 1000); - linearly_independent_subset_finder lisf_big(kern, 1000); - for (unsigned long i = 0; i < n; ++i) - { - samps_small.push_back(randm(4,1,rnd)); - samps_big.push_back(samps_small.back()); - lisf_big.add(samps_small.back()); - lisf_small.add(samps_small.back()); - } - for (unsigned long i = 0; i < extra; ++i) - { - samps_big.push_back(randm(4,1,rnd)); - lisf_big.add(samps_big.back()); - } - - - // test no lisf - { - empirical_kernel_map ekm_small, ekm_big; - ekm_small.load(kern, samps_small); - ekm_big.load(kern, samps_big); - - validate(ekm_small, ekm_big); - } - - // test with lisf - { - empirical_kernel_map ekm_small, ekm_big; - ekm_small.load(lisf_small); - ekm_big.load(lisf_big); - - validate(ekm_small, ekm_big); - } - - // test with partly lisf - { - empirical_kernel_map ekm_small, ekm_big; - ekm_small.load(kern, samps_small); - ekm_big.load(lisf_big); - - validate(ekm_small, ekm_big); - } - - // test with partly lisf - { - empirical_kernel_map ekm_small, ekm_big; - ekm_small.load(lisf_small); - ekm_big.load(kern, samps_big); - - validate(ekm_small, ekm_big); - } - - } - } - - - // test what happens if the bigger ekm only has repeated basis vectors - { - empirical_kernel_map ekm_big, ekm_small; - std::vector samps_big, samps_small; - - sample_type temp = randm(4,1,rnd); - - samps_small.push_back(temp); - samps_big.push_back(temp); - samps_big.push_back(temp); - - ekm_big.load(kern, samps_big); - ekm_small.load(kern, samps_small); - - validate(ekm_small, ekm_big); - - } - { - empirical_kernel_map ekm_big, ekm_small; - linearly_independent_subset_finder lisf_small(kern, 1000); - std::vector samps_big; - - sample_type temp = randm(4,1,rnd); - - lisf_small.add(temp); - samps_big.push_back(temp); - samps_big.push_back(temp); - - ekm_big.load(kern, samps_big); - ekm_small.load(lisf_small); - - validate(ekm_small, ekm_big); - - } - { - empirical_kernel_map ekm_big, ekm_small; - std::vector samps_big, samps_small; - - sample_type temp = randm(4,1,rnd); - sample_type temp2 = randm(4,1,rnd); - - samps_small.push_back(temp); - samps_small.push_back(temp2); - samps_big.push_back(temp); - samps_big.push_back(temp2); - samps_big.push_back(randm(4,1,rnd)); - - ekm_big.load(kern, samps_big); - ekm_small.load(kern, samps_small); - - validate(ekm_small, ekm_big); - - } - { - empirical_kernel_map ekm_big, ekm_small; - linearly_independent_subset_finder lisf_small(kern, 1000); - std::vector samps_big; - - sample_type temp = randm(4,1,rnd); - sample_type temp2 = randm(4,1,rnd); - - lisf_small.add(temp); - lisf_small.add(temp2); - samps_big.push_back(temp); - samps_big.push_back(temp2); - samps_big.push_back(temp); - - ekm_big.load(kern, samps_big); - ekm_small.load(lisf_small); - - validate(ekm_small, ekm_big); - - } - - - } - - - - void perform_test ( - ) - { - ++thetime; - typedef matrix sample_type; - //dlog << LINFO << "time seed: " << thetime; - //rnd.set_seed(cast_to_string(thetime)); - - - typedef radial_basis_kernel kernel_type; - - - for (int n = 1; n < 10; ++n) - { - print_spinner(); - dlog << LINFO << "matrix size " << n; - - std::vector samples; - // make some samples - for (int i = 0; i < n; ++i) - { - samples.push_back(randm(4,1,rnd)); - // double up the samples just to mess with the lisf - if (n > 5) - samples.push_back(samples.back()); - } - - dlog << LINFO << "samples.size(): "<< samples.size(); - - const kernel_type kern(1); - - linearly_independent_subset_finder lisf(kern, 100, 1e-4); - unsigned long count = 0; - for (unsigned long i = 0; i < samples.size(); ++i) - { - if (lisf.add(samples[i])) - { - DLIB_TEST(equal(lisf[lisf.size()-1], samples[i])); - ++count; - } - } - DLIB_TEST(count == lisf.size()); - - DLIB_TEST(lisf.size() == (unsigned int)n); - - - dlog << LINFO << "lisf.size(): "<< lisf.size(); - - // make sure the kernel matrices coming out of the lisf are correct - DLIB_TEST(dlib::equal(lisf.get_kernel_matrix(), kernel_matrix(kern, lisf), 1e-8)); - DLIB_TEST(dlib::equal(lisf.get_inv_kernel_marix(), inv(kernel_matrix(kern, lisf.get_dictionary())), 1e-8)); - - empirical_kernel_map ekm; - ekm.load(lisf); - DLIB_TEST(ekm.basis_size() == lisf.size()); - - std::vector proj_samples; - for (unsigned long i = 0; i < samples.size(); ++i) - { - double err; - proj_samples.push_back(ekm.project(samples[i], err)); - DLIB_TEST(err <= 1e-4); - const double error_agreement = std::abs(err - lisf.projection_error(samples[i])); - dlog << LTRACE << "err: " << err << " error_agreement: "<< error_agreement; - DLIB_TEST(error_agreement < 1e-11); - } - - for (int i = 0; i < 5; ++i) - { - sample_type temp = randm(4,1,rnd); - double err; - ekm.project(temp, err); - const double error_agreement = std::abs(err - lisf.projection_error(temp)); - dlog << LTRACE << "err: " << err << " error_agreement: "<< error_agreement; - DLIB_TEST(error_agreement < 1e-11); - } - - // make sure the EKM did the projection correctly - DLIB_TEST(dlib::equal(kernel_matrix(kern, samples), kernel_matrix(linear_kernel(), proj_samples), 1e-5)); - } - - - test_transformation_stuff(); - - } - }; - - // Create an instance of this object. Doing this causes this test - // to be automatically inserted into the testing framework whenever this cpp file - // is linked into the project. Note that since we are inside an unnamed-namespace - // we won't get any linker errors about the symbol a being defined multiple times. - empirical_kernel_map_tester a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/empirical_kernel_map.cpp b/lib/3rdParty/dlib/include/dlib/test/empirical_kernel_map.cpp deleted file mode 100644 index 95b085ab..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/empirical_kernel_map.cpp +++ /dev/null @@ -1,444 +0,0 @@ -// Copyright (C) 2009 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "tester.h" -#include -#include -#include -#include -#include -#include - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - dlib::logger dlog("test.empirical_kernel_map"); - - - class empirical_kernel_map_tester : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a unit test. When it is constructed - it adds itself into the testing framework. - !*/ - public: - empirical_kernel_map_tester ( - ) : - tester ( - "test_empirical_kernel_map", // the command line argument name for this test - "Run tests on the empirical_kernel_map object.", // the command line argument description - 0 // the number of command line arguments for this test - ) - { - // always use the same time so that tests are repeatable - thetime = 0;//time(0); - } - - time_t thetime; - dlib::rand rnd; - - void test_projection_error() - { - for (int runs = 0; runs < 10; ++runs) - { - print_spinner(); - typedef matrix sample_type; - typedef radial_basis_kernel kernel_type; - const kernel_type kern(0.2); - - empirical_kernel_map ekm; - - // generate samples - const int num = rnd.get_random_8bit_number()%50 + 1; - std::vector samples; - for (int i = 0; i < num; ++i) - { - samples.push_back(randm(5,1,rnd)); - } - - - ekm.load(kern, samples); - DLIB_TEST(ekm.basis_size() == samples.size()); - - double err; - - // the samples in the basis should have zero projection error - for (unsigned long i = 0; i < samples.size(); ++i) - { - ekm.project(samples[i], err); - DLIB_TEST_MSG(abs(err) < 1e-13, abs(err)); - - } - - // Do some sanity tests on the conversion to distance functions while we are at it. - for (int i = 0; i < 30; ++i) - { - // pick two random samples - const sample_type samp1 = samples[rnd.get_random_32bit_number()%samples.size()]; - const sample_type samp2 = samples[rnd.get_random_32bit_number()%samples.size()]; - - const matrix proj1 = ekm.project(samp1); - const matrix proj2 = ekm.project(samp2); - - distance_function df1 = ekm.convert_to_distance_function(proj1); - distance_function df2 = ekm.convert_to_distance_function(proj2); - - DLIB_TEST(df1.get_kernel() == kern); - DLIB_TEST(df2.get_kernel() == kern); - - // make sure the norms are correct - DLIB_TEST(std::abs(df1.get_squared_norm() - - trans(df1.get_alpha())*kernel_matrix(df1.get_kernel(),df1.get_basis_vectors())*df1.get_alpha()) < 1e-10); - DLIB_TEST(std::abs(df2.get_squared_norm() - - trans(df2.get_alpha())*kernel_matrix(df2.get_kernel(),df2.get_basis_vectors())*df2.get_alpha()) < 1e-10); - - - const double true_dist = std::sqrt(kern(samp1,samp1) + kern(samp2,samp2) - 2*kern(samp1,samp2)); - DLIB_TEST_MSG(abs(df1(df2) - true_dist) < 1e-7, abs(df1(df2) - true_dist)); - DLIB_TEST_MSG(abs(length(proj1-proj2) - true_dist) < 1e-7, abs(length(proj1-proj2) - true_dist)); - - - // test distance function operators - const decision_function dec1 = ekm.convert_to_decision_function(proj1); - const decision_function dec2 = ekm.convert_to_decision_function(proj2); - DLIB_TEST(dec1.kernel_function == kern); - DLIB_TEST(dec2.kernel_function == kern); - - distance_function temp; - temp = dec1; - DLIB_TEST(std::abs(temp.get_squared_norm() - df1.get_squared_norm()) < 1e-10); - temp = dec2; - DLIB_TEST(std::abs(temp.get_squared_norm() - df2.get_squared_norm()) < 1e-10); - temp = distance_function(dec1.alpha, dec1.kernel_function, dec1.basis_vectors); - DLIB_TEST(std::abs(temp.get_squared_norm() - df1.get_squared_norm()) < 1e-10); - - df1 = dec1; - - temp = df1 + df2; - decision_function dec3(temp.get_alpha(), 0, temp.get_kernel(), temp.get_basis_vectors()); - DLIB_TEST(std::abs(temp.get_squared_norm() - - trans(temp.get_alpha())*kernel_matrix(temp.get_kernel(),temp.get_basis_vectors())*temp.get_alpha()) < 1e-10); - for (unsigned long j = 0; j < samples.size(); ++j) - { - DLIB_TEST(std::abs(dec3(samples[j]) - (dec1(samples[j]) + dec2(samples[j]))) < 1e-10); - } - - - temp = df1 - df2; - dec3 = decision_function(temp.get_alpha(), 0, temp.get_kernel(), temp.get_basis_vectors()); - DLIB_TEST(std::abs(temp.get_squared_norm() - - trans(temp.get_alpha())*kernel_matrix(temp.get_kernel(),temp.get_basis_vectors())*temp.get_alpha()) < 1e-10); - for (unsigned long j = 0; j < samples.size(); ++j) - { - DLIB_TEST(std::abs(dec3(samples[j]) - (dec1(samples[j]) - dec2(samples[j]))) < 1e-10); - } - - temp = 3*(df1 - df2)*2; - dec3 = decision_function(temp.get_alpha(), 0, temp.get_kernel(), temp.get_basis_vectors()); - DLIB_TEST(std::abs(temp.get_squared_norm() - - trans(temp.get_alpha())*kernel_matrix(temp.get_kernel(),temp.get_basis_vectors())*temp.get_alpha()) < 1e-10); - for (unsigned long j = 0; j < samples.size(); ++j) - { - DLIB_TEST(std::abs(dec3(samples[j]) - 6*(dec1(samples[j]) - dec2(samples[j]))) < 1e-10); - } - - distance_function df_empty(kern); - - temp = df_empty + (df1 + df2)/2 + df_empty - df_empty + (df_empty + df_empty) - (df_empty - df_empty); - dec3 = decision_function(temp.get_alpha(), 0, temp.get_kernel(), temp.get_basis_vectors()); - DLIB_TEST(std::abs(temp.get_squared_norm() - - trans(temp.get_alpha())*kernel_matrix(temp.get_kernel(),temp.get_basis_vectors())*temp.get_alpha()) < 1e-10); - for (unsigned long j = 0; j < samples.size(); ++j) - { - DLIB_TEST(std::abs(dec3(samples[j]) - 0.5*(dec1(samples[j]) + dec2(samples[j]))) < 1e-10); - } - } - // Do some sanity tests on the conversion to distance functions while we are at it. This - // time multiply one of the projections by 30 and see that it still all works out right. - for (int i = 0; i < 30; ++i) - { - // pick two random samples - const sample_type samp1 = samples[rnd.get_random_32bit_number()%samples.size()]; - const sample_type samp2 = samples[rnd.get_random_32bit_number()%samples.size()]; - - matrix proj1 = ekm.project(samp1); - matrix proj2 = 30*ekm.project(samp2); - - distance_function df1 = ekm.convert_to_distance_function(proj1); - distance_function df2 = ekm.convert_to_distance_function(proj2); - - DLIB_TEST_MSG(abs(length(proj1-proj2) - df1(df2)) < 1e-7, abs(length(proj1-proj2) - df1(df2))); - } - - - // now generate points with projection error - for (double i = 1; i < 10; ++i) - { - sample_type test_point = i*randm(5,1,rnd); - ekm.project(test_point, err); - // turn into normal distance rather than squared distance - err = sqrt(err); - dlog << LTRACE << "projection error: " << err; - - distance_function df = ekm.convert_to_distance_function(ekm.project(test_point)); - - // the projection error should be the distance between the test_point and the point it gets - // projected onto - DLIB_TEST_MSG(abs(df(test_point) - err) < 1e-10, abs(df(test_point) - err)); - // while we are at it make sure the squared norm in the distance function is right - double df_error = abs(df.get_squared_norm() - trans(df.get_alpha())*kernel_matrix(kern, samples)*df.get_alpha()); - DLIB_TEST_MSG( df_error < 1e-10, df_error); - } - - - - } - } - - template - void test_with_kernel(const kernel_type& kern) - { - typedef typename kernel_type::sample_type sample_type; - - empirical_kernel_map ekm, ekm2, ekm3; - - for (int j = 0; j < 10; ++j) - { - sample_type samp; - std::vector samples; - std::vector proj_samples; - print_spinner(); - const int num = rnd.get_random_8bit_number()%200 + 1; - // make some random samples - for (int i = 0; i < num; ++i) - { - samples.push_back(randm(4,1,rnd)); - } - // add on a little bit to make sure there is at least one non-zero sample. If all the - // samples are zero then empirical_kernel_map_error will be thrown and we don't want that. - samples.front()(0) += 0.001; - - ekm2.load(kern, samples); - DLIB_TEST(ekm2.basis_size() == samples.size()); - for (unsigned long i = 0; i < samples.size(); ++i) - DLIB_TEST(dlib::equal(ekm2[i] , samples[i])); - - // test serialization - ostringstream sout; - serialize(ekm2, sout); - ekm2.clear(); - istringstream sin(sout.str()); - deserialize(ekm3, sin); - // also test swap - ekm3.swap(ekm); - DLIB_TEST(ekm.get_kernel() == kern); - DLIB_TEST(ekm.out_vector_size() != 0); - DLIB_TEST(ekm2.out_vector_size() == 0); - DLIB_TEST(ekm3.out_vector_size() == 0); - - - - // project all the samples into kernel space - for (unsigned long i = 0; i < samples.size(); ++i) - { - proj_samples.push_back(ekm.project(samples[i])); - } - - DLIB_TEST(max(abs(kernel_matrix(kern, samples) - kernel_matrix(linear_kernel(), proj_samples))) < 1e-12); - DLIB_TEST(ekm.out_vector_size() == proj_samples[0].size()); - - for (int i = 0; i < 30; ++i) - { - const unsigned long idx1 = rnd.get_random_32bit_number()%samples.size(); - const unsigned long idx2 = rnd.get_random_32bit_number()%samples.size(); - decision_function dec_funct = ekm.convert_to_decision_function(proj_samples[idx1]); - distance_function dist_funct = ekm.convert_to_distance_function(proj_samples[idx1]); - - // make sure the distances match - const double dist_error = abs(length(proj_samples[idx1] - proj_samples[idx2]) - dist_funct(samples[idx2])); - DLIB_TEST_MSG( dist_error < 1e-6, dist_error); - // make sure the dot products match - DLIB_TEST(abs(dot(proj_samples[idx1],proj_samples[idx2]) - dec_funct(samples[idx2])) < 1e-10); - - // also try the dec_funct with samples that weren't in the original set - samp = 100*randm(4,1,rnd); - // make sure the dot products match - DLIB_TEST(abs(dot(proj_samples[idx1],ekm.project(samp)) - dec_funct(samp)) < 1e-10); - samp = randm(4,1,rnd); - // make sure the dot products match - DLIB_TEST(abs(dot(proj_samples[idx1],ekm.project(samp)) - dec_funct(samp)) < 1e-10); - } - - - - proj_samples.clear(); - - - // now do the projection but use the projection_function returned by get_projection_function() - projection_function proj2 = ekm.get_projection_function(); - projection_function proj; - sout.clear(); - sout.str(""); - sin.clear(); - sin.str(""); - // test serialization - serialize(proj2, sout); - sin.str(sout.str()); - deserialize(proj, sin); - - for (unsigned long i = 0; i < samples.size(); ++i) - { - proj_samples.push_back(proj(samples[i])); - } - - DLIB_TEST(max(abs(kernel_matrix(kern, samples) - kernel_matrix(linear_kernel(), proj_samples))) < 1e-12); - DLIB_TEST(ekm.out_vector_size() == proj_samples[0].size()); - DLIB_TEST(proj.out_vector_size() == proj_samples[0].size()); - - ekm.clear(); - DLIB_TEST(ekm.out_vector_size() == 0); - DLIB_TEST(ekm2.out_vector_size() == 0); - DLIB_TEST(ekm3.out_vector_size() == 0); - - - for (int i = 0; i < 30; ++i) - { - const unsigned long idx1 = rnd.get_random_32bit_number()%samples.size(); - const unsigned long idx2 = rnd.get_random_32bit_number()%samples.size(); - decision_function dec_funct = convert_to_decision_function(proj,proj_samples[idx1]); - - // make sure the dot products match - DLIB_TEST(abs(dot(proj_samples[idx1],proj_samples[idx2]) - dec_funct(samples[idx2])) < 1e-10); - - // also try the dec_funct with samples that weren't in the original set - samp = 100*randm(4,1,rnd); - // make sure the dot products match - DLIB_TEST(abs(dot(proj_samples[idx1],proj(samp)) - dec_funct(samp)) < 1e-10); - samp = randm(4,1,rnd); - // make sure the dot products match - DLIB_TEST(abs(dot(proj_samples[idx1],proj(samp)) - dec_funct(samp)) < 1e-10); - } - - - - - - } - - for (int j = 1; j <= 20; ++j) - { - dlog << LTRACE << "j: " << j; - sample_type samp, samp2; - std::vector samples1; - std::vector samples2; - print_spinner(); - // make some random samples. At the end samples1 will be a subset of samples2 - for (int i = 0; i < 5*j; ++i) - { - samples1.push_back(randm(10,1,rnd)); - samples2.push_back(samples1.back()); - } - for (int i = 0; i < 5*j; ++i) - { - samples2.push_back(randm(10,1,rnd)); - } - // add on a little bit to make sure there is at least one non-zero sample. If all the - // samples are zero then empirical_kernel_map_error will be thrown and we don't want that. - samples1.front()(0) += 0.001; - samples2.front()(0) += 0.001; - - ekm.load(kern, samples1); - for (unsigned long i = 0; i < samples1.size(); ++i) - DLIB_TEST(dlib::equal(ekm[i] , samples1[i])); - DLIB_TEST(ekm.basis_size() == samples1.size()); - ekm2.load(kern, samples2); - DLIB_TEST(ekm2.basis_size() == samples2.size()); - - dlog << LTRACE << "ekm.out_vector_size(): " << ekm.out_vector_size(); - dlog << LTRACE << "ekm2.out_vector_size(): " << ekm2.out_vector_size(); - const double eps = 1e-6; - - matrix transform; - // Make sure transformations back to yourself work right. Note that we can't just - // check that transform is the identity matrix since it might be an identity transform - // for only a subspace of vectors (this happens if the ekm maps points into a subspace of - // all possible ekm.out_vector_size() vectors). - transform = ekm.get_transformation_to(ekm); - DLIB_TEST(transform.nr() == ekm.out_vector_size()); - DLIB_TEST(transform.nc() == ekm.out_vector_size()); - for (unsigned long i = 0; i < samples1.size(); ++i) - { - samp = ekm.project(samples1[i]); - DLIB_TEST_MSG(length(samp - transform*samp) < eps, length(samp - transform*samp)); - samp = ekm.project((samples1[0] + samples1[i])/2); - DLIB_TEST_MSG(length(samp - transform*samp) < eps, length(samp - transform*samp)); - } - - transform = ekm2.get_transformation_to(ekm2); - DLIB_TEST(transform.nr() == ekm2.out_vector_size()); - DLIB_TEST(transform.nc() == ekm2.out_vector_size()); - for (unsigned long i = 0; i < samples2.size(); ++i) - { - samp = ekm2.project(samples2[i]); - DLIB_TEST_MSG(length(samp - transform*samp) < eps, length(samp - transform*samp)); - samp = ekm2.project((samples2[0] + samples2[i])/2); - DLIB_TEST_MSG(length(samp - transform*samp) < eps, length(samp - transform*samp)); - //dlog << LTRACE << "mapping error: " << length(samp - transform*samp); - } - - - // now test the transform from ekm to ekm2 - transform = ekm.get_transformation_to(ekm2); - DLIB_TEST(transform.nr() == ekm2.out_vector_size()); - DLIB_TEST(transform.nc() == ekm.out_vector_size()); - for (unsigned long i = 0; i < samples1.size(); ++i) - { - samp = ekm.project(samples1[i]); - distance_function df1 = ekm.convert_to_distance_function(samp); - distance_function df2 = ekm2.convert_to_distance_function(transform*samp); - DLIB_TEST_MSG(df1(df2) < eps, df1(df2)); - //dlog << LTRACE << "mapping error: " << df1(df2); - - - samp = ekm.project((samples1[0] + samples1[i])/2); - df1 = ekm.convert_to_distance_function(samp); - df2 = ekm2.convert_to_distance_function(transform*samp); - DLIB_TEST_MSG(df1(df2) < eps, df1(df2)); - } - - - } - } - - void perform_test ( - ) - { - ++thetime; - typedef matrix sample_type; - dlog << LINFO << "time seed: " << thetime; - rnd.set_seed(cast_to_string(thetime)); - - print_spinner(); - test_projection_error(); - print_spinner(); - dlog << LINFO << "test with linear kernel"; - test_with_kernel(linear_kernel()); - print_spinner(); - dlog << LINFO << "test with rbf kernel"; - test_with_kernel(radial_basis_kernel(0.2)); - print_spinner(); - } - }; - - // Create an instance of this object. Doing this causes this test - // to be automatically inserted into the testing framework whenever this cpp file - // is linked into the project. Note that since we are inside an unnamed-namespace - // we won't get any linker errors about the symbol a being defined multiple times. - empirical_kernel_map_tester a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/entropy_coder.cpp b/lib/3rdParty/dlib/include/dlib/test/entropy_coder.cpp deleted file mode 100644 index edf16ccb..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/entropy_coder.cpp +++ /dev/null @@ -1,587 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include - -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace std; - using namespace dlib; - - logger dlog("test.entropy_coder"); - - namespace entropy_coder_kernel_test_helpers - { - template < - typename encoder, - typename decoder - > - std::string test ( - const std::string& input - ) - /*! - ensures - - encodes the data from in and then tries to decode it and returns - "" if it was successfully decoded else it returns the decoded string - !*/ - { - ostringstream sout; - istringstream sin; - istringstream in; - - - in.str(input); - - const unsigned long max_total = 65535; - - - - - unsigned long counts[256]; - for (int i = 0; i < 256; ++i) - { - counts[i] = 1; - } - - - encoder e; - - - - DLIB_TEST(e.stream_is_set() == false); - - e.set_stream(sout); - - DLIB_TEST(e.stream_is_set() == true); - DLIB_TEST(&e.get_stream() == &sout); - - unsigned char ch; - - unsigned long total = 256; - - while (in.read((char*)&ch,1)) - { - if (total > max_total) - { - total = 0; - for (int j = 0; j<256; ++j) - { - counts[j] >>= 1; - if (counts[j] == 0) - counts[j] = 1; - total += counts[j]; - - } - } - - unsigned long low_count = 0; - unsigned long high_count; - for (int i = 0; i < ch; ++i) - low_count += counts[i]; - high_count = low_count + counts[ch]; - - e.encode(low_count,high_count,total); - - - ++total; - counts[ch] += 1; - } - - DLIB_TEST(e.stream_is_set() == true); - DLIB_TEST(&e.get_stream() == &sout); - - - - e.clear(); - - DLIB_TEST(e.stream_is_set() == false); - - - // ***************************************** - - - decoder d; - - - DLIB_TEST(d.stream_is_set() == false); - DLIB_TEST(d.get_target_called() == false); - - sin.str(sout.str()); - sout.str(""); - - d.set_stream(sin); - - DLIB_TEST(d.get_target_called() == false); - - DLIB_TEST(d.stream_is_set() == true); - DLIB_TEST(&d.get_stream() == &sin); - - for (int i = 0; i < 256; ++i) - { - counts[i] = 1; - } - - total = 256; - - for (string::size_type i = 0; i < input.size() ; ++i) - { - if (total > max_total) - { - total = 0; - for (int j = 0; j<256; ++j) - { - counts[j] >>= 1; - if (counts[j] == 0) - counts[j] = 1; - total += counts[j]; - - } - } - - DLIB_TEST(d.get_target_called() == false); - - unsigned long target = d.get_target(total); - - DLIB_TEST(target < total); - - DLIB_TEST(d.get_target_called() == true); - - - unsigned long low_count; - unsigned long high_count = 0; - - unsigned long j; - for (j = 0; high_count <= target; ++j) - { - high_count += counts[j]; - } - --j; - low_count = high_count - counts[j]; - - - ch = static_cast(j); - - - sout.rdbuf()->sputn((char*)&ch,1); - - - - d.decode(low_count,high_count); - DLIB_TEST(d.get_target_called() == false); - ++total; - counts[ch] += 1; - - } - - DLIB_TEST(d.stream_is_set() == true); - DLIB_TEST(&d.get_stream() == &sin); - - d.clear(); - - DLIB_TEST(d.stream_is_set() == false); - DLIB_TEST_MSG(sout.str().size() == input.size(),"the test script is buggy"); - - - if (sout.str() == input) - return ""; - else - return sout.str(); - - } - - } - - - - - template < - typename encoder, - typename decoder - > - void entropy_coder_kernel_test ( - ) - /*! - requires - - encoder is an implementation of entropy_encoder/entropy_encoder_kernel_abstract.h - - decoder is an implementation of entropy_decoder/entropy_decoder_kernel_abstract.h - ensures - - runs tests on encoder and decoder for compliance with the specs - !*/ - { - using namespace entropy_coder_kernel_test_helpers; - - dlog << LTRACE << 1; - - print_spinner(); - string temp, temp2; - - srand(static_cast(time(0))); - - for (int k = 0; k < 10000; ++k) - { - string temp; - istringstream sin; - ostringstream sout; - decoder d; - encoder e; - - e.set_stream(sout); - - int num = ::rand() %200; - unsigned long total[200]; - unsigned long high_count[200]; - unsigned long low_count[200]; - for (int i = 0; i < num; ++i) - { - total[i] = ::rand()%256 + 20; - high_count[i] = ::rand()%total[i] + 1; - low_count[i] = ::rand()%high_count[i]; - - e.encode(low_count[i],high_count[i],total[i]); - } - - e.clear(); - - sout.rdbuf()->sputc('a'); - - sin.str(sout.str()); - - - d.set_stream(sin); - - - for (int i = 0; i < num; ++i) - { - unsigned long N = d.get_target(total[i]); - DLIB_TEST(low_count[i] <= N && N < high_count[i]); - d.decode(low_count[i],high_count[i]); - } - - - - - - - DLIB_TEST_MSG(sin.rdbuf()->sgetc() != EOF,"num: " << num); - DLIB_TEST_MSG(sin.rdbuf()->sgetc() == 'a', - "sin.rdbuf()->sgetc() == " << (char)sin.rdbuf()->sgetc() << - "\nnum: " << num - ); - DLIB_TEST(sin.rdbuf()->sbumpc() == 'a'); - DLIB_TEST(sin.rdbuf()->sgetc() == EOF); - - } // for (int k = 0; k < 10000; ++k) - - dlog << LTRACE << 2; - - print_spinner(); - - // the point of this block is to make sure that the return value - // from decoder.get_target(total) is a always less than total - for (int k = 0; k < 20; ++k) - { - string temp; - temp.push_back(static_cast(::rand()&0xff)); - istringstream sin(temp); - decoder d; - d.set_stream(sin); - unsigned long total = ::rand()%256 + 20; - unsigned long target = d.get_target(total); - DLIB_TEST(target target) - low_count = target; - - d.decode(low_count,high_count); - target = d.get_target(total); - DLIB_TEST_MSG(target(time(0)); - srand(seed1 ); - int array[65536]; - for (int i = 0; i < 65536; ++i) - { - array[i] = ::rand()%256; - } - for (int i = 0; i < 60; ++i) - { - int idx = ::rand()%65536; - int radius = 35; - if (idx > radius && idx <65536-radius) - { - for (int j = idx-radius; j < idx+radius; ++j) - array[j] = array[idx]; - } - } - - // test with 3 random strings of length 10000 - // but use the above array to bias the random numbers - for (int j = 0; j < 3; ++j) - { - print_spinner(); - temp = ""; - //seed2 = static_cast(time(0)); - srand(seed2 ); - for ( int i = 0; i < 10000; ++i) - { - int a = array[::rand()%65536]; - temp += (unsigned char)a; - } - string temp2; - temp2 = test(temp); - if (temp2 != "") - { - - int k = 0; - DLIB_TEST(temp != temp2); - while (temp[k] == temp2[k])++k; - } - - - DLIB_TEST_MSG(temp2 == "","") - } - } - - print_spinner(); - - - dlog << LTRACE << 4; - - - - - // test with a large string which contains all the same character - temp = "eeeeeeeeee"; - for (int i = 0; i < 13; ++i) - { - temp = temp + temp; - } - temp = test(temp); - if (temp != "") - { - // crop off all the e's until we find the part that is messed up - string::size_type pos = temp.find_first_not_of("e"); - temp = temp.substr(pos); - } - DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"") /**/ - - - dlog << LTRACE << 5; - - print_spinner(); - - temp = "davis"; - temp = test(temp); DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"") - - temp = ""; - temp = test(temp); DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"") - - // test for each single character - for ( int i = 0; i <= 255; ++i) - { - temp = (unsigned char)i; - temp = test(temp); DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"") - } - - dlog << LTRACE << 6; - - // test with a long string with the same thing repeated many times - temp = "davis "; - for (int i = 0; i < 10; ++i) - { - temp = temp + temp; - } - temp = test(temp); DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"") - - dlog << LTRACE << 7; - - // test with 10 random strings of length 1000 - for (int j = 0; j < 10; ++j) - { - temp = ""; - srand(static_cast(time(0))); - for ( int i = 0; i < 1000; ++i) - { - int a = ::rand()%256; - temp += (unsigned char)a; - } - temp = test(temp); DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"") - } - - - dlog << LTRACE << 8; - - print_spinner(); - - // test with 15 random strings of length 30000 - for (int j = 0; j < 15; ++j) - { - print_spinner(); - temp = ""; - unsigned long seed = static_cast(time(0)); - srand(seed); - for ( int i = 0; i < 30000; ++i) - { - int a = ::rand()%256; - temp += (unsigned char)a; - } - temp = test(temp); DLIB_TEST_MSG(temp == "","seed: " << seed) - } - - - dlog << LTRACE << 9; - - print_spinner(); - - // test with a large string which contains all the same character - temp = " "; - for (int i = 0; i < 10; ++i) - { - temp = temp + temp; - } - temp = test(temp); - if (temp != "") - { - // crop off all the spacess until we find the part that is messed up - string::size_type pos = temp.find_first_not_of(" "); - temp = temp.substr(pos); - } - DLIB_TEST_MSG(temp == "","decoded string: \"" << temp << "\"")/**/ - - - - - - - dlog << LTRACE << 10; - - - - - - - // test with a large string which contains a bunch of a's followed by a - // bunch of z's - temp = "aaaaaaaa"; - temp2 = "zzzzzzzz"; - for (int i = 0; i < 12; ++i) - { - temp = temp + temp; - temp2 = temp2 + temp2; - } - temp += temp2; - print_spinner(); - temp = test(temp); - DLIB_TEST(temp == ""); - - - - dlog << LTRACE << 11; - - - - } - - - - - class entropy_coder_tester : public tester - { - public: - entropy_coder_tester ( - ) : - tester ("test_entropy_coder", - "Runs tests on the entropy_coder component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a 1"; - entropy_coder_kernel_test< - entropy_encoder::kernel_1a, - entropy_decoder::kernel_1a - >(); - - dlog << LINFO << "testing kernel_1a_c 2"; - entropy_coder_kernel_test< - entropy_encoder::kernel_1a_c, - entropy_decoder::kernel_1a_c - >(); - - dlog << LINFO << "testing kernel_1a 3"; - entropy_coder_kernel_test< - entropy_encoder::kernel_2a, - entropy_decoder::kernel_2a - >(); - - dlog << LINFO << "testing kernel_1a_c 4"; - entropy_coder_kernel_test< - entropy_encoder::kernel_2a_c, - entropy_decoder::kernel_2a_c - >(); - - dlog << LINFO << "testing kernel_1a 5"; - entropy_coder_kernel_test< - entropy_encoder::kernel_1a, - entropy_decoder::kernel_1a_c - >(); - - dlog << LINFO << "testing kernel_1a_c 6"; - entropy_coder_kernel_test< - entropy_encoder::kernel_1a_c, - entropy_decoder::kernel_1a - >(); - - dlog << LINFO << "testing kernel_1a 7"; - entropy_coder_kernel_test< - entropy_encoder::kernel_2a, - entropy_decoder::kernel_2a_c - >(); - - dlog << LINFO << "testing kernel_1a_c 8"; - entropy_coder_kernel_test< - entropy_encoder::kernel_2a_c, - entropy_decoder::kernel_2a - >(); - - } - } a; - - - - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/entropy_encoder_model.cpp b/lib/3rdParty/dlib/include/dlib/test/entropy_encoder_model.cpp deleted file mode 100644 index 0276cbe7..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/entropy_encoder_model.cpp +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright (C) 2005 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include - -#include -#include -#include -#include -#include "tester.h" - -namespace -{ - using namespace test; - using namespace std; - using namespace dlib; - - logger dlog("test.entropy_coder_model"); - - template < - typename ee, - typename ed - > - void entropy_encoder_model_kernel_test ( - ) - /*! - requires - - ee is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h - the alphabet_size for ee is 256 - - ed is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h - the alphabet_size for ed is 256 - - ee and ed must share the same kernel number - ensures - - runs tests on ee and ed for compliance with the specs - !*/ - { - - print_spinner(); - srand(static_cast(time(0))); - - typedef typename ee::entropy_encoder_type ee_type; - typedef typename ed::entropy_decoder_type ed_type; - - - - { - - ee_type ecoder; - ed_type dcoder; - - ee elen(ecoder); - ed dlen(dcoder); - ee elit(ecoder); - ed dlit(dcoder); - - - istringstream sin; - ostringstream sout; - - ecoder.set_stream(sout); - - - unsigned long temp; - - - elen.encode(0); - elit.encode(9); - - elen.encode(0); - elit.encode(0); - - elen.encode(0); - elit.encode(4); - - elen.encode(0); - elit.encode(0); - - elen.encode(0); - elit.encode(2); - - elen.encode(0); - elit.encode(0); - - - - - - - - ecoder.clear(); - sin.str(sout.str()); - dcoder.set_stream(sin); - - - dlen.decode(temp); - DLIB_TEST(temp == 0); - dlit.decode(temp); - DLIB_TEST(temp == 9); - - dlen.decode(temp); - DLIB_TEST(temp == 0); - dlit.decode(temp); - DLIB_TEST(temp == 0); - - dlen.decode(temp); - DLIB_TEST(temp == 0); - dlit.decode(temp); - DLIB_TEST(temp == 4); - - dlen.decode(temp); - DLIB_TEST(temp == 0); - dlit.decode(temp); - DLIB_TEST(temp == 0); - - dlen.decode(temp); - DLIB_TEST(temp == 0); - dlit.decode(temp); - DLIB_TEST(temp == 2); - - dlen.decode(temp); - DLIB_TEST(temp == 0); - dlit.decode(temp); - DLIB_TEST(temp == 0); - - - - - } - - } - - - - - class entropy_encoder_model_tester : public tester - { - public: - entropy_encoder_model_tester ( - ) : - tester ("test_entropy_coder_model", - "Runs tests on the entropy_encoder_model and entropy_decoder_model components.") - {} - - void perform_test ( - ) - { - typedef entropy_encoder::kernel_2a_c ee; - typedef entropy_decoder::kernel_2a_c ed; - - dlog << LINFO << "testing kernel_1a"; - entropy_encoder_model_kernel_test< - entropy_encoder_model<256,ee>::kernel_1a, - entropy_decoder_model<256,ed>::kernel_1a>(); - - dlog << LINFO << "testing kernel_2a"; - entropy_encoder_model_kernel_test< - entropy_encoder_model<256,ee>::kernel_2a, - entropy_decoder_model<256,ed>::kernel_2a>(); - - dlog << LINFO << "testing kernel_3a"; - entropy_encoder_model_kernel_test< - entropy_encoder_model<256,ee>::kernel_3a, - entropy_decoder_model<256,ed>::kernel_3a>(); - - dlog << LINFO << "testing kernel_4a"; - entropy_encoder_model_kernel_test< - entropy_encoder_model<256,ee>::kernel_4a, - entropy_decoder_model<256,ed>::kernel_4a>(); - - dlog << LINFO << "testing kernel_4b"; - entropy_encoder_model_kernel_test< - entropy_encoder_model<256,ee>::kernel_4b, - entropy_decoder_model<256,ed>::kernel_4b>(); - - dlog << LINFO << "testing kernel_5a"; - entropy_encoder_model_kernel_test< - entropy_encoder_model<256,ee>::kernel_5a, - entropy_decoder_model<256,ed>::kernel_5a>(); - - dlog << LINFO << "testing kernel_5c"; - entropy_encoder_model_kernel_test< - entropy_encoder_model<256,ee>::kernel_5c, - entropy_decoder_model<256,ed>::kernel_5c>(); - - dlog << LINFO << "testing kernel_6a"; - entropy_encoder_model_kernel_test< - entropy_encoder_model<256,ee>::kernel_6a, - entropy_decoder_model<256,ed>::kernel_6a>(); - - } - } a; - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/example.cpp b/lib/3rdParty/dlib/include/dlib/test/example.cpp deleted file mode 100644 index 4cf92715..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/example.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (C) 2008 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "tester.h" - -// This is called an unnamed-namespace and it has the effect of making everything -// inside this file "private" so that everything you declare will have static linkage. -// Thus we won't have any multiply defined symbol errors coming out of the linker when -// we try to compile the test suite. -namespace -{ - using namespace test; - // Declare the logger we will use in this test. The name of the logger - // should start with "test." - dlib::logger dlog("test.example"); - - - class example_tester : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a unit test. When it is constructed - it adds itself into the testing framework. - !*/ - public: - example_tester ( - ) : - tester ( - "test_example", // the command line argument name for this test - "Run example tests.", // the command line argument description - 0 // the number of command line arguments for this test - ) - {} - - void perform_test ( - ) - { - // This message gets logged to the file debug.txt if the user has enabled logging by - // supplying the -d option on the command line (and they haven't set the logging level - // to something higher than LINFO). - dlog << dlib::LINFO << "some message you want to log"; - - // This test is considered a success if this function doesn't throw an exception. - // So we can use the DLIB_TEST_MSG macro to perform our tests since it throws an - // exception containing a message if its first argument is false. - - // make sure 3 is bigger than 2 - DLIB_TEST_MSG(3 > 2,"This message prints if your compiler doesn't know 3 is bigger than 2"); - - // make sure 5 is not equal to 9 - DLIB_TEST_MSG(5 != 9,"This message prints if your compiler thinks 5 is the same as 9"); - - // This is a form of test you can use when you don't care about having a message - DLIB_TEST(5 != 8); - - // If your test takes a long time to run you can also call print_spinner() - // periodically. This will cause a spinning / character to display on the - // console to indicate to the user that your test is still running (rather - // than hung) - print_spinner(); - } - }; - - // Create an instance of this object. Doing this causes this test - // to be automatically inserted into the testing framework whenever this cpp file - // is linked into the project. Note that since we are inside an unnamed-namespace - // we won't get any linker errors about the symbol a being defined multiple times. - example_tester a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/example_args.cpp b/lib/3rdParty/dlib/include/dlib/test/example_args.cpp deleted file mode 100644 index 573216c7..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/example_args.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) 2008 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "tester.h" - -// This is called an unnamed-namespace and it has the effect of making everything -// inside this file "private" so that everything you declare will have static linkage. -// Thus we won't have any multiply defined symbol errors coming out of the linker when -// we try to compile the test suite. -namespace -{ - // Declare the logger we will use in this test. The name of the logger - // should start with "test." - dlib::logger dlog("test.example_args"); - - using namespace test; - - class example_args_tester : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a unit test. When it is constructed - it adds itself into the testing framework. - - This particular test requires the user to supply a command line - argument when they run it. - !*/ - public: - example_args_tester ( - ) : - tester ( - "test_example_args", // the command line argument name for this test - "Run example tests with argument.", // the command line argument description - 1 // the number of command line arguments for this test - ) - {} - - void perform_test ( - const std::string& arg - ) - { - // This message gets logged to the file debug.txt if the user has enabled logging by - // supplying the -d option on the command line (and they haven't set the logging level - // to something higher than LINFO). - dlog << dlib::LINFO << "some message you want to log"; - dlog << dlib::LINFO << "the argument passed to this test was " << arg; - - // This test is considered a success if this function doesn't throw an exception. - // So we can use the DLIB_TEST_MSG macro to perform our tests since it throws an - // exception containing a message if its first argument is false. - - // make sure 3 is bigger than 2 - DLIB_TEST_MSG(3 > 2,"This message prints if your compiler doesn't know 3 is bigger than 2"); - - // make sure 5 is not equal to 9 - DLIB_TEST_MSG(5 != 9,"This message prints if your compiler thinks 5 is the same as 9"); - - // If your test takes a long time to run you can also call print_spinner() - // periodically. This will cause a spinning / character to display on the - // console to indicate to the user that your test is still running (rather - // than hung) - print_spinner(); - } - - }; - - // Create an instance of this object. Doing this causes this test - // to be automatically inserted into the testing framework whenever this cpp file - // is linked into the project. Note that since we are inside an unnamed-namespace - // we won't get any linker errors about the symbol a being defined multiple times. - example_args_tester a; -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/examples/CMakeLists.txt b/lib/3rdParty/dlib/include/dlib/test/examples/CMakeLists.txt deleted file mode 100644 index 93bd9a13..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/examples/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ - -# Disable some warnings from gcc when compiling the examples because fixing them would make the -# examples harder to read. -if (CMAKE_COMPILER_IS_GNUCXX) - add_definitions("-Wno-comment -Wno-unused-parameter") -endif() - -add_subdirectory(../../../examples examples_build) diff --git a/lib/3rdParty/dlib/include/dlib/test/face.cpp b/lib/3rdParty/dlib/include/dlib/test/face.cpp deleted file mode 100644 index 1bb1a94b..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/face.cpp +++ /dev/null @@ -1,360 +0,0 @@ -// Copyright (C) 2014 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "tester.h" -#include -#include -#include -#include -#include -#include -#include - -//#include -//#include - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - dlib::logger dlog("test.face"); - - - class face_tester : public tester - { - public: - face_tester ( - ) : - tester ( - "test_face", // the command line argument name for this test - "Run tests on the face detection/landmarking modules.", // the command line argument description - 0 // the number of command line arguments for this test - ) - { - } - - - void get_test_face_landmark_dataset ( - dlib::array >& images, - std::vector >& objects - ) - { - istringstream sin(get_decoded_string()); - images.resize(1); - objects.resize(1); - load_dng(images[0], sin); - pyramid_up(images[0]); - deserialize(objects[0], sin); - } - - void perform_test() - { - print_spinner(); - dlib::array > images; - std::vector > objects; - get_test_face_landmark_dataset(images, objects); - - frontal_face_detector detector = get_frontal_face_detector(); - - print_spinner(); - shape_predictor_trainer trainer; - trainer.set_tree_depth(2); - trainer.set_nu(0.05); - //trainer.be_verbose(); - - shape_predictor sp = trainer.train(images, objects); - - print_spinner(); - - // It should have been able to perfectly fit the data - DLIB_TEST(test_shape_predictor(sp, images, objects) == 0); - - print_spinner(); - - // While we are here, make sure the default face detector works - std::vector dets = detector(images[0]); - DLIB_TEST(dets.size() == 3); - - - /* - // visualize the detections - std::vector shapes; - for (unsigned long j = 0; j < dets.size(); ++j) - { - full_object_detection shape = sp(images[0], dets[j]); - shapes.push_back(shape); - } - image_window win(images[0]); - win.add_overlay(render_face_detections(shapes)); - cin.get(); - */ - - } - - - // ------------------------------------------------------------------------------------ - - // This function returns the contents of the file 'test_faces.dat' - const std::string get_decoded_string() - { - dlib::base64 base64_coder; - dlib::compress_stream::kernel_1ea compressor; - std::ostringstream sout; - std::istringstream sin; - - // The base64 encoded data from the file 'test_faces.dat' we want to decode and return. - sout << "RFYXmMn7UA64INJ2Umw+YCh5xX6v+y3bqV/1EKP3ZtvdIWxDCoyZ8oJjj/LXTw3PyEMQReTyXO+8"; - sout << "423ExTTLMRLxc5gEI4PK8vLMVWdRjRKldYfFLisH5qk7o6TxYfRXqmch/t4c53UfsUuJuVMvA+nf"; - sout << "05tfgx0Z2VgrlMmvKSxX0VHEjQ3ZVqQl0mLeur1qoMRmcPjYA4QJOvcruwyz/hFpVU8snvsri4QA"; - sout << "hkCrOtvl/iTlLvcWXDM98OXEYLk4vr6z2v73mGGEdbaJFafXOgutY0NRESpJfingJkuZKXNV7fQ8"; - sout << "F1DmHwFM0Izoc3fUyN7+xtLo2LSEH8uohv79wjxdbm71n5kgHb6cnpYiiCLOgqKrK+qJUJG1/OBB"; - sout << "9IORGL6SHrogefDg76m4ayil0lE4pQLa1fKhXGqphdxDMyBXHkOpxA356i5Evk7jZb/AqHUu/hQV"; - sout << "QYOsW20TRhuFfrasrb/Veq10hMZomosAnNb+Uhgnu2Ip4igX6ozJqmCL4NngjEgoXuCA02KzmIqK"; - sout << "fcslrBjyg7WZnF2w7UZXcHoZ0AVijb/ANPUqvq9H4k5WCFh53pwG6oj+CG5N7EXLzt9UHtillGJH"; - sout << "S252/dLvzaNxSq0vDP+Y0IvtKhZgIlmX3duu+L7iJUMinE90OXQFzhwCaOM8oP3Mq+Becgto5Vjb"; - sout << "vv+2xeyrYL9hBfMyPzbBhVWZdaPyI62MGMPjTfmAUmufWm3/Pxey5Jw6MUNX1rfWMXYQTtamdtcE"; - sout << "XmuFGhLCWbnJN2GtlOWu+S0LdWAziktr0mdovdFZTwKnd2Fuf1VeMMHBCgF5D56UK6/JTXO1gPlj"; - sout << "VpavizirUH46rHVnGOFZHWarPKymXyrQ/VhFbVBSOi9UGbsMo9sYNYhvFlzSBN5orNoY+5AP+Y2X"; - sout << "BDw342Vg3YRIZBqaXZ7oOqyDtjFYNf2g7ColnaFrPiYCKg9VQvVQVXvr4Oa6TTryepXylHk11ijw"; - sout << "xYgjiENTDKVuXPLVrAEWZD6wq5+LGbmj1cgh59XgLErkoliKxVeEv4ktXqceCFK9YWljqJZSBxFj"; - sout << "T64N945O47Oek591sfRFYrjebJz3kooaaOQ7lm4BWpW64Am/Od0FIkggSzPUgf+jYrnPdH4oqv3d"; - sout << "NJIXJO8aeCi/WCqgbdgLwpu1MB8cTdbK2TrCbi3sHhQddE6rqZ1XIg25gYTw72q4ZFUHmRrBEgdz"; - sout << "i2xh7qHevCWC9Ht7HrUcLl35/UCcNck/ftiDa/xN3rBJp+cJCyS9ZXScFbgFKYfBau8Dx+JA3ygU"; - sout << "pvYbUP29UeK5hXZoQzC74UKw/liapW8GbR3ZPV+59xmw1b7phyApZfODkDLG5lyTB5Co6vIfmqXp"; - sout << "DSA1I0ZPIk7hJHWtddgvAg6Yv4GhMZs/cn08Z/ZRXYSMw20rA66BeMD+IPFe3MPFPnKsl/qRvXIC"; - sout << "gTmLcjPQ5naBo/3haQg4TjJCBCErTC2JktJE0vRfm8v+1kEFoycTsRfhDZtjMnqmqSiNO3VSbnbb"; - sout << "et/mFvCdd9kqBXQ4VaeYdJwORA7/TocC84G91jlfNRhbY2KW9xHXYYwscfaV5DtPWhyJBEimzLsz"; - sout << "F59UbkO/WOT7HEwJ3p1/ReH6feLrIYwR8OdSeuOUtK2oboodiUmx/if9pyNONd0If9jFGDXvWP/r"; - sout << "dL6NdRh68swmPyiCn7sAwaUbd7PF7K+jqgk3jMDMaoWE6p+aAFK3H/JxRO7th2XvX57uA+RKoXEq"; - sout << "LBJrDkoPGbA5Ctj6KUWknMM62HVIO1SjwZH7ROOlCVbHvDd3JTT6TNs2Lj8g78q6WRMnDVV0L9Q7"; - sout << "S6awjHePvyj9fDn66jpmRxI9TkqNPx0b8tGfOnUoXGKK/WcInBjVd+FYy1SO5FIVZ4JQdiSMgehu"; - sout << "EU7X2yjbdgCtVg+kY3ZgYcCMM72NLdm7+U+qVxzfY9bNtzLRsEDNFL2wnq3DkbRRiHKHswEugXjG"; - sout << "fFfzqjU71sDH3gc1dhOQT456XK0zhmV/62+N+oTxrFY2F/ArALeDiR1q1JOrE1UDzU/ezAZVWS/a"; - sout << "DJ8O9TVZsbOXOU4hAiQ6mR5hh6i5c/zb7jBl6ehNgixrJqguo9PT10P3S6I+IiTG2vHlws4ZoTmz"; - sout << "7iOj1ICCN6ivwPj5+afYScxPGLVujxWTW8ksey8RjSIbH+N9wUEAJAcZAGXo2UrP93uRkdLt/cvi"; - sout << "Q4eIONlUrJ79hlo1xyvPmyNw9Ye1zG6epUK+lsXxtUbtX+uX+sDM/Gkr5QUdzzorfa4Mj9vEglQp"; - sout << "iK5319kTeymqqV25YhNZZsoqCg+eckmoZP21cAHkPYZWAzg4lxhm71EAp+fE67Y44szeCSRNydRh"; - sout << "mCl0ZGV59wVfUONdohN/9OQJ8gxifHspscrRszBALwCu2FrniGwRMvIi6lD6tb49dmpPlO1y5SEl"; - sout << "HPF2I271RVx0YwFPprp+2/fzsnKIIhfgTNRVji2tfjHPoge84e5O02Z/cLlg7EzIfr/JK8Xd6mwp"; - sout << "t3kIofktLqWbnBrr8qEvz2BmHRlEjYlpb6HfbK82ZHiOusVJdhAxRcRIqmImh5wtunlJOXdQqfmg"; - sout << "8P0TYVDzQlc6ywbKt/VjTsxI4qisabVvVBkW5VsKU4/JONoNj7fgomwfHqryIIZcgc5vPLawnurD"; - sout << "7JR1LRiTy7+7riDIxKdYtgbTuOnK6tO103XC+5NT07cKydDgtTu1gYoTTgzY+gkK53lX2Swbbme7"; - sout << "wIFOXRwSK4ntGt4XXuuPbF8gc0T8ez8/tOEXE6Di8Ckj2O3uz2vGM27PQH9YU3Y3YCdcuaHlUIMG"; - sout << "s7bgx4nM+xMPmS5baTuAHiPAxp3SepeKpHg0on6Bv99NPSDf7nWRcvvd3+/MHhyDfkbzd88GPnkQ"; - sout << "Y7a91Tlj8RKG6B8W+zzn+SWzTIz5eJcLJCEKN7fXm1YjJjk3Tdi99PZA/K3Ek2k2lcd2oQPXj6fc"; - sout << "EUs9zy6sZdSjttwsYlZzLW0Rpiscjqs1XNA+2D5UahufMk4AVpnDPqZ/OvmSZIPpTT4r+uQsEZlJ"; - sout << "BYf6A9riAPhgR68zPz+i+ffpPcgwURCDviqf370nLIqfbDgJSztxXI2MPsHZqypB+VtvuLTq+M2s"; - sout << "NVdvA6z5J35d3fk8EHVo8/TIWbsSulqnpJvjIHT9GeTV4EvaJo0kh092cFQ3QkbRIIzEqnT/o06z"; - sout << "/+gqB0fKl93o50EUVzJbz02rPc/4qVaqfSJLg+HEZUg30PB8wQHb2oWqgL1lYDlqrv5plbK2kJm9"; - sout << "HW9aQfOyX57rBsYi4aljZl5icy/JElsuNanhnTcTvrHQ/9ntw8QqV2PuVesbbaUQSjDRWG6D1uaK"; - sout << "HSYB/6fvMZ+8hy+gq4d/tMKpoCzgERJjJOU+N0vHpKmyZgE0EGkPJwlgev/oxTJtsQndgrNviPkr"; - sout << "ub9ZRkS5uM7Jb+1mKztyVWDdtVvxnvgboNayuS5/VdwlbQezQKEiB8I8UWLsgEJiXg9sgjBaFrv8"; - sout << "3WgtSQmMRyukOnDPWwDskmUyIHKIye1wOY3H1BUuav52tg8gv1+y2CrVVebRm/8MmhJYe/8DpLeo"; - sout << "1eEAX2SNtZH4VzpZSuAdANtYXgBaNTc0uWtw9Wc8mwo2hTfbu5nVYJ6vlUFP7HH7L+1idfrz832x"; - sout << "l20/+8EKd8y2f20iP6m1mnKCQ9PUPPhWMfWMkJ21VhKJJDcpKhvQq20O/yqhfxabl+73QZiCS/eR"; - sout << "E1ih71FN4x+s952FXOakzYlo5Gge1OCgHE0+YVXBSal4fz6Ye1iRG7+XgLxDIx6AGbOfemRQbOzW"; - sout << "e/8pe0kPqkkS5ogdkCGemb3hKTgGFGXgP9IvJ18VuRDxPSHD1e5THwvULz7V0hUWO4aKx8t8tZIK"; - sout << "flDB/npEo3L/1jU5rLEuX5KQbxJfEY2V22hND1ohUZdU+Uy6BFZ/hdYzFAUyNdLAFS36wB3XThar"; - sout << "54CQ0RGIxCCtv5ucI7VQuc46jkk6SEmZV8FUwv79ExsrB+rAlBvhNOrmVA2vmikrb/iZfA6z1hC2"; - sout << "aj8BGiULdcW0YUiN/TXxoVT0qgh87VjPcOfkj8gTRMF8VGAgRs0HpXVXKZf+ncAOKJ59yu3EsOCp"; - sout << "vSG5zxDxrUYD7TFxrelev/7Jtan4J8ouFsK8ZA4WmBkbWLDBkKvV09c7Jxfmgt27aVI5uuUBJYb0"; - sout << "TdKIG6J/JC85GrRedIb/kRaMiTP0Els6jGp3C/B9PQq6HbzSCUEkLE8is+uWnTDOynbgTtUVEGxH"; - sout << "EKZGBtnPfqgZRDOnZTWMO9Hd9qATpI2qRrgxIvHTUhqD3DQQ37AGTcNsMmj/+mXTBV2vbM9H7Q5K"; - sout << "APzltdgkGc+hZIL8Fy3CXzzRFlXAEoIcnJ3BKT7AdGg3pEaW1YcX4akaOTDmImZelYTCoTGu1R4Y"; - sout << "ZD/rRCeiGR9txS9x9/ptvxeD3J8wYOXxDzCkyMQy1io+izFuN4kTd5MW3RlvepWT4FE2hvjyTyV+"; - sout << "G4F+lcZFjCGmJKguZEzH3Qtww3OTGZqOfL9oADqQsUpEl92hm0uNOPHH6+8gWPZgb3EcCRkWeXaA"; - sout << "DkTbCC5rV04N6Fg3j27K1v7qkykWB4y61W00dFejgPitoYuln4A8lY9RtIKzJYFfSOKnrAqYGMkn"; - sout << "PReI5ZneFTiklSL6FkhWHvr5oz4EsAoU3fLWjky27E1CtpFkPKHLGyc2mnf2N7iBMGa8j2ipy9xd"; - sout << "JwInqdDdGIHR5dUmNAy1A4vyGbOE7qa0ErVy4m3riKkyE0ObQTNoBeYa6CUHwNWCLCbiW2VzRY/H"; - sout << "s6APvI6QIco+Wu9dx36qklvA6/OfM79BsUACnCRG2yo3bHeTeKMwKIx05RkNNJ76eOhjxOiPJBVR"; - sout << "K5V+G3SutaRM0hSK0ABS5nfveZmowfJr8nZHRBAPHyIdv0bJW8lSNIRtZtgwm1dl13+eaeAJNpJm"; - sout << "3eVvhP8c43LG938Bjxs/nfDl5GMzPnyLOIYInIt4wTXCZlRbt6pMXs9IX9/DpUt/AF44b+XQLnUT"; - sout << "DgJa4In4qREDt58wel1oAGe9xpIqdFNPduUuCo/Ly0XHrBFd3jQFgp0JWZ039GtG2YTHpo8rLfu+"; - sout << "TiTAmKnFbVZa6dlOzmVDV+53ptJxiWNfNMa2ri/YEFI7BpKi1FZvMfpGBzNmAdZBAt7kaSvIzqdl"; - sout << "OHMqka3GBbzyW1PusVpj6SWBZ7rsfIFPRdVO4PGcOWSIQ/YlZYXtkV82cw+m4D/ScXdlj0VZBB04"; - sout << "YfeUz1m8tiWsLdHxIKRI1JcLek5PzCQX33RFmfeqGBEa7q/kCzGiJ0QHiJV07Fxm2NKRUZQIWiJO"; - sout << "n1roUf9C06IT03Wd0rcSlwG8Ji9SJZOlBEi7B9Vos61eXMEnkcNiRVeOxLaOfqr20XMde4kquqrS"; - sout << "qZi2ZhNVqokhXNswwMtlMDfWBWWI39q4evlS8c60lQjXg39kyKbyVZOzp6KrJ+xDYUxURb2d/7DZ"; - sout << "+UpikS9DmbUgWqV1pmx84ARtPp8/5teoBM7qd6sRrpJ1Q4cE4WLQfr/nVnVmSfZVzm6yqlxjGvhQ"; - sout << "Bwz85XvMn4xjWIRDNnuwyJh7PoXkoacU54idHA4k7B3qeW59MKtXD3hA34qKUqqE0amH1Xzi3W84"; - sout << "HpL4xT9EoNUPv+ufvo/4Yir/YIMIVuj1BFQACONJWezdbHO7ze7DQrceR9ojpVlkM442CArpnYWZ"; - sout << "3SR0NRB0PFjJcgA3RPVWW591v7Aw3G7/aUh5OLSZsOoxrnE2Hb8wM4wQXutleUjcUCxdliAbLl/k"; - sout << "RcLSE+IzpwRpnSo05sBx91Q71Ws9NeS0Pruy03wScuztfv15MPoBmMH4Nc+JhF/iokGM7C4IICOb"; - sout << "Woffq9KzUSWaIEEO+qaKqfnG7+/bW5U/gDW0xAfvTt0IuXtoJH5/Gq/g/anFdecnyCdBa4C02MFJ"; - sout << "gLqm9Dyiuh5Hny9bAuE08YxgrfpwOx3nGxQ/MrXwGUNjCxJEz4TkmFt/Z6HmOUhobQ4Xue5rK6gp"; - sout << "qWkg7gkXJmpNaj40TFnxQ3Fvw7S1UPNcY3vEvskuYXlB6mI16FCa6ApkR3+krkCKokxelBU5eMxx"; - sout << "+j5Lv8hYzlSlULUJrDOmGRxQ65lOJPmxbuukr6Uaeh3/i5m8GLqJ3EAkeIABkck+sT/OCCS+1hmY"; - sout << "/wRbadX8sd19GjHTLkZ7jwEss0qQj1LdtcEtqXgtzy7+8NhQv9c4KhxFNZdYDezehZYZuf4+UeHM"; - sout << "UAPE6+DX+AtKRD5lSwcAEoFID5GLbsLa+gGWzhmn5dfTDvaJrQNYzI6K1f0MBsWxuXu5SM6dRehm"; - sout << "9FR9es1OnhIFP8bg5uR7lfIEsfAH6ysgkJyylceoooXwE+cALB+IYfk3mIHNuDMbrQxWIMZmS1er"; - sout << "I45Gz53QPLgcSjH9Z1mzrhaZV3ZiJqrTYETtObMRX0136rNLBCaytijF1H4QBJaNEsuJpHAYQHsC"; - sout << "ko8cTk8lzMmh+ENtUjLvrG+pEx9FKCPIgUIZrAAM39fWS5uKhFaAPEkfD/FxbEMdM/hjzbQzcMHy"; - sout << "iYywZCaCYwolzrQtlTIL3I4VqzpUk/vWMIZt/PMK8lUGBDxzELkXNTYepRJ+uR6QZKOU+/LpLk8K"; - sout << "MD6+BZNl2karSYjx9qDDHuADoiNJbSXLV2NqyJiNyTmdKv8E4e52mVFfetoMp+gpd7vMJaAObPuJ"; - sout << "A7rUsNjWz+Zho52LXUSUC1G1MdZPRZPMfk/KvNnXZX93P/KaBXTNLlRf4KkRXQdrnmP5KgKFOvIX"; - sout << "KUMJ7UQtP0koYJl8OsFHG5yX+qI4BOJqVT0eUypXtlW/CHRX51Wl11wIDsTqbi7zEkBu3kFLMfnr"; - sout << "3MEYcVWthG5Y9KecfsdLtRnQVSFRMEKEn1kpVAb7xqZhwKDqREVs+32AawqNxPdO4JOCC/wW0zzH"; - sout << "QlJ8KhbcrxKLaygvVOrqaZGeCNTrrRxpG792CtX4OqXdkxpqcPNjhQJXMgSm/OvHJ1sJOrIHYaru"; - sout << "JPDH/J4e0qg28rlRpN/iY9xc5Q/dMxhoEsv87ehP+MPKF5ByxrWHbNc9IaOiz5BQIQWAc1glXkKc"; - sout << "oyMgoCbZ1Zss8zJ1+k4NwoC59BpnT4KbZHZP7+MbXZidCSosl1P88yC0vj0BX8MK+8x6PA3X9Zc5"; - sout << "Sg2OMThc6WRR3oi/DeHePYqJgPtJwhZt7N651llY8/YIJD7pqVEiB8KJGcrjZ9tDuU0MDTkKnrr7"; - sout << "qhlSl/XFBGq0x9zIfYeBt6k2wgrpE2/FjgziM3YuH/e7jfppGx3S3G4O+yrUuAynknZQ6Opq+Qs1"; - sout << "PYFZMW8Fj+CPMgXGy/2+JPXULK8vf0hN3FfNDeHiGpuGEVaEBHdZdE3CW8cWwyRSdvQHgPbXwEaL"; - sout << "pLGxPhgGQlPLK/JvDQhtL7gqS1LQEAER1sleOHoTV5zEpCsKUcvisz0V7TyFozYnzaG0IcfeGysR"; - sout << "Kx7O4dq05dlnXicv2IrhcCp9+QZSHDL/E/t/SEafxZJu+sIhqknM+Sgx3MAhE/U8KyOANAYy1aPB"; - sout << "H5Qt5RnDbYuFJXHDG9DfEWWcNP8e2EL1CX0/gncYvIz3b5Ge0gv4hwbV23Xzsi3hOki4A/B44nOd"; - sout << "fAE3Ao1D16+6XowEVC8gUh+y1TSnYPTtnB30NbrcMhHNaJP0pYzG41gNaMJNjK8SGXSnPKiXrsJ2"; - sout << "1jsvbLaMTEBdCqw+2lgg/QwEVgUef7JhVNKbQKf/HTtuD50Ofa4PXv37Q92/xnHWHwjbWfeNEZWA"; - sout << "Y5bqQI/MlWBKWSGFjpoQsfbCzS6P3ieD3ID91DmB7tDjTDYm5Wq6LoHAQzx+tTxiq45Qn5tUg0zx"; - sout << "7VC8Xh0ygItADoEqXpKUXdfv0o6G4zxjePM4dvyf4NBkh27q1S/aQwQp8UOury2Eunij57XSxaOb"; - sout << "IFwlFJYC6wtmg6oV0QZAburx8qJMLdIvHyqa5YJJ3HGuHJIyiD+tuxWVxDZSJQ1RedYqBPAiloyy"; - sout << "Z3j6EJKqNh0kq3c0K/B7gpX0P1ZjOFZUadIbEW6dd8bxl0RuyhzdSUMkn4rWgmx7zPvoOEgXzbK+"; - sout << "mJmBT9lEaYE4sFkXfZqDCGq66jdc4RrlD4IZbGkXwMeTuHsfLL1hviKSOyJCTbmS5dKZUdWuVk8R"; - sout << "XFqATzyHHdArHR9RvNa2bQk5b59tODpeKCqECv5DJ5T2ap8u21ctDCJiFCHq3gLfw6IumI1L2m6/"; - sout << "aPGdZ0d4ZMR9ooQvJuhAODKg0ZsA+LjHTakpfUwHpanPWkCbmhuh3oMC+hMX+AqOi55nr2O5uxRL"; - sout << "9UwixLBmRa8g3lbgUGdteTTbvZ2ePyzwxhWp1RS+aFJqtORmRMkgB6vRc4SC1CywKwwHoR3RKEj7"; - sout << "uW6oQyLQqPYevLuBrbO6yn7U6DkU6blGF7jg/2y12MpwYPr8l661YMXXsmVHCVSJ0AsPSGhJ8oL3"; - sout << "Cqk6DJbpyoN8O1xK4zNE0cToRFMhEBjlim0lg56HtbEHfLkqRwnFqfo6vvK6opxJoShMXDa5jrLH"; - sout << "GkpmE4DzaGtZ/P397TF3Y12c6lXJFDYWslp4tMskzsy9FdW63kRUvl6Q3UsWj72qGE6r/PGVetJ9"; - sout << "in33oiVHTjYppFrza0ryzPE02V4uobC3y2DtoG/YK/GJFkhm68O0QKxyuBURMfT4j046fBQAbwUo"; - sout << "B/Ylsb+srIUK6sIEnnzdJ/8ve3f961Yx5Kywf/9kVZnUz5RoiP/bOWXm6jasSq7LEvX2nT2fweup"; - sout << "/TI83XIDWd0rFQoGTfuIuXFfLQbXkX4oZpmYLdr0kQAKjFtNB/JYV5PTE7PskJKD/AS6iYLd2pOf"; - sout << "cEYJxPZWSWUSz+EmRNmeDl3lfch9LD6VXgaxY1xPF0/1uQfU+BBikdVQJPlMzVB9QK17ir6rynim"; - sout << "CP038a8ctWt5RMBsaJPZr7bieh11aTTW2mC65Y3PYQ8WsXofuw4x3xoXI1S/hGCM2QvmgWq29xHp"; - sout << "5Jkp/Z5YLaGBGxCHM+QQm4LzggVnhYjlguAbfEmWFapwhzmx1L26gv2q2AUiozn2I7dAh1vDRKD/"; - sout << "u5XMODPPJE+NTsr5DQz7aIdEwRLZynp1FO+VN71nYDa5G8ruF4v320ocRKm/mQ5uzU4X7w69CLdS"; - sout << "kmag9jfDGvuolYqCooAts5b7tFIcC3WjlXeLPq5y8HmzY69Z72HrISpq0Fyq4vcZaksLSdpv+Pil"; - sout << "iUu6Vmti4LYLHYsmue1UgMzL0qqdRMz6XmCPBkUXYDS4oOoQuDcH5iJo9aWRoADapKUHqIUnoR3O"; - sout << "Vx4h5b2/XtCEb8dNF0ubJ+oZGbAize7SWTGnUCQdpz2wxAWFymc5/5jFxfVU2BKSPhrKRYImgnVU"; - sout << "8GOms14wCx4wyGuRZY3p9s1uPUBNNjDnJqVg6I+7STXJKrYzeP2gP227k2JE3o9eLehe66hcqaPi"; - sout << "egdpG5RfPN9X87FtePJ6lPjJ8j0Ysgoa6l+DDUDuEZHp6APIG5miY893oac8uo/r2RgRNVv6vLFo"; - sout << "8VIFR7IwcLj1zXvwriv/Szw3POh7y8svSb4eGKr1c1/5JTJB58Fcjz0AMm2+rW0Twwb3STxn4SZ6"; - sout << "nXOyP0btY0VCckovcLoFij3lsl21ZGMdfG9cHVlKL88pg4Ip00QmgcQW3QmBBoCjlPlRVSSsDHGY"; - sout << "8TBBGLuxJi7NPzU1HNtjG3cnYw0t49og2hjrIbF+6fHb9x0pPtnJZwX7SbBYlk4Z8v84fR7cjC+9"; - sout << "l6SLvaRgqkTj/aaiiHtC17zaxNhP9wHqXmPUZdKM6xs3vsAF1dYOLPlIv+nmMLBPfravTZDkf3p1"; - sout << "x56EjPHwT1GULNkLBG8iod/cteD0E0GIZf0g5/o0hfI1t18CMGxfMyeaASZugV3+KL1yOwXD07D0"; - sout << "lp8iLn8FlYgXOgUO7+OweJcIu1IwkzLSM2aNbnH3VDPlu/Ff8ZHL0jiuxhQAVT6jdWJSUEOf2yiB"; - sout << "8mIGCK7CH9Xv9l/grSdh6GrE+NvvWqKQrhX1k8wxHEM4PnhMSO4R+5dRFWeeh6cYfTNHTYWZ2xzU"; - sout << "run1L6tULZzpksLtHYDg0vEEq3hDS/3yf+/cvCX4ibt5pUqorTpAtNvbTaguUyBy2TOAy6fSFGh2"; - sout << "eHil/3JEYZXnfFtcBo+pIvt3LWEPlWCUHNKFLQnpd77Y6wUFn3Ku7o7Nu7zBxemmvxxYUXImAlzt"; - sout << "354O5G/5G1GUGFf1K2u11fFcuXrfowEE+1eUEpC0KLyxZhOJa5nA6dKtnQbq8wrGXxuGuJGlDSAu"; - sout << "0sUYLPmELc+kGUyY6A27B0FKFN50bP1U5iWLAtxt0NmPqOnwzvnj5GYQ9R/ZIpzf73N2OoYL4+ba"; - sout << "6E32ION5IxY2YQ1IqEHxsjzvDW5KoQCb8oz63eKgwLHBz/1yhA0ELpzG9ti5pVE4WbGKOtS/2xTh"; - sout << "RIgpnpbB7bPUdtw33cjky7t6UAO+QYI1kg8rscd/Ug44hd627JK61SxnGlK5wBRj7aoUxH2yb3Dt"; - sout << "jMgmcgZYtdIsHjuU63vrN0acMHULcyCRIFuFEtXgnQNIKjPUG3iuN3714Y9sncW5HqDGAYLyRpaA"; - sout << "69XPtqYEajN2uLF1Q9KIeW701X1diQoHw7TFq0p5x1oTMRzjqcz5lnLIM0DycqCPGoGAnyL0o5A3"; - sout << "Rw9qaSq1bB5VOdqpZHyN38huATstlHmcO2GqN2r9k2BKqqDYxuzmhB1K5ugoJID0lm6KfR87e+2q"; - sout << "CQL1tr6ecqFe4LkO6nRR57w6gl48J0tFYuxsgRcktYvkt/BF1JHNnw/BChE9lDBgBZz8TfAqUv5b"; - sout << "Ofi4WiuGxq5sKIa8a5SRwfVbz1h/MBqBEd9nDlZ1acbg9ZGakzwCfH0WrcArLiN9FqGqmiZClS0d"; - sout << "cUwftQDUI7yEoiIb18/479c1VU2q5dJddCBaabm8CtGtd8w8KTANBXX4pZoSuOlYUUQaxYsZ/avm"; - sout << "RYqfU1uOkHlmqm++EvfKEGW/Rmoq/fCIl4mk7YoLpMcub9wlTSVP2W//uvZG0LYwlZScWGOGmo6Z"; - sout << "xa02FmCXVIyXUfnitTEv2oYj3CV/57nW4+1jkXTcYhH8wt5wX5G2eO7qw3esj1x1kL07xmven4Il"; - sout << "nmKMri2FNxrWUBzvCwmfKGfPh1IkQ9LAfaJJATfGeBFI33RQdSILTaozNl88dHbUO8I+ZnySvavV"; - sout << "uX9Ia4Gvrm0nzV6WYbE4SCDjppsaz0CSZy1exA9t/NFoQFjvf25pszQ9JlDtwDm65ssYqCTLjyoJ"; - sout << "AjMMUygef0nD9WxtWkVCywmyR5HIZWqwV/poAROWBUNL72p0kYxDsm8u8D6LFDQJj+/rSQFr4jzF"; - sout << "RkH7zemYp52d7nSo7ZV84Pf11aTTWqg1OCwAFz+bcg5wZObUL48+WzPAPePNtlo2ef4hn3tyi/pj"; - sout << "v62xZax1oHnnB4ozyZqwSd7aH8LGN4G0Pk37PCagVXLEyLEGQXA3NqxxokimT93xORZOF4hZjhUR"; - sout << "EM6aKChyS4DKkB/HN8IEMrPcKL7zadhDrWX6aeAxBOIbF02jTyCo7rFEO4g3TLuy+aX29SStyzAd"; - sout << "bESo1w0hmnjboB/cUVh9SU0rWvyHnBveXBU1QFsmKEpEVXbD9iao+VArYlDKQgXS0elIQIJHLJ2v"; - sout << "8cVk5GtsXQU9Yd5vyzC9R/ZuUD+fuRcoKYwevCjnVegbn4mCK6VICihqWM5etEr9CqdjjzAtemN3"; - sout << "RhW/4c1v6Gfcb3LQIctJmk08SbUfkImRlULjt3sr+iF/9gMx5AneRDqnq1YRbiusqAfpCl83zBFm"; - sout << "/txWD4btmU3/Q9TzIYjcDm8JFIpptv1+F6myuN1ElJPj5dcmfBZ2/KQknRf7cFBSFCfeKS2glsIm"; - sout << "tTj1p8jK+qKf3GS+v/n6VutWgGXAU7bjZSfaWn3wfNX1rJXOX4Czp1dXxmXuxltVQ09bTpEMQL5o"; - sout << "F9LI3ExjgsokVCsnuAc25hTRWP6bUkWsd3fvbVK/Qrg8sYEpq+3836NJyb2BcFVBqmDJaW+MZ2+P"; - sout << "dJwzMjQMFfRNnsEBRwHuVTDwa4tyR+1yFOqG514ohI4UKamdebXPlrjm278ztqaN/4ASFsVoQb7O"; - sout << "nPvqiMT9REV9ZLiK8z2NK4dDr4KUCr/UihBZqX7qQWnFRyy0VooOFAyP9CjfohLthZ8Y0HWFDMpx"; - sout << "0imNkxXlh3CIDNTRXAmgFupIEQyY08sZX/Oqx4NdzpxWLh2S0VJmIupzuxWTnKBRJXWZEVPKqsak"; - sout << "zBsNzdtcqrF5dIIY/7d+8LFdEBIZ56wftYkRRvJt9S7mPIY++gohDronAX/ohfwXwu4jCm0OLWzO"; - sout << "l4FIAdeN0m65Nng2pWnF6M+qB+b5BT3I5cAh7GF4t3woiWOBF7LnjOYmHe7ZkzPzftxeZ820e+eJ"; - sout << "i1pFSQl3/H+aneIsjEQVGxgynGtvGW3pz/0f5rWrRdUG9ZYPJItWXCjJz2k/Eb3fHDA9JVIT9FEM"; - sout << "XCsN2FQguDWy7cDxNMKxVRuhomjmVCR50/W9/Wsjg6+tnNNhY5Iukh40jU9uN/WShMpzXNv2QKxR"; - sout << "bfUtL0zpojBbZOkAd1LZ++bQREzjPBFQ6G18eQa7DphNarttvCzw9qdgvmwpl3CfvW4PeFChxQ2V"; - sout << "SmfUcuFnESjEN30zsEyFtIJNVd1E+4C6vDxk+FRWl+jGbzNkQ1GK+9z6M0HgUxBXMXcHiJbMEJ3s"; - sout << "Ri6PqeKjZUAJzORigJmgOO5wURFI+3EVQ0NuPWfaQ/6UZ1n7fdXi8ncmO4jVwY1ptN/4tJL+bAm0"; - sout << "eu/c6ug2bfNCTx6TnutxBAg5AvxlDrJIUsx+TsM50J4OZmv7pI4dC0UWU3TpzaYHa/cQ+OY61UT/"; - sout << "j1/QPSquxIlWA46SGt/xrUg9iPIWw+2hdRBkhTBE6PrMMHLl5jxWpJ96YH5WDnifNnnhzRDcLfyf"; - sout << "9nZYWQaBzm3JangobvnsDPgjF91OfeFJhVPyUwS5u+Sxw+NKPj9wVAaW3gZVS2BOODAud/EvFfQF"; - sout << "08t3Ab27GGwWNx9ExN/jlq8EHAM+VRcyfn3hBVjLZdt9fs6zZliYdfyNaA/fgO1iLwY4DOSKgALr"; - sout << "Vs5+KDTmyNf5DkAg/W/d1tA/o76/qXUz3gHdm8Q1TqA3ZuR3g1BE6oS4T9Sg62oYIthP99doW8ll"; - sout << "FPr0aF+JHwXzG0k6Ao4wGdKmqi+n91pVYI7r2zE1kKtk7GyF0fSmcVnnP42TQfaUbaKB1bMT+a1V"; - sout << "NMIydv7QD5F2af3El9np7/1S69sGpoNK7PLow71jdlCewGVrq+iYxZaVhe3xHwerQQ1uGfmRxUSK"; - sout << "exonRQPz0yD5fkjRCqq+Hbys1CXe4iKa2uO0pW+yMlvRnMWpV3Bx6uxYR6pECBJ0x8DQHk4cBwa9"; - sout << "J/vAlf6dDaVh4PIZy6PF783iAPRusNy0TcCxXTJbIg5YqUb5QAyJ2HEPbIaKeZwSnhytAJKP98JL"; - sout << "JC+81f3cN/tJKfWQAJz4RgcrbhUfyf5yWK9rPOwvFf5WKfecfPWc6wpT4IqSrlDe3LQqxpFxJwfG"; - sout << "dzNo23TgOFK+H176FNuW7jXD1sUsh9MA3Yycm3BWZ85cK55DOI3T49K2WB0KnFLkhA9wPJNb20qt"; - sout << "m1M8QtKwF6jzpMnbBff/vM4oNL0K0QzXovI4gJTDUkHWUlZ3XxMk9PQIqoKZDp9v2JTNW6cs1zcV"; - sout << "Jcm2XE2ZhTCFmOQ/DIG1AQIzQfOY6s/VRvHPSkIJH76fo1ex2jj5CmbGw2JFNLPDQIIHEjQJGHFw"; - sout << "KpVGso6XF6CdMtcmlswoRrIvN0odvC0md0D1lf09ZuoyNt68aMSxgeBhoQYW4qC6E86Hef3TmzWO"; - sout << "esZCvDs2I3UVKgPEkICz2TEHy7dcC1VzU2k/F/cm3+y33lloDem4Dh2igflppvhthcYCLOmFiEW4"; - sout << "YtxiVJKpIAKbNHqv9qpxNdcbLCsxkENYKwmmG8E3fLSyE7St/z3dvuTuDI35lxANzv1N04YrvfEr"; - sout << "dIPmvepllDz4Ua9TyYQoZezD6UsivW0gfWdbG9dbYnwAZRKEgQjRD1zvGUt/nGCUKdtBDh/Qu7jD"; - sout << "c8KMBJx0meoY4jLZBSw3Rccd/KOvzC3UTSsBeTBSkQL7wuSMWZf2cTI3BiWaVTaUXREVmUG0eeSy"; - sout << "W+Vym1qM2tPWkUm7V3toeS94LU44OlGDPyoHHUOsT663Zew0ao3+rSqS+KASC4L+6oqP3ffSI2WC"; - sout << "517CtYtPA09gFqdWnN02mJ/+gEWrYUZXJsNh31AGQ4e4N2L1Tupy+L+mgkjTyHeiV6dUsvVQ2J36"; - sout << "R2VL8EOQcchBMinBo0WKkP6xoTPcCwwMI7T5sHHR+KVUs2DJXTNluNFhYyOic2ImOwhoOHKwfr7I"; - sout << "bJERGZYKwwBqGPO0mMnB81MZFumFzoo0SNhvNC9a74X8U6gKtDsQCeIHNXWsWxaO2LmjhlZqXEMC"; - sout << "nrLi4UnXweqUgDscbWdq6fE6Ad/ZimmUJlj5iF6aXWj51B2VIgtYXxBFlVPURZDw9z9KPdyidzM1"; - sout << "PSitwb6KwWZK8fJ4ZUVOUt1bIki9wAnpyDdAhrPtDVtngS8RJrcCVRrjQ91Vhr95kSTG4b6VtN23"; - sout << "m3lhkU/T8RAVAphAait/TICzXeXdnFjALDIubsx1e3FMhV/TJHflVQhnahwTaUuIVqb1ZkmP9aMw"; - sout << "0K1G37NbwIRzyHGVWnvJXxKfLeV3n0OJZ3W5dDmTOZSE1s7JdJ4rdEXpiMVsW07TB6JEtIz0c/AV"; - sout << "IvDmgF9QH5Ly4Ko171Lg/tVMjBIhCiBU4zQco6brJHx+MoxEsNUXgUCNoMqqjd1a3F5wGsvhlWpn"; - sout << "iwNpTje2A/ccVQmoJpDSNByMTB/0GsGJTjZ0dWR0KiltaQaKTlRFlGn/2jgbk+i7ujAGj/Gls6DY"; - sout << "WoR/asND5U/rlyzwJS77EefK16ew8w3Nfy2g/vVvpIUQBG67CnjUzxpnutsI7KvZak2Yehg2NIZQ"; - sout << "IAuyXMd5zixobwku63RvLT6Fd6D63HnQhEtgtPTcLJT6rQOf2cXAXN3RLOghcpM44flJ0PW679AQ"; - sout << "pgVrmELVQr2Dvv2fCb3W5k/JdgvTKrJ2YPIY9Y7q5aSZ28VC1u1k6y/KsppJ+6t+TW8PloS+qKNb"; - sout << "2tawgDRraMsNVUTMhABYEPZ+qoYspJPV4rKfVnELc8otpvkR404ulUsELxml0TndtntTjy/f9lmi"; - sout << "I7pfDqPsOUfwUtdhuW1XyIhX3RFmavc/VFLHu8gVSmJgdgxjraoe1ldt4F8vgQu22uZu5yBLtxpw"; - sout << "WgKVifBtJx/lZ4iAPMNJUZt+Fo+1K3uofYmOg78dsM3BSeghNcNI5ki4NrUJ3yWTzfvrUIr90Ee3"; - sout << "VUaGz0/wtOsFI74ef6BaTCYNAt7psf/dwoow4r4FzHgXNqr9MtWvfp22gGCaRLuUWTHgRzIkCflH"; - sout << "YyNFYHD+yTaKmSrYay2bBYFGRFe6Vx9b8FR7fmdyqq4HzRwQ2/FVeSQ50OHeT3vWTTg07M31JkZY"; - sout << "VlTjnw8Ew9N+o+qI9AFaftksVdXr2YjXMpJMwbHcqK6himQLSkzkUEQXsBI6vQSPobBtPM2oNlCs"; - sout << "oEf4AvHYmHxyyzVdSRjQqEoekWURI6htJxRQh0DaDhqOaRQmUp0AkB5StSD8z6o6Wyf0yvzT8OJo"; - sout << "NEjaoZbz82eivQUGf3RmYLZIx4xjZ32GA2fUN50RfgyF/KzW1GNLLykJ2NK+saJKGZB7RC2ZlsI6"; - sout << "CmkHIZeNwG131Opp+ygasp0GBJUzlKnEzmV9CIBigCv2oPPxewEr7T8/OGDPXWhY2LEgVbgyxLdD"; - sout << "MnZlJC28aanAWGoGMcuXgyacFhOWc7I7TTml8jlQv1oDRJU39PQwZZ93HwhhZ2s87wuRYCQdXSH+"; - sout << "pdtb9YblyosciNtYJguXl+2iBdGGIqNAp6oxYj/rI5l0pPY7EUkGEnOzQq/U3zCDPL1tdUymaOh8"; - sout << "+XGYMMo5L34oxvi79Rh4snSaOO5h0fl0aaZES/v/x5QTtQu4H7qwVfWIsOg8ujFFDFeZmmJpb7pc"; - sout << "ff03fNUsHBfS3yf1JvrXhVGDh7byfy8DTFCy07gXUaKJzQJNOjEqX+iu25I+RNxXbfHsRxsWdNEw"; - sout << "6aHRUUb+zThVJGkglO5W/S32SJznnjkHdFu1WXBU/DbM7b/quJTUgWnZRLy6CugMu4I/hp5ArKCh"; - sout << "vekyQySI/9TjOEPEFW37few/H060cZcz1V3DilvOTBrCoItzdjxZB/cmGxPln3mhkPqGr+NsXRdJ"; - sout << "tPMRc91NxvDP1oBnXXEYD418bmxfvqbXZm4Q+bMq07TT5rWABCZ+NFmkgkXryGhfKQWqidxbRenT"; - sout << "8teao4iAbwSHWB/Za5+OPYUS4b2u7OULXqkmbQDnTeJX6ou0VFYUpkXStbtLITLJrvAG0BrMq7G9"; - sout << "09vbgw6e+krF5JHaFXKAgVf3/SlvRrZi6zgPT7wsY1WLGlMAFNAC58UhizDbVV5Xivj/mVxi29s2"; - sout << "tZHKQRshEnuw1KvEp61O4HEnO2dw27v1000YgRz9HtQp9Ra0SsePIjlh8/h5O2VTqJgMlqgAiy9g"; - sout << "l7nvX3Ft3a/K7S8GlVMwM8z4DiSzNf0irgnC/+sVu3ZAy13UiviJTv0gZ6iVL78GdPSqhKq6x8IU"; - sout << "JGX2sbzthVZUpYPm65WjEBKUKsHWIdeAokKh+sS2TGEAo9COawULVwzYttKSY30UlsBLL/ofpjF/"; - sout << "eCWfzunbpZ3MmkXJYVygXCsGgEuxDmWrhcxIF5/pPZDafmaxqHCml/zxew2twDN9lEJV/jqZrwSL"; - sout << "I2awqrzxIp/4TfqYj4C8HOQGb4N246snRl3iH2tvzQZrCg1I2mp1s0+xiHESKtfecHfMt8hbb2QZ"; - sout << "50c/3MAKQb9WatUDqfZuTnnwXMo5vm0Sh9KqLYQj81LFOzKzf1NDil38GSmFGWPsNm7vm8Q6S6BI"; - sout << "MZafbg2gM+ohtKS/u/36ZADS9/bxf90Fzkn5UEjZUOIRBhYowQNilZzHCABNNXFO/5SUzSJqgLIA"; - - // Put the data into the istream sin - sin.str(sout.str()); - sout.str(""); - - // Decode the base64 text into its compressed binary form - base64_coder.decode(sin,sout); - sin.clear(); - sin.str(sout.str()); - sout.str(""); - - // Decompress the data into its original form - compressor.decompress(sin,sout); - - // Return the decoded and decompressed data - return sout.str(); - } - - // ---------------------------------------------------------------------------------------- - - }; - - face_tester a; - -// ---------------------------------------------------------------------------------------- - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/fft.cpp b/lib/3rdParty/dlib/include/dlib/test/fft.cpp deleted file mode 100644 index e324dbba..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/fft.cpp +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright (C) 2013 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.fft"); - -// ---------------------------------------------------------------------------------------- - - matrix > rand_complex(long num) - { - static dlib::rand rnd; - matrix > m(num,1); - - for (long i = 0; i < m.size(); ++i) - { - m(i) = complex(rnd.get_random_gaussian()*10, rnd.get_random_gaussian()*10); - } - return m; - } - - const std::string get_decoded_string(); - void test_against_saved_good_ffts() - { - print_spinner(); - istringstream sin(get_decoded_string()); - matrix,0,1> m1, m2; - matrix,0,1> fm1, fm2; - while (sin.peek() != EOF) - { - deserialize(m1,sin); - deserialize(m2,sin); - - fm1 = matrix_cast >(m1); - fm2 = matrix_cast >(m2); - - DLIB_TEST(max(norm(fft(m1)-m2)) < 1e-16); - DLIB_TEST(max(norm(m1-ifft(m2))) < 1e-16); - - DLIB_TEST(max(norm(fft(fm1)-fm2)) < 1e-7); - DLIB_TEST(max(norm(fm1-ifft(fm2))) < 1e-7); - } - } - -// ---------------------------------------------------------------------------------------- - - void test_random_ffts() - { - print_spinner(); - for (int iter = 0; iter < 10; ++iter) - { - for (int size = 1; size <= 64; size *= 2) - { - const matrix,0,1> m1 = rand_complex(size); - const matrix,0,1> fm1 = matrix_cast >(rand_complex(size)); - - DLIB_TEST(max(norm(ifft(fft(m1))-m1)) < 1e-16); - DLIB_TEST(max(norm(ifft(fft(fm1))-fm1)) < 1e-7); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void test_random_real_ffts() - { - print_spinner(); - for (int iter = 0; iter < 10; ++iter) - { - for (int size = 1; size <= 64; size *= 2) - { - const matrix,0,1> m1 = complex_matrix(real(rand_complex(size))); - const matrix,0,1> fm1 = matrix_cast >(complex_matrix(real(rand_complex(size)))); - - DLIB_TEST(max(norm(ifft(fft(complex_matrix(real(m1))))-m1)) < 1e-16); - } - } - } - -// ---------------------------------------------------------------------------------------- - - class test_fft : public tester - { - public: - test_fft ( - ) : - tester ("test_fft", - "Runs tests on the fft routines.") - {} - - void perform_test ( - ) - { - test_against_saved_good_ffts(); - test_random_ffts(); - test_random_real_ffts(); - } - } a; - -// ---------------------------------------------------------------------------------------- - - // This function returns the contents of the file 'fft_test_data.dat' - const std::string get_decoded_string() - { - dlib::base64 base64_coder; - dlib::compress_stream::kernel_1ea compressor; - std::ostringstream sout; - std::istringstream sin; - - // The base64 encoded data from the file 'fft_test_data.dat' we want to decode and return. - sout << "gO1l2wKz8OsyeYMPYcGx6QdBG65vnrB+omgAJ7Bnsuk9vkTw/Y9Y/UZEFXhVf6qnq92QHPLV16Fo"; - sout << "a+IUHNTjoPAfBOTyfb8QRcTj9SaWpxA65+UCJ+5L6x/TEyPKDtB23S0KRpRSdfxBSW9/rnUrkIv7"; - sout << "6i6LWcxKzdsw2WGsRCX1k3t0adQW49m/yb8LV9Loqs7/phzY7HkJ4D2PLtpc6Wyk1qG/h6KQ7nkF"; - sout << "GFkHIoh+xKXhHpqWaSofx8H8m/++H++g0VSPqfQ1ktFz+K8UtiGoyR2GqpP+br47YLXG3WqVU5Km"; - sout << "Di3+IjQoBH2m4jykD926aRvdRrgUH4gZunokl+U6shv20Zm0NL8j4A46/2f++YPGCVBNJJmcJdI7"; - sout << "9RlPL9SFbJ8rnH5bbLvZ2pKZmmbeZN78yzLUhdGwn4DGpf/Zo1fU2YPUjVKkwY6olW4w3tiBl05a"; - sout << "cS1HwBeQjnajqsXNyudbrBkM1Z9XiwM+J5iMsu5ldaJ8iLn30W2Te2RnZhJRHO8MgL7Fn1j0n0Qb"; - sout << "8dB+6aQYv0l/5LQkr5SX6YSRYX5b5rnqhi8IzJKms6dzoyBm97IGTm8pRxtLXcmsk1MvJcHF2gl2"; - sout << "CslQazsl5iIS6fMxEodmlMdwdfIpp/6MqmeIydSHwdyJJZnNPl2p5X+Il5egmwdaSoDQNphPfTaQ"; - sout << "R0Xh3xqsZKgHLKxB14Rsf/R7Eu9ZASTByX3UrEHsSzLSUo9/G+tS3n1iC30Liusksh2Wkt+/QtDy"; - sout << "A1ZX31H5OlSFwCYC/TYitwyl4U9k7WhHBDoT7MdmVTYQEK1dK48nwOhnZa9prE8n3dD40CCe25q3"; - sout << "Qo4VVYc5tBWu1TfTbshvkmHAcp3Gyw/caqq6jdq5Z2BD1b67i/bY66xhmowOFS8xeA7v6tKdkvpp"; - sout << "Rk8FegzVdB72wpw3872T4K+eplMDcCPGkwIieF5pZStWxhGsNOC0p2wvpFvTpQgfNOGUvRt69hsd"; - sout << "xaUEYlWZcY3sfsiOwPGgBUEEv6b+8W7+8Ddj8Nx4wG+bdWozphfz7THbmOeaDM63imIEHmJbZ47I"; - sout << "QgoyzFD5WoWtZ1wMEv4LL+a63B3FzBcvPvdPaa2QEmyiK9yN7GEePs2Fv2A3ymhGw5NeR1dOzAjz"; - sout << "lEQW01p8opk/dpyLO18zj8d+Hn4EnJkKD0p1u+XuLRda8AnRu/WmSOOpyG5EUrUoEyuvbECLbY9X"; - sout << "3AMgzkbxltmZlkyOOwfCGM0yumGYKdz0aGKdyid7ddLMTpQ908dCNLyRgTybdZG9137PQirgX5+O"; - sout << "08T/+L4EIyyrslOYxpUaLm2ASnSUgiivoIJvfnu8IeH2W9fPupY89ioXIYuwZU8f9FDCA9z7peQw"; - sout << "9H6l4PDdDrB7nwQhncpV9FYLkHQLbSgE1VD+eL6Y2k48pI2zUndcoHEZW72NcmK6E8fDvfgbKkYD"; - sout << "m02RiGuj4tvEEsIVuVa29Q0JGO+37n7Mlz7+RMcUMo1pLnh+jibas6R+1LCy7b4ubiKMFB1gvjut"; - sout << "gjMABy1dJxSOdb9xUa0K/Alwwu3MxdkrbTxwqkn0C2JnVV7z9S2I+PWcfZKzcpg8Itzh/ON6I/DE"; - sout << "EGK3s39XhLI2xPg3PE9R9QMaisqxb3FeP1NkBXrLQtuQfrSk+KZk6ArQWVgtem799fxgipQsa5RH"; - sout << "z2Dq9t+pJzNGUnWg5PWzaAY3lWMscn+BIRhsZfDJ3QBtS9Vmib8r2dtYwXi/Q+FhnAHFfcXbhDC3"; - sout << "GHn16aP2PY1sw8KMtfPRAcqY8Ylbr9EQXjWoIYUs0YyX2Ks8ZgibunTPFz/Wu98RVYswMtjubFaJ"; - sout << "jb0pK9S6qoe/w10CAAHqoAfca7uMOxw9trZZmjCf5vF4leH/nDgsNjesYn21rE6rLhSbg8vaZXo5"; - sout << "I/e1uhZlRz4ZNnMlZSnL70Jt0IjuR0YNphCsGZjmvvZ4ihxrcLrHvAcSTJuqW5EARtvjyQWqBKSP"; - sout << "5XhlkrI73Ejvy+Lhv6n6O7+VrfWa/tGRuvvAToS1wPOP1T2oniDXsNlD0QbMnCao+dTWgkTDiNTk"; - sout << "sFxsoN8YjwHqYUAp+hfnu1Vh2ovyemAUmo87vuG7at6f8MgFSuZffmBkGuijKNDDy7OrHoh7+5/+"; - sout << "aOkcvp0pW3ONZ4l6peRNvzaW5DEBTvcZGvRwVCHWII1eGpzeJKaHWvDfLqjaPkFrG5pR7SGCY/9L"; - sout << "73W2U0JCe2h7VjWbCM7hdvJEgYi/mEarVQpt+0P834es6Rm9rsMCbgbrWl7uv35+LVMTHU29Oxln"; - sout << "bDzBUJQs5KIA81IWR3R7D+HuJvpMkAYMF73c1owI7K74SBOsTq1ayC81aNlK7YwOOjZyBqwsQ5sy"; - sout << "zZi0k9AcKRGmTC323o7Tp/n/gkAU3NObTnqPEJitjGloXqrhPvorixBhHXSZy+wgL5R+04KiF1uU"; - sout << "LEFOzJ0zKUMstTB+fgC7D6ZnVEtUq3HEYnmaRRwEhRSgMTLXE8VvnOdo802pMVN5GMCkH299rJm5"; - sout << "Ina8mTwlC9JrNuYHot5KK/Gny4KPyUeS51cifByPwroemwBHe9EmKCkcEJPoDpG3QMaV36aopyJl"; - sout << "GwhZxaZSqbut9XSWr0IMxHUkFeslRB+n/7Vx+xWpDNjQ7JA5S/B0ZW+YBQPcjA3sRQTey25JD4Jy"; - sout << "RsULxNY5e3mjn59fI8OpBOYfNPTt2Jzppm1GDpym0LHuz7KZ6xk6QAyogk+HMjC/5RcQA7zJWDRM"; - sout << "dXC4CXUjrBxVzmm/YHXv76LrsaFdzJgn+/qzlM6IvIgicMhcJl+hA1swTkgcw6JRalJiDqnvapKP"; - sout << "V+T+/X5PSNMswgZURHQJ2l0PkMrUT909pBOC9t4GCsK8k4rYS2o0I0UYfcpm4jMRU5X34zlT8Qv+"; - sout << "GV3mA0oGq1U2dJwArlPX3gI5sZ2Jsw7Qa5edvQNG5GoRb2j2Muo4AkZXXjbx0KEa5leLIhVL4BAE"; - sout << "2GTdbL7T8hUGY3QlRQGwSVAytjUfXg4jCyn9w6ZbxUOu5MDBuCEtrhRSJNKuBLInK3Bh+fr2FshC"; - sout << "T1eDtIFE2EDEaSbLj4NCNWpTFdKMXZ9CQg2VtoVOIJfgKzqAjjcWX8kqWpMFlQgtdTfIqN7gnFit"; - sout << "do/FO0OzLghevyexHdl+Ze+MjITKOF0mTPPMkcIYcINIR1za6q3rLDZg03+GouzYhL8lwM3WAnkg"; - sout << "Qg+NM6reQATKFK3ieOxacZYnIwOR/ZMM/lO/rHY/ZbdAnJHbMBWwRtK1vDi+o+ZgS7EgsDpsmz/l"; - sout << "PguXPK0Ws51OUhIJJ5YDBv+nVPJabxOYV3dU0z49xFpxNTW9pTISo8mKZvLp2D765kExGJ9YKoAx"; - sout << "Hfi6WEg3pFS9YQLNhOZjE4bQThugIWXhi+2OPgqUIUoV5ctSnP5Lv+xhbkZfjnQQQQffrrU4peSz"; - sout << "6CuNEVLuNuG/mc3WEDZwf1HxYv3u9pr7A79QG0EROf23zPzaf5biE9e9xH+ruPApRHM58H2RpxXU"; - sout << "RlkYnfoAUqyvT3Lhhk6ngv8Axhi4otvz7sRiXQmZO7mtzWzsCTkCJoziwRKlD6P6LYnbm4fRYP1M"; - sout << "MvOuW3NhsQNrsDtgMuvqiVQpRzg157ES1i1qnTjJxTD5emK1RljuQEetbGksyetctWdWiEd8ZfSh"; - sout << "DHBJC2FLucmkMt0LHsVPnk4ni055uMRdKPRKjTE2MjpEsxR52xiWR3MtwXiEhH9fZnUl1IdBl3PG"; - sout << "TfLiZ286m4ePm6JOgNM1chtZir+q8pr4ghk/xycWvHmgkqT9dQcFP8iEtlVLCS22/2mS79cTev2r"; - sout << "yE90otp9vibcTnpORzrnLrMhhpmYRTxRjRaHGhwdJYluARJFBBVTMEenK2ubdLOJ8skZjLzPv1dt"; - sout << "9IrO1sNUwrMpEie8PG7D7DzQ7//jdlC/HUZaGKrwj5aMUULi+ZYiBLYoeL4N8ozAK1u3KtXLKlRE"; - sout << "3Akys4Py8+CmrY5qaaDOXZvwl3FF3skmGhx5KValRXrbndqr3Cks0hXglHgNonZh795galZwu0Jp"; - sout << "ww/mTQLCV0djTdEfjXBUnP49zyGXWWsEsl2jfqEAfBDcT4+mMzAUtBSwwPJYXXAJQz45R32MThNb"; - sout << "k21X+rw63QJe0zIbOJepHz3jaedMkj8GKNYBjqzibNqfYelunBUqW0bpi81HYdN5OFY/3GNKgygG"; - sout << "4R5HJaP+x9e1HxehpI/4pKFC+TAIb29uSV5GtkNTb1fYLm0kjeCZNA5GKtf42gBY52N6STl+lcI0"; - sout << "gD+jJ/ogknne3sRtEJEtCFFe1c50oikyJamQbeUO1PcDUBt8Phl1rI/p4PTP+H686usJVhSDY+b5"; - sout << "9CdS6F7XSSDiXlpFl+Esex30fRZ8zAQsTo9oN0sSZUUJKcyVk0dCqw2mHWPpyM6hYKQ3ij1nYjYl"; - sout << "3PzRfFMlu+dgStcBn70jvlEv5pOWXb2OqrN9nJtb29n8jrB2K2nlbcYoPPiQ3yXk+Wpom82LoT5W"; - sout << "F9NeNwwAB4EDWtB96OU6noW8NHJj7NiADQJGvQpk/3JzIzeBJQCxULYJMRJdBKf61+24F791reHa"; - sout << "qrH+rLUrrv05dIPDTUvGW5LQLTTFFa59OmMIu7WJE7Ln6gMIwDw3FXnGFzaWnHlHL/9jJ0zM1FQL"; - sout << "kfK4wTd++GbeI0gsnXWFK0N0kV/FiHm++J4udWwIXZxH7qZCHtwlT/5oGDVujtAtOPag+txUrjVc"; - sout << "G4iLeiPbV/2Vfc2D1oV5/yyXDDii9qrLH6SOOfgvdiJZr7X3uMUIDGO75x5wBDSxr9t3I2CrX2dM"; - sout << "M6kD7U1+bf5QVRbkh3Us4NAhFVnLNEcrm0x9Yx0wRmxPKgJeGGbWi7/BHi8ShIFllizuxuMyfypC"; - sout << "hhzSlxxbYAQwtcC3cHEnyYZAO7HC6hyke+HQJfxAmKyfguGtzEzsiG18XJVruwz7IoOpZS/O71zy"; - sout << "Nv+T8trOhy59ZUAgIsCAAQJYEBWl/T/qFtkE+tITbVRKtHjbxHSeN12OnHFRoKguJYaakTo4qLs0"; - sout << "fr4E4nZUMfjdF7oI7YutegY9TkiJ9ujLJw4pfY1XRtPrRukEl8orypWXq0gErnYO/RVtK3XImrDp"; - sout << "LY5sXH5pNzkqVH9VCl6lh9sg2HWjNwv9bDcDlIhvTL19Mx9yUtx/iQtG/OKy22tW6ByahPNnMNtA"; - sout << "tBVB38RLf6eJr68mhn10Qg68cXxVL7/zEIZd9rUaCo8xCzeFblDNErKfG02JJ6fbQ6M6ZdNez7Q0"; - sout << "x2IYbz2DEk0wHmR7OtA/oTFMvJlyMt+dDWTEpHnvqkbe+veENpxn2WWy3UsumkvhhtzzmLxyD6Sh"; - sout << "mMbMPwgUjvMG51JfRrgMfJzT49z0sebSfzvid/9QV4lNkR7s9nfUJEwAued4S4klRy3LiFdQhjQR"; - sout << "FOZZNqUge8vxVOzVCfS+xsjvnGrd7azt7LJg6wPXFgPfeE2bRlx+8AoRFG7SUpudmm/bkNw+uNgS"; - sout << "YRdaH8p16RyNoMlSfi/7BNDhtKwrl202pVuCqhFey0mPYehYee2HhLZs6ph+HKMYy8lZ/ac1Q17d"; - sout << "1tcI4WH0Hz0B/3GWl8xWfoq2OO40EIjuCPNhk70MpiytWXggJrKoKPu52GOqTU8+jZ6F+u6U2muZ"; - sout << "6QZLYXDwPaNz/lq5U4ACw767DkhUHd1/h0g6r/RwtLKxdrzYldQto99TAMmHc+z9aIciTv7kl/Gs"; - sout << "WA58nI8aODhwjIkOGaExdlR1k/3JR2tAAj5vRzYlJeakhAA82pA+8xMPZr3HRlQx4DlEjH1spAA="; - - // Put the data into the istream sin - sin.str(sout.str()); - sout.str(""); - - // Decode the base64 text into its compressed binary form - base64_coder.decode(sin,sout); - sin.clear(); - sin.str(sout.str()); - sout.str(""); - - // Decompress the data into its original form - compressor.decompress(sin,sout); - - // Return the decoded and decompressed data - return sout.str(); - } - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/fhog.cpp b/lib/3rdParty/dlib/include/dlib/test/fhog.cpp deleted file mode 100644 index 88377bcc..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/fhog.cpp +++ /dev/null @@ -1,684 +0,0 @@ -// Copyright (C) 2013 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "tester.h" -#include -#include -#include -#include -#include -#include - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - dlib::logger dlog("test.fhog"); - - - class fhog_tester : public tester - { - public: - fhog_tester ( - ) : - tester ( - "test_fhog", // the command line argument name for this test - "Run tests on the fhog functions.", // the command line argument description - 0 // the number of command line arguments for this test - ) - { - } - - template - void test_fhog_interlaced( - const image_type& img, - const int sbin, - const array2d >& ref_hog - ) - { - array2d > hog; - extract_fhog_features(img, hog, sbin); - - DLIB_TEST(hog.nr() == ref_hog.nr()); - DLIB_TEST(hog.nc() == ref_hog.nc()); - for (long r = 0; r < hog.nr(); ++r) - { - for (long c = 0; c < hog.nc(); ++c) - { - DLIB_TEST_MSG(max(abs(hog[r][c] - ref_hog[r][c])) < 1e-6, max(abs(hog[r][c] - ref_hog[r][c]))); - } - } - } - - template - void test_fhog_planar( - const image_type& img, - const int sbin, - const array2d >& ref_hog - ) - { - dlib::array > hog; - extract_fhog_features(img, hog, sbin); - DLIB_TEST(hog.size() == 31); - DLIB_TEST_MSG(hog[0].nr() == max(static_cast(img.nr()/(double)sbin+0.5)-2,0), - hog[0].nr() << " " << max(static_cast(img.nr()/(double)sbin+0.5)-2,0)); - DLIB_TEST(hog[0].nc() == max(static_cast(img.nc()/(double)sbin+0.5)-2,0)); - - DLIB_TEST(hog.size() == 31); - for (long o = 0; o < (long)hog.size(); ++o) - { - DLIB_TEST(hog[o].nr() == ref_hog.nr()); - DLIB_TEST(hog[o].nc() == ref_hog.nc()); - for (long r = 0; r < hog[o].nr(); ++r) - { - for (long c = 0; c < hog[o].nc(); ++c) - { - DLIB_TEST_MSG(std::abs(hog[o][r][c] - ref_hog[r][c](o)) < 1e-6, std::abs(hog[o][r][c] - ref_hog[r][c](o))); - } - } - } - } - - void test_on_small() - { - print_spinner(); - array2d img; - dlib::array > hog; - - // do this just to make sure it doesn't crash on small images - for (int i = 0; i < 10; ++i) - { - img.set_size(i,i); - assign_all_pixels(img, i); - extract_fhog_features(img, hog); - - DLIB_TEST(hog.size() == 31); - DLIB_TEST(hog[0].nr() == max(static_cast(img.nr()/8.0+0.5)-2,0)); - DLIB_TEST(hog[0].nc() == max(static_cast(img.nc()/8.0+0.5)-2,0)); - } - for (int i = 1; i < 10; ++i) - { - img.set_size(i,i+1); - assign_all_pixels(img, i); - extract_fhog_features(img, hog); - DLIB_TEST(hog.size() == 31); - DLIB_TEST(hog[0].nr() == max(static_cast(img.nr()/8.0+0.5)-2,0)); - DLIB_TEST(hog[0].nc() == max(static_cast(img.nc()/8.0+0.5)-2,0)); - } - for (int i = 1; i < 10; ++i) - { - img.set_size(i+1,i); - assign_all_pixels(img, i); - extract_fhog_features(img, hog); - DLIB_TEST(hog.size() == 31); - DLIB_TEST(hog[0].nr() == max(static_cast(img.nr()/8.0+0.5)-2,0)); - DLIB_TEST(hog[0].nc() == max(static_cast(img.nc()/8.0+0.5)-2,0)); - } - } - - void test_point_transforms() - { - dlib::rand rnd; - for (int iter = 0; iter < 100; ++iter) - { - for (int cell_size = 1; cell_size < 10; ++cell_size) - { - print_spinner(); - for (long i = -10; i <= 10; ++i) - { - for (long j = -10; j <= 10; ++j) - { - for (long k = -10; k <= 10; ++k) - { - for (long l = -10; l <= 10; ++l) - { - rectangle rect(point(i,j), point(k,l)); - const int rows = rnd.get_random_32bit_number()%11+1; - const int cols = rnd.get_random_32bit_number()%11+1; - DLIB_TEST_MSG(rect == image_to_fhog(fhog_to_image(rect,cell_size,rows,cols),cell_size,rows,cols), - " rows: "<< rows << - " cols: "<< cols << - " cell_size: "<< cell_size << - " rect: "<< rect << - " irect: "< img; - array2d gimg; - dlog << LINFO << "get_decoded_string_face_dng()"; - istringstream sin(get_decoded_string_face_dng()); - load_dng(img, sin); - assign_image(gimg, img); - dlog << LINFO << "get_decoded_string_fhog_feats()"; - sin.str(get_decoded_string_fhog_feats()); - int sbin1, sbin2, gsbin1; - array2d > vhog1, vhog2, gvhog1; - deserialize(sbin1, sin); - deserialize(vhog1, sin); - deserialize(sbin2, sin); - deserialize(vhog2, sin); - dlog << LINFO << "get_decoded_string_fhog_grayscale()"; - sin.str(get_decoded_string_fhog_grayscale()); - deserialize(gsbin1, sin); - deserialize(gvhog1, sin); - - /* - // code used to generate the saved feature data. - ofstream fout1("feats1.dat", ios::binary); - extract_fhog_features(img, vhog1, sbin1); - extract_fhog_features(img, vhog2, sbin2); - serialize(sbin1,fout1); - serialize(vhog1,fout1); - serialize(sbin2,fout1); - serialize(vhog2,fout1); - ofstream fout2("feats2.dat", ios::binary); - extract_fhog_features(gimg, gvhog1, gsbin1); - serialize(gsbin1,fout2); - serialize(gvhog1,fout2); - */ - - // make sure the feature extractor always outputs the same answer - dlog << LINFO << "1"; - test_fhog_planar(img, sbin1, vhog1); - dlog << LINFO << "2"; - test_fhog_planar(img, sbin2, vhog2); - dlog << LINFO << "3"; - test_fhog_planar(gimg, gsbin1, gvhog1); - dlog << LINFO << "4"; - test_fhog_interlaced(img, sbin1, vhog1); - dlog << LINFO << "5"; - test_fhog_interlaced(img, sbin2, vhog2); - dlog << LINFO << "6"; - test_fhog_interlaced(gimg, gsbin1, gvhog1); - - } - - // This function returns the contents of the file 'face.dng' - const std::string get_decoded_string_face_dng() - { - dlib::base64 base64_coder; - dlib::compress_stream::kernel_1ea compressor; - std::ostringstream sout; - std::istringstream sin; - - // The base64 encoded data from the file 'face.dng' we want to decode and return. - sout << "RFYXmMpdiStV6dVZSJkJX8t7GVavYwTD+Fn11ZjivhnFQyvVJ5t39yJYrK6Qh6K58ovzMlgPiBLV"; - sout << "nd+ZR0JYVCVvwRapp+dznB9SG9dJbBrsYH68k04uOs9ehP8aK4/EXvcZG6s+rL0rnhVAf7SxL7PT"; - sout << "r/11jIuASMa1daKZjAm5Sc1icGXG2FJjO6CxM8mOzWJ1ze69MPD1bz/QYAWtMUqUUIAM0qOPHY0x"; - sout << "T8tdU+Vo6S6E+8dJpV6a6iDdocbp91meDQcT0/kadhC2tmn0eZoNulTn5MtmsmEeuPI2lLLcRJ9P"; - sout << "yt3c/OJIzI8FaDzYG6aWJ/yBQx/DJF0avAlh7V1UmbD8O/dMoF9nUFDwnhGyS6DYfTXxCYgVgoj+"; - sout << "Ik5RLHY0U/DhNTciFaLX41/MyIt0xcGtxhoVcvwkfIigKnYQsYfNpRdUWseRlZ1KYaR4Oc5B2tie"; - sout << "kH3e5AhrY/HtffCah0sf6MBWJEi7CH9AnVLDQefL8Ph+qCWJGf7cGnM/oAaHQCzHIHVi+mK6EBnN"; - sout << "1NDrzbdXmikwYneB3LUZxCLKZmxsFduB2HgiS0A+tTK6IYc+jqCHqz8N6Gw0sSjAK7rrPDTvxhSN"; - sout << "lX3f6E2IDfVmyvk0l3RhuA1PNEh/nlKR+YxcXHyYW4wGf+UfWScAzKGxrHLxLC7LQycCEaCMkU92"; - sout << "SQV5NSSlwKYKACabK6UJ3gGIpvuQK2Aw7VWmC0iLczqgWsX0GKJR0FAcVL9Ed3nV0Wd0s5BkjBsr"; - sout << "RbUKzw11Qu0toj6BNfwXo/5cY2dtjj93a+CBfNrSEuFyJzZU7cn890c9m+q8C41p+wQdf4pFpjcV"; - sout << "8Kz40Fyt8KtxItWSsACIwmUO9h7DGnyGskWBYrxgDV2VVlvuPAnnSCFPkbdsa/pfnohUq0C5a/ii"; - sout << "BjASduPdaBHpjZ64f+TIaXNAGdrFiN61W6e3fOx4fLFlzPQ8szyWuuDh2hIz1FMflbmu6UOEkQji"; - sout << "w+bwDDJ5OUFmY/00+3B0XAFmj7Pt8OQ70lAVLcX5fC553diQJzrrlJ5p9/8+ILln+oleUVJhtp2q"; - sout << "VCZ9XknXLjkQik30M7orOj+tZt7HDgC5sz/wHU5arOL3nIX5IuIHBJRlB8dERZgoPNQlB090rItP"; - sout << "MuT+Hyr/eR7Kcux7Fy2CoMxcIfWEXvxQoolLKC66q4+SFirdMRjXuwbRXrUBbenmBfMMNDAOkQKO"; - sout << "Bi7d8t1wI9ulNbACtqLbmPjW6iabc0yM4g69cZjRx/JYhV5AaykROJxCP6ZKTw+3ddAht8xoyHLN"; - sout << "40rB40fwEXIvv7qxCdCa3h6l6IRV26fOLdcew1G0qjPORcKK1TPhzmneYvhPZ1m0r6KxWNEnYcFq"; - sout << "WhDGNxj/05eBy2qIiIU/KUPhxKyipF0ekgPoCsWT3S8edYjoaIl5cI0TNpNEwKGRLQeOLBDt+MEh"; - sout << "z1yKm0i2jrtxDBpYf5FW/Fln/XJAK6z9yqSDDTDwQleabvRHDH9bc54bLc0TL9g7/eIj9xcshhaB"; - sout << "zbi7baB/yUnI1+0N6CZ45gV3BcD5n2QLiHME8wELveiMxps6MTf3SdKSRZJcnoVfN4AGYqQV42ec"; - sout << "dFB9y8FLZVL3/8rmB+XEu6YoiGcNK6iATLYQfF0GFRrur0Q6bQgdvXv1uZKtNfYfznsAAu/KBdxX"; - sout << "8qskZBMGA3LxJC3j41VW6Fviy+XUxxcmG9ykbf0COJWDul6ZQ7iRI7rn9EpFIYBM1lKzjdC0UFTW"; - sout << "yDWEE+mf9y+RZdlxHdROFj93FNwzSdzNr1yjqHvZHBZYiuArHEuDPXdxqVRePcID4EHzmpDgWFwR"; - sout << "o5qqDxU8e9UYfS8SG545SPZv69SJVJKld5fQLZ4FbcCjv7wTwrOKTROvurKkxopKt1n69BdDA14H"; - sout << "mViSyK22xK/F7/ydjLoqx6aJ8xyNpoUk6XIeJ5Ei2Lhk84VQk9dxzULVy3KsfRUrZCTTi4YiXkHJ"; - sout << "SmQx4NQKqHR2IOgnJBZuNG9J3Fzv3NKhQpmKL0ZbYLXWdKP9FHWUR0x7y8f74Su+GrplBsjh9NIm"; - sout << "QdaKLa3NvJB1TML1/GNcdJVZUuSaX0cQn4bbumvtcENVbC9u99fGnsaS5FOu4AHd3338zLUMy34C"; - sout << "OpJjU1c/IElgyKmaGYlAolgqGU3lixhxPGBhUlXGfHmST2ZWq/l6NxD//HQXRaRUiQGQzWCvhzOO"; - sout << "ywUlVzl9eJ5e5cdLWvffsPRzBgRMrdHJG4TbSuLAREsSD9QEGab3a6y+qa8T3Si/1Ut+Sn2QvPh2"; - sout << "meqqk9g0fRWtrWxcnbUDU6zMlk36L/o/y5inrHdGY+ixIewhI0n4/Nl3wD96SRITcEVSx6K/BVot"; - sout << "+qIP78I6uk+miUF6MW4AnFyCe1wRNyhT48638KIphSQSKdu7TaBndi2DNgFFvWrm6/cPOqkmCzGC"; - sout << "O22uwHyuY9XhafswKLH02+VD24PIS/Fw7JMP+KzvfCHQd4XxxdsISe0/cjwg26ZfGcnULLY2E+dX"; - sout << "LjdgCxNyFBzFTQ4gB4QExF0dHu+SPoo5T3VAojJbYZqIelFY+u2yQDuS4HCUISPkwuLHXHbcBuwg"; - sout << "5TeuFhyBrlwxHQC/OPACmQJREImiqpzrjmh5QipeEgYHK3Zc72tYSeY7eTzS4jj0eRQ8KiNIGSi2"; - sout << "2LjzAfN2Zm7HGbiBtKZVen96E8HLcrd3nSWnizfaLLWTWB3zu9zz9/vFdaa3TlO6BidYsKomTCgB"; - sout << "wy8yMeykE2qbxgrpRqEqmOkrOI9XtTTJIycfAlwBwoFwuqvGIPtFrYmC/MwRMCphg7acSRcjZg81"; - sout << "5IEqpoq9ca7Zc3s4foteVMCJT1A+qmNAJ/j7IoyeX7GnlM3jsqpYt9BmKfbw5Dr2JB9vzroPV++x"; - sout << "UN2VXRPbahjbIvrTULpeBdmlHU0i3Ya8H/C9RY6c2DhImZ1gDjgn0jQ9GC+CsZpiM2xBvfZZGOEu"; - sout << "c8N8pdo2owD8s5q2G5ZCGNdME/AG+iIlb0P00AX+XR8FYhxKb3y50i1giM41mnkKM/WMGFAnpiuo"; - sout << "YordYSi5plePBnxBfd1Iq46PpsD/n/uUTZMHs6TGp1hM6QriyEhOO261HNHoU+n8m1Omz2cfRJyx"; - sout << "AuFLwHSEqvGCSmslmoDpSg2qOaIWK1LWlN+1sYJj18iL4GRM0A5QzXaS0RThqEgmPjeBOkFBjfSO"; - sout << "hB7mb3sDbY49qbN6P48bGV+yF6y34gYAiVkm2NksHzN4ovwg4O6WMQZwEhNk+4gTIzG69jIm6Hbn"; - sout << "2l48A3CYmn8gcjZw39nrlSxpMf7KPkRsdvGmc5Qx9RjP71zH/KJ2TXP0xxzsaGgmqzXfey5l0Hih"; - sout << "XZtfZw8Y28fHBfm3bnIncS4w9S91no+RYMv0aqc9ty7l+Pa28ELwSgQj9eP4u/i5iq/GPmmSxiTd"; - sout << "Si/eeyK1RFJEP4Tv4f3PkV9Js+azu8BbtU+BLO1FBlVg3CzXH5Pc5FMujLdmlqa495hTmi8YW6Et"; - sout << "Fx8dkC80mYFGpVjS+B6pcQLbLBL9gmKzJf4L94/gXZ25BEDob66+XOaRnJ4RkSAN2g6gFJB9lJDh"; - sout << "rLerp3kP/ubPCvcFywuGx3UjJuwFNHE9m62uiaXFU4m04Kc4n7ccHc6hYUkhkY53v2Qb5SDx2qCf"; - sout << "Yg+PWVXujfYrqxRHSwqtV3yX5kMrtYsYpygb7crweOt58BWUa3duyo23UGJHaCwhGwXat6PEC5DQ"; - sout << "2Oe3LVJmc8eYtD97mHKFPhptBl5u2Bztb3zis/oNj1NdMjnDrNuscEAnrpk1CetvHKLglK63Zo/D"; - sout << "rf6SJcmGR2h9g6wAeV7UdsfD6AvteiPj5sl4UuY9x55pP3CTTYklBO1MaDd/XO3A66uMh95RZVGr"; - sout << "VWDd/uKL+rIuI+vKjz8rt80nv3SyUrY9fbftPdK4pBaVnIt73yZrrqv4Zr28H8XpFFQAV9BPlC9o"; - sout << "a8G+AFx/+W2cSfo9r1Uw7npVvRTe6TtIiKagYUmWpx5BfX0VH/VAW0FUh9oiVfx5rm9eaxfSQnD6"; - sout << "7qBINPxsKq+ZDSXni7qfC3J043Le/uL+3XUqsccvEMoU65akKC3lmw1txoUukv92oxyqPX0eOGsB"; - sout << "AU4JdXCldqjU9K3QhyCvv80ZWotGfUr0TlN1LVZqcF2iq3pX1UDOBsPwz9v0QNg8Bmlqy0Vs+MUj"; - sout << "nMCwU9xErzkXLsuVaG+Llk7mmAl7C34BF9O9qSl2kCmbQYoQ87zS7gm/pK7aKGNsICHrar6vlsKo"; - sout << "BJA++/8XKL3nseNZHzq7hKHnOTzagP52MRf+TPXbTVjQPKnCKVAZJcsOlkmuZc7iDnLn4muHDRjg"; - sout << "y09EYcYlFWhLAgsWmatQBsT028ytgMNrQGHDJdjuNkxYfPo+/91ijaaBiey+DgrUVn0fm20k6/Nm"; - sout << "colrwPwHrK3uOdgBn2ysDeUXU8NLMtR94fIL7etQ9tlUuufwrxEL9zYUM8tpks8HDR51xgTwUOVo"; - sout << "DyGFzOdYQRzwi+kkEPEwkpNQbB258d5w9G5eR00P8B/aSjm+w4FU0MsXM0GgPxnQ+gTpS1cezLTn"; - sout << "eelvJYiq/IInLLxoCXycZFPt3WFQqOBpcs6TV/QucjI/5xMZtP3JHUFv16UKPTFI7p9DF+8Ch5HN"; - sout << "gWXCnRSPdYR4ZRid+Xfzi0TvQsXV6u6PaE+H5MpyNMBWhCwxb6FdiLUW0BswGNpHBaFxjB26Qbmv"; - sout << "OW+s0OuXDvKigjQRkeaYawjRAIAN/+CEYR3oUad2HyJ5Ybr/lRlybQuuIqBhuvpkYzszS7BqrxOh"; - sout << "FJYaivT6r3HbHjaJ+Yz/zNW4KsL80zYkPMP7QgcbbSfE2mAavr+ciXdZBqMMUR50sDNLxep9+hoa"; - sout << "ys9wl75QMdx1jn1qn7f04JMSjCyZ7M4bWSyTW7VEr+NBBLmiMzhI6Ufh1iCUpvrIDSQwSDUL88wt"; - sout << "oSiouRbqizt36TldsvFV6afdLgjRrp2cb4vOQBiltwnY06JraGZnsrb4UCfHZhxd8sq/invK9tUd"; - sout << "D3z8hYyLGbS+3LBCK85r74IYvCuhoUp+KobIZPhvWuvdjmmq3SAxIKHNdLC5hnLVMhGJUrckc18H"; - sout << "9zK53uB3QXX6zGKK62Jph4aOdJoDQaPL0K/yHgn9UayEhH/N1uj3Ao39c05puaxzcSotfBeS5+6K"; - sout << "WYyOOMtt5ikKz79qfj6dVWge22fxXUc6yHYfdga0IbYWRocIx+DuyUZnrRQHihNKgYpvF2vhCX/o"; - sout << "R097oHI4ojZFAX/ZWJ7igJvX7ChiwTjK8KDk+vJ4SUd3IHXaiLkkkd9p6tCuc9Lw5jqWiGrrQKuI"; - sout << "7AmGsPFU2EsfOzmwdZctDGXq2/IutVDmwGiucpBKsRN4y12Q1FWKpceVj2q761LfDx2qJoeZKTPZ"; - sout << "jHPdXnGKcWy+DM6GoH9e5jP4CW+HfdHe474bHfLDbP4NE1oF1vdh4NcLy6woi47hg3FS60z+wePD"; - sout << "bWq29WsSwU5oXq58nMxKOBiMcbGFrkOme/Z59Ybi7Cw1+U3nGE3evCFyVMC6g4f/jvCyWF5I3Nm3"; - sout << "OqmkO6fmZ4ahql6C+RwfdRM8A3FllNPgO5riBNX6RA5xKj+JS+OZUrSSN+tUqcgN18IlmLBExEUt"; - sout << "rdG06PKy+WM8Cju3gtbOFX43H4URr9CQcDxWbN6NoqgF8k5a/4+xf7DilfGJg0E2Vu8GG7tmFSU/"; - sout << "LS6gtfLOFyEnQkTzqK8OhVPVLT62cEfCZN9ZY3iKQyZ+VLQhxwarUAgqeNAMXM40NBJqnUIaaTKa"; - sout << "ryhHefUHazhfVgx2+GikVF9wvMobCvvP1qYONlL9EH+ufuLEw1V35BYIIClbrC2uMrnF0H3QbuJQ"; - sout << "ma69tq8TDPkyDLiaczKuAxUzJoj9reJOYGYTxzP7AQKmmEmEZ2cX6+2klWcRXv23XXN8Ypjjnj+d"; - sout << "fTdzxV4kzcHwOYMsI92tadahezCm9uOR0d8p9IH61QQSlUlJw8tX0TpGkNhZpv23STjQhb+uxzAX"; - sout << "1vYdYbPOenr5vCyhnpp33QezQj9cLhSv1WweplUmZjHcJTkPBdflRA9AuqxDVVnbbofXd4EJDC6k"; - sout << "u7xBoD7EKC+kCEkx7ygj8Gv5GVKbgy1js4gLuYwhJ5aqdNpqm881kkxntfRMluVcdH3IGAUzWR5w"; - sout << "26eq7Je4Ttr1cC/xy452i3pJocbhCqrNUG85RyB5FXHAv6GMvm0rUIa6IyC/kfis+sQsdYkQ8GMQ"; - sout << "wL2s8fdDT6l38N9JbRNwdRv8Xa9QAjwcGNbP2v7tAzM5MyhHW7FImYVAaNAaLbzE8v95zeGpT8Cl"; - sout << "CWronhkcJRab8AKP2UcqAD+mW1hVEAqyDe7oWoZziKa2G5aW2vs/WG0z+NqL1zGvUekDcmJ5L4SK"; - sout << "XgdQgxMb/1k48YqYQZFtQrIqoBbYn4qPeB7i378T5TLcCgB6SldsFdlNzs/czN0doroozh3W+sli"; - sout << "d15Qnv5WMjOinjh0Ybt13wcUzeT2p0ovTtYLoiYAhDeAibydJETLdcozfpXFIJNUSoH6TcLge3tr"; - sout << "0uVP92B1O+n0MibJvLsLUKQ9ueIiHgZb6bUSUixAg89QCDRLCZgkg24DLZ4MMTg7IRfFm2eR2lmJ"; - sout << "Erpe62rf2+JE5JTqU88yn6kLK3bQ9vmaGRZ1NUxibTcdpo4hH91qIldLT+jrdmhrawRjYcRduYGO"; - sout << "WXgjTbgKRTxnqrXwRD4Hl/B1EV6ggYC+jn3LQHaT6bYd1hORmtuLKy9duSHVCNBAZvnto27l+h6g"; - sout << "VbUF8eZasmk+q8Fn83bx7C3eKoHjr6acEUyQxtWVCbmeaMd7h48Mt3Z3r8TyX3DkwQmpClciwpyC"; - sout << "E+pbYEWMZXGOuXPmcHTM/Iky8jNSWyw2lLVQQUzPOJ0v0dtNipYRZqBQCDtSE0JuA3Jo8l00uox2"; - sout << "bH11ErfGplsGZJejPGL8ba90e6xeLwH5oe/GduQ0/Xk4+faqBhy/7TFeexQcFDRCCTrC8+jATm82"; - sout << "vHo+NWJjjDlEI4+F2FOhpRg7MtrrzNP/e+cD++wYeGjkRplbxd5PeyALnjZJ6kghJqFLL3NJ1E4Q"; - sout << "gKmRErg1xWWQzyuDbbXPr5dwwRyZU0gkG0WTwyUy2dFV4KRyn2IbMH6STm+0af96YF0joZzkUroH"; - sout << "ztMN8dWtmQESq6EYQfGlhQzNoBKLXjN3LK4TMWBE+1N5ilXkgv3cnN74RZHdLhEXRJnF29x/DmVQ"; - sout << "qZQ4s31Vk0kqKdQ8tW0rs82+dMMtFv8+P2rYA1GZJQV4P5/TBU36BVetlN+swvULk4XpoqhTTMbx"; - sout << "Oj9tONiyIiJitC3YiCU+G5uL0YETB8nSKrtHRiBD8k7nYj4fbUtSbu9+lKRsVK7kU41mKdBImON1"; - sout << "6Qk0XqAx2DEK4w59khYMRRxOD4u2zZWDVp+Nl7Sd7ihas/vQx5yLXHKmIpjCK3SQYjJz09txIErQ"; - sout << "0wJJZoSxH8efhGsTPuVrbQpGcHLD7bIkWf5kjR9MmOBCmUGgeeGOyi45x0k6Cx+z9oaaTXYcvRtY"; - sout << "M+R8tW5gCLaOPjfbq4QjP6yfYogoaTiSEKOPcMgiOQKrXNiv2ahVBT/lvkm6Q8+IdesGWJtD6xqo"; - sout << "+CC486Du6CFDzAHcnLMk5c3CqDfFGl5Yf68bV4aGm28BaM4vikeKRhm2tULeM7PipfQiI9R9Gy/L"; - sout << "1yZB26qciwCalP4CA2NVjiJut7FZgTF2bO/g0qfvyKsAxMetRTmqALBJi8QvKqAE4i/8gRlTuwgV"; - sout << "x6EGsUPCIcQmD8aJkZgy8+erSAY7MLcnUXu90AC37BLyaOt0tzJKfVRb6cP8wfZHqJneoGSNAA=="; - - // Put the data into the istream sin - sin.str(sout.str()); - sout.str(""); - - // Decode the base64 text into its compressed binary form - base64_coder.decode(sin,sout); - sin.clear(); - sin.str(sout.str()); - sout.str(""); - - // Decompress the data into its original form - compressor.decompress(sin,sout); - - // Return the decoded and decompressed data - return sout.str(); - } - - // ------------------------------------------------------------------------------------ - - // This function returns the contents of the file 'feats1.dat' - const std::string get_decoded_string_fhog_feats() - { - dlib::base64 base64_coder; - dlib::compress_stream::kernel_1ea compressor; - std::ostringstream sout; - std::istringstream sin; - - // The base64 encoded data from the file 'fhog.feats' we want to decode and return. - sout << "AXAWQhjCEZzu/U+RFPgnRfCFsyRzQjyOA8TMshjEOL3FZhUZD4amYHfLuNN8NZrJyy2CdiXOWrFH"; - sout << "dTTKsMQkSz9f2VGKE6GCsTcZ+fpbk+d7fBnS2DEUkw5ttiSxj/VsrigkeV0MEUR//EP3/w1uvJad"; - sout << "96PFVeqVf6tEmcuuUbYzViC13lfnps7ftXmic5CwLZ97llqMYpLKgfEIXZpelB2al6PyVAg2FOfe"; - sout << "2L/SzviQ001tYYgx+L2v057L/lJdx2+uOQ7tovbsY0zEBEXTr14ZQW5Wd2lWnj+CrBNQ/4wMQZIV"; - sout << "86X5JV6nl/fxrM3eF5+U6U5cZoZFnn9vRONE0kf6/g6W4Z8qQNL2mJ/M8oKoLGtuaaEjymk0ENRM"; - sout << "0M9GMLrO/qfcH/DHUb/HaK851L5sPuf150ecpIbPmQpxTOpI5XwmvwDAP9BCmLazQWQV85wJJFom"; - sout << "LjT9dNi7eRsV0mNCZDwO9iwUTv6KfAR3Vn4t30X3n3+x+Yhnq5PU/4vu7GJpje25uxICm6+PC9bz"; - sout << "QJC3wiw7jrlF8eRb2kZywIJHWtrN39R1tddENrGZkU8LlPTDcqTqfuwC1HXSt0GKlDRBW42DkSxm"; - sout << "E7yKype2G4bgbSnuf/LKftuWlNXzMP3cDFdChtKJNOws6btgvS014C4UGWe3uNVp9SNAmAFyh+UE"; - sout << "rRTl1w3RNom0yvlee9IP1sB8mOEZn5Rrzo2lCyTm6w49PlLfnS293FxvnpRSSlvqUt1lhzzEh7Wd"; - sout << "YjK90oPWGqvNn/bP1vQW35KlVrc+JT9VlewcZRYJAq2OigVxa9Ao8Gs+fFyh8/Aym6Y3Z6+Y7Xna"; - sout << "fsmYdGaUtfniJemtzHatTuhbuo979fqkIDQ6bhHlMN35IyzK26QKzGrMCaHenZEKck9qR8NTkhc0"; - sout << "urO85952cv4aI/cJ5tz8S6f1v71F1gIz76zL0UNlkULQf3tqEleTqVF5Q+YKAtov0Tig9xiSuCZN"; - sout << "btjVVpg06zlRqmnRqWpZU4W7uu19MKe6BGoZ08l5K/3UNgucyuUBTGtTGt35QaML+N4WLcTYj90J"; - sout << "41Tlt+OD4C8nZ1ID982h7X+YxmnSdMNnaeM2Lc/h8twOwg11vHf6OSo6st4yjK201O8lH0Lemips"; - sout << "LsO2qhAsF4AcWVG7HKUNh5jMr7TTQ/SPP2qiJ6eglJYLFAlwtCSXRSJFuK93Y3eUtzDpVDh44tDJ"; - sout << "y+Bsa9oWJrBeBouo9DHG20N+wJB3rOVDprmq1ZGfhkSzqmVzPk6motDY/jkPGZ2E8/NIWpXpyU8z"; - sout << "cUbc8Er2cAVshJ9uGCg0tUh6lGWsrWucpgCS5lI44PJkbSuyFZMbIZrgxrVmkgOa70pmmuHebs+c"; - sout << "GW0FheFD0IHXVxaJtTuPeDuMML/YrAqdyzibareHbg2Hn4aS+qhRUcMyemOzrvjhGF23oSXbJqaO"; - sout << "sJw/DWkt33eFNqWxofXw2pWMMuF8akESryBDyGEfk9nofHoJhTciXGNkuxIiSZtVYsVnKNU9C4ei"; - sout << "31HWlbHjMtG9RD3zqkIXwerCkhElWfxG2M9ja1S7M4+0VrS9nT2ngc/n/KZDpinuB3GIOnnaqiqQ"; - sout << "8ASsOEl9/Ni9Lflomns/CdxWns3OlcU8KVhWHYz5hqV+MI6SQLlS9j39WFKd1IPaer4y1fd99x44"; - sout << "jkyP4ekjoVVfVxpJlb4favfwI1AnFD2K2TaUeULaALTuBwNT5DnRcLNnwqD+6r33rEv94Nk+2+bB"; - sout << "0QPLkojfPlDJocwcGon+z2EHQO4t+RPAafjQb42dNCymI/bIdgwL64vldhl9KfZtXhE4llYhYuLf"; - sout << "xliN92ELGSt8o5IdAsoOoCPdqQh5NujdDs3p8kVSETq1HLilGRnuxyVwrTqJEUC4G5ntPfqXr1Fp"; - sout << "revo1FOr4SRa8+c2GgA7K8/fvXwN59GONFMKxt+sI/xko8hbOQwOu1VEQ2Ak1aS0cc5MoUrhUFhF"; - sout << "gCTqGd+9bWwg95ELl944dD7MIauKl1wHy5iI7u7EDlhvlGhmtU+6lzCmBiDbbPnoki+yZLc0V0UL"; - sout << "jvaYU1WlKZhjWcA7fHkUyGchIe+KJE8DcW+huCO5iz6gPWwy3ZURQEW+wYPD4Sp6szOTOPsNKcN/"; - sout << "j9PxKGDbNO6/Rou+TEfznVuu4ltLKZSDfYMK9g37+XjMLHTU5jCoPm9KJDjFvCTRAcmRoQfwuXyY"; - sout << "o7w4QwcevrjFdb3/IYMrygb57S0iMkFJPUUiCF/bOfQA8tpLePYYtg2ILGGuH2UFwOLszxguBLLD"; - sout << "ziSVWU+xmCi46kKVuNE9gyeT2OCPtn/U+qEu2B89UkbynI5v/FVpJhJf6MjLc1jfDrEi5NflvvCQ"; - sout << "l2QLJGjtfDRJgcXFuuNzWBMiVglMOhT4n3bta7tV2KraK7Yc3Pc0GIZv/zVHf3BqeDEikXdw73tt"; - sout << "aomM2RQstiy71sMmGkmCvUnEbgrY8O60g5nCSmMZIFbbLit9dLyBjHFUELrLxXup7wmkxu+ZVEzT"; - sout << "FxshL754iYXXkXTqVGirp3NNNhGKPGc4g77Yne+nxpkZ4MwOi3wQ7YqPihwIkIdYewBMiQEJ4Y8W"; - sout << "0+Os7iD8OYrccbHKqvKMTE84QOKGZSsGIaCD+iIvv9F9/EIB2ZDv+2aEs/3ix85vtg8L2f6WmGdq"; - sout << "fOdoKVuU2pPIkzlyTNQAwai3NsjcnI++lEpVC8s0K7fpIN8uWDLRnGGuq/G2gFQEoqN8eP0E944k"; - sout << "l/YTW8+baMZVp/wQNA4mo3v2UvDdHrDcZmIvVuwEaAUW4dwylXMazecCG1SMkusYSXGoorB615oF"; - sout << "DaqndLnQSfyJrsXdBdZDAPmsssTuOvCjrjTPnb36+WebHGuLUNYZ1kqjhZt8hnxTFuYN0sTWb+UU"; - sout << "2tL72LNTK66l8LuuQKUMimV2uHT7Dsv4VX6XE+YXczrC0HycSaVmtshxRh99fnNTEtDKo2bXbSTt"; - sout << "s57BqGWi3/orxqSXecUPFYvQBjrIfDrinany5uht/8FK5JH+c4PMTsbiEeQ95RX7eOaBo6IoF7PB"; - sout << "zaXhJH5TW/qwdO6K/Caqvjp+no08tUTdn/hRdGMyQ8cIYXsMaiQKbkpXlGnhoBK34XA12T6pXa+E"; - sout << "QocfgTw773eQRFWN6vmhvuv8Pd3KPJAJO80slizTFSOvxVO68aM7gZdnDFTgfibe/v+2N1xIUq12"; - sout << "B+YWn9yGP232QOnNq0nuAvFLhuzlau3U+qR2n8DThKWTboF02vsqThaQzF+0EPFk/3we6AeAiatk"; - sout << "dcvXEbGk/TkGI1V5ICcpGS/fvivZlqYhAIL+yi5/5M3wPX14KwriXpFVMGKozUYaW05+27adupOM"; - sout << "p4/0EvfeM8T2m+MQ3GcPLA8njXEDbLLWnoZ+YMC3l2OVRMV/yFXkZvQd6tAQUymv1xB03lNv1M1K"; - sout << "tPE1Ps7ucMH3cOjff0fZOEYabEl81VbmYUCYfntdWlApBLrs3gBWiT0uLoiV3cJkq2VWtgpeyAcJ"; - sout << "PiZ4L7AblENmUS9gr/7gYdn3uridNqfoos0uvUCFrIS4a7siub0FpCMwiwSiyZwtUoD5vcq3Khza"; - sout << "DVGJoijIBo/yEgUTho23FJqMaOYyRnVen4i8GH1H7PUhJe7KThuQYk4UQP+XO1qdLITUwBlbNvks"; - sout << "ciB3IIN6QKQTcoDXEEQaMcPYRNhaaGYFDeSZ4yIRhLV5JyPhOiLFj5EOzrC2B14Op4lOkerAY2J5"; - sout << "cx0CN9xEUrm80GJGtKudSd0JKscXIDTBj9lxngSScCmKQRn4AWJ/acRm/fyc5Gpg5PLx+o0jCI97"; - sout << "hm6qOSqslV4GS3BozqP1x18yqrC++IJvOISjjfSvSAkW2s+qv4ba9gfNYIhsJgAan1vaAgSPDXOD"; - sout << "hf9RJHBE7Xi86Ux4uK/o/0GK3R4QsKa1/t6qij0XAlc6lmt6MXbSr/Tnjs4ykAbSjzmiwON9Jnzo"; - sout << "KYQiY46ULY+o+UjbHTMuxkTJQjCKtyertjpISD1yNYBxItA703l4ZLK0iklv0ZrFMyov8y4ySVmF"; - sout << "Tj/eFWy/PpTEQdyzGXrotmYbb+V+BG5e04bq40FsUhhALgSkcGEYoQtxLCZzkbyWQmEN/uXC9Gdk"; - sout << "wG6Iln2vWqzZSRMeGZ61VMm+dzr5CN2iHtFcNQnjwWHgr8C726YO5j5eWLvHqLouU8ufiojzvsvI"; - sout << "ycQ9aUfkcr3AXu8hv0+SOUK8mT5JdQ5aPXc9WOe4c6mdgfOK9Jq2ZJCLgQvj2swIoGQ4OVXn2D4t"; - sout << "MNaKJu0/5ujgOg/634gfxJbicVJLzn30TgWYXX6Ixj/JQW7yxM2iYyHyOl+/SltruQS+NnF+llzd"; - sout << "rYuXYejtciq7Sf+DFNOJPSaTJuI12jSl4yH4fOMMkkxWMM5QkFzgWGK7A90BJFo4Uhy05TELqU8J"; - sout << "FtUWdrngONpIU6haQcDpoYtXVQ8h06yZYJnVQBToS4szMcsPPUVYxITcGnbT470DR5+Rrsm4MSkO"; - sout << "ZXmf4sC2G/k5at6a8o2OKsohg34bNzdo+R6rpJLcMLmUogDdHj7uNjrvMXgZgN2VS33jpsKaVuww"; - sout << "0fm1I1pD6ltIfO+iF5oEOQz6Ml8TSxcGei4xi9Si7g4KGTZ6+KhS/KcdGQv7HsGH1+auYumQvKIJ"; - sout << "mWY1hPH9tLSAB5t6vh6YUg0Fx9G8Wf5Twz8JXsoyRbOs2AAvXcBQ5EPNbNiKz71rzPb0s4Kd3TKJ"; - sout << "cNZexkD8z0J8U/KVzDHA4kyJU9tKB2ZArGPkIYAWw+u9d9VGdxXgst9WtboxuCOy0+y0XiXez1nq"; - sout << "8Tib6FgDNCMKD4uk1GvVs697TYCphk9MlHPUevFlgBJuVI2uOjsnGjBtzQOeuWHyXoz8xQhyLtI6"; - sout << "MnW6c6lCs8REqpAWwuIPF6YLzAZd4uhpOyKFTWI5jus7I2Rkr7RmFDcOCXcnHw7M60Bvcgsa5xy7"; - sout << "AoMab6/pVJr6EjwK2JEmkLaxPUU/F0WqXpI8roFPbIZ0sfuUzZ7tZmkZtelboyTtuEZTxbKagOWR"; - sout << "78qwMM9feTEwicGFlvyiYdUGaIwiIckil3oQO9w6bQAaPnygDcykVMFK1fZaZztYQ8AKiEjyr/V5"; - sout << "dvc04CEShL8uRKDZNY8Y5cDGVHOSR2g/u0t3PDuzMCfmQeKNJQgc0uF3ozXP4xvTvopiK58Y3656"; - sout << "m2ZUfjDIf/g9gRXmrmte452CbaU4HQzlIblKaEJr153rXTQbZPbSHyHOHWRuczQAtnyP6k8YSC+3"; - sout << "zqBtSIvq637hKi+7Ov8NgiYhw78ehwHiPtenLDlB/YMCwqqPNmo+8eYGmtOoRgaQecIoYHYWfaUE"; - sout << "NMtwvnfU5g3JS0j6VZloZxGNmrtuDqWoXclUftoQdsDlE//Q/5+KHzyZjf60WrXx1Ix35UmF9IEI"; - sout << "jEvtLp8KOoWs077NCkXs0HVwuKxbpZx0v3qVb7HwsgcaoypbjhWaMGYflEKvEbJt+TD4MN8kXDEE"; - sout << "VHFdCSOzUplHRdcy4aOkQdzfEYvNTgaiTSO2CautGYgS2m+l6Cd8B4K5PZs99xYFa7t80L1d2Zpe"; - sout << "M9rYCt6RKakTTFDSR94nxxzdyfbA9sVYu6MCD1G0lN+zrEisA6hjqSAqUXsooaW4WTOd3HoNkZeS"; - sout << "tGviSThwRe0awN4pH5dXfHtxaRBkzOBVw12FB6urObgv+3jcnTzRZWvF14ioEmMuKkHb3Ienbv83"; - sout << "71BeuTrUarJazVmIzbH4ulyWwLxEHeKL0r4PIEfbUg7tiU44lMnfxmrFFR6FiwuBxrUvyv/yEmiP"; - sout << "AbMnRjX+4MVrIHr001qxVFOaeK5FehfvmWotuUW63TvubKCRp++5uQDUh/LeMp5ZSX/RRVpEKEwA"; - sout << "It9wUHj/cafFqSwt603pOOtAC+xL0ozsVF1kYyl9vBEow6mBe66WBwekd+DjlzLbehk5oIXSaYsp"; - sout << "zu0iBnukS7YoO/2Ho5JMdkJuHf5AtuC1bDt51FL9McuIHboobI3/K0YrpwPmFORwSUSroXle6XK8"; - sout << "LeX4Fcp6YaicZoFYpLVbhVvrJSW3F4zBERbSqBrHBMxoXMblajhf58RcPKwZPvPnSL+yB5V0VP5X"; - sout << "RJtdo0ir42WND1VCIfVqCCrSg/m+/R2sffd/CzqQ/JuJnwPtKrAvuaZ8zbmq9UkK0WAWY9Wql+gy"; - sout << "AYQNgM6Nd9TNJ7LEyEJQl3nK2qjg67rBCizIdwRcPFSWoWE9DjVz5eFPIJjPG//dpt296BsBeW7U"; - sout << "NhV2Ig9EstFK3+/GC3annnXsT7OQt7QCnx8BvzbVHiFU0n0yikhA1uU9iYm5qsVwdJ23NWimhTeo"; - sout << "XOWG/MVCrPHpV2qs/4PljiPW2eVdzodj+nfDPVwkHwmFm5Y6TGDRBfJWd+ZiXMkrDa2CEMrMvzEL"; - sout << "/DymDMQfMI9HgMiLWmiXS4DjcRL1Fp7DTHcQa9swLcZwbyE8r14L+5xXzDySF/EKJ9LwmldUaN+t"; - sout << "qjmQ7DecED+MkTHMYXnID/Gl3a1/wnrfxa9IuRAwHiIhuwb8siPJT1S2mncAqk7YwUyaY0hl6TB1"; - sout << "GJqoaPTaeFqzTD1zuz5N3cFxx1O0R7OBzHuBtV/JXrZlyzNKZhUaopWCyQ64+RGa/K/lQcyJNVo9"; - sout << "lErihKgf/LNzd7f94T3CmYMRUJZanOLNUWcOg2iJLGR3hy1pnlmc34IgQ5SHZisUBy2jsdK0xoKA"; - sout << "Kb/cPiaZj6ab/4sq+Owh5I66r7FjACv3uILtt69Fz1o4yaOb8z1ZSvFei4CPrikpxYXltEj+aPZq"; - sout << "pAyL3+qrlJ7eOYE2svEpEAiYTztUAn9/ukCZZ71IafGHnhPggc+eizHPuoqfdUa1NWeM7H/XcFHH"; - sout << "b5PQ2mQPCY1gD4SrBqPS7I1QvfMuOSRba9YFbJAecSC9bPHlQQ+c/rma+R3yhyLyXN2j2xzHpgJr"; - sout << "oT2cEn9yT2fHRiZIWqMAJa0KRJgRN0hLjhGQ1VKN4WZfKy8uyqCrAbzBqR0eYcDjkpvD/syBg81K"; - sout << "8acv+5OjBrHgCofewj2DFs0lC3mMlo8qe+GNjxu/CZufpnNabIY4ggwBxdMWZvZQ7j27VwMmvkdd"; - sout << "Uei0foug3YA/Gy/XUTRLhuyYKy9dqdv6VTSiek0aFQyM4kz4KqKlAbGixu17SFgvZ33fP6ZMZ5Pd"; - sout << "eWC+Z1vRafLRpsABf1DJujXUEUZ8HJfWBuuaMkJkxFApcPwctu4SMpZDjnoc/7gblzc0yLr8BRxD"; - sout << "gygNRNu4uVAT3sbaRzYOvF3tq7wr+R7qS2YmPEzhoZyfubEHdV48wmE3XD/RnZJ8maanzDjEH/Q9"; - sout << "yX/a34y6YSlrtNim3R8pI/AddLi86cAcEKfK3V9QXCGFqO7GfQuyZHO75grKpL+6MwRPUWigaLGN"; - sout << "9JfWrc5tpUu8NPY0ACmztq5p8iNqylVgIYOC9LRIl6TKJQXPSY1k73NpzNNzOJhVCCLY2IaCMUtY"; - sout << "pbxZs+VLufZmNFhq1D5qxUDfKII7x9ocFYqtwLnjZztYT1HhDTcwmB+5uQWHoXKRvsTgvSfR1l33"; - sout << "w4mqzDAI4ykfuNbLmymuKaVV2ST6W7pI6xfZd/YD1em6OQYF+F44tj2G846Ry1IsdVK8AiprcFHA"; - sout << "QFxuwxcY9eUgjSvhbK4BKkQgFSzx7yDZTtDxXSWrGsPoHUCh0GKU757B4ubLvDV197o/No9EKfGh"; - sout << "3tlmEwvvwQd7yTgwdbksgVieGZBJqLK5eRe3CqYXpHryPcxydrO+2LPpzUiiHPY5FDRZjnYY+as0"; - sout << "IC4dtlX5BicqVB2gbHiKHbjLf0pob27d/WqQKKfA/7h2wY/jYyckEiX8g9M6I5QeABzABxyyAMlx"; - sout << "zoi3bd/RD35ijUysmIl/+qi3GHaYKK9Bfu1SRb9oPgmFYKKKRrYxm/cypmJXp+GUjlNokWN1u7OM"; - sout << "Nm6oqRRuqYWiCwZge4HHVQkQs6BuH/Nqvd3Bqkt9U1eH4TnkS5MhnYVdHt0hxmG6Py5A446SERn1"; - sout << "gJRsUDXk/kRkird01o1UqCrlhwX9WG1cjY2I9nFsokudgnYryxn+d+hVdM4E4MO5ZHmOXicEn+hZ"; - sout << "N5eyfU7B75rBT/yZzzot1k+B07BE1x8K7N+S5JX07utAi8/htK/a4vxKhJiyx7p8etztBI06LKss"; - sout << "grLKdJtqZvX3kwFEIXqpJn5W2bijJNeQYnJxfFY+5D/k5POGuBYjf9lw7ilnIkbEDkaMWf9Mrt3W"; - sout << "A30zlSEMksIByxqL5/VFx7oM1oSx872AYwXDNNnfITgNwKBwniRHuU68SjWBO37CYYmDhcB7Ug/M"; - sout << "FMX7oBgPrld/Lg/ut/xbWwFOiM1M6L0TmT5HX6RcFSdKg3Sda6adAkSK3Ux2HTZAUVaK8zG2Mm1e"; - sout << "W+/4SSqK29MAZUBK+oEPrNB7An6NgWZ0TRu8sGeMcZCm2Zb+3+ZVUbsTFoG5pFhzzvMGr9fAsh3Z"; - sout << "4Ngvc76mkiqT7xDZw72BUnrPz+eO+RGqMG+oGWJlXd5PYD4XIkW25kBfOr+iK/gCFUsfZbFoHEFa"; - sout << "M9EFExjXiZYOz4iuSZnpeChRQ5wbl/56iTGSMHpB3KKU9Rfyv4dIDGS0KmnSH7Q7mdn2lXerjDmF"; - sout << "zlc7IbX35O0kHeSXaH08ZFf9vBweKQvEW6Qxs59FWPuS47FpXRAPFClwYskLxByN2ux9kxHprAFr"; - sout << "zuNKRyilr/NlCEJn5SiYU2/fAif/YrNNiyxXx7sWwQW2mf9Emqzsrkb+eCqAPs1NmwuHO8JXIyKO"; - sout << "0EbIUaVuENKa+DLtcrfI9HlxhrF8vd8m8s4ZeBHWr3jkbVdcjX9mmtcSrHyHXcWVImc8CJOiR7jw"; - sout << "0HTAydarj2G229/7kLX6RncrRqY6/Z2e0YEbfTt8RDnwriUmKXuf7VUMljP+tWx8aXMlbm47WMaY"; - sout << "nnjZ4wE7UTgrYUce7ehuGDBEM4VaKYrp4n782gXFdo9VhUZ7JEaveARi8Di1SI5MuTQ8N2hUfPKn"; - sout << "JbK8mEjSmcN1sOZBOXxxWX+e9RRsO5t5ujCSy+UBr4gaqMHAlwxtBmif+kl7s9o+UjHOlWLn7V74"; - sout << "PiLxVUzCTHz5A0rX7MyGXMBai8BT5XjmazTZz8YPIiq/ZmnyULon+uTrmBdivNEjDq4M476YfAma"; - sout << "rcqxp/picZEanq8yctrujPHilXH1WuXhkPM+gn9Gkjp/sGfA13JiFeXZO9GJHkqLwBKApqS1HJIf"; - sout << "bhomnqcdp6+hM/IEaNS3dVZ1aTSefIM/OTR2fNVbmzwfENzVke3dCJvw5B8zTsgEXeKuRE58pYaQ"; - sout << "H+ffv486NoO8gXKrUF47ptIj/Tt5apc5Pt1AVFsuaxvry3UrUmY7MLbfM4xB29ah1PY9iYx/OssX"; - sout << "DGvnDskGHiQJlz1s3saJl9qm3BZr3//6D1/CgGvXw0DffJYL9yIqlzoBRKAue/lQbWagNArmsccI"; - sout << "WxVk2TqYgTHwhl40fWSGIuY1kfj6FEAUxBBxGul8y9Cv3e/hMnE0gDQz2tZs7EGqP8WqKPF4BpDh"; - sout << "Ep+6vvj67y2Hf36GALRYNLlhCB5+HygzOW4jwtQvCHxbmtPWvQkRQ8iQ7XlZH0OOATz1FsccBZXr"; - sout << "3+O26cf7zcoZIE28MIQHIJqsDFHCJVr8JVcYITcv46R1z9ZgQQ+z7KK0M6FY6SOgCyu5kyQR6YJd"; - sout << "HEYkNp9J4N21iRr08DUYycJDtrf7xoyYfj2L5QjpPVEKrEhIkjb1kr8uZp/KfCjCkedPBrMsPuOJ"; - sout << "28Acpne2exkkKaunrJZr64Axfgl5t0OIBP79Cqy8PRnMYQTtqHf/pxaHNyrYaXO9vjtTVoV++kaM"; - sout << "svy9Ol/R4LxEXrgtlSYhKF4o6iCJUSiLhE6j/xzyOtRrCAHZ56WCJ7YTm0oa22TtH0DvoFMY11Tr"; - sout << "SZ04ig5Tl8At1jXKymUSnK7EXANVHZmZ+01xTE4efnFIf33N4uWK+c/hEqmS6KCVjuHT9FwTKEIm"; - sout << "4cKum8uhL11rodikW09dYfIyQV9yO0k6EJpeUSQMhPBqbgTWHnVQoHoot+c1uBoOdK/+bRuz5vip"; - sout << "l6+0nmpZZoO+OjdEap1pQqpcTEhmfBuUGXCibggZhHEvHvFGQo5an4N48OQA2B8CccDHMJIDP9+j"; - sout << "0JfmziBnF+ZOLfKLwuuE4uZg87iSWFkwSynsWwoUQ1Cy3u/URW620WLmkx0GDoGPkcsxJ0LVu9dh"; - sout << "OrWWaFesEANPRMCKuuU55hs913KzoOKdgZPzM8dheJZaZB15wi+u/RTm+obSWZVwibTDyLPQ55mz"; - sout << "FSv7Lyp1EDFvxyel+7osJa5ifhLrU5f6CAcKwS5t2IwaZaBxrVaFgX5lQmifY1Gd2new1mkfWYmb"; - sout << "n4AaURVZOBC4U1Dx65ch0PNeEYxk0DLAGOsvdBDbWbFMNc0LiGEF6GiCMBYVsw/cYnjY07cEZg5N"; - sout << "M9RxGfLfVlyy4MW9ek5ov4+NVLV+vaosZvA9gP92vaiS7jBj8qCb2uYIK1mfrjHcOUFqcxgzltBR"; - sout << "eSU3ewoVRJIaVreWX4RSXTomL1GOyfcFQ7gZghSJLKlwgkK6+yvqig0jyuvmiRFJGDYOxQtDykwM"; - sout << "EKOOZrckRdktXs6aFQOla+IRiN3XVUfY2wvx3egfOYPKrJS2HBEdXeIelB7LK6vRx8nwuFAAwZWQ"; - sout << "iB4OvgM8U9N2H1wa0xXWc1897unEm1KxAP1iS44BmZ0PPASPa1RrltkwWMwRtMp9fD08mwLdGe88"; - sout << "fsGIrnwHA0HIShoZaBmCSvX0yfaJ34nchnMukP0B/8v7f2j0t1F6hr5qJNSV3cTNcc2QToBy03ro"; - sout << "GphkM0UhwwoYTlFppF/8LV4QmtsNK9wuziTmv8ghXUgvFRTtVcBMlHY4SFcRKoagFF+B1UfCuVZt"; - sout << "G8fNilXM8zc2/eP3g5FTU3YXRgw2CAheUNiekne53EE4DmDJ1f6n4OyjZFP8PZ85Nzkkco9FW/8/"; - sout << "31JIClFqSE1VGbDXleZMOrdfoknF55krQB7v6Wsu82gzQU2AvvhbuFlPodDKH1xUuUT7gERKv4ka"; - sout << "fdS1xf/PRafedvPX7k8fFZQerqvvUlgO6PaEAxK5MqZqHiUgUh9A/pqBZNBl1kQLP9+G70i1CY9x"; - sout << "tTETsJJTgYz/HP6yXsqeFm52yO24myKHMURYBmOZU6AFyqFCsOdJG/GA5otaO9MG0A3hPdC3Py+2"; - sout << "GWbnl11yPDVImktL+LYbx2oolBWZrelLRuKAtDp4p/Svt5R6fOvYM9XxZnnpR/MNaTt7I8iEZSQe"; - sout << "w57IL33ZfHgKlxEr/ouJgT3vlxqXsuXnP49ytEVKGja0JAOzlShLYqB3GIY9Gb3EtN0h/id1jqQm"; - sout << "QwR8y5q54W8pdYflhgi92YWYroUUIFRxheAgPwUSqrOUNiN6xpSwr2usNY1zvGGsRqFKuhKgh7P7"; - sout << "cvGc2sOj3izPgl4NlR2DaoFTbXd6uDM3IrYGSCFJdbMlonX5cvO91ySJpKwPOnqjAbzBjnZCfepb"; - sout << "4px8fSH5I6LJVU1R+sGRCoewaHTFlsnaCQrsy9BTGMIWwAKCAYCbWN0T4ItZaXhJWarghYGsT57P"; - sout << "MagSlMpKeiToHWnWhPhtxkhm1ZVRuYekcpwrlWwsHBV6O5pEML3wmWZDWJNZWh/GkmhPhf0aF78F"; - sout << "2lOVKBWLYq+4Xt3lVNvqCr7m2rQNH6KzZUNfeoIJH48SgirJQiNNE2iQOsReTQTbCW87NCN4GKGh"; - sout << "Vf5A2JU03N+5fT+dorN/LTQmeKddK0MR2nshO1m0kZSQ9TDUE6Da7ITtIjGpKK1QqohIx9BEMoML"; - sout << "t3BcLTNkK1SaaYRE9Fm8AZXr4z9AILXUKktv5bytIRBZncs8078FdpF+O2JWEzELgG2s/FTHTyjU"; - sout << "NU3A5q6+8LoeSXuoqOZz2QwEMhKwkz7AlujJU/CJ3+uZBAUBythODaVBlaZM6/f8dSY3489Xiu9z"; - sout << "L917CSsYpq4JQWq7I7pOkPjy0t7Y7QmKPITQv4QQmF3P6SJXiainjWDQlZx59RTzg2Z2MDZ0dcWx"; - sout << "f7f44IkngOVEUHi3iwrSygMTySBYdDxei/kBt7oXAAkOMLucZ24VE26nLD1hMAwRz83ENc0sOZAz"; - sout << "F7He/e0H2I53NAYlk0s55wntUcdp3sHh3UOcGyBGcRUipg6NWy/LrWzxWqJdo1DsBpV4iazYLRfB"; - sout << "JdKobsmPGmWSyABV8tea/IuVgqUm5RrWfBUa6Kw2TqVuos2PsGqsRi4cHKl3XQ0GJjbV7qV7Nacn"; - sout << "mRVqIAetzUUZkuyp6Q8OMLX36zwwrlP0rPJaqk24VBEnx2FKjaR/LkP5lUFenOHJuPXSh89pYWA7"; - sout << "7/y1i2ejWuMrpElkJ7qfpTGD/A5ZkNWCyla2VXOXUVjK2t+cBYByjEwlMCwr+tXUXQYVMPf+UzzT"; - sout << "EVv45u14EhFg5XOu7urPZWyO4EbejgEvyyx0c6Zgt7RaQgXn+akwMHI3oDn2NcZYGo8Vwg/fSs6j"; - sout << "Ggzyse3ShPpUr6qb9TT3Vo6hXegWwd6tDPsqDlc62JhQ0MYdw2A1x8aGK1iUCz4pqsWmXWhGPO1g"; - sout << "rXyqBaIrVHDMim3cZO2LY/TOwIJZGuHNvVnQQ0TDYAQEgyej9mVLuWaFuCE/JZlw/8U2VngPVq0w"; - sout << "EePssUQnewMHYTfceXOETEBkU0xl4WLdwaJbvIXG+pPcVzYW8z/D3yh2LU7KHbklffbjWhYyAm3b"; - sout << "nTTR+YTZoF5PwWA9DmsxIbLQJn3Ejss6pOj1YSqq1cD2r1+TZjWefNmH/nncwjU0T6e/iBxkgQLc"; - sout << "NXouKJEemknL/HOvd5sUS6YYbIGg7Pa3ur3Qn0quKT8QSHRPTxZeTP47rSp+Koibf/XfZOdG5RzB"; - sout << "U2Kbz2vi24JkfzbNCG3tjNvzPJVcZrMde1TNVNQVFbXCzMZgO0Za7o3IRyxy05rmieBcGryGX1ln"; - sout << "hnhwSzxSSxnuJ3szdlfw1j68i8LsX+iaZHonWIw21afDPwXaoflD4cZIZI2uPLAKeBoOYMxKyFGj"; - sout << "2KhIVlr+poDcu9gZBMF3CwwxSRZpwVhpUllBfOJDJTLbM3UOyNRMs/U2T6TdxH1fRbgeQcfQ4CqU"; - sout << "D196crANUlHv6VL0bU8CFS5f85YwKO4JliKHZhvQRDtcBrwKIXttWPt1f3OONAscmsl+JtVgVt+r"; - sout << "h1R+X0b/puYAa4tqBvUBiiokN21cQR40Pp5PPLMszGskImO0XM6Fx9spo80xxDLhOXZsV4rJKs3q"; - sout << "lub2BoFFGa/nbd88uBheoBR8lh5d3sWciz8Y6eMMlEASpLmXFg/nqq1jzTlC7lGmAhyqSTAL2dHJ"; - sout << "+8ACp+IgMI8v7DR1TEp0qgwrVC7B6+8bozJlpH73HdqQYkyjAnVcOBTn6KO1pjAJ+YcXqe2ioiBt"; - sout << "OMAlNQVAJZgxpEnwwd16yXDmK+Fp7v8aGEx1EECVaQYW7ZVvKRC9249ioFaEgFjpo+8veoWFd9G3"; - sout << "1E4aBC8rOXrrsI6U3QqWbYlusqvogtKGwT2pMYSidnPneM9iaJ5ixPSlB7VPp4MwdZvPIpOOR8Hq"; - sout << "cFqQfZAa7sDq5idYKPUrRo5XD6szBNbb9Oob6y3G9RQndEEt2363luFr6Nv80r8yuyaUUlRcmPmU"; - sout << "/VCExotSxcx6B4uWyd6UoA1wZv1hY+OCUL0ahArlLzkR2ZxowfeDCn5eoawdQnazyx9wSAEmqGTT"; - sout << "lrT+MyINZeyxp9DTtvjFwVw1aDVT87PF7E4Yw2H5V/55elbLzn+Rlr4AgU7W+RnuwOk52LCKrSud"; - sout << "JTAq/vix0svgRHAs3E8wsLzBsFXc9SZ6/AWptBKuix0lkoDObM8rLJMjxpQPmIyVvB3jWXITDn+n"; - sout << "8ou5GgmZUDeGu3ZiOWbtPhO90akFKl1XDQJ+k9DGrlQd0dbsDa2lTgPbL+3wOD9fdjFzqfmGA2vI"; - sout << "kg75VqCCEOUXbQ8N2U2IALiOEuYblJk7WVsbmOwmEw7T57QVJvivVJ9Z36TJeWfpzIiHCeReso1y"; - sout << "3RGCo1qlsgfwtz5e3/ycu5aEq+Pg1W4EtSpeuIEZyH7zQaUILmAFP23JDmHyZNh9ewxSRfZGETHg"; - sout << "KKN32MMx6taVzf/8+RQhxI3JJ+PSk0vrvUEX4L/2Bri8meJbN5UtWuRN5gha/O8jPDixa4XrMAiq"; - sout << "etOumapH/QhEJBy5NHmcjLH7XpZ72qxTIL6VS6m2GjFUyekOdKZOHDyEKA0FR6wgEnoki7gS0L6N"; - sout << "5plyHCOmd1aBWEXf5+P8EJeh1nmu6AXtDful0kn8G9nNnWrbC+iIj2QQ+XZPxdZIGuJKd6MrXf0y"; - sout << "zW5dznFYvB8R+LTy2SW4WFvMWzJAlggi1N7w25/rvtnt57E+I5TimCjAKJ5Vcjj/R0DOqX4BNnOK"; - sout << "MqeMDogP+DE9NesTswgfFngZBjomZsx8f2Wdzzi/UW0xBZa3yPk+CV+wwTlWNxgBKFCYFC8GlJ41"; - sout << "MQt+TPDsDZJuBdbexuS/PA/zzOE/wZPVXgzLZFmTKsZAfz9894HEHalRlKLgTlvgW65XDihdoh71"; - sout << "HDwdA9Knb9r2qH0dwsOTpoU0uABJkND+V1Ezr3oi35dJ2zw2gR0omEnVXZM9dW8XIp8ln8zegt+S"; - sout << "dyMbNDzX9RClWSIVIGuRYGCahBqXMCJG/AAKvkXM87mZiQsIz6uLvJpkeGiG1ah7kTSjVFIKSYES"; - sout << "73oz5l7AIAIReUzdvMLk5ZbmqdW4JHBR5XBA3rTpAyNEunRi2Ddy1eBt4i8I7GlXaaZ7sVS028ze"; - sout << "VkY4WR/6FJKO8ccbofsJb8BiM8UZdPmkRdEKGgFv13dkq6inmo3S52P5S50mYapa1YKvWCvMHaov"; - sout << "z8BOe6WqptQRGc+vZ4v1vgq40yaWBa9pSTyvntLUKCkQX0qi3ifKhRykXP6SBylckIHs8DfuJqXP"; - sout << "X06djSx/F7IyvBQg90SLa1h5hYRTAchYX1ZgvG7LlSvPp7i+sWCx5D7KpTbF6O7AU8kMPpaRm2wE"; - sout << "RvZ4DCgXdh9Lgw69wRlMfWJEJcV3mOIGDRoBZToyJqgHMDJigCet6NIsD2xvvza5JWPf3DURWRHz"; - sout << "wdVqLXlUivD6/9r290ZcIbdWFMbz2aY9x/ojLrJmAGX/kySItIXsJlDbcvquJWNc6UYrpxurQEku"; - sout << "ejm7E6HjXUPmi9gh2kRkw29A5xIFaugoph9dZSwyCEx2BbqY21hwQ5elfdcvdJD/fe7iiWmfrtxQ"; - sout << "BqVebUOrY5+/vEvMf7EupYK8cxtCb3mvViCR0rGokTwuw7NVuMH6DEJ/zXB7BO/2bPXnr48Q2pmM"; - sout << "pThaXSCJ5Ta1SZqGZRG5pBsUWg8MCQBc/KmDWv5csQlqDJOLvEULRsKdxxcm2wBthRXx97JVHMwe"; - sout << "Tlb1TkjoSIQonMsvU+dRJCW3qhgbR4i0t7wGfbg9YdXG8LiKJHvkpu/IPKHZtaMxOp3O6kl7Lcb+"; - sout << "Zr412Aanu8BN5GP+rW8/C+TjEBG/WeR23iZr6SByC7TCzZwJO25J6mtC1nFxdAUizSmxUfwDwvdE"; - sout << "5WyGMq8TTIHZ9KvKMw/jODKXcviOmLHY9CsPtYXbChnF/fWgQx/ykshrLmtSqFEaOt4YCiPFKQHh"; - sout << "/IjsYqcs0UQeGTk/6tnp8Cewe8A1DAaBEI1RTllobQKLXEUBWAV0VcrVXILhemvApUW0uqu6dSqg"; - sout << "cfv9uvu1BblNEfNmfTcUssCnDQ5c5vFjEB1KESkrBTL+p6bEn2b1bbxQrhiqnVO6mi9anbtBgBU4"; - sout << "lTjSG4KMnsD63xnrLapoU7ReEZxGjsQgm1Af8/lewJajhNOZi3FmDgkb8Lhq2rz8OYy6pwXCEM07"; - sout << "JwMzOWFBZDUA"; - - // Put the data into the istream sin - sin.str(sout.str()); - sout.str(""); - - // Decode the base64 text into its compressed binary form - base64_coder.decode(sin,sout); - sin.clear(); - sin.str(sout.str()); - sout.str(""); - - // Decompress the data into its original form - compressor.decompress(sin,sout); - - // Return the decoded and decompressed data - return sout.str(); - } - - // ------------------------------------------------------------------------------------ - - // This function returns the contents of the file 'feats2.dat' - const std::string get_decoded_string_fhog_grayscale() - { - dlib::base64 base64_coder; - dlib::compress_stream::kernel_1ea compressor; - std::ostringstream sout; - std::istringstream sin; - - // The base64 encoded data from the file 'fhog.feats' we want to decode and return. - sout << "AXE4jk6QRzUCNtyVtAwaCkqQk/DMJKm1t48e6FXsZJ/Zfw0Utm0AVwNlJU7O2+XVsftV/yE3zO4S"; - sout << "YG9DY33gIQWV6sw7AGva02FE7zlkRbW3IOyZeG5LYs2r4vGYmZvZuYQJ8CVmkJpGrYioIuqWLyoD"; - sout << "IfAFmt0z7HREwTsGxP9BG6UIXb95jQCGocuoO+MxQNpq3qtMAr+C2xnN3Na+ITiKYUX+zEP+FrWJ"; - sout << "uqsYqhyN4H+1rlYaLhrj0nhUs4+Zp+fn3LZecDsZGeq6KDEIM68rOZAY8WWA/o4x30cQ0P299z2m"; - sout << "7Pl1vRxpN3MdgzkS2zlOpGnrexfA3TK07nFcTK4Lc97t/75JULM85uEo6yYUBjyeY7MPYTHaM0tH"; - sout << "+TGdAqQBf6TbnYya1MK0BM0nVLp4TkMeRZj49erCtZIVaFWOYmufs3LywApX8AQZAsBhU0QA5cQu"; - sout << "G6HKcdTiqxUxbjOIueAxWBbDbGIwUj8URJVh/WVW4TAXnzZu48JvRzif++Xeswz6O8+PXdPVp4BG"; - sout << "TaJv9bBwqV1y7lM/T9FxktP3YIcnbW+ezBUh/logAVeLzCAbYaqChRMUkBizO54DEiA+NBDV5ndu"; - sout << "Iax8NL9DFp1zmO8gdJBZZLgzf6K8ZbRwwKNlLEkVEZGKei3aVIwo7ed0tjG4aEIodgAuoXD8oa4p"; - sout << "t7v3sYbn/Wz94AyvAwFV0M1mAMaXqXhpfJSb5CJsSOyKqUtBBhpS58V6Gsq9M9weuwVHee5JI8PI"; - sout << "bY8WlfQNSVo4JcToIdKPhehz4Ywad3gdX8DhSd+WBT2aMomB71jr3m9CcC9da3oxXjh/jVaN/boQ"; - sout << "oY5UqFGZ7T1b42x79PiIoOY339sKYR9vr7WPDHTouVtas/3hJBkBKwXqKmBbRPU2N4DTgpt+1zFq"; - sout << "nig8prSmjiAh9ofp20Pbl5FbYoIdoOfLgYIluAOuT0XhKxLAwWoNGLBA37bGagSxzXnzlDPpFDZ2"; - sout << "WVdrBwehuD4WhBRxMiTZkzJwhzRkyvsBnO/JqFxXAD5b2CvH9p+3P/czeRv2hRjNZaKHEfdMtIWn"; - sout << "lPR1zWmZ3LTMBR8R2kmAUt50Sikzj2TpzLlBhemvUVAcv0HEdiILnp3eilOx/ee7GzEroOMHuOGe"; - sout << "moxWRB1EHj6h2Ya6TVmMb47SzMwKo7mf1PtZ5JLDk61k6Bv9M0WCDiwxlBwC/PjTxHDsTOWRrSJG"; - sout << "roZ/csy/RQF//nA0f8uKC9HWmGTOsrA6VAVteglGi9k6E9etxvmGCQD2ud2tyz2HSnklJAMutXd+"; - sout << "flvArk1avpvwXGoNgT3EsEicUGOg93vXl1A873vbHtwnycMzAa8NYjZGW/GPROg8yKkbpoxK+Zel"; - sout << "+VP14SvqQDKEYDevoGuQWhsQHhW7bYeSa0bSamm9DFzqK2Ld4/aU7JUHYdaAvAJPIHe3F/N8NcJ1"; - sout << "RE7VoQlrVZXBy33Ly6wwiv1rm8yK4sMdBnNXcxzCyG1NkPsmC/16A08Dy8RV7nJhd1iOJ3gy9BUG"; - sout << "Y4ofrw/XzITd6vL8mIJW2jyrVzW2OPqMWy6IO/7CHz7d3k5+7KTKWkksTRsuAYWDgZtU5Umph0kN"; - sout << "/RRnuBRIe/6KYj5/thAY7yLmGFoy8jhDmIikSP/l/pJhUjjgKk1R+oYHGDJ4FSD2KNfRDQ/xHZb2"; - sout << "++ObYSCHAuhB1HoJBwPcmxkFtxjS047iGXnXo+2nchItcrtifnQTeI0qyV6conJnskM4jfhnKsj7"; - sout << "A7y4owQjOvkDwu0GueuDOTo/9mW2NjAaiHCp8yarSV1dPI1b/XR231+p5IEp1zWzqFr+O3pDAL8F"; - sout << "+eU/vj8taOxtT0CcT0gW2rRr8oTigRWCUGP1hxDBdhJtAa7Q+CuFvmtpjm/4fmbroJ5ZVNA/71FN"; - sout << "yL9DKBmiVTwljf+yRpTGhpMG+xky30zS2R150N93YDDXVT9StjKaOrtLap+9w7BtCvXGdPiyR2QN"; - sout << "g7gqzrz31poE36fAwM4san1jbbTC+eYcTErQ2wXCQkVne3kbVOwErB0ayl7rNqkw5b3gAME4+DnN"; - sout << "IM13kdtxY2WeBND96g2enTmFizxHWFzW2asW4/XqGt8EVmzTB4XM/Ytd+XXaNadRUHh44wiNIhPp"; - sout << "txmIbtkSesyQ4YYSmUYEEcYkZwfcRxHUAGCcnQbSKGLq+N5IcyiLVwhXDfK4fqxH7Oi5DmOwAVmV"; - sout << "kdDQ6GP7wDcrkAQS9s6fL04bNf7rodacAPdX4HwIKa2YykdXWOiQhp6BRxjUG44AVV5fiTGP1WVn"; - sout << "MJKXYzSyY5oN3ADAT5em+cIYYVPnsnZBuUzAjHAw3WYj4VlRIrmP+oPdKPFncEyfTn1G7DbmyaPd"; - sout << "TL3DdB8EDImfZ+A2UMr2i7jynH/fFXzsi2PM9cFKxCsEqG2LGr7KZDP2FFEVvWwIDnvUClj9nrHd"; - sout << "zyioiild+DW6PoYvqFQX4LUf9Jr09RiJuIvz35I/15pBQbSnTxD1RFJwR92k0yA3514jYBAtfLmf"; - sout << "/1refalgDjOyD1ntgp3INSYSbpR3TqNIynWwSJGxq9I5aFJypV3Nq8w2Rn3/kld9nqDaTG79ns13"; - sout << "dwfPOiIZyfdrcxkYOtS4+iijs+YE3JhRKVWMf6ub0cVXttJGORgpzgkSoDWNVZ6O3hVydCziYzoS"; - sout << "RgHUH2Oas+aZK5IF3Z3aaRYc0A+wy/PEx84LRHsAYdPUQJr+bGseC4wScP1Dyc3xpeJSR1V9t2tc"; - sout << "AMbhtwcKGX4j5nGnhxSevKzbCDteEnB23TnSQwbuWYmzhB77V3jpu1Cm2h7FcKGM8vPbAQeRBr1b"; - sout << "+RY95s8hsZGi/USiu4TQ/wHZfEGYcHuVBI920d84pPRVe5EJ8+FzZj+Qy7JwriqLN+7WyUCFdwxn"; - sout << "4B+WXHTe2epBJMQzlE25kKDHKb2lDDv5HzVUlrZK4rEShkPNv8SB3U9u20GTLlHJbM8RDvPkNjmu"; - sout << "U4ZLDSJylDaRHWqgchgMnmX08aprI/o1HbgZ5aiByXAUoHSSGHanyYmW/S0LOW7YZH+jOgxzW68U"; - sout << "lheNnX6Z26RdMe5Xtkd5jx2jXgIT7HADCN8wWdZEVT7FvXRoxtO3nz30cbOim/+IvB2lt//OcTJU"; - sout << "BwkyweuhJtiXZV1yY+X2z3dWBjBXVFWidPMMWjTUIwalo9A91RL6ZS25kuBXKm/BV6X/zAHkY+jB"; - sout << "A7qJGLPe5h6SO3GKPSLv0wE+9G6VIhH2TPLfAd+PpqM+xuUNlWlo5JR6ItOgGHuFdjZeDlISYOID"; - sout << "CJn4zfaU6M4Dmw+m1wsIiyQy4Cw0DcZYUjwStEfLJu7BRyFI55wEbXJr36PRWpvB2wzkI4z1u2yM"; - sout << "7bFvguH0teVxtMwQy9S4lT9JlfX8QEqNRsuxzQprPJqj0ie2cFBrvJ2E0FtcuarikbcYAmC1iYdz"; - sout << "Tc2CRVe60taBHR92AsvuTv5OhCIssVc5W+Lbv5e3S0vLwUprWPhfbth/zNevKNiIeogTJOOTQexo"; - sout << "4EhJ2pf8QSz+ixlWi5ffYKLKSx03wYBZ3fNIhJDP+Y0mz2pd0IyGhxDrMAxYHhPjoEGCfYX6fYz2"; - sout << "XQGQ1eTGvNEATqz2v9HxYBicYAcW4mjEcTqsMHMYcboVgqiLxOD+jOHJqNrw+eiuC2Ucu6muQ2es"; - sout << "Zhbo1UNZO/J9XbsZIKa6t0PX0CSczL02Dti8r5rCQ7yeUgwZFzy5oJSShAuUvBDILXBeDhnuU4W3"; - sout << "eooTvk0lkb8sNAgkUlvHXgdN9jkfQuHqX453IOffB9TnxopLuxS3R6uuRa5ED2pWkL0L5ceftRv3"; - sout << "0T/sMlHmTNoQhcJSoINMf7f+WmHa95iD1HolQNFJaDEUzLV1DfD2mntncFZoJ4zlr+b/94qp8s/n"; - sout << "NM0CyoI4ansElbkkjUs7QQp+43pGXu8sRgg7tva7/3vUwLp3Md+8WkX+uppIhj25nlwfkD6IHxdk"; - sout << "uFNPNgdIikcM463W56CKek7LufT8wQG13mJOMJCObvhW/EU/yb/88hegDxeVJKrWHRyebllsFbZ9"; - sout << "UeEWkJPKdA+YHilgfSX0aFgofCDmmh1k/cO2RPqIGIqZSfT//6lFEDdzPcCLp/kd4oq7qh5Ko7lo"; - sout << "bg4N9n6F90oJI+JFJRLy6bEhZC/7obQlP6FFUUqSpizj18+zTLPUaDpt3/eg9QeXUeKcNlkHYt23"; - sout << "AqzS6PqB9t4bUr+E81QUxpegh5V0M4OPQJbFQ4/rna/AwZVDmGRjJLKzkWUwpnIv7f2+Gl+91ly2"; - sout << "ve9Ube6Jf9h9M/j7kppHRARY4QbXauYAcSp3wRaIueJWx36dMsqgzuYfwHIyuhGS3CbC1EHUZwM5"; - sout << "hgCHFvPGHLM7T7p4w6k0e7n8RZJsDybyDAydW8SfSI6LIeX2st4LOHrdLrpUNPyE9JyuIMCSnPaT"; - sout << "1XnjdWev4jjMeXxa1XWbzy0AQpeQ0UYA4OpqRSu1DyoPWf4IA+bf012m5Im/1BiGF972Ie/6CNvS"; - sout << "niYOfmxxLWTihdMtslxiy53y2MW2iDzLxX5nvUSyKXfO1XUlDJGTd/zfUywZcY8cgI/f1IPzr2Lk"; - sout << "3/YKqkJ2De4IpbixDEkbgAroIaoOZXEGD+yNzXVcyISIhMiKHJERdwVxp4j3duc3M04wrwJMZvtK"; - sout << "lk5jnn+ILhTxcpboq8gge4CbWziUUj9du6mklxZaeYBBpB6CzlVLitesXieA/zl2JnWzRMD7Ho3r"; - sout << "LLSqxh9UeFgjFtb3ilKSHNZH6x1DS0hFhEIA"; - - // Put the data into the istream sin - sin.str(sout.str()); - sout.str(""); - - // Decode the base64 text into its compressed binary form - base64_coder.decode(sin,sout); - sin.clear(); - sin.str(sout.str()); - sout.str(""); - - // Decompress the data into its original form - compressor.decompress(sin,sout); - - // Return the decoded and decompressed data - return sout.str(); - } - - // ---------------------------------------------------------------------------------------- - - }; - - fhog_tester a; - -// ---------------------------------------------------------------------------------------- - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/filtering.cpp b/lib/3rdParty/dlib/include/dlib/test/filtering.cpp deleted file mode 100644 index 61dc8844..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/filtering.cpp +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (C) 2012 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.filtering"); - -// ---------------------------------------------------------------------------------------- - - template - double test_filter ( - filter_type kf, - int size - ) - { - // This test has a point moving in a circle around the origin. The point - // also gets a random bump in a random direction at each time step. - - running_stats rs; - - dlib::rand rnd; - int count = 0; - const dlib::vector z(0,0,1); - dlib::vector p(10,10), temp; - for (int i = 0; i < size; ++i) - { - // move the point around in a circle - p += z.cross(p).normalize()/0.5; - // randomly drop measurements - if (rnd.get_random_double() < 0.7 || count < 4) - { - // make a random bump - dlib::vector pp; - pp.x() = rnd.get_random_gaussian()/3; - pp.y() = rnd.get_random_gaussian()/3; - - ++count; - kf.update(p+pp); - } - else - { - kf.update(); - dlog << LTRACE << "MISSED MEASUREMENT"; - } - // figure out the next position - temp = (p+z.cross(p).normalize()/0.5); - const double error = length(temp - rowm(kf.get_predicted_next_state(),range(0,1))); - rs.add(error); - - dlog << LTRACE << temp << "("<< error << "): " << trans(kf.get_predicted_next_state()); - - // test the serialization a few times. - if (count < 10) - { - ostringstream sout; - serialize(kf, sout); - istringstream sin(sout.str()); - filter_type temp; - deserialize(temp, sin); - kf = temp; - } - } - - - return rs.mean(); - - } - -// ---------------------------------------------------------------------------------------- - - void test_kalman_filter() - { - matrix R; - R = 0.3, 0, - 0, 0.3; - - // the variables in the state are - // x,y, x velocity, y velocity, x acceleration, and y acceleration - matrix A; - A = 1, 0, 1, 0, 0, 0, - 0, 1, 0, 1, 0, 0, - 0, 0, 1, 0, 1, 0, - 0, 0, 0, 1, 0, 1, - 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 1; - - // the measurements only tell us the positions - matrix H; - H = 1, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0; - - - kalman_filter<6,2> kf; - kf.set_measurement_noise(R); - matrix pn = 0.01*identity_matrix(); - kf.set_process_noise(pn); - kf.set_observation_model(H); - kf.set_transition_model(A); - - DLIB_TEST(equal(kf.get_observation_model() , H)); - DLIB_TEST(equal(kf.get_transition_model() , A)); - DLIB_TEST(equal(kf.get_measurement_noise() , R)); - DLIB_TEST(equal(kf.get_process_noise() , pn)); - DLIB_TEST(equal(kf.get_current_estimation_error_covariance() , identity_matrix(pn))); - - double kf_error = test_filter(kf, 300); - - dlog << LINFO << "kf error: "<< kf_error; - DLIB_TEST_MSG(kf_error < 0.75, kf_error); - } - -// ---------------------------------------------------------------------------------------- - - void test_rls_filter() - { - - rls_filter rls(10, 0.99, 0.1); - - DLIB_TEST(rls.get_window_size() == 10); - DLIB_TEST(rls.get_forget_factor() == 0.99); - DLIB_TEST(rls.get_c() == 0.1); - - double rls_error = test_filter(rls, 1000); - - dlog << LINFO << "rls error: "<< rls_error; - DLIB_TEST_MSG(rls_error < 0.75, rls_error); - } - -// ---------------------------------------------------------------------------------------- - - class filtering_tester : public tester - { - public: - filtering_tester ( - ) : - tester ("test_filtering", - "Runs tests on the filtering stuff (rls and kalman filters).") - {} - - void perform_test ( - ) - { - test_rls_filter(); - test_kalman_filter(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/find_max_factor_graph_nmplp.cpp b/lib/3rdParty/dlib/include/dlib/test/find_max_factor_graph_nmplp.cpp deleted file mode 100644 index 2260e92a..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/find_max_factor_graph_nmplp.cpp +++ /dev/null @@ -1,787 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.find_max_factor_graph_nmplp"); - -// ---------------------------------------------------------------------------------------- - - dlib::rand rnd; - - template - class map_problem - { - /* - This is a simple 8 node problem with two cycles in it unless fully_connected is true - and then it's a fully connected 8 note graph. - */ - - public: - - mutable std::map,std::map,double> > weights; - map_problem() - { - for (int i = 0; i < 8; ++i) - { - for (int j = i; j < 8; ++j) - { - weights[make_unordered_pair(i,j)][make_pair(0,0)] = rnd.get_random_gaussian(); - weights[make_unordered_pair(i,j)][make_pair(0,1)] = rnd.get_random_gaussian(); - weights[make_unordered_pair(i,j)][make_pair(1,0)] = rnd.get_random_gaussian(); - weights[make_unordered_pair(i,j)][make_pair(1,1)] = rnd.get_random_gaussian(); - } - } - } - - struct node_iterator - { - node_iterator() {} - node_iterator(unsigned long nid_): nid(nid_) {} - bool operator== (const node_iterator& item) const { return item.nid == nid; } - bool operator!= (const node_iterator& item) const { return item.nid != nid; } - - node_iterator& operator++() - { - ++nid; - return *this; - } - - unsigned long nid; - }; - - struct neighbor_iterator - { - neighbor_iterator() : count(0) {} - - bool operator== (const neighbor_iterator& item) const { return item.node_id() == node_id(); } - bool operator!= (const neighbor_iterator& item) const { return item.node_id() != node_id(); } - neighbor_iterator& operator++() - { - ++count; - return *this; - } - - unsigned long node_id () const - { - if (fully_connected) - { - if (count < home_node) - return count; - else - return count+1; - } - - if (home_node < 4) - { - if (count == 0) - return (home_node + 4 + 1)%4; - else if (count == 1) - return (home_node + 4 - 1)%4; - else - return 8; // one past the end - } - else - { - if (count == 0) - return (home_node + 4 + 1)%4 + 4; - else if (count == 1) - return (home_node + 4 - 1)%4 + 4; - else - return 8; // one past the end - } - } - - unsigned long home_node; - unsigned long count; - }; - - unsigned long number_of_nodes ( - ) const - { - return 8; - } - - node_iterator begin( - ) const - { - node_iterator temp; - temp.nid = 0; - return temp; - } - - node_iterator end( - ) const - { - node_iterator temp; - temp.nid = 8; - return temp; - } - - neighbor_iterator begin( - const node_iterator& it - ) const - { - neighbor_iterator temp; - temp.home_node = it.nid; - return temp; - } - - neighbor_iterator begin( - const neighbor_iterator& it - ) const - { - neighbor_iterator temp; - temp.home_node = it.node_id(); - return temp; - } - - neighbor_iterator end( - const node_iterator& - ) const - { - neighbor_iterator temp; - temp.home_node = 9; - temp.count = 8; - return temp; - } - - neighbor_iterator end( - const neighbor_iterator& - ) const - { - neighbor_iterator temp; - temp.home_node = 9; - temp.count = 8; - return temp; - } - - - unsigned long node_id ( - const node_iterator& it - ) const - { - return it.nid; - } - - unsigned long node_id ( - const neighbor_iterator& it - ) const - { - return it.node_id(); - } - - - unsigned long num_states ( - const node_iterator& - ) const - { - return 2; - } - - unsigned long num_states ( - const neighbor_iterator& - ) const - { - return 2; - } - - double factor_value (const node_iterator& it1, const node_iterator& it2, unsigned long s1, unsigned long s2) const - { return basic_factor_value(it1.nid, it2.nid, s1, s2); } - double factor_value (const neighbor_iterator& it1, const node_iterator& it2, unsigned long s1, unsigned long s2) const - { return basic_factor_value(it1.node_id(), it2.nid, s1, s2); } - double factor_value (const node_iterator& it1, const neighbor_iterator& it2, unsigned long s1, unsigned long s2) const - { return basic_factor_value(it1.nid, it2.node_id(), s1, s2); } - double factor_value (const neighbor_iterator& it1, const neighbor_iterator& it2, unsigned long s1, unsigned long s2) const - { return basic_factor_value(it1.node_id(), it2.node_id(), s1, s2); } - - private: - - double basic_factor_value ( - unsigned long n1, - unsigned long n2, - unsigned long s1, - unsigned long s2 - ) const - { - if (n1 > n2) - { - swap(n1,n2); - swap(s1,s2); - } - return weights[make_unordered_pair(n1,n2)][make_pair(s1,s2)]; - } - - }; - -// ---------------------------------------------------------------------------------------- - - class map_problem_chain - { - /* - This is a chain structured 8 node graph (so no cycles). - */ - - public: - - mutable std::map,std::map,double> > weights; - map_problem_chain() - { - for (int i = 0; i < 7; ++i) - { - weights[make_unordered_pair(i,i+1)][make_pair(0,0)] = rnd.get_random_gaussian(); - weights[make_unordered_pair(i,i+1)][make_pair(0,1)] = rnd.get_random_gaussian(); - weights[make_unordered_pair(i,i+1)][make_pair(1,0)] = rnd.get_random_gaussian(); - weights[make_unordered_pair(i,i+1)][make_pair(1,1)] = rnd.get_random_gaussian(); - } - } - - struct node_iterator - { - node_iterator() {} - node_iterator(unsigned long nid_): nid(nid_) {} - bool operator== (const node_iterator& item) const { return item.nid == nid; } - bool operator!= (const node_iterator& item) const { return item.nid != nid; } - - node_iterator& operator++() - { - ++nid; - return *this; - } - - unsigned long nid; - }; - - struct neighbor_iterator - { - neighbor_iterator() : count(0) {} - - bool operator== (const neighbor_iterator& item) const { return item.node_id() == node_id(); } - bool operator!= (const neighbor_iterator& item) const { return item.node_id() != node_id(); } - neighbor_iterator& operator++() - { - ++count; - return *this; - } - - unsigned long node_id () const - { - if (count >= 2) - return 8; - return nid[count]; - } - - unsigned long nid[2]; - unsigned int count; - }; - - unsigned long number_of_nodes ( - ) const - { - return 8; - } - - node_iterator begin( - ) const - { - node_iterator temp; - temp.nid = 0; - return temp; - } - - node_iterator end( - ) const - { - node_iterator temp; - temp.nid = 8; - return temp; - } - - neighbor_iterator begin( - const node_iterator& it - ) const - { - neighbor_iterator temp; - if (it.nid == 0) - { - temp.nid[0] = it.nid+1; - temp.nid[1] = 8; - } - else if (it.nid == 7) - { - temp.nid[0] = it.nid-1; - temp.nid[1] = 8; - } - else - { - temp.nid[0] = it.nid-1; - temp.nid[1] = it.nid+1; - } - return temp; - } - - neighbor_iterator begin( - const neighbor_iterator& it - ) const - { - const unsigned long nid = it.node_id(); - neighbor_iterator temp; - if (nid == 0) - { - temp.nid[0] = nid+1; - temp.nid[1] = 8; - } - else if (nid == 7) - { - temp.nid[0] = nid-1; - temp.nid[1] = 8; - } - else - { - temp.nid[0] = nid-1; - temp.nid[1] = nid+1; - } - return temp; - } - - neighbor_iterator end( - const node_iterator& - ) const - { - neighbor_iterator temp; - temp.nid[0] = 8; - temp.nid[1] = 8; - return temp; - } - - neighbor_iterator end( - const neighbor_iterator& - ) const - { - neighbor_iterator temp; - temp.nid[0] = 8; - temp.nid[1] = 8; - return temp; - } - - - unsigned long node_id ( - const node_iterator& it - ) const - { - return it.nid; - } - - unsigned long node_id ( - const neighbor_iterator& it - ) const - { - return it.node_id(); - } - - - unsigned long num_states ( - const node_iterator& - ) const - { - return 2; - } - - unsigned long num_states ( - const neighbor_iterator& - ) const - { - return 2; - } - - double factor_value (const node_iterator& it1, const node_iterator& it2, unsigned long s1, unsigned long s2) const - { return basic_factor_value(it1.nid, it2.nid, s1, s2); } - double factor_value (const neighbor_iterator& it1, const node_iterator& it2, unsigned long s1, unsigned long s2) const - { return basic_factor_value(it1.node_id(), it2.nid, s1, s2); } - double factor_value (const node_iterator& it1, const neighbor_iterator& it2, unsigned long s1, unsigned long s2) const - { return basic_factor_value(it1.nid, it2.node_id(), s1, s2); } - double factor_value (const neighbor_iterator& it1, const neighbor_iterator& it2, unsigned long s1, unsigned long s2) const - { return basic_factor_value(it1.node_id(), it2.node_id(), s1, s2); } - - private: - - double basic_factor_value ( - unsigned long n1, - unsigned long n2, - unsigned long s1, - unsigned long s2 - ) const - { - if (n1 > n2) - { - swap(n1,n2); - swap(s1,s2); - } - return weights[make_unordered_pair(n1,n2)][make_pair(s1,s2)]; - } - - }; - -// ---------------------------------------------------------------------------------------- - - - class map_problem2 - { - /* - This is a simple tree structured graph. In particular, it is a star made - up of 6 nodes. - */ - public: - matrix numbers; - - map_problem2() - { - numbers = randm(5,3,rnd); - } - - struct node_iterator - { - node_iterator() {} - node_iterator(unsigned long nid_): nid(nid_) {} - bool operator== (const node_iterator& item) const { return item.nid == nid; } - bool operator!= (const node_iterator& item) const { return item.nid != nid; } - - node_iterator& operator++() - { - ++nid; - return *this; - } - - unsigned long nid; - }; - - struct neighbor_iterator - { - neighbor_iterator() : count(0) {} - - bool operator== (const neighbor_iterator& item) const { return item.node_id() == node_id(); } - bool operator!= (const neighbor_iterator& item) const { return item.node_id() != node_id(); } - neighbor_iterator& operator++() - { - ++count; - return *this; - } - - unsigned long node_id () const - { - if (home_node == 6) - return 6; - - if (home_node < 5) - { - // all the nodes are connected to node 5 and nothing else - if (count == 0) - return 5; - else - return 6; // the number returned by the end() functions. - } - else if (count < 5) - { - return count; - } - else - { - return 6; - } - - } - - unsigned long home_node; - unsigned long count; - }; - - unsigned long number_of_nodes ( - ) const - { - return 6; - } - - node_iterator begin( - ) const - { - node_iterator temp; - temp.nid = 0; - return temp; - } - - node_iterator end( - ) const - { - node_iterator temp; - temp.nid = 6; - return temp; - } - - neighbor_iterator begin( - const node_iterator& it - ) const - { - neighbor_iterator temp; - temp.home_node = it.nid; - return temp; - } - - neighbor_iterator begin( - const neighbor_iterator& it - ) const - { - neighbor_iterator temp; - temp.home_node = it.node_id(); - return temp; - } - - neighbor_iterator end( - const node_iterator& - ) const - { - neighbor_iterator temp; - temp.home_node = 6; - return temp; - } - - neighbor_iterator end( - const neighbor_iterator& - ) const - { - neighbor_iterator temp; - temp.home_node = 6; - return temp; - } - - - unsigned long node_id ( - const node_iterator& it - ) const - { - return it.nid; - } - - unsigned long node_id ( - const neighbor_iterator& it - ) const - { - return it.node_id(); - } - - - unsigned long num_states ( - const node_iterator& - ) const - { - return 3; - } - - unsigned long num_states ( - const neighbor_iterator& - ) const - { - return 3; - } - - double factor_value (const node_iterator& it1, const node_iterator& it2, unsigned long s1, unsigned long s2) const - { return basic_factor_value(it1.nid, it2.nid, s1, s2); } - double factor_value (const neighbor_iterator& it1, const node_iterator& it2, unsigned long s1, unsigned long s2) const - { return basic_factor_value(it1.node_id(), it2.nid, s1, s2); } - double factor_value (const node_iterator& it1, const neighbor_iterator& it2, unsigned long s1, unsigned long s2) const - { return basic_factor_value(it1.nid, it2.node_id(), s1, s2); } - double factor_value (const neighbor_iterator& it1, const neighbor_iterator& it2, unsigned long s1, unsigned long s2) const - { return basic_factor_value(it1.node_id(), it2.node_id(), s1, s2); } - - private: - - double basic_factor_value ( - unsigned long n1, - unsigned long n2, - unsigned long s1, - unsigned long s2 - ) const - { - if (n1 > n2) - { - swap(n1,n2); - swap(s1,s2); - } - - - // basically ignore the other node in this factor. The node we - // are ignoring is the center node of this star graph. So we basically - // let it always have a value of 1. - if (s2 == 1) - return numbers(n1,s1) + 1; - else - return numbers(n1,s1); - } - - }; - -// ---------------------------------------------------------------------------------------- - - template - double find_total_score ( - const map_problem& prob, - const std::vector& map_assignment - ) - { - typedef typename map_problem::node_iterator node_iterator; - typedef typename map_problem::neighbor_iterator neighbor_iterator; - - double score = 0; - for (node_iterator i = prob.begin(); i != prob.end(); ++i) - { - const unsigned long id_i = prob.node_id(i); - for (neighbor_iterator j = prob.begin(i); j != prob.end(i); ++j) - { - const unsigned long id_j = prob.node_id(j); - score += prob.factor_value(i,j, map_assignment[id_i], map_assignment[id_j]); - } - } - - return score; - } - -// ---------------------------------------------------------------------------------------- - - - template < - typename map_problem - > - void brute_force_find_max_factor_graph_nmplp ( - const map_problem& prob, - std::vector& map_assignment - ) - { - std::vector temp_assignment; - temp_assignment.resize(prob.number_of_nodes(),0); - - double best_score = -std::numeric_limits::infinity(); - - for (unsigned long i = 0; i < 255; ++i) - { - temp_assignment[0] = (i&0x01)!=0; - temp_assignment[1] = (i&0x02)!=0; - temp_assignment[2] = (i&0x04)!=0; - temp_assignment[3] = (i&0x08)!=0; - temp_assignment[4] = (i&0x10)!=0; - temp_assignment[5] = (i&0x20)!=0; - temp_assignment[6] = (i&0x40)!=0; - temp_assignment[7] = (i&0x80)!=0; - - double score = find_total_score(prob,temp_assignment); - if (score > best_score) - { - best_score = score; - map_assignment = temp_assignment; - } - } - } - -// ---------------------------------------------------------------------------------------- - - template - void do_test( - ) - { - print_spinner(); - std::vector map_assignment1, map_assignment2; - map_problem prob; - find_max_factor_graph_nmplp(prob, map_assignment1, 1000, 1e-8); - - const double score1 = find_total_score(prob, map_assignment1); - - brute_force_find_max_factor_graph_nmplp(prob, map_assignment2); - const double score2 = find_total_score(prob, map_assignment2); - - dlog << LINFO << "score NMPLP: " << score1; - dlog << LINFO << "score MAP: " << score2; - - DLIB_TEST(std::abs(score1 - score2) < 1e-10); - DLIB_TEST(mat(map_assignment1) == mat(map_assignment2)); - } - -// ---------------------------------------------------------------------------------------- - - template - void do_test2( - ) - { - print_spinner(); - std::vector map_assignment1, map_assignment2; - map_problem prob; - find_max_factor_graph_nmplp(prob, map_assignment1, 10, 1e-8); - - const double score1 = find_total_score(prob, map_assignment1); - - map_assignment2.resize(6); - map_assignment2[0] = index_of_max(rowm(prob.numbers,0)); - map_assignment2[1] = index_of_max(rowm(prob.numbers,1)); - map_assignment2[2] = index_of_max(rowm(prob.numbers,2)); - map_assignment2[3] = index_of_max(rowm(prob.numbers,3)); - map_assignment2[4] = index_of_max(rowm(prob.numbers,4)); - map_assignment2[5] = 1; - const double score2 = find_total_score(prob, map_assignment2); - - dlog << LINFO << "score NMPLP: " << score1; - dlog << LINFO << "score MAP: " << score2; - dlog << LINFO << "MAP assignment: "<< trans(mat(map_assignment1)); - - DLIB_TEST(std::abs(score1 - score2) < 1e-10); - DLIB_TEST(mat(map_assignment1) == mat(map_assignment2)); - } - -// ---------------------------------------------------------------------------------------- - - class test_find_max_factor_graph_nmplp : public tester - { - public: - test_find_max_factor_graph_nmplp ( - ) : - tester ("test_find_max_factor_graph_nmplp", - "Runs tests on the find_max_factor_graph_nmplp routine.") - {} - - void perform_test ( - ) - { - rnd.clear(); - - dlog << LINFO << "test on a chain structured graph"; - for (int i = 0; i < 30; ++i) - do_test(); - - dlog << LINFO << "test on a 2 cycle graph"; - for (int i = 0; i < 30; ++i) - do_test >(); - - dlog << LINFO << "test on a fully connected graph"; - for (int i = 0; i < 5; ++i) - do_test >(); - - dlog << LINFO << "test on a tree structured graph"; - for (int i = 0; i < 10; ++i) - do_test2(); - } - } a; - -} - - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/find_max_factor_graph_viterbi.cpp b/lib/3rdParty/dlib/include/dlib/test/find_max_factor_graph_viterbi.cpp deleted file mode 100644 index 82754aef..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/find_max_factor_graph_viterbi.cpp +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.find_max_factor_graph_viterbi"); - -// ---------------------------------------------------------------------------------------- - - dlib::rand rnd; - -// ---------------------------------------------------------------------------------------- - - template < - unsigned long O, - unsigned long NS, - unsigned long num_nodes, - bool all_negative - > - class map_problem - { - public: - unsigned long order() const { return O; } - unsigned long num_states() const { return NS; } - - map_problem() - { - data = randm(number_of_nodes(),(long)std::pow(num_states(),(double)order()+1), rnd); - if (all_negative) - data = -data; - } - - unsigned long number_of_nodes ( - ) const - { - return num_nodes; - } - - template < - typename EXP - > - double factor_value ( - unsigned long node_id, - const matrix_exp& node_states - ) const - { - if (node_states.size() == 1) - return data(node_id, node_states(0)); - else if (node_states.size() == 2) - return data(node_id, node_states(0) + node_states(1)*NS); - else if (node_states.size() == 3) - return data(node_id, (node_states(0) + node_states(1)*NS)*NS + node_states(2)); - else - return data(node_id, ((node_states(0) + node_states(1)*NS)*NS + node_states(2))*NS + node_states(3)); - } - - matrix data; - }; - - -// ---------------------------------------------------------------------------------------- - - template < - typename map_problem - > - void brute_force_find_max_factor_graph_viterbi ( - const map_problem& prob, - std::vector& map_assignment - ) - { - using namespace dlib::impl; - const int order = prob.order(); - const int num_states = prob.num_states(); - - map_assignment.resize(prob.number_of_nodes()); - double best_score = -std::numeric_limits::infinity(); - matrix node_states; - node_states.set_size(prob.number_of_nodes()); - node_states = 0; - do - { - double score = 0; - for (unsigned long i = 0; i < prob.number_of_nodes(); ++i) - { - score += prob.factor_value(i, (colm(node_states,range(i,i-std::min(order,i))))); - } - - if (score > best_score) - { - for (unsigned long i = 0; i < map_assignment.size(); ++i) - map_assignment[i] = node_states(i); - best_score = score; - } - - } while(advance_state(node_states,num_states)); - - } - -// ---------------------------------------------------------------------------------------- - - template < - unsigned long order, - unsigned long num_states, - unsigned long num_nodes, - bool all_negative - > - void do_test_() - { - dlog << LINFO << "order: "<< order - << " num_states: " << num_states - << " num_nodes: " << num_nodes - << " all_negative: " << all_negative; - - for (int i = 0; i < 25; ++i) - { - print_spinner(); - map_problem prob; - std::vector assign, assign2; - brute_force_find_max_factor_graph_viterbi(prob, assign); - find_max_factor_graph_viterbi(prob, assign2); - - DLIB_TEST_MSG(mat(assign) == mat(assign2), - trans(mat(assign)) - << trans(mat(assign2)) - ); - } - } - - template < - unsigned long order, - unsigned long num_states, - unsigned long num_nodes - > - void do_test() - { - do_test_(); - } - - template < - unsigned long order, - unsigned long num_states, - unsigned long num_nodes - > - void do_test_negative() - { - do_test_(); - } - -// ---------------------------------------------------------------------------------------- - - class test_find_max_factor_graph_viterbi : public tester - { - public: - test_find_max_factor_graph_viterbi ( - ) : - tester ("test_find_max_factor_graph_viterbi", - "Runs tests on the find_max_factor_graph_viterbi routine.") - {} - - void perform_test ( - ) - { - do_test<1,3,0>(); - do_test<1,3,1>(); - do_test<1,3,2>(); - do_test<0,3,2>(); - do_test_negative<0,3,2>(); - - do_test<1,3,8>(); - do_test<2,3,7>(); - do_test_negative<2,3,7>(); - do_test<3,3,8>(); - do_test<4,3,8>(); - do_test_negative<4,3,8>(); - do_test<0,3,8>(); - do_test<4,3,1>(); - do_test<4,3,0>(); - - do_test<3,2,1>(); - do_test<3,2,0>(); - do_test<3,2,2>(); - do_test<2,2,1>(); - do_test_negative<3,2,1>(); - do_test_negative<3,2,0>(); - do_test_negative<3,2,2>(); - do_test_negative<2,2,1>(); - - do_test<0,3,0>(); - do_test<1,2,8>(); - do_test<2,2,7>(); - do_test<3,2,8>(); - do_test<0,2,8>(); - - do_test<1,1,8>(); - do_test<2,1,8>(); - do_test<3,1,8>(); - do_test<0,1,8>(); - } - } a; - -} - - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/geometry.cpp b/lib/3rdParty/dlib/include/dlib/test/geometry.cpp deleted file mode 100644 index 2e6baf05..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/geometry.cpp +++ /dev/null @@ -1,805 +0,0 @@ -// Copyright (C) 2008 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.geometry"); - - void geometry_test ( - ) - /*! - ensures - - runs tests on the geometry stuff compliance with the specs - !*/ - { - print_spinner(); - - point p1; - point p2(2,3); - - DLIB_TEST(p1.x() == 0); - DLIB_TEST(p1.y() == 0); - DLIB_TEST(p2.x() == 2); - DLIB_TEST(p2.y() == 3); - - DLIB_TEST((-p2).x() == -2); - DLIB_TEST((-p2).y() == -3); - - - p2 += p2; - DLIB_TEST(p2.x() == 4); - DLIB_TEST(p2.y() == 6); - - dlib::vector v1 = point(1,0); - dlib::vector v2(0,0,1); - - p1 = v2.cross(v1); - DLIB_TEST(p1 == point(0,1)); - DLIB_TEST(p1 != point(1,1)); - DLIB_TEST(p1 != point(1,0)); - - p1 = point(2,3); - rectangle rect1 = p1; - DLIB_TEST(rect1.width() == 1); - DLIB_TEST(rect1.height() == 1); - p2 = point(1,1); - - rect1 += p2; - DLIB_TEST(rect1.left() == 1); - DLIB_TEST(rect1.top() == 1); - DLIB_TEST(rect1.right() == 2); - DLIB_TEST(rect1.bottom() == 3); - - DLIB_TEST(rect1.width() == 2); - DLIB_TEST(rect1.height() == 3); - - // test the iostream << and >> operators (via string_cast and cast_to_string) - DLIB_TEST(string_cast(" (1, 2 )") == point(1,2)); - DLIB_TEST(string_cast(" ( -1, 2 )") == point(-1,2)); - DLIB_TEST(string_cast(" [(1, 2 )(3,4)]") == rectangle(1,2,3,4)); - DLIB_TEST(string_cast >(" (1, 2 , 3.5)") == dlib::vector(1,2,3.5)); - - DLIB_TEST(string_cast(cast_to_string(rect1)) == rect1); - DLIB_TEST(string_cast(cast_to_string(p1)) == p1); - DLIB_TEST(string_cast >(cast_to_string(v1)) == v1); - - rectangle rect2; - - // test the serialization code - ostringstream sout; - serialize(rect1,sout); - serialize(p1,sout); - serialize(v1,sout); - serialize(rect1,sout); - serialize(p1,sout); - serialize(v1,sout); - - istringstream sin(sout.str()); - - deserialize(rect2,sin); - deserialize(p2,sin); - deserialize(v2,sin); - DLIB_TEST(rect2 == rect1); - DLIB_TEST(p2 == p1); - DLIB_TEST(v2 == v1); - deserialize(rect2,sin); - deserialize(p2,sin); - deserialize(v2,sin); - DLIB_TEST(rect2 == rect1); - DLIB_TEST(p2 == p1); - DLIB_TEST(v2 == v1); - DLIB_TEST(sin.good()); - DLIB_TEST(sin.get() == EOF); - - - v1.x() = 1; - v1.y() = 2; - v1.z() = 3; - - matrix mv = v1; - DLIB_TEST(mv.nr() == 3); - DLIB_TEST(mv.nc() == 1); - DLIB_TEST(mv(0) == 1); - DLIB_TEST(mv(1) == 2); - DLIB_TEST(mv(2) == 3); - - set_all_elements(mv,0); - DLIB_TEST(mv(0) == 0); - DLIB_TEST(mv(1) == 0); - DLIB_TEST(mv(2) == 0); - - mv(0) = 5; - mv(1) = 6; - mv(2) = 7; - - v1 = mv; - DLIB_TEST(v1.x() == 5); - DLIB_TEST(v1.y() == 6); - DLIB_TEST(v1.z() == 7); - - - { - dlib::vector vd2; - dlib::vector vd3; - dlib::vector vl2; - dlib::vector vl3; - - vd2.x() = 2.3; - vd2.y() = 4.7; - - vd3.z() = 9; - - vd3 = vd2; - - - - vl2 = vd3; - vl3 = vd3; - - - DLIB_TEST(vd2.z() == 0); - DLIB_TEST(vd3.z() == 0); - DLIB_TEST(vl2.z() == 0); - DLIB_TEST(vl3.z() == 0); - - DLIB_TEST(vl2.x() == 2); - DLIB_TEST(vl3.x() == 2); - DLIB_TEST(vl2.y() == 5); - DLIB_TEST(vl3.y() == 5); - - - DLIB_TEST(abs(vd2.cross(vd3).dot(vd2)) < 1e-7); - DLIB_TEST(abs(vd3.cross(vd2).dot(vd2)) < 1e-7); - DLIB_TEST(abs(vd2.cross(vd3).dot(vd3)) < 1e-7); - DLIB_TEST(abs(vd3.cross(vd2).dot(vd3)) < 1e-7); - - DLIB_TEST(abs(vl2.cross(vl3).dot(vl2)) == 0); - DLIB_TEST(abs(vl3.cross(vl2).dot(vl2)) == 0); - DLIB_TEST(abs(vl2.cross(vl3).dot(vl3)) == 0); - DLIB_TEST(abs(vl3.cross(vl2).dot(vl3)) == 0); - - - DLIB_TEST((vd2-vd3).length() < 1e-7); - - DLIB_TEST(vl2 == vl3); - - - vl2.x() = 0; - vl2.y() = 0; - vl3 = vl2; - - vl2.x() = 4; - vl3.y() = 3; - - DLIB_TEST(vl2.cross(vl3).length() == 12); - DLIB_TEST(vl3.cross(vl2).length() == 12); - - - matrix m(3,3); - m = 1,2,3, - 4,5,6, - 7,8,9; - - vd3.x() = 2; - vd3.y() = 3; - vd3.z() = 4; - - vd3 = m*vd3; - - DLIB_TEST_MSG(vd3.x() == 1*2 + 2*3 + 3*4,vd3.x() << " == " << (1*2 + 2*3 + 3*4)); - DLIB_TEST(vd3.y() == 4*2 + 5*3 + 6*4); - DLIB_TEST(vd3.z() == 7*2 + 8*3 + 9*4); - - (vd3*2).dot(vd3); - (vd2*2).dot(vd3); - (vd3*2).dot(vd2); - (vd2*2).dot(vd2); - (2*vd3*2).dot(vd3); - (2*vd2*2).dot(vd3); - (2*vd3*2).dot(vd2); - (2*vd2*2).dot(vd2); - - (vd2 + vd3).dot(vd2); - (vd2 - vd3).dot(vd2); - (vd2/2).dot(vd2); - (vd3/2).dot(vd2); - } - - { - dlib::vector vd2; - dlib::vector vl3; - - vl3.x() = 1; - vl3.y() = 2; - vl3.z() = 3; - - vd2.x() = 6.5; - vd2.y() = 7.5; - - DLIB_TEST((vl3 + vd2).x() == 1+6.5); - DLIB_TEST((vl3 + vd2).y() == 2+7.5); - DLIB_TEST((vl3 + vd2).z() == 3+0); - - DLIB_TEST((vl3 - vd2).x() == 1-6.5); - DLIB_TEST((vl3 - vd2).y() == 2-7.5); - DLIB_TEST((vl3 - vd2).z() == 3-0); - - } - - { - dlib::vector v(3,4,5); - DLIB_TEST((-v).x() == -3.0); - DLIB_TEST((-v).y() == -4.0); - DLIB_TEST((-v).z() == -5.0); - } - - { - rectangle rect; - - point tl(2,3); - point tr(8,3); - point bl(2,9); - point br(8,9); - - rect += tl; - rect += tr; - rect += bl; - rect += br; - - DLIB_TEST(rect.tl_corner() == tl); - DLIB_TEST(rect.tr_corner() == tr); - DLIB_TEST(rect.bl_corner() == bl); - DLIB_TEST(rect.br_corner() == br); - - } - - { - point p1, center; - - center = point(3,4); - p1 = point(10,4); - - DLIB_TEST(rotate_point(center, p1, pi/2) == point(3,7+4)); - - center = point(3,3); - p1 = point(10,3); - - DLIB_TEST(rotate_point(center, p1, pi/4) == point(8,8)); - DLIB_TEST(rotate_point(center, p1, -pi/4) == point(8,-2)); - - DLIB_TEST(rotate_point(center, p1, pi/4 + 10*pi) == point(8,8)); - DLIB_TEST(rotate_point(center, p1, -pi/4 + 10*pi) == point(8,-2)); - DLIB_TEST(rotate_point(center, p1, pi/4 - 10*pi) == point(8,8)); - DLIB_TEST(rotate_point(center, p1, -pi/4 - 10*pi) == point(8,-2)); - - point_rotator rot(pi/2); - DLIB_TEST(rot(point(1,0)) == point(0,1)); - DLIB_TEST(rot(point(0,1)) == point(-1,0)); - DLIB_TEST(point(rot.get_m()*(dlib::vector(1,0))) == point(0,1)); - DLIB_TEST(point(rot.get_m()*(dlib::vector(0,1))) == point(-1,0)); - } - - { - rectangle rect; - - rect = grow_rect(rect,1); - DLIB_TEST(rect.width() == 2); - DLIB_TEST(rect.height() == 2); - DLIB_TEST(rect.left() == -1); - DLIB_TEST(rect.top() == -1); - DLIB_TEST(rect.right() == 0); - DLIB_TEST(rect.bottom() == 0); - } - { - rectangle rect; - - rect = grow_rect(rect,2); - DLIB_TEST(rect.width() == 4); - DLIB_TEST(rect.height() == 4); - DLIB_TEST(rect.left() == -2); - DLIB_TEST(rect.top() == -2); - DLIB_TEST(rect.right() == 1); - DLIB_TEST(rect.bottom() == 1); - - rect = shrink_rect(rect,1); - DLIB_TEST(rect.width() == 2); - DLIB_TEST(rect.height() == 2); - DLIB_TEST(rect.left() == -1); - DLIB_TEST(rect.top() == -1); - DLIB_TEST(rect.right() == 0); - DLIB_TEST(rect.bottom() == 0); - } - { - std::vector< dlib::vector > a; - - dlib::vector v; - dlib::rand rnd; - - for (int i = 0; i < 10; ++i) - { - v.x() = rnd.get_random_double(); - v.y() = rnd.get_random_double(); - v.z() = rnd.get_random_double(); - a.push_back(v); - - } - - // This test is just to make sure the covariance function can compile when used - // on a dlib::vector. The actual test doesn't matter. - DLIB_TEST(sum(covariance(mat(a))) < 10); - - } - - - DLIB_TEST(rectangle() + point(5,4) + point(10,10) == rectangle(5,4,10,10)); - - // make sure the center of a centered rectangle is always right - for (long x = -10; x <= 10; ++x) - { - for (long y = -10; y <= 10; ++y) - { - for (long w = 0; w < 10; ++w) - { - for (long h = 0; h < 10; ++h) - { - DLIB_TEST(center(centered_rect(x,y,w,h)) == point(x,y)); - } - } - } - } - - } - -// ---------------------------------------------------------------------------------------- - - void test_border_enumerator() - { - - - - border_enumerator be; - DLIB_TEST(be.at_start() == true); - DLIB_TEST(be.size() == 0); - DLIB_TEST(be.current_element_valid() == false); - DLIB_TEST(be.move_next() == false); - DLIB_TEST(be.at_start() == false); - DLIB_TEST(be.current_element_valid() == false); - DLIB_TEST(be.move_next() == false); - DLIB_TEST(be.at_start() == false); - DLIB_TEST(be.current_element_valid() == false); - DLIB_TEST(be.size() == 0); - - be = border_enumerator(rectangle(4,4,4,4),1); - DLIB_TEST(be.at_start() == true); - DLIB_TEST(be.size() == 1); - be = border_enumerator(rectangle(4,4,4,4),3); - DLIB_TEST(be.at_start() == true); - DLIB_TEST(be.size() == 1); - be = border_enumerator(rectangle(4,4,4,4),0); - DLIB_TEST(be.at_start() == true); - DLIB_TEST(be.size() == 0); - be = border_enumerator(rectangle(4,4,5,5),0); - DLIB_TEST(be.at_start() == true); - DLIB_TEST(be.size() == 0); - be = border_enumerator(rectangle(4,4,5,5),1); - DLIB_TEST(be.at_start() == true); - DLIB_TEST(be.size() == 4); - be = border_enumerator(rectangle(4,4,5,5),2); - DLIB_TEST(be.size() == 4); - be = border_enumerator(rectangle(4,4,6,6),1); - DLIB_TEST(be.size() == 8); - be = border_enumerator(rectangle(4,4,6,6),2); - DLIB_TEST(be.size() == 9); - be = border_enumerator(rectangle(4,4,6,6),3); - DLIB_TEST(be.size() == 9); - DLIB_TEST(be.at_start() == true); - - array2d img, img2; - for (int size = 1; size < 10; ++size) - { - for (int bs = 0; bs < 4; ++bs) - { - img.set_size(size,size); - img2.set_size(size,size); - - assign_all_pixels(img, 1); - assign_all_pixels(img2, 1); - - zero_border_pixels(img2, bs,bs); - - be = border_enumerator(get_rect(img),bs); - DLIB_TEST(be.at_start() == true); - DLIB_TEST(be.current_element_valid() == false); - while (be.move_next()) - { - DLIB_TEST(be.at_start() == false); - DLIB_TEST(be.current_element_valid() == true); - DLIB_TEST_MSG(get_rect(img).contains(be.element()) == true, - get_rect(img) << " " << be.element() - ); - const point p = be.element(); - img[p.y()][p.x()] = 0; - } - DLIB_TEST(be.at_start() == false); - DLIB_TEST(be.current_element_valid() == false); - DLIB_TEST(be.move_next() == false); - DLIB_TEST(be.current_element_valid() == false); - DLIB_TEST(be.move_next() == false); - DLIB_TEST(be.current_element_valid() == false); - DLIB_TEST(be.at_start() == false); - - DLIB_TEST(mat(img) == mat(img2)); - - } - } - - for (int size = 1; size < 10; ++size) - { - for (int bs = 0; bs < 4; ++bs) - { - img.set_size(size,size+5); - img2.set_size(size,size+5); - - assign_all_pixels(img, 1); - assign_all_pixels(img2, 1); - - zero_border_pixels(img2, bs,bs); - - const point shift(4,5); - - be = border_enumerator(translate_rect(get_rect(img),shift),bs); - DLIB_TEST(be.at_start() == true); - DLIB_TEST(be.current_element_valid() == false); - while (be.move_next()) - { - DLIB_TEST(be.current_element_valid() == true); - DLIB_TEST(be.at_start() == false); - DLIB_TEST_MSG(get_rect(img).contains(be.element()-shift) == true, - get_rect(img) << " " << be.element() - ); - const point p = be.element()-shift; - img[p.y()][p.x()] = 0; - } - DLIB_TEST(be.current_element_valid() == false); - DLIB_TEST(be.move_next() == false); - DLIB_TEST(be.current_element_valid() == false); - DLIB_TEST(be.move_next() == false); - DLIB_TEST(be.current_element_valid() == false); - DLIB_TEST(be.at_start() == false); - - DLIB_TEST(mat(img) == mat(img2)); - - } - } - - for (int size = 1; size < 10; ++size) - { - for (int bs = 0; bs < 4; ++bs) - { - img.set_size(size+2,size); - img2.set_size(size+2,size); - - assign_all_pixels(img, 1); - assign_all_pixels(img2, 1); - - zero_border_pixels(img2, bs,bs); - - const point shift(-4,5); - - be = border_enumerator(translate_rect(get_rect(img),shift),bs); - DLIB_TEST(be.current_element_valid() == false); - while (be.move_next()) - { - DLIB_TEST(be.current_element_valid() == true); - DLIB_TEST_MSG(get_rect(img).contains(be.element()-shift) == true, - get_rect(img) << " " << be.element() - ); - const point p = be.element()-shift; - img[p.y()][p.x()] = 0; - } - DLIB_TEST(be.current_element_valid() == false); - DLIB_TEST(be.move_next() == false); - DLIB_TEST(be.current_element_valid() == false); - DLIB_TEST(be.move_next() == false); - DLIB_TEST(be.current_element_valid() == false); - - DLIB_TEST(mat(img) == mat(img2)); - - } - } - - { - matrix hits, truth; - const rectangle rect = rectangle(1,1,4,3); - - border_enumerator be(rect, rectangle(2,2, 3, 3)); - DLIB_TEST(be.size() == 8); - hits = false; - while (be.move_next()) - { - DLIB_TEST(rect.contains(be.element())); - hits(be.element().y(), be.element().x()) = true; - } - DLIB_TEST(be.current_element_valid() == false); - DLIB_TEST(be.size() == 8); - truth = false; - truth(1,1) = truth(1,2) = truth(1,3) = truth(1,4) = truth(2,1) = - truth(3,1) = truth(2,4) = truth(3,4) = true; - DLIB_TEST_MSG(truth == hits, truth << endl << hits); - - - - - be = border_enumerator(rect, rectangle(0,0, 9, 9)); - DLIB_TEST(be.size() == 0); - hits = false; - while (be.move_next()) - { - DLIB_TEST(rect.contains(be.element())); - hits(be.element().y(), be.element().x()) = true; - } - DLIB_TEST(be.current_element_valid() == false); - DLIB_TEST(be.size() == 0); - truth = false; - DLIB_TEST(truth == hits); - - - - be = border_enumerator(rect, rectangle(0,0, 3, 9)); - DLIB_TEST(be.size() == 3); - hits = false; - while (be.move_next()) - { - DLIB_TEST(rect.contains(be.element())); - hits(be.element().y(), be.element().x()) = true; - } - DLIB_TEST(be.current_element_valid() == false); - DLIB_TEST(be.size() == 3); - truth = false; - truth(1,4) = truth(2,4) = truth(3,4) = true; - DLIB_TEST(truth == hits); - - - - - be = border_enumerator(rect, rectangle(2,1, 4, 3)); - DLIB_TEST(be.size() == 3); - hits = false; - while (be.move_next()) - { - DLIB_TEST(rect.contains(be.element())); - hits(be.element().y(), be.element().x()) = true; - } - DLIB_TEST(be.current_element_valid() == false); - DLIB_TEST(be.size() == 3); - truth = false; - truth(1,1) = truth(2,1) = truth(3,1) = true; - DLIB_TEST(truth == hits); - - - - be = border_enumerator(rect, rectangle(1,1, 5, 2)); - DLIB_TEST(be.size() == 4); - hits = false; - while (be.move_next()) - { - DLIB_TEST(rect.contains(be.element())); - hits(be.element().y(), be.element().x()) = true; - } - DLIB_TEST(be.current_element_valid() == false); - DLIB_TEST(be.size() == 4); - truth = false; - truth(3,1) = truth(3,2) = truth(3,3) = truth(3,4) = true; - DLIB_TEST(truth == hits); - - - - } - - } - -// ---------------------------------------------------------------------------------------- - - void test_find_affine_transform() - { - //typedef dlib::vector vect; - typedef point vect; - std::vector from, to; - - from.push_back(vect(0,0)); - to.push_back(vect(0,1)); - - from.push_back(vect(0,1)); - to.push_back(vect(1,1)); - - from.push_back(vect(1,1)); - to.push_back(vect(1,0)); - - from.push_back(vect(1,0)); - to.push_back(vect(0,0)); - - point_transform_affine t = find_affine_transform(from,to); - point_transform_affine tinv = inv(t); - - for (unsigned long i = 0; i < from.size(); ++i) - { - dlog << LINFO << "affine transformation error: "<< length(t(from[i])-to[i]); - DLIB_TEST(length(t(from[i])-to[i]) < 1e-14); - DLIB_TEST(length(tinv(t(from[i]))-from[i]) < 1e-14); - DLIB_TEST(length(t(tinv(from[i]))-from[i]) < 1e-14); - } - - ostringstream sout; - serialize(t, sout); - istringstream sin(sout.str()); - point_transform_affine t2; - DLIB_TEST(length(t2(point(2,3)) - point(2,3)) < 1e-14); - deserialize(t2, sin); - DLIB_TEST(max(abs(t2.get_m()-t.get_m())) < 1e-14); - DLIB_TEST(max(abs(t2.get_b()-t.get_b())) < 1e-14); - } - -// ---------------------------------------------------------------------------------------- - - double projective_transform_pass_rate(const double error_rate) - { - print_spinner(); - dlog << LINFO << "projective_transform_pass_rate, error_rate: "<< error_rate; - dlib::rand rnd; - running_stats pass_rate; - for (int rounds = 0; rounds < 1000; ++rounds) - { - running_stats rs, rs_true; - matrix H = 2*(randm(3,3,rnd)-0.5); - - H(0,2) = rnd.get_random_gaussian()*10; - H(1,2) = rnd.get_random_gaussian()*10; - - - H(2,0) = rnd.get_random_double()*2.1; - H(2,1) = rnd.get_random_double()*2.1; - H(2,2) = 1 + rnd.get_random_gaussian()*3.1; - - point_transform_projective tran(H); - point_transform_projective traninv = inv(tran); - - const int num = rnd.get_random_32bit_number()%8 + 4; - - std::vector > from_points, to_points; - for (int i = 0; i < num; ++i) - { - dlib::vector p = randm(2,1,rnd)*1000; - from_points.push_back(p); - to_points.push_back(tran(p) + (randm(2,1,rnd)-0.5)*error_rate); - DLIB_TEST(length(traninv(tran(p))-p) <= 1e-5); - DLIB_TEST(length(tran(traninv(p))-p) <= 1e-5); - } - - - point_transform_projective tran2 = find_projective_transform(from_points, to_points); - - for (unsigned long i = 0; i < from_points.size(); ++i) - { - const double err = length_squared(tran2(from_points[i]) - to_points[i]); - rs.add(err); - const double err_true = length_squared(tran(from_points[i]) - to_points[i]); - rs_true.add(err_true); - } - - if ( rs.mean() < 0.01) - { - pass_rate.add(1); - } - else - { - dlog << LINFO << " errors: mean/max: " << rs.mean() << " " << rs.max(); - pass_rate.add(0); - } - - ostringstream sout; - serialize(tran, sout); - istringstream sin(sout.str()); - point_transform_projective tran3; - DLIB_TEST(length(tran3(point(2,3)) - point(2,3)) < 1e-14); - deserialize(tran3, sin); - DLIB_TEST(max(abs(tran3.get_m()-tran.get_m())) < 1e-14); - } - - dlog << LINFO << " pass_rate.mean(): "<< pass_rate.mean(); - return pass_rate.mean(); - } - -// ---------------------------------------------------------------------------------------- - - template - void test_find_similarity_transform() - { - print_spinner(); - std::vector > from_points, to_points; - - from_points.push_back(dlib::vector(0,0)); - from_points.push_back(dlib::vector(0,1)); - from_points.push_back(dlib::vector(1,0)); - - to_points.push_back(dlib::vector(8,0)); - to_points.push_back(dlib::vector(6,0)); - to_points.push_back(dlib::vector(8,2)); - - point_transform_affine tform = find_similarity_transform(from_points, to_points); - - for (unsigned long i = 0; i < from_points.size(); ++i) - { - DLIB_TEST(length(tform(from_points[i]) - to_points[i]) < 1e-14); - } - } - - template - void test_find_similarity_transform2() - { - print_spinner(); - std::vector > from_points, to_points; - - from_points.push_back(dlib::vector(0,0)); - from_points.push_back(dlib::vector(0,1)); - - to_points.push_back(dlib::vector(8,0)); - to_points.push_back(dlib::vector(6,0)); - - point_transform_affine tform = find_similarity_transform(from_points, to_points); - - for (unsigned long i = 0; i < from_points.size(); ++i) - { - DLIB_TEST(length(tform(from_points[i]) - to_points[i]) < 1e-14); - } - } - -// ---------------------------------------------------------------------------------------- - - class geometry_tester : public tester - { - public: - geometry_tester ( - ) : - tester ("test_geometry", - "Runs tests on the geometry stuff.") - {} - - void perform_test ( - ) - { - geometry_test(); - test_border_enumerator(); - test_find_affine_transform(); - DLIB_TEST(projective_transform_pass_rate(0.1) > 0.99); - DLIB_TEST(projective_transform_pass_rate(0.0) == 1); - - test_find_similarity_transform(); - test_find_similarity_transform2(); - test_find_similarity_transform(); - test_find_similarity_transform2(); - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/graph.cpp b/lib/3rdParty/dlib/include/dlib/test/graph.cpp deleted file mode 100644 index 0651f304..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/graph.cpp +++ /dev/null @@ -1,414 +0,0 @@ -// Copyright (C) 2007 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -// This is called an unnamed-namespace and it has the effect of making everything inside this file "private" -// so that everything you declare will have static linkage. Thus we won't have any multiply -// defined symbol errors coming out of the linker when we try to compile the test suite. -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - - - // Declare the logger we will use in this test. The name of the tester - // should start with "test." - logger dlog("test.graph"); - - template < - typename graph - > - void graph_test ( - ) - /*! - requires - - graph is an implementation of graph/graph_kernel_abstract.h - is instantiated with int - ensures - - runs tests on graph for compliance with the specs - !*/ - { - - print_spinner(); - - COMPILE_TIME_ASSERT(is_graph::value); - - graph a, b; - dlib::set::compare_1b_c s; - - DLIB_TEST(graph_contains_length_one_cycle(a) == false); - DLIB_TEST(graph_contains_undirected_cycle(a) == false); - - DLIB_TEST(a.number_of_nodes() == 0); - - a.set_number_of_nodes(5); - DLIB_TEST(graph_is_connected(a) == false); - DLIB_TEST(graph_contains_undirected_cycle(a) == false); - DLIB_TEST(a.number_of_nodes() == 5); - DLIB_TEST(graph_contains_length_one_cycle(a) == false); - - for (int i = 0; i < 5; ++i) - { - a.node(i).data = i; - DLIB_TEST(a.node(i).index() == (unsigned int)i); - } - - a.remove_node(1); - - DLIB_TEST(a.number_of_nodes() == 4); - - - // make sure that only the number with data == 1 was removed - int count = 0; - for (int i = 0; i < 4; ++i) - { - count += a.node(i).data; - DLIB_TEST(a.node(i).number_of_neighbors() == 0); - DLIB_TEST(a.node(i).index() == (unsigned int)i); - } - - DLIB_TEST(count == 9); - - - a.add_edge(1,1); - DLIB_TEST(graph_contains_length_one_cycle(a) == true); - DLIB_TEST(graph_contains_undirected_cycle(a) == true); - DLIB_TEST(a.has_edge(1,1)); - DLIB_TEST(a.node(1).number_of_neighbors() == 1); - - a.add_edge(1,3); - DLIB_TEST(a.node(1).number_of_neighbors() == 2); - DLIB_TEST(a.node(2).number_of_neighbors() == 0); - DLIB_TEST(a.node(3).number_of_neighbors() == 1); - DLIB_TEST(a.has_edge(1,1)); - DLIB_TEST(a.has_edge(1,3)); - DLIB_TEST(a.has_edge(3,1)); - DLIB_TEST(graph_contains_undirected_cycle(a) == true); - a.remove_edge(1,1); - DLIB_TEST(graph_contains_length_one_cycle(a) == false); - DLIB_TEST(graph_contains_undirected_cycle(a) == false); - DLIB_TEST(a.node(1).number_of_neighbors() == 1); - DLIB_TEST(a.node(2).number_of_neighbors() == 0); - DLIB_TEST(a.node(3).number_of_neighbors() == 1); - DLIB_TEST(a.has_edge(1,1) == false); - DLIB_TEST(a.has_edge(1,3)); - DLIB_TEST(a.has_edge(3,1)); - DLIB_TEST(graph_contains_undirected_cycle(a) == false); - - swap(a,b); - - - DLIB_TEST(graph_contains_undirected_cycle(b) == false); - DLIB_TEST(b.node(1).number_of_neighbors() == 1); - DLIB_TEST(b.node(2).number_of_neighbors() == 0); - DLIB_TEST(b.node(3).number_of_neighbors() == 1); - DLIB_TEST(b.has_edge(1,1) == false); - DLIB_TEST(b.has_edge(1,3)); - DLIB_TEST(b.has_edge(3,1)); - DLIB_TEST(graph_contains_undirected_cycle(b) == false); - - DLIB_TEST(a.number_of_nodes() == 0); - DLIB_TEST(b.number_of_nodes() == 4); - - copy_graph_structure(b,b); - DLIB_TEST(b.number_of_nodes() == 4); - - b.add_edge(1,2); - DLIB_TEST(graph_contains_undirected_cycle(b) == false); - DLIB_TEST(graph_contains_undirected_cycle(b) == false); - b.add_edge(3,2); - DLIB_TEST(graph_contains_undirected_cycle(b) == true); - b.add_edge(1,1); - DLIB_TEST(graph_is_connected(b) == false); - b.add_edge(0,2); - DLIB_TEST(graph_is_connected(b) == true); - - DLIB_TEST(graph_contains_undirected_cycle(b) == true); - - DLIB_TEST(a.number_of_nodes() == 0); - - for (unsigned long i = 0; i < b.number_of_nodes(); ++i) - { - for (unsigned long j = 0; j < b.node(i).number_of_neighbors(); ++j) - { - b.node(i).edge(j) = 'c'; - } - } - - b.node(1).edge(0) = 'a'; - const unsigned long e1 = b.node(1).neighbor(0).index(); - b.node(0).edge(0) = 'n'; - const unsigned long e2 = b.node(0).neighbor(0).index(); - - ostringstream sout; - serialize(b, sout); - istringstream sin(sout.str()); - - DLIB_TEST(graph_contains_undirected_cycle(a) == false); - - a.set_number_of_nodes(10); - deserialize(a, sin); - DLIB_TEST(graph_contains_undirected_cycle(a) == true); - - for (unsigned long i = 0; i < a.number_of_nodes(); ++i) - { - for (unsigned long j = 0; j < a.node(i).number_of_neighbors(); ++j) - { - if ((i == 0 && a.node(i).neighbor(j).index() == e2) || - (i == e2 && a.node(i).neighbor(j).index() == 0) ) - { - DLIB_TEST(a.node(i).edge(j) == 'n'); - } - else if ((i == 1 && a.node(i).neighbor(j).index() == e1) || - (i == e1 && a.node(i).neighbor(j).index() == 1)) - { - DLIB_TEST(a.node(i).edge(j) == 'a'); - } - else - { - DLIB_TEST(i != 0 || a.node(i).neighbor(j).index() != e2); - DLIB_TEST_MSG(a.node(i).edge(j) == 'c',a.node(i).edge(j)); - } - } - } - - DLIB_TEST(a.number_of_nodes() == 4); - DLIB_TEST(a.has_edge(1,2) == true); - DLIB_TEST(a.has_edge(3,2) == true); - DLIB_TEST(a.has_edge(1,1) == true); - DLIB_TEST(a.has_edge(0,2) == true); - DLIB_TEST(a.has_edge(1,3) == true); - DLIB_TEST(a.has_edge(0,1) == false); - DLIB_TEST(a.has_edge(0,3) == false); - DLIB_TEST(a.has_edge(0,0) == false); - DLIB_TEST(a.has_edge(1,0) == false); - DLIB_TEST(a.has_edge(3,0) == false); - - - for (unsigned long i = 0; i < a.number_of_nodes(); ++i) - { - a.node(i).data = static_cast(i); - } - - a.remove_node(2); - DLIB_TEST(a.number_of_nodes() == 3); - DLIB_TEST(graph_contains_undirected_cycle(a) == true); - - count = 0; - for (unsigned long i = 0; i < a.number_of_nodes(); ++i) - { - if (a.node(i).data == 0) - { - DLIB_TEST(a.node(i).number_of_neighbors() == 0); - } - else if (a.node(i).data == 1) - { - DLIB_TEST(a.node(i).number_of_neighbors() == 2); - } - else if (a.node(i).data == 3) - { - DLIB_TEST(a.node(i).number_of_neighbors() == 1); - } - else - { - DLIB_TEST_MSG(false,"this is impossible"); - } - - for (unsigned long j = 0; j < a.number_of_nodes(); ++j) - { - if ((a.node(i).data == 1 && a.node(j).data == 1) || - (a.node(i).data == 1 && a.node(j).data == 3) || - (a.node(i).data == 3 && a.node(j).data == 1)) - { - DLIB_TEST(a.has_edge(i,j) == true); - ++count; - } - else - { - DLIB_TEST(a.has_edge(i,j) == false); - } - } - } - DLIB_TEST_MSG(count == 3,count); - DLIB_TEST(graph_contains_undirected_cycle(a) == true); - a.remove_edge(1,1); - DLIB_TEST(graph_contains_undirected_cycle(a) == false); - - DLIB_TEST(b.number_of_nodes() == 4); - b.clear(); - DLIB_TEST(b.number_of_nodes() == 0); - - - a.clear(); - - /* - 1 7 - | / \ - 2 6 0 - \ / | - 3 / - / \ / - 4 5 - */ - a.set_number_of_nodes(8); - a.add_edge(1,2); - a.add_edge(2,3); - a.add_edge(3,4); - a.add_edge(3,5); - a.add_edge(3,6); - a.add_edge(6,7); - a.add_edge(7,0); - a.add_edge(0,5); - - DLIB_TEST(graph_is_connected(a)); - - dlib::set::compare_1b_c>::kernel_1b_c sos; - - dlib::graph::compare_1b_c, dlib::set::compare_1b_c>::kernel_1a_c join_tree; - unsigned long temp; - triangulate_graph_and_find_cliques(a,sos); - DLIB_TEST(a.number_of_nodes() == 8); - - create_join_tree(a, join_tree); - DLIB_TEST(join_tree.number_of_nodes() == 6); - DLIB_TEST(graph_is_connected(join_tree) == true); - DLIB_TEST(graph_contains_undirected_cycle(join_tree) == false); - DLIB_TEST(is_join_tree(a, join_tree)); - - // check old edges - DLIB_TEST(a.has_edge(1,2)); - DLIB_TEST(a.has_edge(2,3)); - DLIB_TEST(a.has_edge(3,4)); - DLIB_TEST(a.has_edge(3,5)); - DLIB_TEST(a.has_edge(3,6)); - DLIB_TEST(a.has_edge(6,7)); - DLIB_TEST(a.has_edge(7,0)); - DLIB_TEST(a.has_edge(0,5)); - - DLIB_TEST(graph_is_connected(a)); - - DLIB_TEST(sos.size() == 6); - - - temp = 1; s.add(temp); - temp = 2; s.add(temp); - DLIB_TEST(sos.is_member(s)); - s.clear(); - temp = 2; s.add(temp); - temp = 3; s.add(temp); - DLIB_TEST(sos.is_member(s)); - s.clear(); - temp = 4; s.add(temp); - temp = 3; s.add(temp); - DLIB_TEST(sos.is_member(s)); - - sos.reset(); - while (sos.move_next()) - { - DLIB_TEST(is_clique(a, sos.element())); - DLIB_TEST(is_maximal_clique(a, sos.element())); - } - - } - - - void test_copy() - { - { - graph::kernel_1a_c a,b; - - a.set_number_of_nodes(3); - a.node(0).data = 1; - a.node(1).data = 2; - a.node(2).data = 3; - a.add_edge(0,1); - a.add_edge(0,2); - edge(a,0,1) = 4; - edge(a,0,2) = 5; - - a.add_edge(0,0); - edge(a,0,0) = 9; - copy_graph(a, b); - - DLIB_TEST(b.number_of_nodes() == 3); - DLIB_TEST(b.node(0).data == 1); - DLIB_TEST(b.node(1).data == 2); - DLIB_TEST(b.node(2).data == 3); - DLIB_TEST(edge(b,0,1) == 4); - DLIB_TEST(edge(b,0,2) == 5); - DLIB_TEST(edge(b,0,0) == 9); - } - { - graph::kernel_1a_c a,b; - - a.set_number_of_nodes(4); - a.node(0).data = 1; - a.node(1).data = 2; - a.node(2).data = 3; - a.node(3).data = 8; - a.add_edge(0,1); - a.add_edge(0,2); - a.add_edge(2,3); - edge(a,0,1) = 4; - edge(a,0,2) = 5; - edge(a,2,3) = 6; - - copy_graph(a, b); - - DLIB_TEST(b.number_of_nodes() == 4); - DLIB_TEST(b.node(0).data == 1); - DLIB_TEST(b.node(1).data == 2); - DLIB_TEST(b.node(2).data == 3); - DLIB_TEST(b.node(3).data == 8); - DLIB_TEST(edge(b,0,1) == 4); - DLIB_TEST(edge(b,0,2) == 5); - DLIB_TEST(edge(b,2,3) == 6); - } - } - - - - class graph_tester : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a test for the graph object. When it is constructed - it adds itself into the testing framework. The command line switch is - specified as test_directed_graph by passing that string to the tester constructor. - !*/ - public: - graph_tester ( - ) : - tester ("test_graph", - "Runs tests on the graph component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a_c"; - graph_test::kernel_1a_c>(); - - dlog << LINFO << "testing kernel_1a"; - graph_test::kernel_1a>(); - - test_copy(); - } - } a; - - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/graph_cuts.cpp b/lib/3rdParty/dlib/include/dlib/test/graph_cuts.cpp deleted file mode 100644 index 43ba35c1..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/graph_cuts.cpp +++ /dev/null @@ -1,1217 +0,0 @@ -// Copyright (C) 2012 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - - logger dlog("test.graph_cuts"); - -// ---------------------------------------------------------------------------------------- - - class dense_potts_problem - { - public: - typedef double value_type; - private: - - matrix factors1; - matrix factors2; - matrix labels; - public: - - dense_potts_problem ( - unsigned long num_nodes, - dlib::rand& rnd - ) - { - factors1 = -7*(randm(num_nodes, 1, rnd)-0.5); - factors2 = make_symmetric(randm(num_nodes, num_nodes, rnd) > 0.5); - labels.set_size(num_nodes); - labels = FREE_NODE; - } - - unsigned long number_of_nodes ( - ) const { return factors1.nr(); } - - unsigned long number_of_neighbors ( - unsigned long // idx - ) const { return number_of_nodes()-1; } - - unsigned long get_neighbor_idx ( - unsigned long node_id1, - unsigned long node_id2 - ) const - { - if (node_id2 < node_id1) - return node_id2; - else - return node_id2-1; - } - - unsigned long get_neighbor ( - unsigned long node_id, - unsigned long idx - ) const - { - DLIB_TEST(node_id < number_of_nodes()); - DLIB_TEST(idx < number_of_neighbors(node_id)); - if (idx < node_id) - return idx; - else - return idx+1; - } - - void set_label ( - const unsigned long& idx, - node_label value - ) - { - labels(idx) = value; - } - - node_label get_label ( - const unsigned long& idx - ) const - { - return labels(idx); - } - - - value_type factor_value (unsigned long idx) const - { - DLIB_TEST(idx < number_of_nodes()); - - return factors1(idx); - } - - value_type factor_value_disagreement (unsigned long idx1, unsigned long idx2) const - { - DLIB_TEST(idx1 != idx2); - DLIB_TEST(idx1 < number_of_nodes()); - DLIB_TEST(idx2 < number_of_nodes()); - DLIB_TEST(get_neighbor_idx(idx1,idx2) < number_of_neighbors(idx1)); - DLIB_TEST(get_neighbor_idx(idx2,idx1) < number_of_neighbors(idx2)); - - return factors2(idx1, idx2); - } - - }; - -// ---------------------------------------------------------------------------------------- - - class image_potts_problem - { - public: - typedef double value_type; - const static unsigned long max_number_of_neighbors = 4; - private: - - matrix factors1; - matrix factors2; - matrix labels; - long nr; - long nc; - rectangle rect, inner_rect; - mutable long count; - public: - - image_potts_problem ( - long nr_, - long nc_, - dlib::rand& rnd - ) : nr(nr_), nc(nc_) - { - rect = rectangle(0,0,nc-1,nr-1); - inner_rect = shrink_rect(rect,1); - const unsigned long num_nodes = nr*nc; - factors1 = -7*(randm(num_nodes, 1, rnd)); - factors2 = randm(num_nodes, 4, rnd) > 0.5; - - //factors1 = 0; - //set_rowm(factors1, range(0, factors1.nr()/2)) = -1; - - labels.set_size(num_nodes); - labels = FREE_NODE; - - count = 0; - } - - ~image_potts_problem() - { - dlog << LTRACE << "interface calls: " << count; - dlog << LTRACE << "labels hash: "<< murmur_hash3_128bit(&labels(0), labels.size()*sizeof(labels(0)), 0).first; - } - - unsigned long number_of_nodes ( - ) const { return factors1.nr(); } - - unsigned long number_of_neighbors ( - unsigned long idx - ) const - { - ++count; - const point& p = get_loc(idx); - if (inner_rect.contains(p)) - return 4; - else if (p == rect.tl_corner() || - p == rect.bl_corner() || - p == rect.tr_corner() || - p == rect.br_corner() ) - return 2; - else - return 3; - } - - unsigned long get_neighbor_idx ( - long node_id1, - long node_id2 - ) const - { - ++count; - const point& p = get_loc(node_id1); - long ret = 0; - if (rect.contains(p + point(1,0))) - { - if (node_id2-node_id1 == 1) - return ret; - ++ret; - } - - if (rect.contains(p - point(1,0))) - { - if (node_id2-node_id1 == -1) - return ret; - ++ret; - } - - if (rect.contains(p + point(0,1))) - { - if (node_id2-node_id1 == nc) - return ret; - ++ret; - } - - return ret; - } - - unsigned long get_neighbor ( - long node_id, - long idx - ) const - { - ++count; - const point& p = get_loc(node_id); - if (rect.contains(p + point(1,0))) - { - if (idx == 0) - return node_id+1; - --idx; - } - - if (rect.contains(p - point(1,0))) - { - if (idx == 0) - return node_id-1; - --idx; - } - - if (rect.contains(p + point(0,1))) - { - if (idx == 0) - return node_id+nc; - --idx; - } - - return node_id-nc; - } - - void set_label ( - const unsigned long& idx, - node_label value - ) - { - ++count; - labels(idx) = value; - } - - node_label get_label ( - const unsigned long& idx - ) const - { - ++count; - return labels(idx); - } - - value_type factor_value (unsigned long idx) const - { - ++count; - DLIB_TEST(idx < (unsigned long)number_of_nodes()); - - return factors1(idx); - } - - value_type factor_value_disagreement (unsigned long idx1, unsigned long idx2) const - { - ++count; - DLIB_TEST(idx1 != idx2); - DLIB_TEST(idx1 < (unsigned long)number_of_nodes()); - DLIB_TEST(idx2 < (unsigned long)number_of_nodes()); - - // make this function symmetric - if (idx1 > idx2) - swap(idx1,idx2); - - - DLIB_TEST(get_neighbor(idx1, get_neighbor_idx(idx1, idx2)) == idx2); - DLIB_TEST(get_neighbor(idx2, get_neighbor_idx(idx2, idx1)) == idx1); - - // the neighbor relationship better be symmetric - DLIB_TEST(get_neighbor_idx(idx1,idx2) < number_of_neighbors(idx1)); - DLIB_TEST_MSG(get_neighbor_idx(idx2,idx1) < number_of_neighbors(idx2), - "\n idx1: "<< idx1 << - "\n idx2: "<< idx2 << - "\n get_neighbor_idx(idx2,idx1): "<< get_neighbor_idx(idx2,idx1) << - "\n number_of_neighbors(idx2): " << number_of_neighbors(idx2) << - "\n nr: "<< nr << - "\n nc: "<< nc - ); - - return factors2(idx1, get_neighbor_idx(idx1,idx2)); - } - - private: - point get_loc ( - const unsigned long& idx - ) const - { - return point(idx%nc, idx/nc); - } - - }; - -// ---------------------------------------------------------------------------------------- - - template - void brute_force_potts_model ( - potts_model& g - ) - { - potts_model m(g); - - const unsigned long num = (unsigned long)std::pow(2.0, (double)m.number_of_nodes()); - - double best_score = -std::numeric_limits::infinity(); - for (unsigned long i = 0; i < num; ++i) - { - for (unsigned long j = 0; j < m.number_of_nodes(); ++j) - { - unsigned long T = (1)< best_score) - { - best_score = score; - g = m; - } - } - } - -// ---------------------------------------------------------------------------------------- - - template - void brute_force_potts_model_on_graph ( - const graph_type& g, - std::vector& labels_ - ) - { - std::vector labels; - labels.resize(g.number_of_nodes()); - - const unsigned long num = (unsigned long)std::pow(2.0, (double)g.number_of_nodes()); - - double best_score = -std::numeric_limits::infinity(); - for (unsigned long i = 0; i < num; ++i) - { - for (unsigned long j = 0; j < g.number_of_nodes(); ++j) - { - unsigned long T = (1)< best_score) - { - best_score = score; - labels_ = labels; - } - } - } - -// ---------------------------------------------------------------------------------------- - - template - void make_random_undirected_graph( - dlib::rand& rnd, - graph_type& g - ) - { - typedef typename graph_type::edge_type edge_weight_type; - g.clear(); - const unsigned int num_nodes = rnd.get_random_32bit_number()%8; - g.set_number_of_nodes(num_nodes); - - const unsigned int num_edges = static_cast(num_nodes*(num_nodes-1)/2*rnd.get_random_double() + 0.5); - - // add the right number of randomly selected edges - unsigned int count = 0; - while (count < num_edges) - { - unsigned long i = rnd.get_random_32bit_number()%g.number_of_nodes(); - unsigned long j = rnd.get_random_32bit_number()%g.number_of_nodes(); - if (i != j && g.has_edge(i, j) == false) - { - ++count; - g.add_edge(i, j); - edge(g, i, j) = static_cast(rnd.get_random_double()*50); - } - } - - for (unsigned long i = 0; i < g.number_of_nodes(); ++i) - { - g.node(i).data = static_cast(rnd.get_random_gaussian()*200); - } - } - -// ---------------------------------------------------------------------------------------- - - void test_graph_potts_model( - dlib::rand& rnd - ) - { - using namespace std; - double brute_force_score; - double graph_cut_score; - - graph::kernel_1a_c temp; - make_random_undirected_graph(rnd,temp); - - { - std::vector labels; - - brute_force_potts_model_on_graph(temp, labels); - - for (unsigned long i = 0; i < temp.number_of_nodes(); ++i) - { - dlog << LTRACE << "node " << i << ": "<< (int)labels[i]; - } - - brute_force_score = potts_model_score(temp, labels); - dlog << LTRACE << "brute force score: "<< brute_force_score; - } - dlog << LTRACE << "******************"; - - { - std::vector labels; - find_max_factor_graph_potts(temp, labels); - DLIB_TEST(temp.number_of_nodes() == labels.size()); - - for (unsigned long i = 0; i < temp.number_of_nodes(); ++i) - { - dlog << LTRACE << "node " << i << ": "<< (int)labels[i]; - } - graph_cut_score = potts_model_score(temp, labels); - dlog << LTRACE << "graph cut score: "<< graph_cut_score; - } - - DLIB_TEST_MSG(graph_cut_score == brute_force_score, std::abs(graph_cut_score - brute_force_score)); - - dlog << LTRACE << "##################"; - dlog << LTRACE << "##################"; - dlog << LTRACE << "##################"; - } - -// ---------------------------------------------------------------------------------------- - - template - void impl_test_potts_model ( - potts_prob& p - ) - { - using namespace std; - double brute_force_score; - double graph_cut_score; - - { - potts_prob temp(p); - brute_force_potts_model(temp); - - for (unsigned long i = 0; i < temp.number_of_nodes(); ++i) - { - dlog << LTRACE << "node " << i << ": "<< (int)temp.get_label(i); - } - brute_force_score = potts_model_score(temp); - dlog << LTRACE << "brute force score: "<< brute_force_score; - } - dlog << LTRACE << "******************"; - - { - potts_prob temp(p); - find_max_factor_graph_potts(temp); - - for (unsigned long i = 0; i < temp.number_of_nodes(); ++i) - { - dlog << LTRACE << "node " << i << ": "<< (int)temp.get_label(i); - } - graph_cut_score = potts_model_score(temp); - dlog << LTRACE << "graph cut score: "<< graph_cut_score; - } - - DLIB_TEST_MSG(graph_cut_score == brute_force_score, std::abs(graph_cut_score - brute_force_score)); - - dlog << LTRACE << "##################"; - dlog << LTRACE << "##################"; - dlog << LTRACE << "##################"; - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// BASIC MIN CUT STUFF -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - template - void brute_force_min_cut ( - directed_graph& g, - unsigned long source, - unsigned long sink - ) - { - typedef typename directed_graph::edge_type edge_weight_type; - const unsigned long num = (unsigned long)std::pow(2.0, (double)g.number_of_nodes()); - - std::vector best_cut(g.number_of_nodes(),FREE_NODE); - - edge_weight_type best_score = std::numeric_limits::max(); - for (unsigned long i = 0; i < num; ++i) - { - for (unsigned long j = 0; j < g.number_of_nodes(); ++j) - { - unsigned long T = (1)< - void print_graph( - const directed_graph& g - ) - { - using namespace std; - dlog << LTRACE << "number of nodes: "<< g.number_of_nodes(); - for (unsigned long i = 0; i < g.number_of_nodes(); ++i) - { - for (unsigned long n = 0; n < g.node(i).number_of_children(); ++n) - dlog << LTRACE << i << " -(" << g.node(i).child_edge(n) << ")-> " << g.node(i).child(n).index(); - } - } - - template - void copy_edge_weights ( - directed_graph& dest, - const directed_graph& src - ) - { - for (unsigned long i = 0; i < src.number_of_nodes(); ++i) - { - for (unsigned long n = 0; n < src.node(i).number_of_children(); ++n) - { - dest.node(i).child_edge(n) = src.node(i).child_edge(n); - } - } - } - -// ---------------------------------------------------------------------------------------- - - template - void pick_random_source_and_sink ( - dlib::rand& rnd, - const graph_type& g, - unsigned long& source, - unsigned long& sink - ) - { - source = rnd.get_random_32bit_number()%g.number_of_nodes(); - sink = rnd.get_random_32bit_number()%g.number_of_nodes(); - while (sink == source) - sink = rnd.get_random_32bit_number()%g.number_of_nodes(); - } - -// ---------------------------------------------------------------------------------------- - - template - void make_random_graph( - dlib::rand& rnd, - dgraph_type& g, - unsigned long& source, - unsigned long& sink - ) - { - typedef typename dgraph_type::edge_type edge_weight_type; - g.clear(); - const unsigned int num_nodes = rnd.get_random_32bit_number()%7 + 2; - g.set_number_of_nodes(num_nodes); - - const unsigned int num_edges = static_cast(num_nodes*(num_nodes-1)/2*rnd.get_random_double() + 0.5); - - // add the right number of randomly selected edges - unsigned int count = 0; - while (count < num_edges) - { - unsigned long parent = rnd.get_random_32bit_number()%g.number_of_nodes(); - unsigned long child = rnd.get_random_32bit_number()%g.number_of_nodes(); - if (parent != child && g.has_edge(parent, child) == false) - { - ++count; - g.add_edge(parent, child); - edge(g, parent, child) = static_cast(rnd.get_random_double()*50); - - // have to have edges both ways - swap(parent, child); - g.add_edge(parent, child); - edge(g, parent, child) = static_cast(rnd.get_random_double()*50); - } - } - - pick_random_source_and_sink(rnd, g, source, sink); - } - -// ---------------------------------------------------------------------------------------- - - template - void make_random_chain_graph( - dlib::rand& rnd, - dgraph_type& g, - unsigned long& source, - unsigned long& sink - ) - { - typedef typename dgraph_type::edge_type edge_weight_type; - g.clear(); - const unsigned int num_nodes = rnd.get_random_32bit_number()%7 + 2; - g.set_number_of_nodes(num_nodes); - - for (unsigned long i = 1; i < g.number_of_nodes(); ++i) - { - g.add_edge(i,i-1); - g.add_edge(i-1,i); - edge(g, i, i-1) = static_cast(rnd.get_random_double()*50); - edge(g, i-1, i) = static_cast(rnd.get_random_double()*50); - } - - pick_random_source_and_sink(rnd, g, source, sink); - } - -// ---------------------------------------------------------------------------------------- - - template - void make_random_grid_graph( - dlib::rand& rnd, - dgraph_type& g, - unsigned long& source, - unsigned long& sink - ) - /*! - ensures - - makes a grid graph like the kind used for potts models. - !*/ - { - typedef typename dgraph_type::edge_type edge_weight_type; - g.clear(); - const long nr = rnd.get_random_32bit_number()%2 + 2; - const long nc = rnd.get_random_32bit_number()%2 + 2; - g.set_number_of_nodes(nr*nc+2); - - const rectangle rect(0,0,nc-1,nr-1); - for (long r = 0; r < nr; ++r) - { - for (long c = 0; c < nc; ++c) - { - const point p(c,r); - const unsigned long i = p.y()*nc + p.x(); - - const point n2(c-1,r); - if (rect.contains(n2)) - { - const unsigned long j = n2.y()*nc + n2.x(); - g.add_edge(i,j); - g.add_edge(j,i); - edge(g,i,j) = static_cast(rnd.get_random_double()*50); - edge(g,j,i) = static_cast(rnd.get_random_double()*50); - } - - const point n4(c,r-1); - if (rect.contains(n4)) - { - const unsigned long j = n4.y()*nc + n4.x(); - g.add_edge(i,j); - g.add_edge(j,i); - edge(g,i,j) = static_cast(rnd.get_random_double()*50); - edge(g,j,i) = static_cast(rnd.get_random_double()*50); - } - } - } - - // use the last two nodes as source and sink. Also connect them to all the other nodes. - source = g.number_of_nodes()-1; - sink = g.number_of_nodes()-2; - for (unsigned long i = 0; i < g.number_of_nodes()-2; ++i) - { - g.add_edge(i,source); - g.add_edge(source,i); - g.add_edge(i,sink); - g.add_edge(sink,i); - - edge(g,i,source) = static_cast(rnd.get_random_double()*50); - edge(g,source,i) = static_cast(rnd.get_random_double()*50); - edge(g,i,sink) = static_cast(rnd.get_random_double()*50); - edge(g,sink,i) = static_cast(rnd.get_random_double()*50); - } - } - -// ---------------------------------------------------------------------------------------- - - template - void run_test_on_graphs ( - const min_cut& mc, - dgraph_type& g1, - dgraph_type& g2, - unsigned long source, - unsigned long sink - ) - { - typedef typename dgraph_type::edge_type edge_weight_type; - using namespace std; - - - dlog << LTRACE << "number of nodes: "<< g1.number_of_nodes(); - dlog << LTRACE << "is graph connected: "<< graph_is_connected(g1); - dlog << LTRACE << "has self loops: "<< graph_contains_length_one_cycle(g1); - dlog << LTRACE << "SOURCE_CUT: " << source; - dlog << LTRACE << "SINK_CUT: " << sink; - mc(g1, source, sink); - brute_force_min_cut(g2, source, sink); - - print_graph(g1); - - // make sure the flow residuals are 0 at the cut locations - for (unsigned long i = 0; i < g1.number_of_nodes(); ++i) - { - for (unsigned long j = 0; j < g1.node(i).number_of_children(); ++j) - { - if ((g1.node(i).data == SOURCE_CUT && g1.node(i).child(j).data != SOURCE_CUT) || - (g1.node(i).data != SINK_CUT && g1.node(i).child(j).data == SINK_CUT) - ) - { - DLIB_TEST_MSG(g1.node(i).child_edge(j) == 0, g1.node(i).child_edge(j)); - } - } - } - - // copy the edge weights from g2 back to g1 so we can compute cut scores - copy_edge_weights(g1, g2); - - DLIB_TEST(g1.number_of_nodes() == g2.number_of_nodes()); - for (unsigned long i = 0; i < g1.number_of_nodes(); ++i) - { - dlog << LTRACE << "node " << i << ": " << (int)g1.node(i).data << ", " << (int)g2.node(i).data; - if (g1.node(i).data != g2.node(i).data) - { - edge_weight_type cut_score = graph_cut_score(g1); - edge_weight_type brute_force_score = graph_cut_score(g2); - dlog << LTRACE << "graph cut score: "<< cut_score; - dlog << LTRACE << "brute force score: "<< brute_force_score; - - if (brute_force_score != cut_score) - print_graph(g1); - DLIB_TEST_MSG(brute_force_score == cut_score,std::abs(brute_force_score-cut_score)); - } - } - - } - -// ---------------------------------------------------------------------------------------- - - template - void test_graph_cuts(dlib::rand& rnd) - { - typedef typename dlib::directed_graph::kernel_1a_c dgraph_type; - // we will create two identical graphs. - dgraph_type g1, g2; - min_cut mc; - - unsigned long source, sink; - - dlib::rand rnd_copy(rnd); - make_random_graph(rnd,g1, source, sink); - make_random_graph(rnd_copy,g2, source, sink); - run_test_on_graphs(mc, g1, g2, source, sink); - - rnd_copy = rnd; - make_random_grid_graph(rnd,g1, source, sink); - make_random_grid_graph(rnd_copy,g2, source, sink); - run_test_on_graphs(mc, g1, g2, source, sink); - - rnd_copy = rnd; - make_random_chain_graph(rnd,g1, source, sink); - make_random_chain_graph(rnd_copy,g2, source, sink); - run_test_on_graphs(mc, g1, g2, source, sink); - - } - -// ---------------------------------------------------------------------------------------- - - class test_potts_grid_problem - { - public: - test_potts_grid_problem(int seed_) :seed(seed_){} - int seed; - - long nr() const { return 3;} - long nc() const { return 3;} - - typedef double value_type; - - value_type factor_value(unsigned long idx) const - { - // Copy idx into a char buffer to avoid warnings about violation of strict aliasing - // rules when murmur_hash3() gets inlined into this function. - char buf[sizeof(idx)]; - memcpy(buf,&idx,sizeof(idx)); - // now hash the buffer rather than idx. - return ((double)murmur_hash3(buf, sizeof(buf), seed) - std::numeric_limits::max()/2.0)/1000.0; - } - - value_type factor_value_disagreement(unsigned long idx1, unsigned long idx2) const - { - return std::abs(factor_value(idx1+idx2)/10.0); - } - }; - -// ---------------------------------------------------------------------------------------- - - template - void brute_force_potts_grid_problem( - const prob_type& prob, - array2d& labels - ) - { - const unsigned long num = (unsigned long)std::pow(2.0, (double)prob.nr()*prob.nc()); - - array2d temp(prob.nr(), prob.nc()); - unsigned char* data = &temp[0][0]; - - double best_score = -std::numeric_limits::infinity(); - for (unsigned long i = 0; i < num; ++i) - { - for (unsigned long j = 0; j < temp.size(); ++j) - { - unsigned long T = (1)< best_score) - { - best_score = score; - assign_image(labels, temp); - } - } - } - - void test_inf() - { - graph::kernel_1a_c g; - g.set_number_of_nodes(4); - g.add_edge(0,1); - g.add_edge(1,2); - g.add_edge(2,3); - g.add_edge(3,0); - - g.node(0).data = std::numeric_limits::infinity(); - g.node(1).data = -std::numeric_limits::infinity(); - g.node(2).data = std::numeric_limits::infinity(); - g.node(3).data = -std::numeric_limits::infinity(); - - edge(g,0,1) = 1; - edge(g,1,2) = 1; - edge(g,2,3) = 1; - edge(g,3,0) = 1; - - std::vector labels; - find_max_factor_graph_potts(g, labels); - - DLIB_TEST(labels[0] != 0); - DLIB_TEST(labels[1] == 0); - DLIB_TEST(labels[2] != 0); - DLIB_TEST(labels[3] == 0); - - // -------------------------- - - g.node(0).data = std::numeric_limits::infinity(); - g.node(1).data = 0; - g.node(2).data = 0; - g.node(3).data = -3; - - edge(g,0,1) = 1; - edge(g,1,2) = 1; - edge(g,2,3) = 1; - edge(g,3,0) = 1; - - find_max_factor_graph_potts(g, labels); - - DLIB_TEST(labels[0] != 0); - DLIB_TEST(labels[1] != 0); - DLIB_TEST(labels[2] != 0); - DLIB_TEST(labels[3] == 0); - - // -------------------------- - - g.node(0).data = std::numeric_limits::infinity(); - g.node(1).data = 0; - g.node(2).data = 0; - g.node(3).data = -0.1; - - edge(g,0,1) = 1; - edge(g,1,2) = 1; - edge(g,2,3) = 1; - edge(g,3,0) = 1; - - find_max_factor_graph_potts(g, labels); - - DLIB_TEST(labels[0] != 0); - DLIB_TEST(labels[1] != 0); - DLIB_TEST(labels[2] != 0); - DLIB_TEST(labels[3] != 0); - - // -------------------------- - - g.node(0).data = std::numeric_limits::infinity(); - g.node(1).data = 0; - g.node(2).data = 0; - g.node(3).data = -0.1; - - edge(g,0,1) = 1; - edge(g,1,2) = 1; - edge(g,2,3) = 0; - edge(g,3,0) = 0; - - find_max_factor_graph_potts(g, labels); - - DLIB_TEST(labels[0] != 0); - DLIB_TEST(labels[1] != 0); - DLIB_TEST(labels[2] != 0); - DLIB_TEST(labels[3] == 0); - - // -------------------------- - - g.node(0).data = -std::numeric_limits::infinity(); - g.node(1).data = 0; - g.node(2).data = 0; - g.node(3).data = 0.1; - - edge(g,0,1) = 1; - edge(g,1,2) = 1; - edge(g,2,3) = 0; - edge(g,3,0) = 0; - - find_max_factor_graph_potts(g, labels); - - DLIB_TEST(labels[0] == 0); - DLIB_TEST(labels[1] == 0); - DLIB_TEST(labels[2] == 0); - DLIB_TEST(labels[3] != 0); - - // -------------------------- - - g.node(0).data = -std::numeric_limits::infinity(); - g.node(1).data = std::numeric_limits::infinity(); - g.node(2).data = 0; - g.node(3).data = 0.1; - - edge(g,0,1) = 1; - edge(g,1,2) = 1; - edge(g,2,3) = 0; - edge(g,3,0) = 0; - - find_max_factor_graph_potts(g, labels); - - DLIB_TEST(labels[0] == 0); - DLIB_TEST(labels[1] != 0); - DLIB_TEST(labels[2] != 0); - DLIB_TEST(labels[3] != 0); - - // -------------------------- - - g.node(0).data = -10; - g.node(1).data = std::numeric_limits::infinity(); - g.node(2).data = 0; - g.node(3).data = 0.1; - - edge(g,0,1) = std::numeric_limits::infinity(); - edge(g,1,2) = std::numeric_limits::infinity(); - edge(g,2,3) = std::numeric_limits::infinity(); - edge(g,3,0) = std::numeric_limits::infinity(); - - find_max_factor_graph_potts(g, labels); - - DLIB_TEST(labels[0] != 0); - DLIB_TEST(labels[1] != 0); - DLIB_TEST(labels[2] != 0); - DLIB_TEST(labels[3] != 0); - - // -------------------------- - - g.node(0).data = 10; - g.node(1).data = -std::numeric_limits::infinity(); - g.node(2).data = 20.05; - g.node(3).data = -0.1; - - edge(g,0,1) = std::numeric_limits::infinity(); - edge(g,1,2) = 10; - edge(g,2,3) = std::numeric_limits::infinity(); - edge(g,3,0) = 10; - - find_max_factor_graph_potts(g, labels); - - DLIB_TEST(labels[0] == 0); - DLIB_TEST(labels[1] == 0); - DLIB_TEST(labels[2] == 0); - DLIB_TEST(labels[3] == 0); - - // -------------------------- - - g.node(0).data = 10; - g.node(1).data = -std::numeric_limits::infinity(); - g.node(2).data = 20.2; - g.node(3).data = -0.1; - - edge(g,0,1) = std::numeric_limits::infinity(); - edge(g,1,2) = 10; - edge(g,2,3) = std::numeric_limits::infinity(); - edge(g,3,0) = 10; - - find_max_factor_graph_potts(g, labels); - - DLIB_TEST(labels[0] == 0); - DLIB_TEST(labels[1] == 0); - DLIB_TEST(labels[2] != 0); - DLIB_TEST(labels[3] != 0); - } - - struct potts_pair_image_model - { - typedef double value_type; - - template - value_type factor_value ( - const pixel_type1& , - const pixel_type2& v2 - ) const - { - return v2; - } - - template - value_type factor_value_disagreement ( - const pixel_type& v1, - const pixel_type& v2 - ) const - { - if (v1 == v2) - return 10; - else - return 0; - } - }; - - void test_potts_pair_grid() - { - array2d img1(40,40); - array2d img2(40,40); - - assign_all_pixels(img1, -1); - assign_all_pixels(img2, -1); - - img1[4][4] = 1000; - - img2[4][3] = 1; - img2[4][4] = 1; - img2[4][5] = 1; - img2[3][3] = 1; - img2[3][4] = 1; - img2[3][5] = 1; - img2[5][3] = 1; - img2[5][4] = 1; - img2[5][5] = 1; - - array2d labels; - find_max_factor_graph_potts(make_potts_grid_problem(potts_pair_image_model(),img2,img1), labels); - - dlog << LINFO << "num true labels: " << sum(matrix_cast(mat(labels)!=0)); - DLIB_TEST(sum(matrix_cast(mat(labels)!=0)) == 9); - DLIB_TEST(sum(matrix_cast(mat(labels)==0)) == (int)img1.size()-9); - - DLIB_TEST(labels[4][3] != 0); - DLIB_TEST(labels[4][4] != 0); - DLIB_TEST(labels[4][5] != 0); - DLIB_TEST(labels[3][3] != 0); - DLIB_TEST(labels[3][4] != 0); - DLIB_TEST(labels[3][5] != 0); - DLIB_TEST(labels[5][3] != 0); - DLIB_TEST(labels[5][4] != 0); - DLIB_TEST(labels[5][5] != 0); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - class graph_cuts_tester : public tester - { - public: - graph_cuts_tester ( - ) : - tester ("test_graph_cuts", - "Runs tests on the graph cuts tools.") - {} - - dlib::rand rnd; - - void perform_test ( - ) - { - test_potts_pair_grid(); - test_inf(); - - for (int i = 0; i < 500; ++i) - { - array2d labels, brute_labels; - test_potts_grid_problem prob(i); - find_max_factor_graph_potts(prob, labels); - brute_force_potts_grid_problem(prob, brute_labels); - - DLIB_TEST(labels.nr() == brute_labels.nr()); - DLIB_TEST(labels.nc() == brute_labels.nc()); - for (long r = 0; r < labels.nr(); ++r) - { - for (long c = 0; c < labels.nc(); ++c) - { - bool normal = (labels[r][c] != 0); - bool brute = (brute_labels[r][c] != 0); - DLIB_TEST(normal == brute); - } - } - } - - for (int i = 0; i < 1000; ++i) - { - print_spinner(); - dlog << LTRACE << "test_grpah_cuts iter: " << i; - test_graph_cuts(rnd); - print_spinner(); - dlog << LTRACE << "test_grpah_cuts iter: " << i; - test_graph_cuts(rnd); - } - - - for (int k = 0; k < 300; ++k) - { - dlog << LTRACE << "image_potts_problem iter " << k; - print_spinner(); - image_potts_problem p(3,3, rnd); - impl_test_potts_model(p); - } - for (int k = 0; k < 300; ++k) - { - dlog << LTRACE << "dense_potts_problem iter " << k; - print_spinner(); - dense_potts_problem p(6, rnd); - impl_test_potts_model(p); - } - - for (int k = 0; k < 300; ++k) - { - dlog << LTRACE << "dense_potts_problem iter " << k; - print_spinner(); - test_graph_potts_model(rnd); - } - } - } a; - - -} - - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/graph_labeler.cpp b/lib/3rdParty/dlib/include/dlib/test/graph_labeler.cpp deleted file mode 100644 index 11287389..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/graph_labeler.cpp +++ /dev/null @@ -1,472 +0,0 @@ -// Copyright (C) 2012 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - - - logger dlog("test.graph_cuts"); - - - template < - typename graph_type, - typename samples_type, - typename labels_type - > - void make_data( - samples_type& samples, - labels_type& labels - ) - { - //samples.clear(); - //labels.clear(); - - std::vector label; - graph_type g; - - // --------------------------- - g.set_number_of_nodes(4); - label.resize(g.number_of_nodes()); - g.node(0).data = 0, 0, 1; label[0] = true; - g.node(1).data = 0, 0, 1; label[1] = true; - g.node(2).data = 0, 1, 0; label[2] = false; - g.node(3).data = 0, 1, 0; label[3] = false; - - g.add_edge(0,1); - g.add_edge(1,2); - g.add_edge(2,3); - g.add_edge(3,0); - - edge(g,0,1) = 1, 1; - edge(g,1,2) = 1, 1; - edge(g,2,3) = 1, 1; - edge(g,3,0) = 1, 1; - samples.push_back(g); - labels.push_back(label); - // --------------------------- - - g.clear(); - g.set_number_of_nodes(4); - label.resize(g.number_of_nodes()); - g.node(0).data = 0, 0, 1; label[0] = true; - g.node(1).data = 0, 0, 0; label[1] = true; - g.node(2).data = 0, 1, 0; label[2] = false; - g.node(3).data = 0, 0, 0; label[3] = false; - - g.add_edge(0,1); - g.add_edge(1,2); - g.add_edge(2,3); - g.add_edge(3,0); - - edge(g,0,1) = 1, 0; - edge(g,1,2) = 0, 1; - edge(g,2,3) = 1, 0; - edge(g,3,0) = 0, 1; - samples.push_back(g); - labels.push_back(label); - // --------------------------- - - g.clear(); - g.set_number_of_nodes(4); - label.resize(g.number_of_nodes()); - g.node(0).data = 0, 1, 0; label[0] = false; - g.node(1).data = 0, 1, 0; label[1] = false; - g.node(2).data = 0, 1, 0; label[2] = false; - g.node(3).data = 0, 0, 0; label[3] = false; - - g.add_edge(0,1); - g.add_edge(1,2); - g.add_edge(2,3); - g.add_edge(3,0); - - edge(g,0,1) = 1, 0; - edge(g,1,2) = 0, 1; - edge(g,2,3) = 1, 0; - edge(g,3,0) = 0, 1; - samples.push_back(g); - labels.push_back(label); - // --------------------------- - } - - - - - template < - typename graph_type, - typename samples_type, - typename labels_type - > - void make_data_sparse( - samples_type& samples, - labels_type& labels - ) - { - //samples.clear(); - //labels.clear(); - - std::vector label; - graph_type g; - typename graph_type::edge_type v; - - // --------------------------- - g.set_number_of_nodes(4); - label.resize(g.number_of_nodes()); - g.node(0).data[2] = 1; label[0] = true; - g.node(1).data[2] = 1; label[1] = true; - g.node(2).data[1] = 1; label[2] = false; - g.node(3).data[1] = 1; label[3] = false; - - g.add_edge(0,1); - g.add_edge(1,2); - g.add_edge(2,3); - g.add_edge(3,0); - g.add_edge(3,1); - - v[0] = 1; v[1] = 1; - edge(g,0,1) = v; - edge(g,1,2) = v; - edge(g,2,3) = v; - edge(g,3,0) = v; - samples.push_back(g); - labels.push_back(label); - // --------------------------- - - g.clear(); - g.set_number_of_nodes(5); - label.resize(g.number_of_nodes()); - g.node(0).data[2] = 1; label[0] = true; - g.node(1).data[0] = 0; label[1] = true; - g.node(2).data[1] = 1; label[2] = false; - g.node(3).data[0] = 0; label[3] = false; - label[4] = true; - - g.add_edge(0,1); - g.add_edge(1,4); - g.add_edge(1,2); - g.add_edge(2,3); - g.add_edge(3,0); - - edge(g,0,1)[0] = 1; - edge(g,1,4)[0] = 1; - edge(g,1,2)[1] = 1; - edge(g,2,3)[0] = 1; - edge(g,3,0)[1] = 1; - samples.push_back(g); - labels.push_back(label); - // --------------------------- - - g.clear(); - g.set_number_of_nodes(4); - label.resize(g.number_of_nodes()); - g.node(0).data[1] = 1; label[0] = false; - g.node(1).data[1] = 1; label[1] = false; - g.node(2).data[1] = 1; label[2] = false; - g.node(3).data[1] = 0; label[3] = false; - - g.add_edge(0,1); - g.add_edge(1,2); - g.add_edge(2,3); - g.add_edge(3,0); - - edge(g,0,1)[0] = 1; - edge(g,1,2)[1] = 1; - edge(g,2,3)[0] = 1; - edge(g,3,0)[1] = 1; - samples.push_back(g); - labels.push_back(label); - // --------------------------- - } - - - - - - - template < - typename graph_type, - typename samples_type, - typename labels_type - > - void make_data2( - samples_type& samples, - labels_type& labels - ) - { - //samples.clear(); - //labels.clear(); - - std::vector label; - graph_type g; - - // --------------------------- - g.set_number_of_nodes(4); - label.resize(g.number_of_nodes()); - g.node(0).data = 0, 0, 1; label[0] = true; - g.node(1).data = 0, 0, 1; label[1] = true; - g.node(2).data = 0, 1, 0; label[2] = false; - g.node(3).data = 0, 1, 0; label[3] = false; - - g.add_edge(0,1); - g.add_edge(1,2); - g.add_edge(2,3); - g.add_edge(3,0); - - edge(g,0,1) = 1, 1; - edge(g,1,2) = 1, 1; - edge(g,2,3) = 1, 1; - edge(g,3,0) = 1, 1; - samples.push_back(g); - labels.push_back(label); - // --------------------------- - } - - - - - template < - typename graph_type, - typename samples_type, - typename labels_type - > - void make_data2_sparse( - samples_type& samples, - labels_type& labels - ) - { - //samples.clear(); - //labels.clear(); - - std::vector label; - graph_type g; - typename graph_type::edge_type v; - - // --------------------------- - g.set_number_of_nodes(4); - label.resize(g.number_of_nodes()); - g.node(0).data[2] = 1; label[0] = true; - g.node(1).data[2] = 1; label[1] = true; - g.node(2).data[1] = 1; label[2] = false; - g.node(3).data[1] = 1; label[3] = false; - - g.add_edge(0,1); - g.add_edge(1,2); - g.add_edge(2,3); - g.add_edge(3,0); - - v[0] = 1; v[1] = 1; - edge(g,0,1) = v; - edge(g,1,2) = v; - edge(g,2,3) = v; - edge(g,3,0) = v; - samples.push_back(g); - labels.push_back(label); - // --------------------------- - - } - - - - - - template < - typename node_vector_type, - typename edge_vector_type, - typename vector_type, - typename graph_type - > - void test1( - const dlib::array& samples, - const std::vector >& labels - ) - { - dlog << LINFO << "begin test1()"; - - structural_graph_labeling_trainer trainer; - //trainer.be_verbose(); - trainer.set_epsilon(1e-12); - graph_labeler labeler = trainer.train(samples, labels); - - - // test serialization code for the labeler. - std::ostringstream sout; - serialize(labeler, sout); - std::istringstream sin(sout.str()); - labeler = graph_labeler(); - deserialize(labeler, sin); - - std::vector temp; - for (unsigned long k = 0; k < samples.size(); ++k) - { - temp = labeler(samples[k]); - for (unsigned long i = 0; i < temp.size(); ++i) - { - const bool true_label = (labels[k][i] != 0); - const bool pred_label = (temp[i] != 0); - DLIB_TEST(true_label == pred_label); - } - } - - matrix cv; - - cv = test_graph_labeling_function(labeler, samples, labels); - DLIB_TEST(sum(cv) == 2); - cv = cross_validate_graph_labeling_trainer(trainer, samples, labels, 4); - DLIB_TEST(sum(cv) == 2); - - dlog << LINFO << "edge weights: " << trans(sparse_to_dense(labeler.get_edge_weights())); - dlog << LINFO << "node weights: " << trans(sparse_to_dense(labeler.get_node_weights())); - } - - - - class graph_labeling_tester : public tester - { - public: - graph_labeling_tester ( - ) : - tester ("test_graph_labeling", - "Runs tests on the graph labeling component.") - {} - - void perform_test ( - ) - { - print_spinner(); - // test with dense vectors - { - typedef matrix node_vector_type; - typedef matrix edge_vector_type; - typedef matrix vector_type; - typedef dlib::graph::kernel_1a_c graph_type; - - dlib::array samples; - std::vector > labels; - - make_data(samples, labels); - make_data(samples, labels); - make_data(samples, labels); - make_data(samples, labels); - - - test1(samples, labels); - } - print_spinner(); - // test with dense vectors and sparse vectors together - { - typedef matrix node_vector_type; - typedef matrix edge_vector_type; - typedef std::map vector_type; - typedef dlib::graph::kernel_1a_c graph_type; - - dlib::array samples; - std::vector > labels; - - make_data(samples, labels); - make_data(samples, labels); - make_data(samples, labels); - make_data(samples, labels); - - - test1(samples, labels); - } - print_spinner(); - // test with sparse vectors - { - typedef std::vector > vector_type; - typedef std::map edge_vector_type; - typedef std::map node_vector_type; - typedef dlib::graph::kernel_1a_c graph_type; - - dlib::array samples; - std::vector > labels; - - make_data_sparse(samples, labels); - make_data_sparse(samples, labels); - make_data_sparse(samples, labels); - make_data_sparse(samples, labels); - - - test1(samples, labels); - } - - - - print_spinner(); - // test with dense vectors - { - typedef matrix node_vector_type; - typedef matrix edge_vector_type; - typedef matrix vector_type; - typedef dlib::graph::kernel_1a_c graph_type; - - dlib::array samples; - std::vector > labels; - - make_data2(samples, labels); - make_data2(samples, labels); - make_data2(samples, labels); - make_data2(samples, labels); - - - test1(samples, labels); - } - print_spinner(); - // test with sparse vectors - { - typedef std::vector > vector_type; - typedef std::map edge_vector_type; - typedef std::map node_vector_type; - typedef dlib::graph::kernel_1a_c graph_type; - - dlib::array samples; - std::vector > labels; - - make_data2_sparse(samples, labels); - make_data2_sparse(samples, labels); - make_data2_sparse(samples, labels); - make_data2_sparse(samples, labels); - - - test1(samples, labels); - } - print_spinner(); - // test with sparse vectors and dense mix - { - typedef matrix vector_type; - typedef std::map edge_vector_type; - typedef std::map node_vector_type; - typedef dlib::graph::kernel_1a_c graph_type; - - dlib::array samples; - std::vector > labels; - - make_data2_sparse(samples, labels); - make_data2_sparse(samples, labels); - make_data2_sparse(samples, labels); - make_data2_sparse(samples, labels); - - - test1(samples, labels); - } - } - } a; - - -} - - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/gui/CMakeLists.txt b/lib/3rdParty/dlib/include/dlib/test/gui/CMakeLists.txt deleted file mode 100644 index b673dc45..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/gui/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -# -# This is a CMake makefile. You can find the cmake utility and -# information about it at http://www.cmake.org -# - -# create a variable called target_name and set it to the string "test" -set (target_name gui) - -PROJECT(${target_name}) - -# add all the cpp files we want to compile to this list. This tells -# cmake that they are part of our target (which is the executable named test) -ADD_EXECUTABLE(${target_name} main.cpp ) - -# Add the folder containing the dlib folder to the include path -INCLUDE_DIRECTORIES(../../..) - -# Tell cmake to link our target executable to dlib. -TARGET_LINK_LIBRARIES(${target_name} dlib ) - diff --git a/lib/3rdParty/dlib/include/dlib/test/gui/main.cpp b/lib/3rdParty/dlib/include/dlib/test/gui/main.cpp deleted file mode 100644 index 56b42b3b..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/gui/main.cpp +++ /dev/null @@ -1,837 +0,0 @@ -#include "dlib/image_io.h" -#include "dlib/array2d.h" -#include "dlib/gui_core.h" -#include "dlib/assert.h" -#include "dlib/misc_api.h" -#include -#include "dlib/image_transforms.h" - -#include "dlib/timer.h" - -#include "dlib/gui_widgets.h" -#include "dlib/queue.h" -#include -#include -#include - -using namespace dlib; -using namespace std; - - -typedef dlib::array2d image; - - - - -#include "dlib/base64.h" - - - - -class color_box : public draggable -{ - unsigned char red, green,blue; - -public: - color_box ( - drawable_window& w, - rectangle area, - unsigned char red_, - unsigned char green_, - unsigned char blue_ - ) : - draggable(w, MOUSE_WHEEL), - red(red_), - green(green_), - blue(blue_), - t(*this,&color_box::action) - { - rect = area; - - t.set_delay_time(4); - // t.start(); - - set_draggable_area(rectangle(10,10,500,500)); - - enable_events(); - } - - ~color_box() - { - disable_events(); - } - -private: - - void action ( - ) - { - ++red; - parent.invalidate_rectangle(rect); - } - - void draw ( - const canvas& c - ) const - { - if (hidden == false ) - { - fill_rect(c,rect,rgb_pixel(red,green,blue)); - std::vector poly; - poly.push_back((rect.tl_corner()+rect.tr_corner())/2); - poly.push_back((rect.tr_corner()+rect.br_corner())/2); - poly.push_back((rect.br_corner()+rect.bl_corner())/2); - poly.push_back((rect.bl_corner()+rect.tl_corner())/2); - draw_solid_convex_polygon(c,poly,rgb_alpha_pixel(0,0,0,70)); - } - } - - void on_wheel_up( - unsigned long state - ) - { - if (state == base_window::NONE) - cout << "up scroll, NONE" << endl; - else if (state&base_window::LEFT) - cout << "up scroll, LEFT" << endl; - else if (state&base_window::RIGHT) - cout << "up scroll, RIGHT" << endl; - else if (state&base_window::MIDDLE) - cout << "up scroll, MIDDLE" << endl; - else if (state&base_window::SHIFT) - cout << "up scroll, SHIFT" << endl; - else if (state&base_window::CONTROL) - cout << "up scroll, CONTROL" << endl; - - } - - void on_wheel_down( - unsigned long state - ) - { - - if (state == base_window::NONE) - cout << "down scroll, NONE" << endl; - else if (state&base_window::LEFT) - cout << "down scroll, LEFT" << endl; - else if (state&base_window::RIGHT) - cout << "down scroll, RIGHT" << endl; - else if (state&base_window::MIDDLE) - cout << "down scroll, MIDDLE" << endl; - else if (state&base_window::SHIFT) - cout << "down scroll, SHIFT" << endl; - else if (state&base_window::CONTROL) - cout << "down scroll, CONTROL" << endl; - - } - - - void on_window_resized () - { - draggable::on_window_resized(); - } - timer t; -}; - - - - - - -class win : public drawable_window -{ - - label lbl_last_keydown; - label lbl_mod_shift; - label lbl_mod_control; - label lbl_mod_alt; - label lbl_mod_meta; - label lbl_mod_caps_lock; - label lbl_mod_num_lock; - label lbl_mod_scroll_lock; - void on_keydown ( - unsigned long key, - bool is_printable, - unsigned long state - ) - { - if (is_printable) - lbl_last_keydown.set_text(string("last keydown: ") + (char)key); - else - lbl_last_keydown.set_text(string("last keydown: nonprintable")); - - if (state&base_window::KBD_MOD_SHIFT) - lbl_mod_shift.set_text("shift is on"); - else - lbl_mod_shift.set_text("shift is off"); - - if (state&base_window::KBD_MOD_CONTROL) - lbl_mod_control.set_text("control is on"); - else - lbl_mod_control.set_text("control is off"); - - if (state&base_window::KBD_MOD_ALT) - lbl_mod_alt.set_text("alt is on"); - else - lbl_mod_alt.set_text("alt is off"); - - - if (state&base_window::KBD_MOD_META) - lbl_mod_meta.set_text("meta is on"); - else - lbl_mod_meta.set_text("meta is off"); - - if (state&base_window::KBD_MOD_CAPS_LOCK) - lbl_mod_caps_lock.set_text("caps_lock is on"); - else - lbl_mod_caps_lock.set_text("caps_lock is off"); - - if (state&base_window::KBD_MOD_NUM_LOCK) - lbl_mod_num_lock.set_text("num_lock is on"); - else - lbl_mod_num_lock.set_text("num_lock is off"); - - - if (state&base_window::KBD_MOD_SCROLL_LOCK) - lbl_mod_scroll_lock.set_text("scroll_lock is on"); - else - lbl_mod_scroll_lock.set_text("scroll_lock is off"); - - drawable_window::on_keydown(key,is_printable,state); - } - - void rb_click ( - ) - { - if (rb.is_checked()) - rb.set_name("radio button checked"); - else - rb.set_name("radio button"); - rb.set_checked(); - } - - void cb_sb_enabled ( - toggle_button& - ) - { - if (sb_enabled.is_checked()) - { - sb.enable(); - lb.enable(); - b.enable(); - } - else - { - lb.disable(); - sb.disable(); - b.disable(); - } - - if (sb_enabled.is_checked()) - rb.enable(); - else - rb.disable(); - - if (sb_enabled.is_checked()) - tabs.enable(); - else - tabs.disable(); - - if (sb_enabled.is_checked()) - tf.enable(); - else - tf.disable(); - - if (sb_enabled.is_checked()) - tb.enable(); - else - tb.disable(); - - } - - void cb_sb_shown ( - ) - { - if (sb_shown.is_checked()) - { - sb.show(); - tabs.show(); - lb.show(); - } - else - { - sb.hide(); - tabs.hide(); - lb.hide(); - } - } - - - void tab_change ( - unsigned long new_idx, - unsigned long - ) - { - tab_label.set_text(tabs.tab_name(new_idx)); - } - - void scroll_handler ( - ) - { - ostringstream sout; - sout << "scroll bar pos: " << sb.slider_pos(); - sbl.set_text(sout.str()); - } - - void scroll2_handler ( - ) - { - sb.set_length(sb2.slider_pos()); - ostringstream sout; - sout << "scroll bar2 pos: " << sb2.slider_pos(); - sbl2.set_text(sout.str()); - scroll_handler(); - } - - void scroll3_handler ( - ) - { - sb.set_max_slider_pos(sb3.slider_pos()); - ostringstream sout; - sout << "scroll bar3 pos: " << sb3.slider_pos(); - sbl3.set_text(sout.str()); - scroll_handler(); - } - - void lb_double_click ( - unsigned long - ) - { - dlib::queue::kernel_2a_c sel; - lb.get_selected(sel); - sel.reset(); - while (sel.move_next()) - { - cout << lb[sel.element()] << endl; - } - //message_box("list_box",lb[idx]); - } - - void msg_box ( - ) - { - message_box("title","you clicked the ok button!\n HURRAY!"); - } - - static void try_this_junk ( - void* param - ) - { - win& p = *reinterpret_cast(param); - put_on_clipboard(p.tf.text() + "\nfoobar"); - - - } - - void on_set_clipboard ( - ) - { - create_new_thread(try_this_junk,this); - //try_this_junk(this); - } - - static void try_this_junk2 ( - void* - ) - { - - string temp; - get_from_clipboard(temp); - message_box("clipboard",temp); - - } - void on_get_clipboard ( - ) - { - create_new_thread(try_this_junk2,this); - } - - - void on_show_msg_click ( - ) - { - message_box("title","This is a test message.",*this,&win::msg_box); - } - - void on_menu_help ( - ) - { - message_box("About","This is the messy dlib gui regression test program"); - } - -public: - - ~win() - { - close_window(); - } - - void cbox_clicked ( - ) - { - if (cbox.is_checked()) - cbl.set_text(cbox.name() + " box is checked"); - else - cbl.set_text("box NOT is checked"); - } - - win ( - ): - drawable_window(true), - lbl_last_keydown(*this), - lbl_mod_shift(*this), - lbl_mod_control(*this), - lbl_mod_alt(*this), - lbl_mod_meta(*this), - lbl_mod_caps_lock(*this), - lbl_mod_num_lock(*this), - lbl_mod_scroll_lock(*this), - b(*this), - btn_count(*this), - btn_get_clipboard(*this), - btn_set_clipboard(*this), - btn_show_message(*this), - cb1(*this,rectangle(100,100,200,200),255,0,0), - cb2(*this,rectangle(150,150,250,240),0,255,0), - cbl(*this), - cbox(*this), - group1(*this), - group2(*this), - group3(*this), - keyboard_count(1), - keydown(*this), - keyup(*this), - l1(*this), - l2(*this), - l3(*this), - lb(*this), - leave_count(*this), - left_down(*this), - left_up(*this), - middle_down(*this), - middle_up(*this), - mouse_state(*this), - mt(*this), - nrect(*this), - pos(*this), - rb(*this), - right_down(*this), - right_up(*this), - sb2(*this,scroll_bar::VERTICAL), - sb3(*this,scroll_bar::VERTICAL), - sb_enabled(*this), - sbl2(*this), - sbl3(*this), - sbl(*this), - sb_shown(*this), - sb(*this,scroll_bar::HORIZONTAL), - scroll(*this), - tab_label(*this), - tabs(*this), - tf(*this), - tb(*this), - mbar(*this) - { - bool use_bdf_fonts = false; - - shared_ptr_thread_safe f(new bdf_font); - - if (use_bdf_fonts) - { - - ifstream fin("/home/davis/source/10x20.bdf"); - f->read_bdf_file(fin,0xFFFF); - - mt.set_main_font(f); - } - //mt.hide(); - mt.set_pos(5,200); - - - lbl_last_keydown.set_text("?"); - lbl_mod_shift.set_text("?"); - lbl_mod_control.set_text("?"); - lbl_mod_alt.set_text("?"); - lbl_mod_meta.set_text("?"); - lbl_mod_caps_lock.set_text("?"); - lbl_mod_num_lock.set_text("?"); - lbl_mod_scroll_lock.set_text("?"); - - lbl_last_keydown.set_pos(20,420); - lbl_mod_shift.set_pos(20,lbl_last_keydown.bottom()+5); - lbl_mod_control.set_pos(20,lbl_mod_shift.bottom()+5); - lbl_mod_alt.set_pos(20,lbl_mod_control.bottom()+5); - lbl_mod_meta.set_pos(20,lbl_mod_alt.bottom()+5); - lbl_mod_caps_lock.set_pos(20,lbl_mod_meta.bottom()+5); - lbl_mod_num_lock.set_pos(20,lbl_mod_caps_lock.bottom()+5); - lbl_mod_scroll_lock.set_pos(20,lbl_mod_num_lock.bottom()+5); - - lb.set_pos(580,200); - lb.set_size(200,300); - if (use_bdf_fonts) - lb.set_main_font(f); - - dlib::queue::kernel_2a_c qos; - string a; - a = "Davis"; qos.enqueue(a); - a = "king"; qos.enqueue(a); - a = "one"; qos.enqueue(a); - a = "two"; qos.enqueue(a); - a = "three"; qos.enqueue(a); - a = "yo yo yo alsdkjf asfj lsa jfsf\n this is a long phrase"; qos.enqueue(a); - a = "four"; qos.enqueue(a); - a = "five"; qos.enqueue(a); - a = "six"; qos.enqueue(a); - a = "seven"; qos.enqueue(a); - a = "eight"; qos.enqueue(a); - a = "nine"; qos.enqueue(a); - a = "ten"; qos.enqueue(a); - a = "eleven"; qos.enqueue(a); - a = "twelve"; qos.enqueue(a); - for (int i = 0; i < 1000; ++i) - { - a = "thirteen"; qos.enqueue(a); - } - lb.load(qos); - lb.select(1); - lb.select(2); - lb.select(3); - lb.select(5); - lb.enable_multiple_select(); - lb.set_double_click_handler(*this,&win::lb_double_click); - // lb.disable_multiple_select(); - - btn_show_message.set_pos(50,350); - btn_show_message.set_name("message_box()"); - mbar.set_number_of_menus(2); - mbar.set_menu_name(0,"File",'F'); - mbar.set_menu_name(1,"Help",'H'); - mbar.menu(0).add_menu_item(menu_item_text("show msg click",*this,&win::on_show_msg_click,'s')); - mbar.menu(0).add_menu_item(menu_item_text("get clipboard",*this,&win::on_get_clipboard,'g')); - mbar.menu(0).add_menu_item(menu_item_text("set clipboard",*this,&win::on_set_clipboard,'c')); - mbar.menu(0).add_menu_item(menu_item_separator()); - mbar.menu(0).add_submenu(menu_item_submenu("submenu",'m'), submenu); - submenu.add_menu_item(menu_item_separator()); - submenu.add_menu_item(menu_item_separator()); - submenu.add_menu_item(menu_item_text("show msg click",*this,&win::on_show_msg_click,'s')); - submenu.add_menu_item(menu_item_text("get clipboard",*this,&win::on_get_clipboard,'g')); - submenu.add_menu_item(menu_item_text("set clipboard",*this,&win::on_set_clipboard,'c')); - submenu.add_menu_item(menu_item_separator()); - submenu.add_menu_item(menu_item_separator()); - mbar.menu(1).add_menu_item(menu_item_text("About",*this,&win::on_menu_help,'A')); - - btn_show_message.set_click_handler(*this,&win::on_show_msg_click); - btn_get_clipboard.set_pos(btn_show_message.right()+5,btn_show_message.top()); - btn_get_clipboard.set_name("get_from_clipboard()"); - btn_get_clipboard.set_click_handler(*this,&win::on_get_clipboard); - - btn_get_clipboard.set_style(button_style_toolbar1()); - btn_set_clipboard.set_pos(btn_get_clipboard.right()+5,btn_get_clipboard.top()); - btn_set_clipboard.set_name("put_on_clipboard()"); - btn_set_clipboard.set_click_handler(*this,&win::on_set_clipboard); - - nrect.set_size(700,500); - nrect.set_name("test widgets"); - nrect.set_pos(2,mbar.bottom()+2); - - //throw dlib::error("holy crap batman"); - tab_label.set_pos(10,440); - - tabs.set_click_handler(*this,&win::tab_change); - tabs.set_pos(5,mbar.bottom()+10); - tabs.set_size(280,100); - tabs.set_number_of_tabs(3); - tabs.set_tab_name(0,"davis"); - tabs.set_tab_name(1,"edward"); - tabs.set_tab_name(2,"king alsklsdkfj asfd"); - tabs.set_tab_group(0,group1); - tabs.set_tab_group(1,group2); - tabs.set_tab_group(2,group3); - - l1.set_text("group one"); - l2.set_text("group two"); - l3.set_text("group three"); - - group1.add(l1,0,0); - group2.add(l2,20,10); - group3.add(l3,0,0); - - - - sb_enabled.set_name("enabled"); - sb_shown.set_name("shown"); - sb_shown.set_checked(); - sb_enabled.set_checked(); - sb_shown.set_click_handler(*this,&win::cb_sb_shown); - sb_enabled.set_click_handler(*this,&win::cb_sb_enabled); - - sb_shown.set_tooltip_text("I'm a checkbox"); - - rb.set_click_handler(*this,&win::rb_click); - - - sb3.set_pos(440,mbar.bottom()+10); - sb3.set_max_slider_pos(300); - sb3.set_slider_pos(150); - sb3.set_length(300); - sb2.set_pos(470,mbar.bottom()+10); - sb2.set_max_slider_pos(300); - sb2.set_length(300); - sb.set_pos(500,mbar.bottom()+10); - sb.set_max_slider_pos(30); - sb.set_length(300); - - - sb.set_scroll_handler(*this,&win::scroll_handler); - sb2.set_scroll_handler(*this,&win::scroll2_handler); - sb3.set_scroll_handler(*this,&win::scroll3_handler); - sbl.set_pos(540,mbar.bottom()+20); - sbl2.set_pos(540,mbar.bottom()+40); - sbl3.set_pos(540,mbar.bottom()+60); - - cbox.set_pos(300,mbar.bottom()+30); - cbox.set_name("davis king"); - cbox.set_click_handler(*this,&win::cbox_clicked); - - cbl.set_pos(300,cbox.get_rect().bottom()+1); - cbox.set_checked(); - sb_enabled.set_pos(cbox.get_rect().left(),cbox.get_rect().bottom()+20); - sb_shown.set_pos(sb_enabled.get_rect().left(),sb_enabled.get_rect().bottom()+2); - - - - if (use_bdf_fonts) - rb.set_main_font(f); - rb.set_name("radio button"); - rb.set_pos(sb_shown.get_rect().left(),sb_shown.get_rect().bottom()+2); - - - cb1.set_z_order(10); - cb2.set_z_order(20); - - pos.set_pos(50,50); - left_up.set_pos(50,70); - left_down.set_pos(50,90); - middle_up.set_pos(50,110); - middle_down.set_pos(50,130); - right_up.set_pos(50,150); - right_down.set_pos(50,170); - - mouse_state.set_pos(50,190); - - leave_count.set_pos(50,210); - - scroll_count = 0; - scroll.set_pos(50,230); - - btn_count.set_pos(50,250); - - - keydown.set_pos(50,270); - keyup.set_pos(50,290); - - tf.set_pos(50,310); - tf.set_text("Davis685g@"); - tf.set_width(500); - tf.set_text_color(rgb_pixel(255,0,0)); - tf.set_enter_key_handler(*this,&win::on_enter_key); - tf.set_focus_lost_handler(*this,&win::on_tf_focus_lost); - - tb.set_pos(250,400); - tb.set_text("initial test\nstring"); - tb.set_size(300,300); - tb.set_text_color(rgb_pixel(255,0,0)); - tb.set_enter_key_handler(*this,&win::on_enter_key); - tb.set_focus_lost_handler(*this,&win::on_tf_focus_lost); - - - button_count = 0; - count = 0; - b.set_name("button"); - b.set_pos(540,100); - b.set_click_handler(*this,&win::on_click); - b.set_tooltip_text("hurray i'm a button!"); - if (use_bdf_fonts) - b.set_main_font(f); - - - set_size(815,730); - - nrect.wrap_around( - cbox.get_rect() + - rb.get_rect() + - sb_enabled.get_rect() + - sb_shown.get_rect()); - - flip = 0; - open_file_box(*this,&win::on_open_file); - open_existing_file_box(*this,&win::on_open_file); - save_file_box(*this,&win::on_open_file); - - if (use_bdf_fonts) - { - tf.set_main_font(f); - tb.set_main_font(f); - } - if (use_bdf_fonts) - tabs.set_main_font(f); - - } - -private: - - - void on_enter_key() - { - cout << "enter key pressed" << endl; - } - - void on_tf_focus_lost() - { - cout << "text field/box lost focus" << endl; - } - - - void on_open_file (const std::string& file) - { - message_box("file opened",file); - } - - - - - void on_click ( - ) - { - ostringstream sout; - sout << "text field: " << tf.text(); - ++button_count; - btn_count.set_text(sout.str()); - - if (flip == 0) - { - flip = 1; - lb.set_size(200,200); - } - else if (flip == 1) - { - flip = 2; - lb.set_size(150,200); - } - else if (flip == 2) - { - flip = 3; - lb.set_size(150,300); - } - else - { - flip = 0; - lb.set_size(200,300); - } - } - - - button b; - label btn_count; - button btn_get_clipboard; - button btn_set_clipboard; - button btn_show_message; - int button_count; - color_box cb1; - color_box cb2; - label cbl; - check_box cbox; - int count; - int flip; - widget_group group1; - widget_group group2; - widget_group group3; - int keyboard_count; - label keydown; - label keyup; - label l1; - label l2; - label l3; - list_box lb; - label leave_count; - label left_down; - label left_up; - label middle_down; - label middle_up; - label mouse_state; - mouse_tracker mt; - named_rectangle nrect; - label pos; - radio_button rb; - label right_down; - label right_up; - scroll_bar sb2; - scroll_bar sb3; - check_box sb_enabled; - label sbl2; - label sbl3; - label sbl; - check_box sb_shown; - scroll_bar sb; - int scroll_count; - label scroll; - label tab_label; - tabbed_display tabs; - text_field tf; - text_box tb; - menu_bar mbar; - popup_menu submenu; - -}; - - -win w; - -int main() -{ - - try - { - - image_window win; - - array2d img; - img.set_size(100,100); - assign_all_pixels(img,0); - - fill_rect(img, rectangle(1,1,1,1), 255); - fill_rect(img, rectangle(1,3,2,5), 255); - fill_rect(img, rectangle(4,3,5,4), 255); - fill_rect(img, rectangle(9,9,13,10), 255); - - win.set_image(img); - - win.add_overlay(image_display::overlay_rect(rectangle(1,1,1,1), rgb_pixel(255,0,0))); - win.add_overlay(image_display::overlay_rect(rectangle(1,3,2,5), rgb_pixel(255,0,0))); - win.add_overlay(image_display::overlay_rect(rectangle(4,3,5,4), rgb_pixel(255,0,0))); - win.add_overlay(image_display::overlay_rect(rectangle(9,9,13,10), rgb_pixel(255,0,0))); - - - - w.set_pos (100,200); - w.set_title("test window"); - w.show(); - - w.wait_until_closed(); - } - catch (exception& e) - { - cout << e.what() << endl; - } - -} diff --git a/lib/3rdParty/dlib/include/dlib/test/hash.cpp b/lib/3rdParty/dlib/include/dlib/test/hash.cpp deleted file mode 100644 index 94930e62..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/hash.cpp +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.hash"); - - - template - void to_little ( - std::vector& item - ) - { - byte_orderer bo; - for (unsigned long i = 0; i < item.size(); ++i) - bo.host_to_little(item[i]); - } - - - template - void to_little ( - matrix& item - ) - { - byte_orderer bo; - for (long r = 0; r < item.nr(); ++r) - { - for (long c = 0; c < item.nc(); ++c) - { - bo.host_to_little(item(r,c)); - } - } - } - - // Run the official test for MurmurHash3 - void murmur_hash_test() - { - uint8 key[256]; - uint32 hashes[256]; - uint32 final = 0; - - memset(key,0,sizeof(key)); - memset(hashes,0,sizeof(hashes)); - - // Hash keys of the form {0}, {0,1}, {0,1,2}... up to N=255,using 256-N as - // the seed. - for(int i = 0; i < 256; i++) - { - key[i] = (uint8)i; - - hashes[i] = murmur_hash3(key,i,256-i); - } - - byte_orderer bo; - bo.host_to_little(hashes); - final = murmur_hash3(hashes,sizeof(hashes),0); - - // using ostringstream to avoid compiler error in visual studio 2005 - ostringstream sout; - sout << hex << final; - dlog << LINFO << "final: "<< sout.str(); - DLIB_TEST(final == 0xB0F57EE3); - } - - void murmur_hash_128_test() - { - uint8 key[256]; - uint64 hashes[256*2]; - uint32 final = 0; - - memset(key,0,sizeof(key)); - memset(hashes,0,sizeof(hashes)); - - // Hash keys of the form {0}, {0,1}, {0,1,2}... up to N=255,using 256-N as - // the seed. - for(int i = 0; i < 256; i++) - { - key[i] = (uint8)i; - - const std::pair temp = murmur_hash3_128bit(key,i,256-i); - hashes[2*i] = temp.first; - hashes[2*i+1] = temp.second; - } - - byte_orderer bo; - bo.host_to_little(hashes); - final = static_cast(murmur_hash3_128bit(hashes,sizeof(hashes),0).first); - - // using ostringstream to avoid compiler error in visual studio 2005 - ostringstream sout; - sout << hex << final; - dlog << LINFO << "final 64: "<< sout.str(); - DLIB_TEST(final == 0x6384BA69); - } - - void test_murmur_hash_128_4() - { - byte_orderer bo; - dlib::rand rnd; - for (int i = 0; i < 100; ++i) - { - uint32 buf[4] = { rnd.get_random_32bit_number(), - rnd.get_random_32bit_number(), - rnd.get_random_32bit_number(), - rnd.get_random_32bit_number() - }; - - bo.host_to_little(buf); - - std::pair temp1, temp2; - - // Make sure the 4 integer version of murmur hash does the same thing - // as the memory block version. - temp1 = murmur_hash3_128bit(buf, sizeof(buf), 0); - temp2 = murmur_hash3_128bit(buf[0], buf[1], buf[2], buf[3]); - DLIB_TEST( temp1.first == temp2.first); - DLIB_TEST( temp1.second == temp2.second); - } - } - - void test_murmur_hash_128_3() - { - byte_orderer bo; - dlib::rand rnd; - for (int i = 0; i < 100; ++i) - { - uint64 buf[2] = { rnd.get_random_64bit_number(), - rnd.get_random_64bit_number(), - }; - - const uint32 seed = rnd.get_random_32bit_number(); - - bo.host_to_little(buf); - std::pair temp1, temp2; - - // Make sure the 3 integer version of murmur hash does the same thing - // as the memory block version. - temp1 = murmur_hash3_128bit(buf, sizeof(buf), seed); - temp2 = murmur_hash3_128bit_3(buf[0], buf[1], seed); - DLIB_TEST( temp1.first == temp2.first); - DLIB_TEST( temp1.second == temp2.second); - } - } - - void test_murmur_hash_64_2() - { - byte_orderer bo; - dlib::rand rnd; - for (int i = 0; i < 100; ++i) - { - uint32 val = rnd.get_random_32bit_number(); - const uint32 seed = rnd.get_random_32bit_number(); - - - bo.host_to_little(val); - uint32 temp1, temp2; - - // Make sure the 2 integer version of murmur hash does the same thing - // as the memory block version. - temp1 = murmur_hash3(&val, sizeof(val), seed); - temp2 = murmur_hash3_2(val, seed); - DLIB_TEST(temp1 == temp2); - } - } - - void test_murmur_hash_64_3() - { - byte_orderer bo; - dlib::rand rnd; - for (int i = 0; i < 100; ++i) - { - uint32 buf[2] = {rnd.get_random_32bit_number(), - rnd.get_random_32bit_number()}; - const uint32 seed = rnd.get_random_32bit_number(); - - - bo.host_to_little(buf); - uint32 temp1, temp2; - - // Make sure the 2 integer version of murmur hash does the same thing - // as the memory block version. - temp1 = murmur_hash3(&buf, sizeof(buf), seed); - temp2 = murmur_hash3_3(buf[0], buf[1], seed); - DLIB_TEST(temp1 == temp2); - } - } - -// ---------------------------------------------------------------------------------------- - - uint64 slow_count_bits ( uint64 v) - { - uint64 count = 0; - for (int i = 0; i < 64; ++i) - { - if (v&1) - ++count; - v >>= 1; - } - return count; - } - - - uint32 slow_count_bits ( uint32 v) - { - uint32 count = 0; - for (int i = 0; i < 32; ++i) - { - if (v&1) - ++count; - v >>= 1; - } - return count; - } - - -// ---------------------------------------------------------------------------------------- - - void test_hamming_stuff() - { - dlib::rand rnd; - for (int i = 0; i < 10000; ++i) - { - uint32 v = rnd.get_random_32bit_number(); - uint64 v2 = rnd.get_random_64bit_number(); - DLIB_TEST(slow_count_bits(v) == count_bits(v)); - DLIB_TEST(slow_count_bits(v2) == count_bits(v2)); - } - - DLIB_TEST(hamming_distance((uint32)0x1F, (uint32)0x0F) == 1); - DLIB_TEST(hamming_distance((uint32)0x1F, (uint32)0x1F) == 0); - DLIB_TEST(hamming_distance((uint32)0x1F, (uint32)0x19) == 2); - DLIB_TEST(hamming_distance((uint32)0x2F, (uint32)0x19) == 4); - } - -// ---------------------------------------------------------------------------------------- - - class test_hash : public tester - { - public: - test_hash ( - ) : - tester ("test_hash", - "Runs tests on the hash routines.") - {} - - void perform_test ( - ) - { - print_spinner(); - - test_hamming_stuff(); - - murmur_hash_test(); - murmur_hash_128_test(); - - std::string str1 = "some random string"; - matrix mat(2,2); - - mat = 1,2,3,4; - - matrix mat2(2,3); - - mat2 = 1,2,3,4,5,6; - - to_little(mat2); - - std::vector v(4); - v[0] = 'c'; - v[1] = 'a'; - v[2] = 't'; - v[3] = '!'; - - std::vector v2(4); - v[0] = 'c'; - v[1] = 'a'; - v[2] = 't'; - v[3] = '!'; - to_little(v2); - - std::map m; - m['c'] = 'C'; - m['a'] = 'A'; - m['t'] = 'T'; - - dlog << LINFO << "hash(str1): "<< dlib::hash(str1); - dlog << LINFO << "hash(v): "<< dlib::hash(v); - dlog << LINFO << "hash(v2): "<< dlib::hash(v2); - dlog << LINFO << "hash(m): "<< dlib::hash(m); - dlog << LINFO << "hash(mat): "<< dlib::hash(mat); - dlog << LINFO << "hash(mat2): "<< dlib::hash(mat2); - - uint32 ui1 = 123485393; - uint64 ui2 = ui1; - ui2 *= ui2; - ui2 *= ui2; - dlog << LINFO << "hash(ui1): "<< dlib::hash(ui1); - dlog << LINFO << "hash(ui2): "<< dlib::hash(ui2); - dlog << LINFO << "hash(make_pair(ui2,ui1)): "<< dlib::hash(make_pair(ui2,ui1)); - dlog << LINFO << "hash(make_pair(ui2,ui2)): "<< dlib::hash(make_pair(ui2,ui2)); - dlog << LINFO << "hash(make_pair(ui1,ui1)): "<< dlib::hash(make_pair(ui1,ui1)); - dlog << LINFO << "hash(ui1,3): "<< dlib::hash(ui1,3); - dlog << LINFO << "hash(ui2,3): "<< dlib::hash(ui2,3); - dlog << LINFO << "hash(make_pair(ui2,ui1),3): "<< dlib::hash(make_pair(ui2,ui1),3); - dlog << LINFO << "hash(make_pair(ui2,ui2),3): "<< dlib::hash(make_pair(ui2,ui2),3); - dlog << LINFO << "hash(make_pair(ui1,ui1),3): "<< dlib::hash(make_pair(ui1,ui1),3); - - DLIB_TEST(dlib::hash(ui1) == 0x63e272e4); - DLIB_TEST(dlib::hash(ui2) == 0xaf55561a); - DLIB_TEST(dlib::hash(make_pair(ui2,ui1)) == 0x52685376); - DLIB_TEST(dlib::hash(make_pair(ui2,ui2)) == 0xd25d6929); - DLIB_TEST(dlib::hash(make_pair(ui1,ui1)) == 0xeea3b63e); - DLIB_TEST(dlib::hash(ui1,3) == 0x95d1c4c0); - DLIB_TEST(dlib::hash(ui2,3) == 0x6ada728d); - DLIB_TEST(dlib::hash(make_pair(ui2,ui1),3) == 0x2f72a0ff); - DLIB_TEST(dlib::hash(make_pair(ui2,ui2),3) == 0xac1407f0); - DLIB_TEST(dlib::hash(make_pair(ui1,ui1),3) == 0x39ad637a); - - - DLIB_TEST(dlib::hash(str1) == 0x3ffe6bf6); - DLIB_TEST(dlib::hash(v) == 0xf1af2ca6); - DLIB_TEST(dlib::hash(v2) == 0x63852afc); - DLIB_TEST(dlib::hash(m) == 0xaacc3f6f); - DLIB_TEST(dlib::hash(mat) == 0x3e349da5); - DLIB_TEST(dlib::hash(mat2) == 0x3a95dc52); - DLIB_TEST(murmur_hash3(&str1[0], str1.size(), 0) == 0x3ffe6bf6); - - dlog << LINFO << "hash(str1,1): "<< dlib::hash(str1,1); - dlog << LINFO << "hash(v,3): "<< dlib::hash(v,3); - dlog << LINFO << "hash(v2,3): "<< dlib::hash(v2,3); - dlog << LINFO << "hash(m,4): "<< dlib::hash(m,4); - dlog << LINFO << "hash(mat,5): "<< dlib::hash(mat,5); - dlog << LINFO << "hash(mat2,6): "<< dlib::hash(mat2,6); - - DLIB_TEST(dlib::hash(str1,1) == 0xb17cea93); - DLIB_TEST(dlib::hash(v,3) == 0x7ec9284c); - DLIB_TEST(dlib::hash(v2,3) == 0xb2ce147f); - DLIB_TEST(dlib::hash(m,4) == 0xfa5e7ac2); - DLIB_TEST(dlib::hash(mat,5) == 0x8de27259); - DLIB_TEST(dlib::hash(mat2,6) == 0xb8aa7714); - DLIB_TEST(murmur_hash3(&str1[0], str1.size(), 1) == 0xb17cea93); - - test_murmur_hash_128_4(); - test_murmur_hash_128_3(); - test_murmur_hash_64_2(); - test_murmur_hash_64_3(); - } - } a; - - - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/hash_map.cpp b/lib/3rdParty/dlib/include/dlib/test/hash_map.cpp deleted file mode 100644 index 09af0993..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/hash_map.cpp +++ /dev/null @@ -1,450 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include - -#include -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace std; - using namespace dlib; - - logger dlog("test.hash_map"); - - template < - typename hash_map - > - void hash_map_kernel_test ( - ) - /*! - requires - - hash_map is an implementation of hash_map/hash_map_kernel_abstract.h and - is instantiated to map int to int - ensures - - runs tests on hash_map for compliance with the specs - !*/ - { - - srand(static_cast(time(0))); - - print_spinner(); - - - hash_map test, test2; - - enumerable >& e = test; - DLIB_TEST(e.at_start() == true); - - for (int j = 0; j < 4; ++j) - { - print_spinner(); - - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == false); - - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.is_in_domain(5) == false); - DLIB_TEST(test.is_in_domain(0) == false); - DLIB_TEST(test.is_in_domain(-999) == false); - DLIB_TEST(test.is_in_domain(4999) == false); - - - int a,b; - a = 8; - b = 94; - test.add(a,b); - DLIB_TEST(test.size() == 1); - DLIB_TEST(test.is_in_domain(8) == true); - DLIB_TEST(test.is_in_domain(5) == false); - DLIB_TEST(test.is_in_domain(0) == false); - DLIB_TEST(test.is_in_domain(-999) == false); - DLIB_TEST(test.is_in_domain(4999) == false); - DLIB_TEST(test[8] == 94); - a = 53; - b = 4; - test.add(a,b); - DLIB_TEST(test.size() == 2); - DLIB_TEST(test.is_in_domain(53) == true); - DLIB_TEST(test.is_in_domain(5) == false); - DLIB_TEST(test.is_in_domain(0) == false); - DLIB_TEST(test.is_in_domain(-999) == false); - DLIB_TEST(test.is_in_domain(4999) == false); - DLIB_TEST(test[53] == 4); - - - swap(test,test2); - - - DLIB_TEST_MSG(test2.size() == 2,test2.size()); - DLIB_TEST(test2.is_in_domain(8) == true); - DLIB_TEST(test2.is_in_domain(5) == false); - DLIB_TEST(test2.is_in_domain(0) == false); - DLIB_TEST(test2.is_in_domain(-999) == false); - DLIB_TEST(test2.is_in_domain(4999) == false); - DLIB_TEST(test2[8] == 94); - DLIB_TEST(test2.size() == 2); - DLIB_TEST(test2.is_in_domain(53) == true); - DLIB_TEST(test2.is_in_domain(5) == false); - DLIB_TEST(test2.is_in_domain(0) == false); - DLIB_TEST(test2.is_in_domain(-999) == false); - DLIB_TEST(test2.is_in_domain(4999) == false); - DLIB_TEST(test2[53] == 4); - - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.is_in_domain(8) == false); - DLIB_TEST(test.is_in_domain(5) == false); - DLIB_TEST(test.is_in_domain(0) == false); - DLIB_TEST(test.is_in_domain(-999) == false); - DLIB_TEST(test.is_in_domain(4999) == false); - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.is_in_domain(53) == false); - DLIB_TEST(test.is_in_domain(5) == false); - DLIB_TEST(test.is_in_domain(0) == false); - DLIB_TEST(test.is_in_domain(-999) == false); - DLIB_TEST(test.is_in_domain(4999) == false); - - - test.clear(); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.at_start() == false); - - - DLIB_TEST(test.size() == 0); - - while (test.size() < 10000) - { - a = ::rand(); - b = ::rand(); - if (!test.is_in_domain(a)) - test.add(a,b); - } - - DLIB_TEST(test.size() == 10000); - test.clear(); - DLIB_TEST(test.size() == 0); - - while (test.size() < 10000) - { - a = ::rand(); - b = ::rand(); - if (!test.is_in_domain(a)) - test.add(a,b); - } - - DLIB_TEST(test.size() == 10000); - - int count = 0; - while (test.move_next()) - { - DLIB_TEST(test.element().key() == test.element().key()); - DLIB_TEST(test.element().value() == test.element().value()); - DLIB_TEST(test.element().key() == test.element().key()); - DLIB_TEST(test.element().value() == test.element().value()); - - - - ++count; - } - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.move_next() == false); - - DLIB_TEST(count == 10000); - - test.swap(test2); - - DLIB_TEST(test.size() == 2); - DLIB_TEST(test2.size() == 10000); - count = 0; - test2.reset(); - - test2.move_next(); - test2.element().value() = 99; - DLIB_TEST(test2[test2.element().key()] == 99); - DLIB_TEST(test2.element().value() == 99); - - test2.reset(); - - while (test2.move_next()) - { - DLIB_TEST(test2[test2.element().key()] == test2.element().value()); - DLIB_TEST(test2.element().key() == test2.element().key()); - DLIB_TEST(test2.element().value() == test2.element().value()); - DLIB_TEST(test2.element().key() == test2.element().key()); - DLIB_TEST(test2.element().value() == test2.element().value()); - - ++count; - } - DLIB_TEST(test2.size() == 10000); - DLIB_TEST(count == 10000); - DLIB_TEST(test2.current_element_valid() == false); - DLIB_TEST(test2.at_start() == false); - DLIB_TEST(test2.move_next() == false); - DLIB_TEST(test2.current_element_valid() == false); - DLIB_TEST(test2.at_start() == false); - DLIB_TEST(test2.move_next() == false); - - - - test2.clear(); - DLIB_TEST(test2.size() == 0); - DLIB_TEST(test2.at_start() == true); - - while (test.size() < 20000) - { - a = ::rand(); - b = ::rand(); - if (!test.is_in_domain(a)) - test.add(a,b); - } - - DLIB_TEST(test.at_start() == true); - - { - int* array1 = new int[test.size()]; - int* array2 = new int[test.size()]; - - int* tmp1 = array1; - int* tmp2 = array2; - - - - // serialize the state of test, then clear test, then - // load the state back into test. - ostringstream sout; - serialize(test,sout); - DLIB_TEST(test.at_start() == true); - istringstream sin(sout.str()); - test.clear(); - deserialize(test,sin); - DLIB_TEST(test.at_start() == true); - - - count = 0; - while (test.move_next()) - { - DLIB_TEST(test.element().key() == test.element().key()); - DLIB_TEST(test.element().value() == test.element().value()); - DLIB_TEST(test.element().key() == test.element().key()); - DLIB_TEST(test.current_element_valid() == true); - *tmp1 = test.element().key(); - *tmp2 = test.element().value(); - ++tmp1; - ++tmp2; - ++count; - } - DLIB_TEST(count == 20000); - - tmp1 = array1; - tmp2 = array2; - for (int i = 0; i < 20000; ++i) - { - DLIB_TEST(test.is_in_domain(*tmp1) == true); - DLIB_TEST(test[*tmp1] == *tmp2); - ++tmp1; - ++tmp2; - } - - DLIB_TEST(test.size() == 20000); - - tmp1 = array1; - tmp2 = array2; - count = 0; - while (test.size() > 10000) - { - test.remove(*tmp1,a,b); - DLIB_TEST(*tmp1 == a); - DLIB_TEST(*tmp2 == b); - ++tmp1; - ++tmp2; - ++count; - } - DLIB_TEST(count == 10000); - DLIB_TEST(test.size() == 10000); - - while (test.move_next()) - { - DLIB_TEST(test.element().key() == *tmp1); - DLIB_TEST(test.element().key() == *tmp1); - DLIB_TEST(test.element().key() == *tmp1); - DLIB_TEST(test.element().value() == *tmp2); - DLIB_TEST(test.element().value() == *tmp2); - DLIB_TEST(test.element().value() == *tmp2); - ++tmp1; - ++tmp2; - ++count; - } - DLIB_TEST(count == 20000); - DLIB_TEST(test.size() == 10000); - - while (test.size() < 20000) - { - a = ::rand(); - b = ::rand(); - if (!test.is_in_domain(a)) - test.add(a,b); - } - - test2.swap(test); - - count = 0; - while (test2.move_next()) - { - DLIB_TEST(test2.element().key() == test2.element().key()); - DLIB_TEST(test2.element().value() == test2.element().value()); - DLIB_TEST(test2.element().key() == test2.element().key()); - - ++count; - } - - DLIB_TEST(count == 20000); - DLIB_TEST(test2.size() == 20000); - - int c = 0; - while (test2.size()>0) - { - test2.remove_any(b,c); - - } - - DLIB_TEST(test2.size() == 0); - delete [] array1; - delete [] array2; - } - - test.clear(); - test2.clear(); - while (test.size() < 10000) - { - a = ::rand(); - b = ::rand(); - if (!test.is_in_domain(a)) - test.add(a,b); - } - - count = 0; - while (test.move_next()) - { - - DLIB_TEST(test[test.element().key()] == test.element().value()); - - ++count; - if (count == 5000) - break; - DLIB_TEST(test.current_element_valid() == true); - } - - test.reset(); - - count = 0; - - while (test.move_next()) - { - - ++count; - DLIB_TEST(test.current_element_valid() == true); - } - - DLIB_TEST(count == 10000); - - - test.clear(); - test2.clear(); - } - - - - - { - test.clear(); - DLIB_TEST(test.size() == 0); - int a = 5; - int b = 6; - test.add(a,b); - a = 7; - b = 8; - test.add(a,b); - DLIB_TEST(test.size() == 2); - DLIB_TEST(test[7] == 8); - DLIB_TEST(test[5] == 6); - DLIB_TEST(test.is_in_domain(7)); - DLIB_TEST(test.is_in_domain(5)); - test.destroy(7); - DLIB_TEST(test.size() == 1); - DLIB_TEST(!test.is_in_domain(7)); - DLIB_TEST(test.is_in_domain(5)); - test.destroy(5); - DLIB_TEST(test.size() == 0); - DLIB_TEST(!test.is_in_domain(7)); - DLIB_TEST(!test.is_in_domain(5)); - } - - - - } - - - - - - class hash_map_tester : public tester - { - public: - hash_map_tester ( - ) : - tester ("test_hash_map", - "Runs tests on the hash_map component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a"; - hash_map_kernel_test::kernel_1a>(); - - dlog << LINFO << "testing kernel_1b_c"; - hash_map_kernel_test::kernel_1a_c>(); - - dlog << LINFO << "testing kernel_1b"; - hash_map_kernel_test::kernel_1b>(); - - dlog << LINFO << "testing kernel_1a_c"; - hash_map_kernel_test::kernel_1b_c>(); - - dlog << LINFO << "testing kernel_1c"; - hash_map_kernel_test::kernel_1c>(); - - dlog << LINFO << "testing kernel_1c_c"; - hash_map_kernel_test::kernel_1c_c>(); - } - } a; - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/hash_set.cpp b/lib/3rdParty/dlib/include/dlib/test/hash_set.cpp deleted file mode 100644 index 02b665bd..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/hash_set.cpp +++ /dev/null @@ -1,387 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include - -#include -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace std; - using namespace dlib; - - logger dlog("test.hash_set"); - - template < - typename hash_set - > - void hash_set_kernel_test ( - ) - /*! - requires - - hash_set is an implementation of hash_set/hash_set_kernel_abstract.h and - is instantiated with int - ensures - - runs tests on hash_set for compliance with the specs - !*/ - { - - - srand(static_cast(time(0))); - - - print_spinner(); - - hash_set test, test2; - - - enumerable& e = test; - DLIB_TEST(e.at_start() == true); - - - for (int j = 0; j < 4; ++j) - { - print_spinner(); - - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == false); - - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.is_member(5) == false); - DLIB_TEST(test.is_member(0) == false); - DLIB_TEST(test.is_member(-999) == false); - DLIB_TEST(test.is_member(4999) == false); - - - int a,b = 0; - a = 8; - test.add(a); - DLIB_TEST(test.size() == 1); - DLIB_TEST(test.is_member(8) == true); - DLIB_TEST(test.is_member(5) == false); - DLIB_TEST(test.is_member(0) == false); - DLIB_TEST(test.is_member(-999) == false); - DLIB_TEST(test.is_member(4999) == false); - a = 53; - test.add(a); - DLIB_TEST(test.size() == 2); - DLIB_TEST(test.is_member(53) == true); - DLIB_TEST(test.is_member(5) == false); - DLIB_TEST(test.is_member(0) == false); - DLIB_TEST(test.is_member(-999) == false); - DLIB_TEST(test.is_member(4999) == false); - - - swap(test,test2); - - - - DLIB_TEST(test2.is_member(8) == true); - DLIB_TEST(test2.is_member(5) == false); - DLIB_TEST(test2.is_member(0) == false); - DLIB_TEST(test2.is_member(-999) == false); - DLIB_TEST(test2.is_member(4999) == false); - DLIB_TEST(test2.size() == 2); - DLIB_TEST(test2.is_member(53) == true); - DLIB_TEST(test2.is_member(5) == false); - DLIB_TEST(test2.is_member(0) == false); - DLIB_TEST(test2.is_member(-999) == false); - DLIB_TEST(test2.is_member(4999) == false); - - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.is_member(8) == false); - DLIB_TEST(test.is_member(5) == false); - DLIB_TEST(test.is_member(0) == false); - DLIB_TEST(test.is_member(-999) == false); - DLIB_TEST(test.is_member(4999) == false); - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.is_member(53) == false); - DLIB_TEST(test.is_member(5) == false); - DLIB_TEST(test.is_member(0) == false); - DLIB_TEST(test.is_member(-999) == false); - DLIB_TEST(test.is_member(4999) == false); - - - test.clear(); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.at_start() == false); - - - DLIB_TEST(test.size() == 0); - - while (test.size() < 10000) - { - a = ::rand(); - if (!test.is_member(a)) - test.add(a); - } - - DLIB_TEST(test.size() == 10000); - test.clear(); - DLIB_TEST(test.size() == 0); - - while (test.size() < 10000) - { - a = ::rand(); - if (!test.is_member(a)) - test.add(a); - } - - DLIB_TEST(test.size() == 10000); - - int count = 0; - while (test.move_next()) - { - DLIB_TEST(test.element() == test.element()); - DLIB_TEST(test.element() == test.element()); - DLIB_TEST(test.element() == test.element()); - - - ++count; - } - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.move_next() == false); - - DLIB_TEST(count == 10000); - - test.swap(test2); - - DLIB_TEST(test.size() == 2); - DLIB_TEST(test2.size() == 10000); - count = 0; - test2.reset(); - while (test2.move_next()) - { - DLIB_TEST(test2.element() == test2.element()); - DLIB_TEST(test2.element() == test2.element()); - DLIB_TEST(test2.element() == test2.element()); - - ++count; - } - DLIB_TEST(test2.size() == 10000); - DLIB_TEST(count == 10000); - DLIB_TEST(test2.current_element_valid() == false); - DLIB_TEST(test2.at_start() == false); - DLIB_TEST(test2.move_next() == false); - DLIB_TEST(test2.current_element_valid() == false); - DLIB_TEST(test2.at_start() == false); - DLIB_TEST(test2.move_next() == false); - - - - test2.clear(); - DLIB_TEST(test2.size() == 0); - DLIB_TEST(test2.at_start() == true); - - while (test.size() < 20000) - { - a = ::rand(); - if (!test.is_member(a)) - test.add(a); - } - - DLIB_TEST(test.at_start() == true); - - { - int* array = new int[test.size()]; - int* tmp = array; - - // serialize the state of test, then clear test, then - // load the state back into test. - ostringstream sout; - serialize(test,sout); - DLIB_TEST(test.at_start() == true); - istringstream sin(sout.str()); - test.clear(); - deserialize(test,sin); - - - - count = 0; - while (test.move_next()) - { - DLIB_TEST(test.element() == test.element()); - DLIB_TEST(test.element() == test.element()); - DLIB_TEST(test.element() == test.element()); - *tmp = test.element(); - ++tmp; - ++count; - } - DLIB_TEST(count == 20000); - - tmp = array; - for (int i = 0; i < 20000; ++i) - { - DLIB_TEST(test.is_member(*tmp) == true); - ++tmp; - } - - DLIB_TEST(test.size() == 20000); - - tmp = array; - count = 0; - while (test.size() > 10000) - { - test.remove(*tmp,a); - DLIB_TEST(*tmp == a); - ++tmp; - ++count; - } - DLIB_TEST(count == 10000); - DLIB_TEST(test.size() == 10000); - - while (test.move_next()) - { - ++count; - } - DLIB_TEST(count == 20000); - DLIB_TEST(test.size() == 10000); - - while (test.size() < 20000) - { - a = ::rand(); - if (!test.is_member(a)) - test.add(a); - } - - test2.swap(test); - - count = 0; - while (test2.move_next()) - { - DLIB_TEST(test2.element() == test2.element()); - DLIB_TEST(test2.element() == test2.element()); - DLIB_TEST(test2.element() == test2.element()); - - ++count; - } - - DLIB_TEST(count == 20000); - DLIB_TEST(test2.size() == 20000); - - - while (test2.size()>0) - { - test2.remove_any(b); - } - - DLIB_TEST(test2.size() == 0); - delete [] array; - } - - test.clear(); - test2.clear(); - while (test.size() < 10000) - { - a = ::rand(); - if (!test.is_member(a)) - test.add(a); - } - - count = 0; - while (test.move_next()) - { - ++count; - if (count == 5000) - break; - DLIB_TEST(test.current_element_valid() == true); - } - - test.reset(); - - count = 0; - while (test.move_next()) - { - ++count; - DLIB_TEST(test.current_element_valid() == true); - } - - DLIB_TEST(count == 10000); - - - test.clear(); - test2.clear(); - } - - - { - test.clear(); - DLIB_TEST(test.size() == 0); - int a = 5; - test.add(a); - a = 7; - test.add(a); - DLIB_TEST(test.size() == 2); - DLIB_TEST(test.is_member(7)); - DLIB_TEST(test.is_member(5)); - test.destroy(7); - DLIB_TEST(test.size() == 1); - DLIB_TEST(!test.is_member(7)); - DLIB_TEST(test.is_member(5)); - test.destroy(5); - DLIB_TEST(test.size() == 0); - DLIB_TEST(!test.is_member(7)); - DLIB_TEST(!test.is_member(5)); - } - - } - - - - - class hash_set_tester : public tester - { - public: - hash_set_tester ( - ) : - tester ("test_hash_set", - "Runs tests on the hash_set component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a"; - hash_set_kernel_test::kernel_1a>(); - dlog << LINFO << "testing kernel_1a_c"; - hash_set_kernel_test::kernel_1a_c>(); - dlog << LINFO << "testing kernel_1b"; - hash_set_kernel_test::kernel_1b>(); - dlog << LINFO << "testing kernel_1b_c"; - hash_set_kernel_test::kernel_1b_c>(); - dlog << LINFO << "testing kernel_1c"; - hash_set_kernel_test::kernel_1c>(); - dlog << LINFO << "testing kernel_1c_c"; - hash_set_kernel_test::kernel_1c_c>(); - } - } a; - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/hash_table.cpp b/lib/3rdParty/dlib/include/dlib/test/hash_table.cpp deleted file mode 100644 index f4754835..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/hash_table.cpp +++ /dev/null @@ -1,663 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include - -#include -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace std; - using namespace dlib; - - logger dlog("test.hash_table"); - - template < - typename hash_table - > - void hash_table_kernel_test ( - ) - /*! - requires - - hash_table is an implementation of hash_table/hash_table_kernel_abstract.h - and is instantiated to map ints to ints - ensures - - runs tests on hash_table for compliance with the specs - !*/ - { - - srand(static_cast(time(0))); - - - - - { - hash_table test(16); - - DLIB_TEST(test.count(3) == 0); - - enumerable >& e = test; - DLIB_TEST(e.at_start() == true); - - hash_table test2(16); - - hash_table test3(0); - hash_table test4(0); - - - print_spinner(); - - int b; - for (int j = 0; j < 4; ++j) - { - int a = 4; - b = 5; - test2.add(a,b); - DLIB_TEST(test2.size() == 1); - DLIB_TEST(*test2[4] == 5); - DLIB_TEST(test2[99] == 0); - - DLIB_TEST(test2.move_next()); - DLIB_TEST(test2.element().key() == 4); - DLIB_TEST(test2.element().value() == 5); - - swap(test,test2); - DLIB_TEST(test.size() == 1); - DLIB_TEST(*test[4] == 5); - DLIB_TEST(test[99] == 0); - - test.swap(test2); - - a = 99; - b = 35; - test2.add(a,b); - DLIB_TEST(test2.size() == 2); - DLIB_TEST(*test2[4] == 5); - DLIB_TEST(*test2[99] == 35); - DLIB_TEST(test2[99] != 0); - DLIB_TEST(test2[949] == 0); - - test2.destroy(4); - DLIB_TEST(test2.size() == 1); - DLIB_TEST(test2[4] == 0); - DLIB_TEST(*test2[99] == 35); - DLIB_TEST(test2[99] != 0); - DLIB_TEST(test2[949] == 0); - - - - test2.destroy(99); - DLIB_TEST(test2.size() == 0); - DLIB_TEST(test2[4] == 0); - DLIB_TEST(test2[99] == 0); - DLIB_TEST(test2[949] == 0); - - - - test2.clear(); - } - - - print_spinner(); - - - - - for (int j = 0; j < 4; ++j) - { - - DLIB_TEST(test.count(3) == 0); - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - - int a; - - for (int i = 0; i < 10000; ++i) - { - a = ::rand()%1000; - int temp = a; - unsigned long count = test.count(a); - test.add(a,b); - DLIB_TEST(test.count(temp) == count+1); - } - - { - unsigned long count = test.count(3); - - a = 3; test.add(a,b); ++count; - DLIB_TEST(test.count(3) == count); - a = 3; test.add(a,b); ++count; - DLIB_TEST(test.count(3) == count); - a = 3; test.add(a,b); ++count; - DLIB_TEST(test.count(3) == count); - a = 3; test.add(a,b); ++count; - DLIB_TEST(test.count(3) == count); - } - - - test.clear(); - - - for (int i = 0; i < 10000; ++i) - { - a = b = i; - unsigned long count = test.count(a); - test.add(a,b); - DLIB_TEST(test.count(i) == count+1); - } - - DLIB_TEST(test.size() == 10000); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == true); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == true); - DLIB_TEST(test.move_next() == true); - DLIB_TEST(test.move_next() == true); - DLIB_TEST(test.current_element_valid() == true); - - - test.reset(); - - DLIB_TEST(test.size() == 10000); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - - - if (test.size() > 0) - { - int* array = new int[test.size()]; - int* tmp = array; - - int count = 0; - while (test.move_next()) - { - ++count; - *tmp = test.element().key(); - DLIB_TEST(test[*tmp] != 0); - DLIB_TEST(*tmp == test.element().key()); - DLIB_TEST(*tmp == test.element().value()); - DLIB_TEST(*tmp == test.element().key()); - DLIB_TEST(test.current_element_valid() == true); - ++tmp; - } - - DLIB_TEST(count == 10000); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == false); - - DLIB_TEST(test.size() == 10000); - - swap(test,test2); - - - - - // serialize the state of test2, then clear test2, then - // load the state back into test2. - ostringstream sout; - serialize(test2,sout); - DLIB_TEST(test2.at_start() == true); - istringstream sin(sout.str()); - test2.clear(); - deserialize(test2,sin); - DLIB_TEST(test2.at_start() == true); - - - - - tmp = array; - for (int i = 0; i < 10000; ++i) - { - DLIB_TEST(*test2[*tmp] == *tmp); - DLIB_TEST(*test2[*tmp] == *tmp); - DLIB_TEST(*test2[*tmp] == *tmp); - ++tmp; - } - - test2.swap(test); - test.reset(); - - DLIB_TEST(test.at_start() == true); - count = 0; - tmp = array; - while (test.size() > 0) - { - test.remove(*tmp,a,b); - - ++tmp; - ++count; - } - - DLIB_TEST(count == 10000); - DLIB_TEST(test.size() == 0); - - - - DLIB_TEST(count == 10000); - - - - - - - - delete [] array; - } - - test.move_next(); - - for (int i = 0; i < 10000; ++i) - { - a = ::rand(); - test.add(a,b); - } - - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.move_next() == true); - - DLIB_TEST(test.size() == 10000); - - for (int i = 0; i < 10000; ++i) - { - test.remove_any(a,b); - } - - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.size() == 0); - - test.clear(); - - - - - - - - - - int* dtmp = new int[10000]; - int* rtmp = new int[10000]; - - int* d = dtmp; - int* r = rtmp; - for (unsigned long i = 0; i < 10000; ++i) - { - a = ::rand(); - b = ::rand(); - *d = a; - *r = b; - if (test[a] != 0) - { - --i; - continue; - } - test.add(a,b); - ++d; - ++r; - DLIB_TEST(test.size() == i+1); - } - - DLIB_TEST(test.size() == 10000); - - for (int i = 0; i < 10000; ++i) - { - DLIB_TEST(*test[dtmp[i]] == rtmp[i]); - } - - - delete [] dtmp; - delete [] rtmp; - - test.clear(); - }} - - - print_spinner(); - - - - - - - - - - - - - - - - - - - - - - - - - // now do the same thing as above but with a much smaller hash table - { - hash_table test(13); - - DLIB_TEST(test.count(3) == 0); - - enumerable >& e = test; - DLIB_TEST(e.at_start() == true); - - hash_table test2(16); - - hash_table test3(0); - hash_table test4(0); - - - int b; - for (int j = 0; j < 4; ++j) - { - int a = 4; - b = 5; - test2.add(a,b); - DLIB_TEST(test2.size() == 1); - DLIB_TEST(*test2[4] == 5); - DLIB_TEST(test2[99] == 0); - - - DLIB_TEST(test2.move_next()); - DLIB_TEST(test2.element().key() == 4); - DLIB_TEST(test2.element().value() == 5); - - swap(test,test2); - DLIB_TEST(test.size() == 1); - DLIB_TEST(*test[4] == 5); - DLIB_TEST(test[99] == 0); - - test.swap(test2); - - a = 99; - b = 35; - test2.add(a,b); - DLIB_TEST(test2.size() == 2); - DLIB_TEST(*test2[4] == 5); - DLIB_TEST(*test2[99] == 35); - DLIB_TEST(test2[99] != 0); - DLIB_TEST(test2[949] == 0); - - test2.destroy(4); - DLIB_TEST(test2.size() == 1); - DLIB_TEST(test2[4] == 0); - DLIB_TEST(*test2[99] == 35); - DLIB_TEST(test2[99] != 0); - DLIB_TEST(test2[949] == 0); - - - - test2.destroy(99); - DLIB_TEST(test2.size() == 0); - DLIB_TEST(test2[4] == 0); - DLIB_TEST(test2[99] == 0); - DLIB_TEST(test2[949] == 0); - - - - test2.clear(); - } - - - print_spinner(); - - - - - for (int j = 0; j < 4; ++j) - { - - DLIB_TEST(test.count(3) == 0); - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - - int a; - - for (int i = 0; i < 10000; ++i) - { - a = ::rand()%1000; - int temp = a; - unsigned long count = test.count(a); - test.add(a,b); - DLIB_TEST(test.count(temp) == count+1); - } - - { - unsigned long count = test.count(3); - - a = 3; test.add(a,b); ++count; - DLIB_TEST(test.count(3) == count); - a = 3; test.add(a,b); ++count; - DLIB_TEST(test.count(3) == count); - a = 3; test.add(a,b); ++count; - DLIB_TEST(test.count(3) == count); - a = 3; test.add(a,b); ++count; - DLIB_TEST(test.count(3) == count); - } - - - test.clear(); - - - for (int i = 0; i < 10000; ++i) - { - a = b = i; - unsigned long count = test.count(a); - test.add(a,b); - DLIB_TEST(test.count(i) == count+1); - } - - DLIB_TEST(test.size() == 10000); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == true); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == true); - DLIB_TEST(test.move_next() == true); - DLIB_TEST(test.move_next() == true); - DLIB_TEST(test.current_element_valid() == true); - - - test.reset(); - - DLIB_TEST(test.size() == 10000); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - - - if (test.size() > 0) - { - int* array = new int[test.size()]; - int* tmp = array; - - int count = 0; - while (test.move_next()) - { - ++count; - *tmp = test.element().key(); - DLIB_TEST(test[*tmp] != 0); - DLIB_TEST(*tmp == test.element().key()); - DLIB_TEST(*tmp == test.element().value()); - DLIB_TEST(*tmp == test.element().key()); - DLIB_TEST(test.current_element_valid() == true); - ++tmp; - } - - DLIB_TEST(count == 10000); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == false); - - DLIB_TEST(test.size() == 10000); - - swap(test,test2); - - tmp = array; - for (int i = 0; i < 10000; ++i) - { - DLIB_TEST(*test2[*tmp] == *tmp); - DLIB_TEST(*test2[*tmp] == *tmp); - DLIB_TEST(*test2[*tmp] == *tmp); - ++tmp; - } - - test2.swap(test); - test.reset(); - - DLIB_TEST(test.at_start() == true); - count = 0; - tmp = array; - while (test.size() > 0) - { - test.remove(*tmp,a,b); - - ++tmp; - ++count; - } - - DLIB_TEST(count == 10000); - DLIB_TEST(test.size() == 0); - - - - DLIB_TEST(count == 10000); - - - - - - - - delete [] array; - } - - test.move_next(); - - for (int i = 0; i < 10000; ++i) - { - a = ::rand(); - test.add(a,b); - } - - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.move_next() == true); - - DLIB_TEST(test.size() == 10000); - - for (int i = 0; i < 10000; ++i) - { - test.remove_any(a,b); - } - - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.size() == 0); - - test.clear(); - - - - - - - - - int* dtmp = new int[10000]; - int* rtmp = new int[10000]; - - int* d = dtmp; - int* r = rtmp; - for (unsigned long i = 0; i < 10000; ++i) - { - a = ::rand(); - b = ::rand(); - *d = a; - *r = b; - if (test[a] != 0) - { - --i; - continue; - } - test.add(a,b); - ++d; - ++r; - DLIB_TEST(test.size() == i+1); - } - - DLIB_TEST(test.size() == 10000); - - for (int i = 0; i < 10000; ++i) - { - DLIB_TEST(*test[dtmp[i]] == rtmp[i]); - } - - - delete [] dtmp; - delete [] rtmp; - - test.clear(); - }} - - } - - - - - class hash_table_tester : public tester - { - public: - hash_table_tester ( - ) : - tester ("test_hash_table", - "Runs tests on the hash_table component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a"; - hash_table_kernel_test::kernel_1a> (); - dlog << LINFO << "testing kernel_1a_c"; - hash_table_kernel_test::kernel_1a_c>(); - dlog << LINFO << "testing kernel_2a"; - hash_table_kernel_test::kernel_2a> (); - dlog << LINFO << "testing kernel_2a_c"; - hash_table_kernel_test::kernel_2a_c>(); - } - } a; - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/hog_image.cpp b/lib/3rdParty/dlib/include/dlib/test/hog_image.cpp deleted file mode 100644 index 615e4d2f..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/hog_image.cpp +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.hog_image"); - -// ---------------------------------------------------------------------------------------- - - class test_hog_image : public tester - { - public: - test_hog_image ( - ) : - tester ("test_hog_image", - "Runs tests on the hog_image object.") - {} - - void perform_test ( - ) - { - print_spinner(); - array2d img; - img.set_size(200,200); - - assign_all_pixels(img, 0); - - hog_image<3,3,1,4,hog_signed_gradient,hog_full_interpolation> hog1, hog1_deserialized; - hog_image<4,4,2,4,hog_signed_gradient,hog_full_interpolation> hog2; - - hog1.load(img); - hog2.load(img); - - - // Just test all the coordinate mapping functions. - - DLIB_TEST(hog1.get_block_rect(0,0).width() == 3*3); - DLIB_TEST(hog1.get_block_rect(0,0).height() == 3*3); - DLIB_TEST(hog2.get_block_rect(0,0).width() == 4*4); - DLIB_TEST(hog2.get_block_rect(0,0).height() == 4*4); - - DLIB_TEST(get_rect(img).contains(hog1.get_block_rect(0,0))); - DLIB_TEST(get_rect(img).contains(hog1.get_block_rect(hog1.nr()-1,hog1.nc()-1))); - DLIB_TEST(get_rect(img).contains(hog2.get_block_rect(0,0))); - DLIB_TEST(get_rect(img).contains(hog2.get_block_rect(hog2.nr()-1,hog2.nc()-1))); - - dlib::rand rnd; - for (int i = 0; i < 20000; ++i) - { - point p(rnd.get_random_16bit_number(), rnd.get_random_16bit_number()); - p.x() -= 20000; - p.y() -= 20000; - - DLIB_TEST((hog1.feat_to_image_space(hog1.image_to_feat_space(p)) - p).length() <= 3); - DLIB_TEST((hog2.feat_to_image_space(hog2.image_to_feat_space(p)) - p).length() <= 10); - - DLIB_TEST_MSG((hog1.image_to_feat_space(hog1.feat_to_image_space(p)) - p).length() <= 3, - p << " " << hog1.feat_to_image_space(p) << " " << hog1.image_to_feat_space(hog1.feat_to_image_space(p)) ); - DLIB_TEST((hog2.image_to_feat_space(hog2.feat_to_image_space(p)) - p).length() <= 10); - } - - - DLIB_TEST(hog1.feat_to_image_space(point(0,0)) == point(5,5)); - DLIB_TEST(hog2.feat_to_image_space(point(0,0)) == point(9,9)); - - DLIB_TEST(hog1.feat_to_image_space(point(1,1)) == point(8,8)); - DLIB_TEST(hog2.feat_to_image_space(point(1,1)) == point(17,17)); - - DLIB_TEST(hog1.image_to_feat_space(hog1.feat_to_image_space(point(0,0))) == point(0,0)); - DLIB_TEST(hog2.image_to_feat_space(hog2.feat_to_image_space(point(0,0))) == point(0,0)); - DLIB_TEST(hog1.image_to_feat_space(hog1.feat_to_image_space(point(1,1))) == point(1,1)); - DLIB_TEST(hog2.image_to_feat_space(hog2.feat_to_image_space(point(1,1))) == point(1,1)); - DLIB_TEST(hog1.image_to_feat_space(hog1.feat_to_image_space(point(1,2))) == point(1,2)); - DLIB_TEST(hog2.image_to_feat_space(hog2.feat_to_image_space(point(1,2))) == point(1,2)); - - - - DLIB_TEST(hog1_deserialized.size() != hog1.size()); - DLIB_TEST(hog1_deserialized.nr() != hog1.nr()); - DLIB_TEST(hog1_deserialized.nc() != hog1.nc()); - ostringstream sout; - serialize(hog1, sout); - istringstream sin(sout.str()); - deserialize(hog1_deserialized, sin); - - DLIB_TEST(hog1_deserialized.size() == hog1.size()); - DLIB_TEST(hog1_deserialized.nr() == hog1.nr()); - DLIB_TEST(hog1_deserialized.nc() == hog1.nc()); - DLIB_TEST(hog1_deserialized(0,2) == hog1(0,2)); - DLIB_TEST(hog1_deserialized.get_block_rect(1,2) == hog1.get_block_rect(1,2)); - DLIB_TEST(hog1_deserialized.image_to_feat_space(hog1_deserialized.feat_to_image_space(point(0,0))) == point(0,0)); - DLIB_TEST(hog1_deserialized.image_to_feat_space(hog1_deserialized.feat_to_image_space(point(1,1))) == point(1,1)); - DLIB_TEST(hog1_deserialized.image_to_feat_space(hog1_deserialized.feat_to_image_space(point(1,2))) == point(1,2)); - - - - DLIB_TEST(hog1.size() > 1); - DLIB_TEST(hog1.nr() > 1); - DLIB_TEST(hog1.nc() > 1); - hog1.clear(); - DLIB_TEST(hog1.size() == 0); - DLIB_TEST(hog1.nr() == 0); - DLIB_TEST(hog1.nc() == 0); - } - } a; - -} - - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/image.cpp b/lib/3rdParty/dlib/include/dlib/test/image.cpp deleted file mode 100644 index 01a3414f..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/image.cpp +++ /dev/null @@ -1,1750 +0,0 @@ -// Copyright (C) 2008 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.image"); - - - void image_test ( - ) - /*! - ensures - - runs tests on pixel objects and functions for compliance with the specs - !*/ - { - - print_spinner(); - - array2d img1, img2; - - img1.set_size(100,100); - - assign_all_pixels(img1,7); - - assign_image(img2, img1); - - DLIB_TEST_MSG(img1.nr() == 100 && img1.nc() == 100 && - img2.nr() == 100 && img2.nc() == 100,""); - - - for (long r = 0; r < img1.nr(); ++r) - { - for (long c = 0; c < img1.nc(); ++c) - { - DLIB_TEST(img1[r][c] == 7); - DLIB_TEST(img2[r][c] == 7); - } - } - - img2.clear(); - DLIB_TEST(img2.size() == 0); - DLIB_TEST(img2.nr() == 0); - DLIB_TEST(img2.nc() == 0); - assign_image(img2, mat(img1)); - - DLIB_TEST_MSG(img1.nr() == 100 && img1.nc() == 100 && - img2.nr() == 100 && img2.nc() == 100,""); - - - for (long r = 0; r < img1.nr(); ++r) - { - for (long c = 0; c < img1.nc(); ++c) - { - DLIB_TEST(img1[r][c] == 7); - DLIB_TEST(img2[r][c] == 7); - } - } - - - threshold_image(img1, img2, 4); - - for (long r = 0; r < img1.nr(); ++r) - { - for (long c = 0; c < img1.nc(); ++c) - { - DLIB_TEST(img1[r][c] == 7); - DLIB_TEST(img2[r][c] == on_pixel); - } - } - - { - array2d img; - img.set_size(14,15); - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - img[r][c].h = static_cast(r*14 + c + 1); - img[r][c].s = static_cast(r*14 + c + 2); - img[r][c].i = static_cast(r*14 + c + 3); - } - } - - ostringstream sout; - save_dng(img, sout); - istringstream sin(sout.str()); - - img.clear(); - DLIB_TEST(img.nr() == 0); - DLIB_TEST(img.nc() == 0); - - load_dng(img, sin); - - DLIB_TEST(img.nr() == 14); - DLIB_TEST(img.nc() == 15); - - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - DLIB_TEST(img[r][c].h == r*14 + c + 1); - DLIB_TEST(img[r][c].s == r*14 + c + 2); - DLIB_TEST(img[r][c].i == r*14 + c + 3); - } - } - } - - - - - { - array2d img; - img.set_size(14,15); - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - img[r][c].red = static_cast(r*14 + c + 1); - img[r][c].green = static_cast(r*14 + c + 2); - img[r][c].blue = static_cast(r*14 + c + 3); - img[r][c].alpha = static_cast(r*14 + c + 4); - } - } - - ostringstream sout; - save_dng(img, sout); - istringstream sin(sout.str()); - - img.clear(); - DLIB_TEST(img.nr() == 0); - DLIB_TEST(img.nc() == 0); - - load_dng(img, sin); - - DLIB_TEST(img.nr() == 14); - DLIB_TEST(img.nc() == 15); - - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - DLIB_TEST(img[r][c].red == r*14 + c + 1); - DLIB_TEST(img[r][c].green == r*14 + c + 2); - DLIB_TEST(img[r][c].blue == r*14 + c + 3); - DLIB_TEST(img[r][c].alpha == r*14 + c + 4); - } - } - } - -#ifdef DLIB_PNG_SUPPORT - { - array2d img; - array2d img2, img3; - img.set_size(14,15); - img2.set_size(img.nr(),img.nc()); - img3.set_size(img.nr(),img.nc()); - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - img[r][c].red = static_cast(r*14 + c + 1); - img[r][c].green = static_cast(r*14 + c + 2); - img[r][c].blue = static_cast(r*14 + c + 3); - img[r][c].alpha = static_cast(r*14 + c + 4); - } - } - - save_png(img, "test.png"); - - img.clear(); - DLIB_TEST(img.nr() == 0); - DLIB_TEST(img.nc() == 0); - - load_png(img, "test.png"); - - DLIB_TEST(img.nr() == 14); - DLIB_TEST(img.nc() == 15); - - assign_all_pixels(img2, 255); - assign_all_pixels(img3, 0); - load_png(img2, "test.png"); - assign_image(img3, img); - - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - DLIB_TEST(img[r][c].red == r*14 + c + 1); - DLIB_TEST(img[r][c].green == r*14 + c + 2); - DLIB_TEST(img[r][c].blue == r*14 + c + 3); - DLIB_TEST(img[r][c].alpha == r*14 + c + 4); - - DLIB_TEST(img2[r][c].red == img3[r][c].red); - DLIB_TEST(img2[r][c].green == img3[r][c].green); - DLIB_TEST(img2[r][c].blue == img3[r][c].blue); - } - } - } -#endif // DLIB_PNG_SUPPORT - - - - { - array2d img; - img.set_size(14,15); - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - img[r][c].red = static_cast(r*14 + c + 1); - img[r][c].green = static_cast(r*14 + c + 2); - img[r][c].blue = static_cast(r*14 + c + 3); - } - } - - ostringstream sout; - save_dng(img, sout); - save_bmp(img, sout); - save_dng(img, sout); - save_bmp(img, sout); - istringstream sin(sout.str()); - - for (int i = 0; i < 2; ++i) - { - img.clear(); - DLIB_TEST(img.nr() == 0); - DLIB_TEST(img.nc() == 0); - - load_dng(img, sin); - - DLIB_TEST(img.nr() == 14); - DLIB_TEST(img.nc() == 15); - - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - DLIB_TEST(img[r][c].red == r*14 + c + 1); - DLIB_TEST(img[r][c].green == r*14 + c + 2); - DLIB_TEST(img[r][c].blue == r*14 + c + 3); - } - } - - img.clear(); - DLIB_TEST(img.nr() == 0); - DLIB_TEST(img.nc() == 0); - - load_bmp(img, sin); - - DLIB_TEST(img.nr() == 14); - DLIB_TEST(img.nc() == 15); - - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - DLIB_TEST_MSG(img[r][c].red == r*14 + c + 1, "got " << (int)img[r][c].red << " but expected " << r*14 + c + 1); - DLIB_TEST(img[r][c].green == r*14 + c + 2); - DLIB_TEST(img[r][c].blue == r*14 + c + 3); - } - } - } - } - { - array2d img; - img.set_size(14,15); - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - img[r][c].red = static_cast(r*14 + c + 1); - img[r][c].green = static_cast(r*14 + c + 2); - img[r][c].blue = static_cast(r*14 + c + 3); - } - } - - ostringstream sout; - save_dng(img, sout); - save_bmp(img, sout); - save_dng(img, sout); - save_bmp(img, sout); - istringstream sin(sout.str()); - - for (int i = 0; i < 2; ++i) - { - img.clear(); - DLIB_TEST(img.nr() == 0); - DLIB_TEST(img.nc() == 0); - - load_dng(img, sin); - - DLIB_TEST(img.nr() == 14); - DLIB_TEST(img.nc() == 15); - - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - DLIB_TEST(img[r][c].red == r*14 + c + 1); - DLIB_TEST(img[r][c].green == r*14 + c + 2); - DLIB_TEST(img[r][c].blue == r*14 + c + 3); - } - } - - img.clear(); - DLIB_TEST(img.nr() == 0); - DLIB_TEST(img.nc() == 0); - - load_bmp(img, sin); - - DLIB_TEST(img.nr() == 14); - DLIB_TEST(img.nc() == 15); - - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - DLIB_TEST_MSG(img[r][c].red == r*14 + c + 1, "got " << (int)img[r][c].red << " but expected " << r*14 + c + 1); - DLIB_TEST(img[r][c].green == r*14 + c + 2); - DLIB_TEST(img[r][c].blue == r*14 + c + 3); - } - } - } - } - -#ifdef DLIB_PNG_SUPPORT - { - array2d img; - img.set_size(14,15); - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - img[r][c].red = static_cast(r*14 + c + 1); - img[r][c].green = static_cast(r*14 + c + 2); - img[r][c].blue = static_cast(r*14 + c + 3); - } - } - - save_png(img, "test.png"); - - img.clear(); - DLIB_TEST(img.nr() == 0); - DLIB_TEST(img.nc() == 0); - - load_png(img, "test.png"); - - DLIB_TEST(img.nr() == 14); - DLIB_TEST(img.nc() == 15); - - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - DLIB_TEST(img[r][c].red == r*14 + c + 1); - DLIB_TEST(img[r][c].green == r*14 + c + 2); - DLIB_TEST(img[r][c].blue == r*14 + c + 3); - } - } - } - { - array2d img; - img.set_size(14,15); - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - img[r][c].red = static_cast(r*14 + c + 1); - img[r][c].green = static_cast(r*14 + c + 2); - img[r][c].blue = static_cast(r*14 + c + 3); - } - } - - save_png(img, "test.png"); - - img.clear(); - DLIB_TEST(img.nr() == 0); - DLIB_TEST(img.nc() == 0); - - load_png(img, "test.png"); - - DLIB_TEST(img.nr() == 14); - DLIB_TEST(img.nc() == 15); - - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - DLIB_TEST(img[r][c].red == r*14 + c + 1); - DLIB_TEST(img[r][c].green == r*14 + c + 2); - DLIB_TEST(img[r][c].blue == r*14 + c + 3); - } - } - } -#endif // DLIB_PNG_SUPPORT - - - - { - array2d img; - img.set_size(14,15); - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - img[r][c] = static_cast(r*14 + c + 0xF0); - } - } - - ostringstream sout; - save_dng(img, sout); - istringstream sin(sout.str()); - - img.clear(); - DLIB_TEST(img.nr() == 0); - DLIB_TEST(img.nc() == 0); - - load_dng(img, sin); - - DLIB_TEST(img.nr() == 14); - DLIB_TEST(img.nc() == 15); - - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - DLIB_TEST(img[r][c] == r*14 + c + 0xF0); - } - } - } - - -#ifdef DLIB_PNG_SUPPORT - { - array2d img; - img.set_size(14,15); - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - img[r][c] = static_cast(r*14 + c + 0xF0); - } - } - - save_png(img, "test.png"); - - img.clear(); - DLIB_TEST(img.nr() == 0); - DLIB_TEST(img.nc() == 0); - - load_png(img, "test.png"); - - DLIB_TEST(img.nr() == 14); - DLIB_TEST(img.nc() == 15); - - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - DLIB_TEST(img[r][c] == r*14 + c + 0xF0); - } - } - } -#endif // DLIB_PNG_SUPPORT - - - - { - array2d img; - img.set_size(14,15); - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - img[r][c] = static_cast(r*14 + c*111); - } - } - - ostringstream sout; - save_dng(img, sout); - save_bmp(img, sout); - save_dng(img, sout); - save_bmp(img, sout); - istringstream sin(sout.str()); - - for (int i = 0; i < 2; ++i) - { - img.clear(); - DLIB_TEST(img.nr() == 0); - DLIB_TEST(img.nc() == 0); - - load_dng(img, sin); - - DLIB_TEST(img.nr() == 14); - DLIB_TEST(img.nc() == 15); - - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - DLIB_TEST(img[r][c] == static_cast(r*14 + c*111)); - } - } - - - img.clear(); - DLIB_TEST(img.nr() == 0); - DLIB_TEST(img.nc() == 0); - - load_bmp(img, sin); - - DLIB_TEST(img.nr() == 14); - DLIB_TEST(img.nc() == 15); - - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - DLIB_TEST(img[r][c] == static_cast(r*14 + c*111)); - } - } - } - } - - -#ifdef DLIB_PNG_SUPPORT - { - array2d img; - img.set_size(14,15); - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - img[r][c] = static_cast(r*14 + c); - } - } - - save_png(img, "test.png"); - - img.clear(); - DLIB_TEST(img.nr() == 0); - DLIB_TEST(img.nc() == 0); - - load_png(img, "test.png"); - - DLIB_TEST(img.nr() == 14); - DLIB_TEST(img.nc() == 15); - - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - DLIB_TEST(img[r][c] == r*14 + c); - } - } - - } -#endif // DLIB_PNG_SUPPORT - - - { - // in this test we will only assign pixel values that can be - // represented with 8 bits even though we are using a wider pixel type. - array2d img; - img.set_size(14,15); - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - img[r][c] = static_cast(r*14 + c); - } - } - - ostringstream sout; - save_dng(img, sout); - save_bmp(img, sout); - save_dng(img, sout); - save_bmp(img, sout); - istringstream sin(sout.str()); - - for (int i = 0; i < 2; ++i) - { - img.clear(); - DLIB_TEST(img.nr() == 0); - DLIB_TEST(img.nc() == 0); - - load_dng(img, sin); - - DLIB_TEST(img.nr() == 14); - DLIB_TEST(img.nc() == 15); - - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - DLIB_TEST(img[r][c] == r*14 + c); - } - } - - - img.clear(); - DLIB_TEST(img.nr() == 0); - DLIB_TEST(img.nc() == 0); - - load_bmp(img, sin); - - DLIB_TEST(img.nr() == 14); - DLIB_TEST(img.nc() == 15); - - for (long r = 0; r < 14; ++r) - { - for (long c = 0; c < 15; ++c) - { - DLIB_TEST(img[r][c] == r*14 + c); - } - } - } - } - - { - array2d img1; - array2d img2; - img1.set_size(10,10); - assign_all_pixels(img1, 0); - - img1[5][5] = 10000; - img1[7][7] = 10000; - - equalize_histogram(img1, img2); - - for (long r = 0; r < img1.nr(); ++r) - { - for (long c = 0; c < img2.nc(); ++c) - { - if ((r == 5 && c == 5) || - (r == 7 && c == 7)) - { - DLIB_TEST(img2[r][c] == 255); - } - else - { - DLIB_TEST(img2[r][c] == 0); - } - } - } - - } - - { - array2d img; - img.set_size(10,10); - assign_all_pixels(img, 0); - - assign_border_pixels(img, 2,2, 4); - - DLIB_TEST(zeros_matrix(6,6) == subm(mat(img), rectangle(2,2,7,7))); - DLIB_TEST(uniform_matrix(1,10, 4) == rowm(mat(img), 0)); - DLIB_TEST(uniform_matrix(1,10, 4) == rowm(mat(img), 1)); - DLIB_TEST(uniform_matrix(1,10, 4) == rowm(mat(img), 8)); - DLIB_TEST(uniform_matrix(1,10, 4) == rowm(mat(img), 9)); - - DLIB_TEST(uniform_matrix(10,1, 4) == colm(mat(img), 0)); - DLIB_TEST(uniform_matrix(10,1, 4) == colm(mat(img), 1)); - DLIB_TEST(uniform_matrix(10,1, 4) == colm(mat(img), 8)); - DLIB_TEST(uniform_matrix(10,1, 4) == colm(mat(img), 9)); - - - assign_border_pixels(img, 7, 7, 5); - DLIB_TEST(uniform_matrix(10,10, 5) == mat(img)); - assign_border_pixels(img, 37, 47, 5); - DLIB_TEST(uniform_matrix(10,10, 5) == mat(img)); - } - - { - array2d img; - img.set_size(11,11); - assign_all_pixels(img, 0); - - assign_border_pixels(img, 2,2, 4); - - DLIB_TEST(zeros_matrix(7,7) == subm(mat(img), rectangle(2,2,8,8))); - DLIB_TEST(uniform_matrix(1,11, 4) == rowm(mat(img), 0)); - DLIB_TEST(uniform_matrix(1,11, 4) == rowm(mat(img), 1)); - DLIB_TEST(uniform_matrix(1,11, 4) == rowm(mat(img), 9)); - DLIB_TEST(uniform_matrix(1,11, 4) == rowm(mat(img), 10)); - - DLIB_TEST(uniform_matrix(11,1, 4) == colm(mat(img), 0)); - DLIB_TEST(uniform_matrix(11,1, 4) == colm(mat(img), 1)); - DLIB_TEST(uniform_matrix(11,1, 4) == colm(mat(img), 9)); - DLIB_TEST(uniform_matrix(11,1, 4) == colm(mat(img), 10)); - - assign_border_pixels(img, 7, 7, 5); - DLIB_TEST(uniform_matrix(11,11, 5) == mat(img)); - assign_border_pixels(img, 70, 57, 5); - DLIB_TEST(uniform_matrix(11,11, 5) == mat(img)); - } - - - } - - - template - void test_integral_image ( - ) - { - dlib::rand rnd; - - array2d img; - integral_image_generic int_img; - - int_img.load(img); - DLIB_TEST(int_img.nr() == 0); - DLIB_TEST(int_img.nc() == 0); - - // make 5 random images - for (int i = 0; i < 5; ++i) - { - print_spinner(); - img.set_size(rnd.get_random_16bit_number()%200+1, rnd.get_random_16bit_number()%200+1); - - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - img[r][c] = (int)rnd.get_random_8bit_number() - 100; - } - } - - int_img.load(img); - DLIB_TEST(int_img.nr() == img.nr()); - DLIB_TEST(int_img.nc() == img.nc()); - - // make 200 random rectangles - for (int j = 0; j < 500; ++j) - { - point p1(rnd.get_random_32bit_number()%img.nc(), rnd.get_random_32bit_number()%img.nr()); - point p2(rnd.get_random_32bit_number()%img.nc(), rnd.get_random_32bit_number()%img.nr()); - rectangle rect(p1,p2); - DLIB_TEST(int_img.get_sum_of_area(rect) == sum(subm(matrix_cast(mat(img)), rect))); - rect = rectangle(p1,p1); - DLIB_TEST(int_img.get_sum_of_area(rect) == sum(subm(matrix_cast(mat(img)), rect))); - } - - } - - - } - - void test_filtering2(int nr, int nc, dlib::rand& rnd) - { - print_spinner(); - dlog << LINFO << "test_filtering2(): " << nr << " " << nc; - array2d img(302,301); - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - img[r][c] = rnd.get_random_gaussian(); - } - } - matrix filt = matrix_cast(randm(nr,nc,rnd)); - - matrix out = xcorr_same(mat(img),filt); - matrix out2 = subm(conv(mat(img),flip(filt)), filt.nr()/2, filt.nc()/2, img.nr(), img.nc()); - // make sure xcorr_same does exactly what the docs say it should. - DLIB_TEST(max(abs(out-out2)) < 1e-7); - - // Now compare the filtering functions to xcorr_same to make sure everything does - // filtering in the same way. - array2d imout(img.nr(), img.nc()); - assign_all_pixels(imout, 10); - rectangle rect = spatially_filter_image(img, imout, filt); - border_enumerator be(get_rect(imout),rect); - while (be.move_next()) - { - DLIB_TEST(imout[be.element().y()][be.element().x()] == 0) - } - DLIB_TEST_MSG(max(abs(subm(mat(imout),rect) - subm(out,rect))) < 1e-5, max(abs(subm(mat(imout),rect) - subm(out,rect)))); - - - assign_all_pixels(imout, 10); - out = 10; - rect = spatially_filter_image(img, imout, filt,2,true,true); - be = border_enumerator(get_rect(imout),rect); - while (be.move_next()) - { - DLIB_TEST(imout[be.element().y()][be.element().x()] == 10) - } - out += abs(xcorr_same(mat(img),filt)/2); - DLIB_TEST(max(abs(subm(mat(imout),rect) - subm(out,rect))) < 1e-7); - - - assign_all_pixels(imout, -10); - out = -10; - rect = spatially_filter_image(img, imout, filt,2,false,true); - be = border_enumerator(get_rect(imout),rect); - while (be.move_next()) - { - DLIB_TEST(imout[be.element().y()][be.element().x()] == -10) - } - out += xcorr_same(mat(img),filt)/2; - DLIB_TEST_MSG(max(abs(subm(mat(imout),rect) - subm(out,rect))) < 1e-5, max(abs(subm(mat(imout),rect) - subm(out,rect)))); - - - - - matrix row_filt = matrix_cast(randm(nc,1,rnd)); - matrix col_filt = matrix_cast(randm(nr,1,rnd)); - assign_all_pixels(imout, 10); - rect = spatially_filter_image_separable(img, imout, row_filt, col_filt); - out = xcorr_same(tmp(xcorr_same(mat(img),trans(row_filt))), col_filt); - DLIB_TEST_MSG(max(abs(subm(mat(imout),rect) - subm(out,rect))) < 1e-5, max(abs(subm(mat(imout),rect) - subm(out,rect)))); - - be = border_enumerator(get_rect(imout),rect); - while (be.move_next()) - { - DLIB_TEST(imout[be.element().y()][be.element().x()] == 0); - } - - - assign_all_pixels(imout, 10); - out = 10; - rect = spatially_filter_image_separable(img, imout, row_filt, col_filt,2,true,true); - out += abs(xcorr_same(tmp(xcorr_same(mat(img),trans(row_filt))), col_filt)/2); - DLIB_TEST_MSG(max(abs(subm(mat(imout),rect) - subm(out,rect))) < 1e-7, - max(abs(subm(mat(imout),rect) - subm(out,rect)))); - - be = border_enumerator(get_rect(imout),rect); - while (be.move_next()) - { - DLIB_TEST(imout[be.element().y()][be.element().x()] == 10); - } - - } - - template - void test_filtering(bool use_abs, unsigned long scale ) - { - print_spinner(); - dlog << LINFO << "test_filtering(" << use_abs << "," << scale << ")"; - array2d img, img2, img3; - img.set_size(10,11); - - assign_all_pixels(img, 10); - - matrix filter2; - filter2 = 1,1,1,1,1, - 1,1,1,1,1, - 1,1,1,1,1; - - assign_all_pixels(img2,3); - rectangle brect = spatially_filter_image(img, img2, filter2); - DLIB_TEST(brect == shrink_rect(get_rect(img), filter2.nc()/2, filter2.nr()/2)); - - const rectangle rect(2,1,img.nc()-3,img.nr()-2); - - for (long r = 0; r row_filter; - matrix col_filter; - - row_filter = 1,1,1,1,1; - col_filter = 1,1,1; - - spatially_filter_image_separable(img, img3, row_filter, col_filter); - - DLIB_TEST(mat(img2) == mat(img3)); - - - dlib::rand rnd; - - for (int i = 0; i < 30; ++i) - { - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - img[r][c] = rnd.get_random_8bit_number(); - } - } - - row_filter(0) = ((int)rnd.get_random_8bit_number() - 100)/10; - row_filter(1) = ((int)rnd.get_random_8bit_number() - 100)/10; - row_filter(2) = ((int)rnd.get_random_8bit_number() - 100)/10; - row_filter(3) = ((int)rnd.get_random_8bit_number() - 100)/10; - row_filter(4) = ((int)rnd.get_random_8bit_number() - 100)/10; - col_filter(0) = ((int)rnd.get_random_8bit_number() - 100)/10; - col_filter(1) = ((int)rnd.get_random_8bit_number() - 100)/10; - col_filter(2) = ((int)rnd.get_random_8bit_number() - 100)/10; - - const matrix filter = trans(col_filter)*row_filter; - - assign_all_pixels(img2,3); - assign_all_pixels(img3,3); - // Just make sure both filtering methods give the same results. - rectangle brect1, brect2; - brect1 = spatially_filter_image(img, img2, filter, scale, use_abs); - brect2 = spatially_filter_image_separable(img, img3, row_filter, col_filter, scale, use_abs); - DLIB_TEST(mat(img2) == mat(img3)); - - DLIB_TEST(brect1 == shrink_rect(get_rect(img), filter.nc()/2, filter.nr()/2)); - DLIB_TEST(brect1 == brect2); - } - - { - array2d img, img2; - img.set_size(3,4); - - matrix filter(3,3); - filter = 1; - assign_all_pixels(img,-1); - - spatially_filter_image(img,img2,filter); - - DLIB_TEST(img2[0][0] == 0); - DLIB_TEST(img2[0][1] == 0); - DLIB_TEST(img2[0][2] == 0); - DLIB_TEST(img2[0][3] == 0); - - DLIB_TEST(img2[1][0] == 0); - DLIB_TEST(img2[1][1] == -9); - DLIB_TEST(img2[1][2] == -9); - DLIB_TEST(img2[1][3] == 0); - - DLIB_TEST(img2[2][0] == 0); - DLIB_TEST(img2[2][1] == 0); - DLIB_TEST(img2[2][2] == 0); - DLIB_TEST(img2[2][3] == 0); - - assign_all_pixels(img,-1); - - spatially_filter_image(img,img2,filter,2,true); - - DLIB_TEST(img2[0][0] == 0); - DLIB_TEST(img2[0][1] == 0); - DLIB_TEST(img2[0][2] == 0); - DLIB_TEST(img2[0][3] == 0); - - DLIB_TEST(img2[1][0] == 0); - DLIB_TEST(img2[1][1] == 4); - DLIB_TEST(img2[1][2] == 4); - DLIB_TEST(img2[1][3] == 0); - - DLIB_TEST(img2[2][0] == 0); - DLIB_TEST(img2[2][1] == 0); - DLIB_TEST(img2[2][2] == 0); - DLIB_TEST(img2[2][3] == 0); - - matrix rowf(3,1), colf(3,1); - rowf = 1; - colf = 1; - assign_all_pixels(img,-1); - - spatially_filter_image_separable(img,img2,rowf,colf); - DLIB_TEST(img2[0][0] == 0); - DLIB_TEST(img2[0][1] == 0); - DLIB_TEST(img2[0][2] == 0); - DLIB_TEST(img2[0][3] == 0); - - DLIB_TEST(img2[1][0] == 0); - DLIB_TEST(img2[1][1] == -9); - DLIB_TEST(img2[1][2] == -9); - DLIB_TEST(img2[1][3] == 0); - - DLIB_TEST(img2[2][0] == 0); - DLIB_TEST(img2[2][1] == 0); - DLIB_TEST(img2[2][2] == 0); - DLIB_TEST(img2[2][3] == 0); - - spatially_filter_image_separable(img,img2,rowf,colf,1,true); - DLIB_TEST(img2[0][0] == 0); - DLIB_TEST(img2[0][1] == 0); - DLIB_TEST(img2[0][2] == 0); - DLIB_TEST(img2[0][3] == 0); - - DLIB_TEST(img2[1][0] == 0); - DLIB_TEST(img2[1][1] == 9); - DLIB_TEST(img2[1][2] == 9); - DLIB_TEST(img2[1][3] == 0); - - DLIB_TEST(img2[2][0] == 0); - DLIB_TEST(img2[2][1] == 0); - DLIB_TEST(img2[2][2] == 0); - DLIB_TEST(img2[2][3] == 0); - - assign_all_pixels(img2, 3); - spatially_filter_image_separable(img,img2,rowf,colf,1,true, true); - DLIB_TEST(img2[0][0] == 3); - DLIB_TEST(img2[0][1] == 3); - DLIB_TEST(img2[0][2] == 3); - DLIB_TEST(img2[0][3] == 3); - - DLIB_TEST(img2[1][0] == 3); - DLIB_TEST_MSG(img2[1][1] == 9+3, img2[1][1] ); - DLIB_TEST(img2[1][2] == 9+3); - DLIB_TEST(img2[1][3] == 3); - - DLIB_TEST(img2[2][0] == 3); - DLIB_TEST(img2[2][1] == 3); - DLIB_TEST(img2[2][2] == 3); - DLIB_TEST(img2[2][3] == 3); - } - { - array2d img, img2; - img.set_size(3,4); - - matrix filter(3,3); - filter = 1; - assign_all_pixels(img,-1); - - spatially_filter_image(img,img2,filter,2); - - DLIB_TEST(img2[0][0] == 0); - DLIB_TEST(img2[0][1] == 0); - DLIB_TEST(img2[0][2] == 0); - DLIB_TEST(img2[0][3] == 0); - - DLIB_TEST(img2[1][0] == 0); - DLIB_TEST(std::abs(img2[1][1] - -4.5) < 1e-14); - DLIB_TEST(std::abs(img2[1][2] - -4.5) < 1e-14); - DLIB_TEST(img2[1][3] == 0); - - DLIB_TEST(img2[2][0] == 0); - DLIB_TEST(img2[2][1] == 0); - DLIB_TEST(img2[2][2] == 0); - DLIB_TEST(img2[2][3] == 0); - - } - { - array2d img, img2; - img.set_size(3,4); - img2.set_size(3,4); - assign_all_pixels(img2, 8); - - matrix filter(3,3); - filter = 1; - assign_all_pixels(img,-1); - - spatially_filter_image(img,img2,filter,2, false, true); - - DLIB_TEST(img2[0][0] == 8); - DLIB_TEST(img2[0][1] == 8); - DLIB_TEST(img2[0][2] == 8); - DLIB_TEST(img2[0][3] == 8); - - DLIB_TEST(img2[1][0] == 8); - DLIB_TEST(std::abs(img2[1][1] - -4.5 - 8) < 1e-14); - DLIB_TEST(std::abs(img2[1][2] - -4.5 - 8) < 1e-14); - DLIB_TEST(img2[1][3] == 8); - - DLIB_TEST(img2[2][0] == 8); - DLIB_TEST(img2[2][1] == 8); - DLIB_TEST(img2[2][2] == 8); - DLIB_TEST(img2[2][3] == 8); - - } - } - - - void test_zero_border_pixels( - ) - { - array2d img; - img.set_size(4,5); - - assign_all_pixels(img, 1); - zero_border_pixels(img, 2,1); - - DLIB_TEST(img[0][0] == 0); - DLIB_TEST(img[1][0] == 0); - DLIB_TEST(img[2][0] == 0); - DLIB_TEST(img[3][0] == 0); - DLIB_TEST(img[0][1] == 0); - DLIB_TEST(img[1][1] == 0); - DLIB_TEST(img[2][1] == 0); - DLIB_TEST(img[3][1] == 0); - - DLIB_TEST(img[0][3] == 0); - DLIB_TEST(img[1][3] == 0); - DLIB_TEST(img[2][3] == 0); - DLIB_TEST(img[3][3] == 0); - DLIB_TEST(img[0][4] == 0); - DLIB_TEST(img[1][4] == 0); - DLIB_TEST(img[2][4] == 0); - DLIB_TEST(img[3][4] == 0); - - DLIB_TEST(img[0][2] == 0); - DLIB_TEST(img[3][2] == 0); - - DLIB_TEST(img[1][2] == 1); - DLIB_TEST(img[2][2] == 1); - - rectangle rect = get_rect(img); - rect.left()+=2; - rect.top()+=1; - rect.right()-=2; - rect.bottom()-=1; - assign_all_pixels(img, 1); - zero_border_pixels(img, rect); - - DLIB_TEST(img[0][0] == 0); - DLIB_TEST(img[1][0] == 0); - DLIB_TEST(img[2][0] == 0); - DLIB_TEST(img[3][0] == 0); - DLIB_TEST(img[0][1] == 0); - DLIB_TEST(img[1][1] == 0); - DLIB_TEST(img[2][1] == 0); - DLIB_TEST(img[3][1] == 0); - - DLIB_TEST(img[0][3] == 0); - DLIB_TEST(img[1][3] == 0); - DLIB_TEST(img[2][3] == 0); - DLIB_TEST(img[3][3] == 0); - DLIB_TEST(img[0][4] == 0); - DLIB_TEST(img[1][4] == 0); - DLIB_TEST(img[2][4] == 0); - DLIB_TEST(img[3][4] == 0); - - DLIB_TEST(img[0][2] == 0); - DLIB_TEST(img[3][2] == 0); - - DLIB_TEST(img[1][2] == 1); - DLIB_TEST(img[2][2] == 1); - - rect.right()+=1; - assign_all_pixels(img, 1); - zero_border_pixels(img, rect); - DLIB_TEST(img[0][0] == 0); - DLIB_TEST(img[1][0] == 0); - DLIB_TEST(img[2][0] == 0); - DLIB_TEST(img[3][0] == 0); - DLIB_TEST(img[0][1] == 0); - DLIB_TEST(img[1][1] == 0); - DLIB_TEST(img[2][1] == 0); - DLIB_TEST(img[3][1] == 0); - - DLIB_TEST(img[0][3] == 0); - DLIB_TEST(img[1][3] == 1); - DLIB_TEST(img[2][3] == 1); - DLIB_TEST(img[3][3] == 0); - DLIB_TEST(img[0][4] == 0); - DLIB_TEST(img[1][4] == 0); - DLIB_TEST(img[2][4] == 0); - DLIB_TEST(img[3][4] == 0); - - DLIB_TEST(img[0][2] == 0); - DLIB_TEST(img[3][2] == 0); - - DLIB_TEST(img[1][2] == 1); - DLIB_TEST(img[2][2] == 1); - } - - - void test_label_connected_blobs() - { - array2d img; - img.set_size(400,401); - - assign_all_pixels(img,0); - - rectangle rect1, rect2, rect3; - - rect1 = centered_rect(99,120, 50,70); - rect2 = centered_rect(199,80, 34,68); - rect3 = centered_rect(249,180, 120,78); - - fill_rect(img, rect1, 255); - fill_rect(img, rect2, 255); - fill_rect(img, rect3, 255); - - array2d labels; - unsigned long num; - num = label_connected_blobs(img, - zero_pixels_are_background(), - neighbors_8(), - connected_if_both_not_zero(), - labels); - - DLIB_TEST(num == 4); - DLIB_TEST(labels.nr() == img.nr()); - DLIB_TEST(labels.nc() == img.nc()); - - const unsigned char l1 = labels[rect1.top()][rect1.left()]; - const unsigned char l2 = labels[rect2.top()][rect2.left()]; - const unsigned char l3 = labels[rect3.top()][rect3.left()]; - - DLIB_TEST(l1 != 0 && l2 != 0 && l3 != 0); - DLIB_TEST(l1 != l2 && l1 != l3 && l2 != l3); - - for (long r = 0; r < labels.nr(); ++r) - { - for (long c = 0; c < labels.nc(); ++c) - { - if (rect1.contains(c,r)) - { - DLIB_TEST(labels[r][c] == l1); - } - else if (rect2.contains(c,r)) - { - DLIB_TEST(labels[r][c] == l2); - } - else if (rect3.contains(c,r)) - { - DLIB_TEST(labels[r][c] == l3); - } - else - { - DLIB_TEST(labels[r][c] == 0); - } - } - } - } - - void test_label_connected_blobs2() - { - array2d img; - img.set_size(400,401); - - assign_all_pixels(img,0); - - rectangle rect1, rect2, rect3; - - rect1 = centered_rect(99,120, 50,70); - rect2 = centered_rect(199,80, 34,68); - rect3 = centered_rect(249,180, 120,78); - - fill_rect(img, rect1, 255); - fill_rect(img, rect2, 253); - fill_rect(img, rect3, 255); - - array2d labels; - unsigned long num; - num = label_connected_blobs(img, - nothing_is_background(), - neighbors_4(), - connected_if_equal(), - labels); - - DLIB_TEST(num == 5); - DLIB_TEST(labels.nr() == img.nr()); - DLIB_TEST(labels.nc() == img.nc()); - - const unsigned char l0 = labels[0][0]; - const unsigned char l1 = labels[rect1.top()][rect1.left()]; - const unsigned char l2 = labels[rect2.top()][rect2.left()]; - const unsigned char l3 = labels[rect3.top()][rect3.left()]; - - DLIB_TEST(l0 != 0 && l1 != 0 && l2 != 0 && l3 != 0); - DLIB_TEST(l1 != l2 && l1 != l3 && l2 != l3 && - l0 != l1 && l0 != l2 && l0 != l3); - - for (long r = 0; r < labels.nr(); ++r) - { - for (long c = 0; c < labels.nc(); ++c) - { - if (rect1.contains(c,r)) - { - DLIB_TEST(labels[r][c] == l1); - } - else if (rect2.contains(c,r)) - { - DLIB_TEST(labels[r][c] == l2); - } - else if (rect3.contains(c,r)) - { - DLIB_TEST(labels[r][c] == l3); - } - else - { - DLIB_TEST(labels[r][c] == l0); - } - } - } - } - -// ---------------------------------------------------------------------------------------- - - template < - typename in_image_type, - typename out_image_type - > - void downsample_image ( - const unsigned long downsample, - const in_image_type& in_img, - out_image_type& out_img, - bool add_to - ) - { - out_img.set_size((in_img.nr()+downsample-1)/downsample, - (in_img.nc()+downsample-1)/downsample); - - for (long r = 0; r < out_img.nr(); ++r) - { - for (long c = 0; c < out_img.nc(); ++c) - { - if (add_to) - out_img[r][c] += in_img[r*downsample][c*downsample]; - else - out_img[r][c] = in_img[r*downsample][c*downsample]; - } - } - } - - template < - typename in_image_type, - typename out_image_type, - typename EXP1, - typename EXP2, - typename T - > - void test_spatially_filter_image_separable_down_simple ( - const unsigned long downsample, - const in_image_type& in_img, - out_image_type& out_img, - const matrix_exp& row_filter, - const matrix_exp& col_filter, - T scale, - bool use_abs = false, - bool add_to = false - ) - { - out_image_type temp; - spatially_filter_image_separable(in_img, temp, row_filter, col_filter, scale, use_abs, false); - downsample_image(downsample, temp, out_img, add_to); - } - - - - - template - void test_downsampled_filtering_helper(long row_filt_size, long col_filt_size) - { - print_spinner(); - dlog << LTRACE << "***********************************"; - dlog << LTRACE << "downsample: " << downsample; - dlog << LTRACE << "row_filt_size: "<< row_filt_size; - dlog << LTRACE << "col_filt_size: "<< col_filt_size; - dlib::rand rnd; - array2d out1, out2; - for (long nr = 0; nr < 3; ++nr) - { - for (long nc = 0; nc < 3; ++nc) - { - dlog << LTRACE << "nr: "<< nr; - dlog << LTRACE << "nc: "<< nc; - array2d img(25+nr,25+nc); - for (int k = 0; k < 5; ++k) - { - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - img[r][c] = rnd.get_random_8bit_number(); - } - } - - matrix row_filter(row_filt_size); - matrix col_filter(col_filt_size); - - row_filter = matrix_cast(10*randm(row_filt_size,1, rnd)); - col_filter = matrix_cast(10*randm(col_filt_size,1, rnd)); - - row_filter -= 3; - col_filter -= 3; - - - test_spatially_filter_image_separable_down_simple(downsample, img, out1, row_filter, col_filter,1 ); - spatially_filter_image_separable_down(downsample, img, out2, row_filter, col_filter); - - DLIB_TEST(get_rect(out1) == get_rect(out2)); - DLIB_TEST(mat(out1) == mat(out2)); - - test_spatially_filter_image_separable_down_simple(downsample, img, out1, row_filter, col_filter,3, true, true ); - spatially_filter_image_separable_down(downsample, img, out2, row_filter, col_filter, 3, true, true); - - DLIB_TEST(get_rect(out1) == get_rect(out2)); - DLIB_TEST(mat(out1) == mat(out2)); - - } - } - } - } - - void test_downsampled_filtering() - { - test_downsampled_filtering_helper<1>(5,5); - test_downsampled_filtering_helper<2>(5,5); - test_downsampled_filtering_helper<3>(5,5); - test_downsampled_filtering_helper<1>(3,5); - test_downsampled_filtering_helper<2>(3,5); - test_downsampled_filtering_helper<3>(3,5); - test_downsampled_filtering_helper<1>(5,3); - test_downsampled_filtering_helper<2>(5,3); - test_downsampled_filtering_helper<3>(5,3); - - test_downsampled_filtering_helper<1>(3,3); - test_downsampled_filtering_helper<2>(3,3); - test_downsampled_filtering_helper<3>(3,3); - - test_downsampled_filtering_helper<1>(1,1); - test_downsampled_filtering_helper<2>(1,1); - test_downsampled_filtering_helper<3>(1,1); - - } - -// ---------------------------------------------------------------------------------------- - - template - void test_segment_image() - { - print_spinner(); - array2d img(100,100); - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - if (c < 50 || r < 50) - assign_pixel(img[r][c], 0); - else - assign_pixel(img[r][c], 255); - } - } - - array2d out; - segment_image(img, out); - - DLIB_TEST(get_rect(img) == get_rect(out)); - const unsigned long v1 = out[0][0]; - const unsigned long v2 = out[90][90]; - - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - if (c < 50 || r < 50) - { - DLIB_TEST(out[r][c] == v1); - } - else - { - DLIB_TEST(out[r][c] == v2); - } - } - } - } - -// ---------------------------------------------------------------------------------------- - - template - void test_dng_floats(double scale) - { - dlog << LINFO << "in test_dng_floats"; - print_spinner(); - array2d img(100,101); - - dlib::rand rnd; - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - T val = rnd.get_random_double()*scale; - img[r][c] = val; - - // Lets the float_details object while we are here doing this stuff. - float_details temp = val; - T val2 = temp; - // for the same type we should exactly reproduce the value (unless - // it's long double and then maybe it's slightly different). - if (is_same_type::value) - { - DLIB_TEST(std::abs(val2-val) < scale*std::numeric_limits::epsilon()); - } - else - { - DLIB_TEST(val2 == val); - } - - float valf = temp; - double vald = temp; - long double vall = temp; - - DLIB_TEST(std::abs(valf-val) < scale*std::numeric_limits::epsilon()); - DLIB_TEST(std::abs(vald-val) < scale*std::numeric_limits::epsilon()); - DLIB_TEST(std::abs(vall-val) < scale*std::numeric_limits::epsilon()); - } - } - - ostringstream sout; - save_dng(img, sout); - istringstream sin; - - array2d img1; - array2d img2; - array2d img3; - - sin.clear(); sin.str(sout.str()); - load_dng(img1, sin); - - sin.clear(); sin.str(sout.str()); - load_dng(img2, sin); - - sin.clear(); sin.str(sout.str()); - load_dng(img3, sin); - - DLIB_TEST(img.nr() == img1.nr()); - DLIB_TEST(img.nr() == img2.nr()); - DLIB_TEST(img.nr() == img3.nr()); - DLIB_TEST(img.nc() == img1.nc()); - DLIB_TEST(img.nc() == img2.nc()); - DLIB_TEST(img.nc() == img3.nc()); - - DLIB_TEST(max(abs(mat(img) - matrix_cast(mat(img1)))) < scale*std::numeric_limits::epsilon()); - DLIB_TEST(max(abs(mat(img) - matrix_cast(mat(img2)))) < scale*std::numeric_limits::epsilon()); - DLIB_TEST(max(abs(mat(img) - matrix_cast(mat(img3)))) < scale*std::numeric_limits::epsilon()); - } - - void test_dng_float_int() - { - dlog << LINFO << "in test_dng_float_int"; - print_spinner(); - - array2d img; - assign_image(img, gaussian_randm(101,100)*10000); - - ostringstream sout; - save_dng(img, sout); - istringstream sin(sout.str()); - array2d img2; - load_dng(img2, sin); - sout.clear(); sout.str(""); - - save_dng(img2, sout); - sin.clear(); sin.str(sout.str()); - array2d img3; - load_dng(img3, sin); - - // this whole thing should have been totally lossless. - DLIB_TEST(mat(img) == mat(img3)); - } - -// ---------------------------------------------------------------------------------------- - - template - void test_filtering_center ( - dlib::rand& rnd - ) - { - array2d img(rnd.get_random_32bit_number()%100+1, - rnd.get_random_32bit_number()%100+1); - matrix filt(rnd.get_random_32bit_number()%10+1, - rnd.get_random_32bit_number()%10+1); - - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - img[r][c] = rnd.get_random_32bit_number()%100; - } - } - for (long r = 0; r < filt.nr(); ++r) - { - for (long c = 0; c < filt.nc(); ++c) - { - filt(r,c) = rnd.get_random_32bit_number()%100; - } - } - - array2d out; - const rectangle area = spatially_filter_image(img, out, filt); - - for (long r = 0; r < out.nr(); ++r) - { - for (long c = 0; c < out.nc(); ++c) - { - const rectangle rect = centered_rect(point(c,r), filt.nc(), filt.nr()); - if (get_rect(out).contains(rect)) - { - T val = sum(pointwise_multiply(filt, subm(mat(img),rect))); - DLIB_CASSERT(val == out[r][c],"err: " << val-out[r][c]); - DLIB_CASSERT(area.contains(point(c,r)),""); - } - else - { - DLIB_CASSERT(!area.contains(point(c,r)),""); - } - } - } - } - - template - void test_separable_filtering_center ( - dlib::rand& rnd - ) - { - array2d img(rnd.get_random_32bit_number()%100+1, - rnd.get_random_32bit_number()%100+1); - matrix row_filt(rnd.get_random_32bit_number()%10+1); - matrix col_filt(rnd.get_random_32bit_number()%10+1); - - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - img[r][c] = rnd.get_random_32bit_number()%10; - } - } - for (long r = 0; r < row_filt.size(); ++r) - { - row_filt(r) = rnd.get_random_32bit_number()%10; - } - for (long r = 0; r < col_filt.size(); ++r) - { - col_filt(r) = rnd.get_random_32bit_number()%10; - } - - array2d out; - const rectangle area = spatially_filter_image_separable(img, out, row_filt, col_filt); - - for (long r = 0; r < out.nr(); ++r) - { - for (long c = 0; c < out.nc(); ++c) - { - const rectangle rect = centered_rect(point(c,r), row_filt.size(), col_filt.size()); - if (get_rect(out).contains(rect)) - { - T val = sum(pointwise_multiply(col_filt*row_filt, subm(mat(img),rect))); - DLIB_CASSERT(val == out[r][c],"err: " << val-out[r][c]); - - DLIB_CASSERT(area.contains(point(c,r)),""); - } - else - { - DLIB_CASSERT(!area.contains(point(c,r)),""); - } - } - } - } - -// ---------------------------------------------------------------------------------------- - - class image_tester : public tester - { - public: - image_tester ( - ) : - tester ("test_image", - "Runs tests on the image processing objects and functions.") - {} - - void perform_test ( - ) - { - image_test(); - test_integral_image(); - test_integral_image(); - test_integral_image(); - test_integral_image(); - - test_zero_border_pixels(); - - test_filtering(false,1); - test_filtering(true,1); - test_filtering(false,3); - test_filtering(true,3); - test_filtering(false,1); - test_filtering(true,1); - test_filtering(false,3); - test_filtering(true,3); - - test_label_connected_blobs(); - test_label_connected_blobs2(); - test_downsampled_filtering(); - - test_segment_image(); - test_segment_image(); - test_segment_image(); - test_segment_image(); - test_segment_image(); - test_segment_image(); - - test_dng_floats(1); - test_dng_floats(1); - test_dng_floats(1); - test_dng_floats(1e30); - test_dng_floats(1e30); - test_dng_floats(1e30); - - test_dng_float_int(); - - dlib::rand rnd; - for (int i = 0; i < 10; ++i) - { - // the spatial filtering stuff is the same as xcorr_same when the filter - // sizes are odd. - test_filtering2(3,3,rnd); - test_filtering2(5,5,rnd); - test_filtering2(7,7,rnd); - } - - for (int i = 0; i < 100; ++i) - test_filtering_center(rnd); - for (int i = 0; i < 100; ++i) - test_filtering_center(rnd); - for (int i = 0; i < 100; ++i) - test_separable_filtering_center(rnd); - for (int i = 0; i < 100; ++i) - test_separable_filtering_center(rnd); - - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/iosockstream.cpp b/lib/3rdParty/dlib/include/dlib/test/iosockstream.cpp deleted file mode 100644 index c68de7bd..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/iosockstream.cpp +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright (C) 2012 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - - logger dlog("test.iosockstream"); - -// ---------------------------------------------------------------------------------------- - - class serv : public server_iostream - { - virtual void on_connect ( - std::istream& in, - std::ostream& out, - const std::string& , - const std::string& , - unsigned short , - unsigned short , - uint64 - ) - { - try - { - dlog << LINFO << "serv1: serving connection"; - - std::string temp; - in >> temp; - DLIB_TEST(temp == "word"); - in >> temp; - DLIB_TEST(temp == "another"); - out << "yay words "; - in >> temp; - DLIB_TEST(temp == "yep"); - } - catch (error& e) - { - error_string = e.what(); - } - - } - - - public: - std::string error_string; - - }; - - class serv2 : public server_iostream - { - virtual void on_connect ( - std::istream& , - std::ostream& out, - const std::string& , - const std::string& , - unsigned short , - unsigned short , - uint64 - ) - { - try - { - dlog << LINFO << "serv2: serving connection"; - - out << "one two three four five"; - } - catch (error& e) - { - error_string = e.what(); - } - - } - - - public: - std::string error_string; - - }; - -// ---------------------------------------------------------------------------------------- - - void test1() - { - dlog << LINFO << "in test1()"; - serv theserv; - theserv.set_listening_port(12345); - theserv.start_async(); - - // wait a little bit to make sure the server has started listening before we try - // to connect to it. - dlib::sleep(500); - - for (int i = 0; i < 200; ++i) - { - dlog << LINFO << "i: " << i; - print_spinner(); - iosockstream stream("localhost:12345"); - - stream << "word another "; - std::string temp; - stream >> temp; - DLIB_TEST(temp == "yay"); - stream >> temp; - DLIB_TEST(temp == "words"); - stream << "yep "; - } - - // Just to make sure the server finishes processing the last connection before - // we kill it and accidentally trigger a DLIB_TEST(). - dlib::sleep(500); - - if (theserv.error_string.size() != 0) - throw error(theserv.error_string); - } - -// ---------------------------------------------------------------------------------------- - - void test2() - { - dlog << LINFO << "in test2()"; - serv2 theserv; - theserv.set_listening_port(12345); - theserv.start_async(); - - // wait a little bit to make sure the server has started listening before we try - // to connect to it. - dlib::sleep(500); - - for (int i = 0; i < 200; ++i) - { - dlog << LINFO << "i: " << i; - print_spinner(); - iosockstream stream("localhost:12345"); - - std::string temp; - stream >> temp; DLIB_TEST(temp == "one"); - stream >> temp; DLIB_TEST(temp == "two"); - stream >> temp; DLIB_TEST(temp == "three"); - stream >> temp; DLIB_TEST(temp == "four"); - stream >> temp; DLIB_TEST(temp == "five"); - } - } - -// ---------------------------------------------------------------------------------------- - - class test_iosockstream : public tester - { - public: - test_iosockstream ( - ) : - tester ("test_iosockstream", - "Runs tests on the iosockstream component.") - {} - - void perform_test ( - ) - { - test1(); - test2(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/is_same_object.cpp b/lib/3rdParty/dlib/include/dlib/test/is_same_object.cpp deleted file mode 100644 index d915eb95..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/is_same_object.cpp +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (C) 2010 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "tester.h" -#include -#include -#include - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - dlib::logger dlog("test.is_same_object"); - - DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_booya_template, void, template booya, (std::string)const); - DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_booya2_template, void, template booya2, (int)const); - DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_funct_int, void, funct, (int)); - DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_funct_double, void, funct, (double)); - DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_funct_f, float, funct_f, (int)); - - class htest - { - public: - template - void booya(std::string) const {} - - template - void booya2(EXP) const {} - - void funct(double) {} - }; - - class htest2 - { - public: - - void funct(int) {} - - float funct_f(int) { return 0;} - }; - - void test_metaprog() - { - DLIB_TEST(has_booya2_template::value == true) - DLIB_TEST(has_booya2_template::value == false) - -#if _MSC_VER > 1600 // there is a bug in visual studio 2010 and older that prevents this test from working - DLIB_TEST(has_booya_template::value == true) -#endif - - DLIB_TEST(has_booya_template::value == false) - - DLIB_TEST(has_funct_int::value == false) - DLIB_TEST(has_funct_int::value == true) - DLIB_TEST(has_funct_double::value == true) - DLIB_TEST(has_funct_double::value == false) - - DLIB_TEST(has_funct_f::value == false) - DLIB_TEST(has_funct_f::value == true) - } - - class is_same_object_tester : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a unit test. When it is constructed - it adds itself into the testing framework. - !*/ - public: - is_same_object_tester ( - ) : - tester ( - "test_is_same_object", // the command line argument name for this test - "Run tests on the is_same_object function.", // the command line argument description - 0 // the number of command line arguments for this test - ) - { - } - - struct base {}; - struct derived : public base {}; - - template - void go(const base& a, const base& b) - { - DLIB_TEST( is_same_object(a,b) == truth) ; - DLIB_TEST( is_same_object(b,a) == truth) ; - } - - - template - void go2(const base& a, const derived& b) - { - DLIB_TEST( is_same_object(a,b) == truth) ; - DLIB_TEST( is_same_object(b,a) == truth) ; - } - - - void perform_test ( - ) - { - print_spinner(); - - int a, b; - double d; - DLIB_TEST( is_same_object(a,a) == true) ; - DLIB_TEST( is_same_object(a,b) == false) ; - DLIB_TEST( is_same_object(d,b) == false) ; - DLIB_TEST( is_same_object(d,d) == true) ; - - base sb; - derived sd, sd2; - - DLIB_TEST( is_same_object(sb,sd) == false) ; - DLIB_TEST( is_same_object(sd,sb) == false) ; - - go(sd, sd); - go(sd, sd2); - go(sb, sb); - go(sd, sb); - - go2(sd, sd); - go2(sd2, sd); - go2(sd, sd2); - go2(sb, sd); - - test_metaprog(); - } - }; - - // Create an instance of this object. Doing this causes this test - // to be automatically inserted into the testing framework whenever this cpp file - // is linked into the project. Note that since we are inside an unnamed-namespace - // we won't get any linker errors about the symbol a being defined multiple times. - is_same_object_tester a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/kcentroid.cpp b/lib/3rdParty/dlib/include/dlib/test/kcentroid.cpp deleted file mode 100644 index c16ab6ec..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/kcentroid.cpp +++ /dev/null @@ -1,684 +0,0 @@ -// Copyright (C) 2009 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include -#include "../stl_checked.h" -#include "../array.h" -#include "../rand.h" -#include "checkerboard.h" -#include - -#include "tester.h" -#include - - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.kcentroid"); - -// ---------------------------------------------------------------------------------------- - - template - struct unopt_sparse_linear_kernel - { - typedef typename T::value_type::second_type scalar_type; - typedef T sample_type; - typedef default_memory_manager mem_manager_type; - - scalar_type operator() ( - const sample_type& a, - const sample_type& b - ) const - { - return dot(a,b); - } - - bool operator== ( - const unopt_sparse_linear_kernel& - ) const - { - return true; - } - }; - - template - struct unopt_linear_kernel - { - typedef typename T::type scalar_type; - typedef T sample_type; - typedef typename T::mem_manager_type mem_manager_type; - - scalar_type operator() ( - const sample_type& a, - const sample_type& b - ) const - { - return trans(a)*b; - } - - bool operator== ( - const unopt_linear_kernel& - ) const - { - return true; - } - }; - - bool approx_equal(double a, double b) - { - return (std::abs(a-b) < 1000*(std::numeric_limits::epsilon())); - } - - bool approx_equal(double a, double b, double eps) - { - return (std::abs(a-b) < eps); - } - - template - double dist ( - const K& k, - const matrix& a, - const matrix& b - ) - /*! - ensures - - returns the distance between the a and b vectors in the - feature space defined by the given kernel k. - !*/ - { - const double bias = std::sqrt(k.offset); - return std::sqrt(length_squared(a-colm(b,0,4)) + std::pow(b(4)-bias,2.0)); - - } - - template - double dist ( - const K& k, - std::map a, - std::map b - ) - /*! - ensures - - returns the distance between the a and b vectors in the - feature space defined by the given kernel k. - !*/ - { - double temp = 0; - const double bias = std::sqrt(k.offset); - temp += std::pow(a[0]-b[0],2.0); - temp += std::pow(a[1]-b[1],2.0); - temp += std::pow(a[2]-b[2],2.0); - temp += std::pow(a[3]-b[3],2.0); - temp += std::pow(bias-b[4],2.0); - - return std::sqrt(temp); - - } - -// ---------------------------------------------------------------------------------------- - - template - void test_kcentroid_with_linear_kernel( - ) - /*! - requires - - kernel_type::sample_type == a matrix - - kernel_type == a kernel that just computes a dot product - between its inputs. I.e. a linear kernel - ensures - - tests the kcentroid object with the given kernel - !*/ - { - // Here we declare that our samples will be 2 dimensional column vectors. - typedef typename kernel_type::sample_type sample_type; - - kernel_type default_kernel; - kcentroid test(default_kernel,0.001,20); - - sample_type temp, temp2; - - temp = 2,0,0,0,0; - dlog << LDEBUG << test(temp) ; - dlog << LDEBUG << "squared_norm(): " << test.squared_norm() ; - - DLIB_TEST(approx_equal(test(temp), 2)); - DLIB_TEST(approx_equal(test.squared_norm(), 0)); - - // make test store the point(2,0,0,0,0) - test.train(temp, 0, 1); - dlog << LDEBUG << test(temp) ; - dlog << LDEBUG << "squared_norm(): " << test.squared_norm() ; - DLIB_TEST(approx_equal(test(temp), 0)); - DLIB_TEST(approx_equal(test.get_distance_function()(temp), 0)); - DLIB_TEST(approx_equal(test.squared_norm(), 4)); - - temp = 0,2,0,0,0; - dlog << LDEBUG << test(temp) ; - DLIB_TEST(approx_equal(test(temp), std::sqrt(2*2 + 2*2.0))); - DLIB_TEST(approx_equal(test.squared_norm(), 4)); - - // make test store the point(0,2,0,0,0) - test.train(temp, 0, 1); - - dlog << LDEBUG << test(temp) ; - DLIB_TEST(approx_equal(test(temp), 0)); - DLIB_TEST(approx_equal(test.squared_norm(), 4)); - - temp = 2,0,0,0,0; - DLIB_TEST(approx_equal(test(temp), std::sqrt(2*2 + 2*2.0))); - DLIB_TEST(approx_equal(test.squared_norm(), 4)); - - // make test store the point(1,1,0,0,0) - test.train(temp, 0.5, 0.5); - - temp = 0; - DLIB_TEST(approx_equal(test(temp), std::sqrt(2.0))); - DLIB_TEST(approx_equal(test.squared_norm(), 2)); - - // make test store the point(1,1,0,3,0) - temp = 0,0,0,3,0; - temp2 = 1,1,0,3,0; - test.train(temp, 1, 1); - - temp = 0; - DLIB_TEST(approx_equal(test(temp), length(temp2))); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2))); - temp = 1,2,3,4,5; - DLIB_TEST(approx_equal(test(temp), length(temp2-temp))); - DLIB_TEST(approx_equal(test.get_distance_function()(temp), length(temp2-temp))); - - // make test store the point(0,1,0,3,-1) - temp = 1,0,0,0,1; - test.train(temp, 1, -1); - temp2 = 0,1,0,3,-1; - - temp = 0; - DLIB_TEST(approx_equal(test(temp), length(temp2))); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2))); - temp = 1,2,3,4,5; - DLIB_TEST(approx_equal(test(temp), length(temp2-temp))); - - - // make test store the -1*point(0,1,0,3,-1) - temp = 0,0,0,0,0; - test.train(temp, -1, 0); - temp2 = -temp2; - - temp = 0; - DLIB_TEST(approx_equal(test(temp), length(temp2))); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2))); - temp = 1,2,-3,4,5; - DLIB_TEST(approx_equal(test(temp), length(temp2-temp))); - - - - // make test store the point(0,0,0,0,0) - temp = 0,0,0,0,0; - test.train(temp, 0, 0); - temp2 = 0; - - temp = 0; - DLIB_TEST(approx_equal(test(temp), length(temp2))); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2))); - temp = 1,2,-3,4,5; - DLIB_TEST(approx_equal(test(temp), length(temp2-temp))); - - - - // make test store the point(1,0,0,0,0) - temp = 1,0,0,0,0; - test.train(temp, 1, 1); - temp2 = 1,0,0,0,0; - - temp = 0; - DLIB_TEST(approx_equal(test(temp), length(temp2))); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2))); - DLIB_TEST(approx_equal(test.inner_product(test), length_squared(temp2))); - temp = 1,2,-3,4,5; - DLIB_TEST(approx_equal(test(temp), length(temp2-temp))); - DLIB_TEST(approx_equal(test(test), 0)); - DLIB_TEST(approx_equal(test.get_distance_function()(test.get_distance_function()), 0)); - - } - -// ---------------------------------------------------------------------------------------- - - template - void test_kcentroid_with_offset_linear_kernel( - ) - /*! - requires - - kernel_type::sample_type == a matrix - - kernel_type == a kernel that just computes a dot product - between its inputs + some constant. I.e. a linear kernel - wrapped by offset_kernel - ensures - - tests the kcentroid object with the given kernel - !*/ - { - // Here we declare that our samples will be 2 dimensional column vectors. - typedef typename kernel_type::sample_type sample_type; - - kernel_type k; - kcentroid test(k,0.001,20); - - sample_type temp, temp2, temp3; - - matrix val, val2; - - const double b = std::sqrt(k.offset); - - temp = 2,0,0,0; - temp2 = 0; - val = 0; - DLIB_TEST(approx_equal(test(temp), dist(k,temp,val))); - DLIB_TEST(approx_equal(test(temp2), dist(k,temp2,val))); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val))); - - - temp2 = 0; - - // make test store the point(0,0,0,0,b) - val = 0,0,0,0,b; - test.train(temp2, 0,1); - - temp = 2,0,0,0; - dlog << LDEBUG << test(temp) ; - dlog << LDEBUG << "squared_norm(): " << test.squared_norm() ; - - DLIB_TEST(approx_equal(test(temp), dist(k,temp,val))); - DLIB_TEST(approx_equal(test(temp2), dist(k,temp2,val))); - DLIB_TEST_MSG(approx_equal(test.get_distance_function()(temp2), dist(k,temp2,val), 1e-6), - test.get_distance_function()(temp2) - dist(k,temp2,val) << " compare to: " << - test(temp2) - dist(k,temp2,val) - ); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val))); - - - // make test store the point(0,0,0,0,0) - val = 0,0,0,0,0; - test.train(temp2, 1,-1); - DLIB_TEST(approx_equal(test(temp), dist(k,temp,val))); - DLIB_TEST(approx_equal(test(temp2), dist(k,temp2,val))); - DLIB_TEST_MSG(approx_equal(test.get_distance_function()(temp2), dist(k,temp2,val)), - test.get_distance_function()(temp2) - dist(k,temp2,val) << " compare to: " << - test(temp2) - dist(k,temp2,val) - ); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val))); - - - - val2 = 0,1,0,0,b; - val += val2; - temp2 = 0,1,0,0; - // make test store the point val - test.train(temp2, 1,1); - - temp = 1,0,3,0; - DLIB_TEST(approx_equal(test(temp), dist(k,temp,val))); - DLIB_TEST_MSG(approx_equal(test(temp2), dist(k,temp2,val), 1e-7), - test(temp2) - dist(k,temp2,val)); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val))); - DLIB_TEST_MSG(approx_equal(test(test), 0, 1e-7), test(test)); - - - val2 = 0,1,2.6,8,b; - val += val2; - temp2 = 0,1,2.6,8; - // make test store the point val - test.train(temp2, 1,1); - - temp = 1,1,3,0; - DLIB_TEST(approx_equal(test(temp), dist(k,temp,val))); - DLIB_TEST_MSG(approx_equal(test(temp2), dist(k,temp2,val)), test(temp2) - dist(k,temp2,val)); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val))); - DLIB_TEST(approx_equal(test.inner_product(test), length_squared(val))); - DLIB_TEST(approx_equal(test(test), 0)); - DLIB_TEST_MSG(approx_equal(test.get_distance_function()(test.get_distance_function()), 0, 1e-6), - test.get_distance_function()(test.get_distance_function())); - } - -// ---------------------------------------------------------------------------------------- - - template - void test_kcentroid_with_sparse_linear_kernel( - ) - /*! - requires - - kernel_type::sample_type == a std::map - - kernel_type == a kernel that just computes a dot product - between its inputs. I.e. a linear kernel - ensures - - tests the kcentroid object with the given kernel - !*/ - { - // Here we declare that our samples will be 2 dimensional column vectors. - typedef typename kernel_type::sample_type sample_type; - - kernel_type default_kernel; - kcentroid test(default_kernel,0.001,20); - - dlog << LDEBUG << "AAAA 1" ; - - sample_type temp, temp2; - - temp[0] = 2; - dlog << LDEBUG << test(temp) ; - dlog << LDEBUG << "squared_norm(): " << test.squared_norm() ; - - DLIB_TEST(approx_equal(test(temp), 2)); - DLIB_TEST(approx_equal(test.squared_norm(), 0)); - - // make test store the point(2,0,0,0,0) - test.train(temp, 0, 1); - dlog << LDEBUG << test(temp) ; - dlog << LDEBUG << "squared_norm(): " << test.squared_norm() ; - DLIB_TEST(approx_equal(test(temp), 0)); - DLIB_TEST(approx_equal(test.squared_norm(), 4)); - - dlog << LDEBUG << "AAAA 2" ; - temp.clear(); - temp[1] = 2; - dlog << LDEBUG << test(temp) ; - DLIB_TEST(approx_equal(test(temp), std::sqrt(2*2 + 2*2.0))); - DLIB_TEST(approx_equal(test.squared_norm(), 4)); - - // make test store the point(0,2,0,0,0) - test.train(temp, 0, 1); - - dlog << LDEBUG << test(temp) ; - DLIB_TEST(approx_equal(test(temp), 0)); - DLIB_TEST(approx_equal(test.squared_norm(), 4)); - - temp.clear(); - temp[0] = 2; - DLIB_TEST(approx_equal(test(temp), std::sqrt(2*2 + 2*2.0))); - DLIB_TEST(approx_equal(test.squared_norm(), 4)); - - // make test store the point(1,1,0,0,0) - test.train(temp, 0.5, 0.5); - - dlog << LDEBUG << "AAAA 3" ; - temp.clear(); - DLIB_TEST(approx_equal(test(temp), std::sqrt(2.0))); - DLIB_TEST(approx_equal(test.squared_norm(), 2)); - DLIB_TEST(approx_equal(test(test), 0)); - DLIB_TEST(approx_equal(test.get_distance_function()(test.get_distance_function()), 0)); - - dlog << LDEBUG << "AAAA 3.1" ; - // make test store the point(1,1,0,3,0) - temp.clear(); temp[3] = 3; - temp2.clear(); - temp2[0] = 1; - temp2[1] = 1; - temp2[3] = 3; - test.train(temp, 1, 1); - - dlog << LDEBUG << "AAAA 3.2" ; - temp.clear(); - DLIB_TEST(approx_equal(test(temp), length(temp2))); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2))); - dlog << LDEBUG << "AAAA 3.3" ; - temp[0] = 1; - temp[1] = 2; - temp[2] = 3; - temp[3] = 4; - temp[4] = 5; - dlog << LDEBUG << "AAAA 3.4" ; - double junk = dlib::distance(temp2,temp); - dlog << LDEBUG << "AAAA 3.5" ; - DLIB_TEST(approx_equal(test(temp), junk) ); - - dlog << LDEBUG << "AAAA 4" ; - // make test store the point(0,1,0,3,-1) - temp.clear(); - temp[0] = 1; - temp[4] = 1; - test.train(temp, 1, -1); - temp2.clear(); - temp2[1] = 1; - temp2[3] = 3; - temp2[4] = -1; - - temp.clear(); - DLIB_TEST(approx_equal(test(temp), length(temp2))); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2))); - temp[0] = 1; - temp[1] = 2; - temp[2] = 3; - temp[3] = 4; - temp[4] = 5; - DLIB_TEST(approx_equal(test(temp), dlib::distance(temp2,temp))); - - - // make test store the -1*point(0,1,0,3,-1) - temp.clear(); - test.train(temp, -1, 0); - temp2[0] = -temp2[0]; - temp2[1] = -temp2[1]; - temp2[2] = -temp2[2]; - temp2[3] = -temp2[3]; - temp2[4] = -temp2[4]; - - dlog << LDEBUG << "AAAA 5" ; - temp.clear(); - DLIB_TEST(approx_equal(test(temp), length(temp2))); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2))); - temp[0] = 1; - temp[1] = 2; - temp[2] = -3; - temp[3] = 4; - temp[4] = 5; - DLIB_TEST(approx_equal(test(temp), dlib::distance(temp2,temp))); - - - - // make test store the point(0,0,0,0,0) - temp.clear(); - test.train(temp, 0, 0); - temp2.clear(); - - temp.clear(); - DLIB_TEST(approx_equal(test(temp), length(temp2))); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2))); - temp[0] = 1; - temp[1] = 2; - temp[2] = -3; - temp[3] = 4; - temp[4] = 5; - DLIB_TEST(approx_equal(test(temp), dlib::distance(temp2,temp))); - DLIB_TEST(approx_equal(test.get_distance_function()(temp), dlib::distance(temp2,temp))); - - - dlog << LDEBUG << "AAAA 6" ; - - // make test store the point(1,0,0,0,0) - temp.clear(); - temp[0] = 1; - test.train(temp, 1, 1); - temp2.clear(); - temp2[0] = 1; - - temp.clear(); - DLIB_TEST(approx_equal(test(temp), length(temp2))); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(temp2))); - DLIB_TEST(approx_equal(test.inner_product(test), length_squared(temp2))); - temp[0] = 1; - temp[1] = 2; - temp[2] = -3; - temp[3] = 4; - temp[4] = 5; - DLIB_TEST(approx_equal(test(temp), dlib::distance(temp2,temp))); - DLIB_TEST(approx_equal(test.get_distance_function()(temp), dlib::distance(temp2,temp))); - DLIB_TEST(approx_equal(test(test), 0)); - DLIB_TEST(approx_equal(test.get_distance_function()(test.get_distance_function()), 0)); - - dlog << LDEBUG << "AAAA 7" ; - } - -// ---------------------------------------------------------------------------------------- - - template - void test_kcentroid_with_offset_sparse_linear_kernel( - ) - /*! - requires - - kernel_type::sample_type == a std::map - - kernel_type == a kernel that just computes a dot product - between its inputs + some constant. I.e. a linear kernel - wrapped by offset_kernel - ensures - - tests the kcentroid object with the given kernel - !*/ - { - // Here we declare that our samples will be 2 dimensional column vectors. - typedef typename kernel_type::sample_type sample_type; - - kernel_type k; - kcentroid test(k,0.001,20); - - sample_type temp, temp2, temp3; - - std::map val, val2; - - const double b = std::sqrt(k.offset); - - temp.clear(); - temp[0] = 2; - temp2.clear(); - val.clear(); - DLIB_TEST(approx_equal(test(temp), dist(k,temp,val))); - DLIB_TEST(approx_equal(test(temp2), dist(k,temp2,val))); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val))); - - - temp2.clear(); - - // make test store the point(0,0,0,0,b) - val.clear(); - val[4] = b; - test.train(temp2, 0,1); - - temp.clear(); - temp[0] = 2; - dlog << LDEBUG << test(temp) ; - dlog << LDEBUG << "squared_norm(): " << test.squared_norm() ; - - DLIB_TEST(approx_equal(test(temp), dist(k,temp,val))); - DLIB_TEST(approx_equal(test(temp2), dist(k,temp2,val))); - DLIB_TEST_MSG(approx_equal(test.get_distance_function()(temp2), dist(k,temp2,val), 1e-7), - test.get_distance_function()(temp2) - dist(k,temp2,val) - ); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val))); - DLIB_TEST(approx_equal(test(test), 0)); - DLIB_TEST(approx_equal(test.get_distance_function()(test.get_distance_function()), 0, 1e-6)); - - // make test store the point(0,0,0,0,0) - val.clear(); - test.train(temp2, 1,-1); - - temp.clear(); - temp[0] = 2; - dlog << LDEBUG << test(temp) ; - dlog << LDEBUG << "squared_norm(): " << test.squared_norm() ; - - DLIB_TEST_MSG(approx_equal(test(temp), dist(k,temp,val)), test(temp) - dist(k,temp,val)); - DLIB_TEST(approx_equal(test(temp2), dist(k,temp2,val))); - DLIB_TEST(approx_equal(test.get_distance_function()(temp2), dist(k,temp2,val))); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val))); - DLIB_TEST(approx_equal(test(test), 0)); - DLIB_TEST(approx_equal(test.get_distance_function()(test.get_distance_function()), 0)); - - val2.clear(); - val2[0] = 0; - val2[1] = 1; - val2[2] = 0; - val2[3] = 0; - val2[4] = b; - for (unsigned int i = 0; i < 5; ++i) val[i] += val2[i]; - temp2.clear(); - temp2[1] = 1; - // make test store the point val - test.train(temp2, 1,1); - - temp.clear(); - temp[0] = 1; - temp[2] = 3; - DLIB_TEST(approx_equal(test(temp), dist(k,temp,val))); - DLIB_TEST_MSG(approx_equal(test(temp2), dist(k,temp2,val), 1e-7), - test(temp2) - dist(k,temp2,val)); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val))); - - - val2.clear(); - val2[0] = 0; - val2[1] = 1; - val2[2] = 2.6; - val2[3] = 8; - val2[4] = b; - for (unsigned int i = 0; i < 5; ++i) val[i] += val2[i]; - - temp2.clear(); - temp2[0] = 0; - temp2[1] = 1; - temp2[2] = 2.6; - temp2[3] = 8; - // make test store the point val - test.train(temp2, 1,1); - - temp.clear(); - temp[0] = 1; - temp[1] = 1; - temp[2] = 3; - temp[3] = 0; - DLIB_TEST(approx_equal(test(temp), dist(k,temp,val))); - DLIB_TEST_MSG(approx_equal(test(temp2), dist(k,temp2,val)), test(temp2) - dist(k,temp2,val)); - DLIB_TEST(approx_equal(test.squared_norm(), length_squared(val))); - DLIB_TEST(approx_equal(test.inner_product(test), length_squared(val))); - DLIB_TEST_MSG(approx_equal(test(test), 0, 1e-6), test(test)); - DLIB_TEST(approx_equal(test.get_distance_function()(test.get_distance_function()), 0)); - } - -// ---------------------------------------------------------------------------------------- - - class kcentroid_tester : public tester - { - public: - kcentroid_tester ( - ) : - tester ("test_kcentroid", - "Runs tests on the kcentroid components.") - {} - - void perform_test ( - ) - { - // The idea here is to exercize all the various overloads of the kcentroid object. We also want - // to exercize the non-overloaded default version. That is why we have these unopt_* linear - // kernels - test_kcentroid_with_linear_kernel > >(); - test_kcentroid_with_offset_linear_kernel > > >(); - test_kcentroid_with_linear_kernel > >(); - test_kcentroid_with_offset_linear_kernel > > >(); - test_kcentroid_with_sparse_linear_kernel > >(); - test_kcentroid_with_offset_sparse_linear_kernel > > >(); - test_kcentroid_with_sparse_linear_kernel > >(); - test_kcentroid_with_offset_sparse_linear_kernel > > >(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/kernel_matrix.cpp b/lib/3rdParty/dlib/include/dlib/test/kernel_matrix.cpp deleted file mode 100644 index 8fc3a2d2..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/kernel_matrix.cpp +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (C) 2009 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "tester.h" -#include -#include -#include - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - dlib::logger dlog("test.kernel_matrix"); - - - class kernel_matrix_tester : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a unit test. When it is constructed - it adds itself into the testing framework. - !*/ - public: - kernel_matrix_tester ( - ) : - tester ( - "test_kernel_matrix", // the command line argument name for this test - "Run tests on the kernel_matrix functions.", // the command line argument description - 0 // the number of command line arguments for this test - ) - { - } - - - void perform_test ( - ) - { - print_spinner(); - - typedef matrix sample_type; - typedef radial_basis_kernel kernel_type; - kernel_type kern(0.1); - - std::vector vect1; - std::vector vect2; - - const sample_type samp = randm(4,1); - sample_type samp2, samp3; - - vect1.push_back(randm(4,1)); - vect1.push_back(randm(4,1)); - vect1.push_back(randm(4,1)); - vect1.push_back(randm(4,1)); - - vect2.push_back(randm(4,1)); - vect2.push_back(randm(4,1)); - vect2.push_back(randm(4,1)); - vect2.push_back(randm(4,1)); - vect2.push_back(randm(4,1)); - - matrix K; - - K.set_size(vect1.size(), vect2.size()); - for (long r = 0; r < K.nr(); ++r) - { - for (long c = 0; c < K.nc(); ++c) - { - K(r,c) = kern(vect1[r], vect2[c]); - } - } - DLIB_TEST(equal(K, kernel_matrix(kern, vect1, vect2))); - DLIB_TEST(equal(K, kernel_matrix(kern, mat(vect1), mat(vect2)))); - - - K.set_size(vect2.size(), vect1.size()); - for (long r = 0; r < K.nr(); ++r) - { - for (long c = 0; c < K.nc(); ++c) - { - K(r,c) = kern(vect2[r], vect1[c]); - } - } - DLIB_TEST(equal(K, kernel_matrix(kern, vect2, vect1))); - DLIB_TEST(equal(K, tmp(kernel_matrix(kern, vect2, vect1)))); - DLIB_TEST(equal(K, kernel_matrix(kern, mat(vect2), mat(vect1)))); - - - K.set_size(vect1.size(), vect1.size()); - for (long r = 0; r < K.nr(); ++r) - { - for (long c = 0; c < K.nc(); ++c) - { - K(r,c) = kern(vect1[r], vect1[c]); - } - } - DLIB_TEST(equal(K, kernel_matrix(kern, vect1, vect1))); - DLIB_TEST(equal(K, tmp(kernel_matrix(kern, vect1, vect1)))); - DLIB_TEST(equal(K, kernel_matrix(kern, vect1))); - DLIB_TEST(equal(K, tmp(kernel_matrix(kern, vect1)))); - DLIB_TEST(equal(K, kernel_matrix(kern, mat(vect1), mat(vect1)))); - DLIB_TEST(equal(K, tmp(kernel_matrix(kern, mat(vect1), mat(vect1))))); - DLIB_TEST(equal(K, kernel_matrix(kern, mat(vect1)))); - DLIB_TEST(equal(K, tmp(kernel_matrix(kern, mat(vect1))))); - - - K.set_size(vect1.size(),1); - for (long r = 0; r < K.nr(); ++r) - { - for (long c = 0; c < K.nc(); ++c) - { - K(r,c) = kern(vect1[r], samp); - } - } - DLIB_TEST(equal(K, kernel_matrix(kern, vect1, samp))); - DLIB_TEST(equal(K, kernel_matrix(kern, mat(vect1), samp))); - - - K.set_size(1, vect1.size()); - for (long r = 0; r < K.nr(); ++r) - { - for (long c = 0; c < K.nc(); ++c) - { - K(r,c) = kern(samp, vect1[c]); - } - } - DLIB_TEST(equal(K, kernel_matrix(kern, samp, vect1))); - DLIB_TEST(equal(K, kernel_matrix(kern, samp, mat(vect1)))); - DLIB_TEST(equal(K, tmp(kernel_matrix(kern, samp, vect1)))); - DLIB_TEST(equal(K, tmp(kernel_matrix(kern, samp, mat(vect1))))); - - - - samp2 = samp; - samp3 = samp; - - // test the alias detection - samp2 = kernel_matrix(kern, vect1, samp2); - DLIB_TEST(equal(samp2, kernel_matrix(kern, vect1, samp))); - - samp3 = trans(kernel_matrix(kern, samp3, vect2)); - DLIB_TEST(equal(samp3, trans(kernel_matrix(kern, samp, vect2)))); - - - samp2 += kernel_matrix(kern, vect1, samp); - DLIB_TEST(equal(samp2, 2*kernel_matrix(kern, vect1, samp))); - - samp3 += trans(kernel_matrix(kern, samp, vect2)); - DLIB_TEST(equal(samp3, 2*trans(kernel_matrix(kern, samp, vect2)))); - } - }; - - // Create an instance of this object. Doing this causes this test - // to be automatically inserted into the testing framework whenever this cpp file - // is linked into the project. Note that since we are inside an unnamed-namespace - // we won't get any linker errors about the symbol a being defined multiple times. - kernel_matrix_tester a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/kmeans.cpp b/lib/3rdParty/dlib/include/dlib/test/kmeans.cpp deleted file mode 100644 index b015a4fc..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/kmeans.cpp +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.kmeans"); - - dlib::rand rnd; - - template - void run_test( - const std::vector& seed_centers - ) - { - print_spinner(); - - - sample_type samp; - - std::vector samples; - - - for (unsigned long j = 0; j < seed_centers.size(); ++j) - { - for (int i = 0; i < 250; ++i) - { - samp = randm(seed_centers[0].size(),1,rnd) - 0.5; - samples.push_back(samp + seed_centers[j]); - } - } - - randomize_samples(samples); - - std::vector centers; - pick_initial_centers(seed_centers.size(), centers, samples, linear_kernel()); - - find_clusters_using_kmeans(samples, centers); - - DLIB_TEST(centers.size() == seed_centers.size()); - - std::vector hits(centers.size(),0); - for (unsigned long i = 0; i < samples.size(); ++i) - { - unsigned long best_idx = 0; - double best_dist = 1e100; - for (unsigned long j = 0; j < centers.size(); ++j) - { - if (length(samples[i] - centers[j]) < best_dist) - { - best_dist = length(samples[i] - centers[j]); - best_idx = j; - } - } - hits[best_idx]++; - } - - for (unsigned long i = 0; i < hits.size(); ++i) - { - DLIB_TEST(hits[i] == 250); - } - } - - - class test_kmeans : public tester - { - public: - test_kmeans ( - ) : - tester ("test_kmeans", - "Runs tests on the find_clusters_using_kmeans() function.") - {} - - void perform_test ( - ) - { - { - dlog << LINFO << "test dlib::vector"; - typedef dlib::vector sample_type; - std::vector seed_centers; - seed_centers.push_back(sample_type(10,10)); - seed_centers.push_back(sample_type(10,-10)); - seed_centers.push_back(sample_type(-10,10)); - seed_centers.push_back(sample_type(-10,-10)); - - run_test(seed_centers); - } - { - dlog << LINFO << "test dlib::vector"; - typedef dlib::vector sample_type; - std::vector seed_centers; - seed_centers.push_back(sample_type(10,10)); - seed_centers.push_back(sample_type(10,-10)); - seed_centers.push_back(sample_type(-10,10)); - seed_centers.push_back(sample_type(-10,-10)); - - run_test(seed_centers); - } - { - dlog << LINFO << "test dlib::matrix"; - typedef dlib::matrix sample_type; - std::vector seed_centers; - sample_type samp; - samp = 10,10,0; seed_centers.push_back(samp); - samp = -10,10,1; seed_centers.push_back(samp); - samp = -10,-10,2; seed_centers.push_back(samp); - - run_test(seed_centers); - } - - - } - } a; - - - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/learning_to_track.cpp b/lib/3rdParty/dlib/include/dlib/test/learning_to_track.cpp deleted file mode 100644 index 730c01ba..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/learning_to_track.cpp +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright (C) 2014 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include "tester.h" -#include -#include - - - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.learning_to_track"); - -// ---------------------------------------------------------------------------------------- - - struct detection_dense - { - typedef struct track_dense track_type; - matrix measurements; - }; - - - struct track_dense - { - typedef matrix feature_vector_type; - - track_dense() - { - time_since_last_association = 0; - } - - void get_similarity_features(const detection_dense det, feature_vector_type& feats) const - { - feats = abs(last_measurements - det.measurements); - } - - void update_track(const detection_dense det) - { - last_measurements = det.measurements; - time_since_last_association = 0; - } - - void propagate_track() - { - ++time_since_last_association; - } - - matrix last_measurements; - unsigned long time_since_last_association; - }; - -// ---------------------------------------------------------------------------------------- - - struct detection_sparse - { - typedef struct track_sparse track_type; - matrix measurements; - }; - - - struct track_sparse - { - typedef std::vector > feature_vector_type; - - track_sparse() - { - time_since_last_association = 0; - } - - void get_similarity_features(const detection_sparse det, feature_vector_type& feats) const - { - matrix temp = abs(last_measurements - det.measurements); - feats.clear(); - for (long i = 0; i < temp.size(); ++i) - feats.push_back(make_pair(i, temp(i))); - } - - void update_track(const detection_sparse det) - { - last_measurements = det.measurements; - time_since_last_association = 0; - } - - void propagate_track() - { - ++time_since_last_association; - } - - matrix last_measurements; - unsigned long time_since_last_association; - }; - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - dlib::rand rnd; - const long num_objects = 4; - const long num_properties = 6; - std::vector > object_properties(num_objects); - - void initialize_object_properties() - { - rnd.set_seed("23ja2oirfjaf"); - for (unsigned long i = 0; i < object_properties.size(); ++i) - object_properties[i] = randm(num_properties,1,rnd); - } - - template - detection sample_detection_from_sensor(long object_id) - { - DLIB_CASSERT(object_id < num_objects, - "You can't ask to sample a detection from an object that doesn't exist."); - detection temp; - // Set the measurements equal to the object's true property values plus a little bit of - // noise. - temp.measurements = object_properties[object_id] + randm(num_properties,1,rnd)*0.1; - return temp; - } - -// ---------------------------------------------------------------------------------------- - - - template - std::vector > > make_random_tracking_data_for_training() - { - typedef std::vector > detections_at_single_time_step; - typedef std::vector track_history; - - track_history data; - - // At each time step we get a set of detections from the objects in the world. - // Simulate 100 time steps worth of data where there are 3 objects present. - const int num_time_steps = 100; - for (int i = 0; i < num_time_steps; ++i) - { - detections_at_single_time_step dets(3); - // sample a detection from object 0 - dets[0].det = sample_detection_from_sensor(0); - dets[0].label = 0; - - // sample a detection from object 1 - dets[1].det = sample_detection_from_sensor(1); - dets[1].label = 1; - - // sample a detection from object 2 - dets[2].det = sample_detection_from_sensor(2); - dets[2].label = 2; - - randomize_samples(dets, rnd); - data.push_back(dets); - } - - // Now let's imagine object 1 and 2 are gone but a new object, object 3 has arrived. - for (int i = 0; i < num_time_steps; ++i) - { - detections_at_single_time_step dets(2); - // sample a detection from object 0 - dets[0].det = sample_detection_from_sensor(0); - dets[0].label = 0; - - // sample a detection from object 3 - dets[1].det = sample_detection_from_sensor(3); - dets[1].label = 3; - - randomize_samples(dets, rnd); - data.push_back(dets); - } - - return data; - } - -// ---------------------------------------------------------------------------------------- - - template - std::vector make_random_detections(long num_dets) - { - DLIB_CASSERT(num_dets <= num_objects, - "You can't ask for more detections than there are objects in our little simulation."); - - std::vector dets(num_dets); - for (unsigned long i = 0; i < dets.size(); ++i) - { - dets[i] = sample_detection_from_sensor(i); - } - randomize_samples(dets, rnd); - return dets; - } - -// ---------------------------------------------------------------------------------------- - - template - void test_tracking_stuff() - { - print_spinner(); - - - typedef std::vector > detections_at_single_time_step; - typedef std::vector track_history; - std::vector data; - data.push_back(make_random_tracking_data_for_training()); - data.push_back(make_random_tracking_data_for_training()); - data.push_back(make_random_tracking_data_for_training()); - data.push_back(make_random_tracking_data_for_training()); - data.push_back(make_random_tracking_data_for_training()); - - - structural_track_association_trainer trainer; - trainer.set_c(1000); - track_association_function assoc = trainer.train(data); - - double test_val = test_track_association_function(assoc, data); - DLIB_TEST_MSG( test_val == 1, test_val); - test_val = cross_validate_track_association_trainer(trainer, data, 5); - DLIB_TEST_MSG ( test_val == 1, test_val); - - - - typedef typename detection::track_type track; - std::vector tracks; - - std::vector dets = make_random_detections(3); - assoc(tracks, dets); - DLIB_TEST(tracks.size() == 3); - - dets = make_random_detections(3); - assoc(tracks, dets); - DLIB_TEST(tracks.size() == 3); - - dets = make_random_detections(3); - assoc(tracks, dets); - DLIB_TEST(tracks.size() == 3); - - dets = make_random_detections(4); - assoc(tracks, dets); - DLIB_TEST(tracks.size() == 4); - - dets = make_random_detections(3); - assoc(tracks, dets); - DLIB_TEST(tracks.size() == 4); - unsigned long total_miss = 0; - for (unsigned long i = 0; i < tracks.size(); ++i) - total_miss += tracks[i].time_since_last_association; - DLIB_TEST(total_miss == 1); - - dets = make_random_detections(3); - assoc(tracks, dets); - DLIB_TEST(tracks.size() == 4); - total_miss = 0; - unsigned long num_zero = 0; - for (unsigned long i = 0; i < tracks.size(); ++i) - { - total_miss += tracks[i].time_since_last_association; - if (tracks[i].time_since_last_association == 0) - ++num_zero; - } - DLIB_TEST(total_miss == 2); - DLIB_TEST(num_zero == 3); - - - - ostringstream sout; - serialize(assoc, sout); - - istringstream sin(sout.str()); - deserialize(assoc, sin); - DLIB_TEST( test_track_association_function(assoc, data) == 1); - } - - -// ---------------------------------------------------------------------------------------- - - class test_learning_to_track : public tester - { - public: - test_learning_to_track ( - ) : - tester ("test_learning_to_track", - "Runs tests on the assignment learning code.") - {} - - void perform_test ( - ) - { - initialize_object_properties(); - for (int i = 0; i < 3; ++i) - { - dlog << LINFO << "run test_tracking_stuff()"; - test_tracking_stuff(); - dlog << LINFO << "run test_tracking_stuff()"; - test_tracking_stuff(); - } - } - } a; - -// ---------------------------------------------------------------------------------------- - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/least_squares.cpp b/lib/3rdParty/dlib/include/dlib/test/least_squares.cpp deleted file mode 100644 index 068a3c68..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/least_squares.cpp +++ /dev/null @@ -1,450 +0,0 @@ -// Copyright (C) 2010 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include "optimization_test_functions.h" -#include -#include -#include -#include -#include -#include "../rand.h" - -#include "tester.h" - - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - using namespace dlib::test_functions; - - logger dlog("test.least_squares"); - -// ---------------------------------------------------------------------------------------- - - void test_with_chebyquad() - { - print_spinner(); - { - matrix ch; - - ch = chebyquad_start(2); - - solve_least_squares(objective_delta_stop_strategy(1e-13, 80), - chebyquad_residual, - derivative(chebyquad_residual), - range(0,ch.size()-1), - ch); - - dlog << LINFO << "chebyquad 2 obj: " << chebyquad(ch); - dlog << LINFO << "chebyquad 2 der: " << length(chebyquad_derivative(ch)); - dlog << LINFO << "chebyquad 2 error: " << length(ch - chebyquad_solution(2)); - - DLIB_TEST(length(ch - chebyquad_solution(2)) < 1e-5); - - } - { - matrix ch; - - ch = chebyquad_start(2); - - solve_least_squares_lm(objective_delta_stop_strategy(1e-13, 80), - chebyquad_residual, - derivative(chebyquad_residual), - range(0,ch.size()-1), - ch); - - dlog << LINFO << "LM chebyquad 2 obj: " << chebyquad(ch); - dlog << LINFO << "LM chebyquad 2 der: " << length(chebyquad_derivative(ch)); - dlog << LINFO << "LM chebyquad 2 error: " << length(ch - chebyquad_solution(2)); - - DLIB_TEST(length(ch - chebyquad_solution(2)) < 1e-5); - - } - - print_spinner(); - { - matrix ch; - - ch = chebyquad_start(2); - - solve_least_squares(objective_delta_stop_strategy(1e-13, 80), - chebyquad_residual, - derivative(chebyquad_residual), - range(0,ch.size()-1), - ch); - - dlog << LINFO << "chebyquad 2 obj: " << chebyquad(ch); - dlog << LINFO << "chebyquad 2 der: " << length(chebyquad_derivative(ch)); - dlog << LINFO << "chebyquad 2 error: " << length(ch - chebyquad_solution(2)); - - DLIB_TEST(length(ch - chebyquad_solution(2)) < 1e-5); - - } - print_spinner(); - { - matrix ch; - - ch = chebyquad_start(2); - - solve_least_squares_lm(objective_delta_stop_strategy(1e-13, 80), - chebyquad_residual, - derivative(chebyquad_residual), - range(0,ch.size()-1), - ch); - - dlog << LINFO << "LM chebyquad 2 obj: " << chebyquad(ch); - dlog << LINFO << "LM chebyquad 2 der: " << length(chebyquad_derivative(ch)); - dlog << LINFO << "LM chebyquad 2 error: " << length(ch - chebyquad_solution(2)); - - DLIB_TEST(length(ch - chebyquad_solution(2)) < 1e-5); - - } - - print_spinner(); - { - matrix ch; - - ch = chebyquad_start(4); - - solve_least_squares(objective_delta_stop_strategy(1e-13, 80), - chebyquad_residual, - derivative(chebyquad_residual), - range(0,ch.size()-1), - ch); - - dlog << LINFO << "chebyquad 4 obj: " << chebyquad(ch); - dlog << LINFO << "chebyquad 4 der: " << length(chebyquad_derivative(ch)); - dlog << LINFO << "chebyquad 4 error: " << length(ch - chebyquad_solution(4)); - - DLIB_TEST(length(ch - chebyquad_solution(4)) < 1e-5); - - } - print_spinner(); - { - matrix ch; - - ch = chebyquad_start(4); - - solve_least_squares_lm(objective_delta_stop_strategy(1e-13, 80), - chebyquad_residual, - derivative(chebyquad_residual), - range(0,ch.size()-1), - ch); - - dlog << LINFO << "LM chebyquad 4 obj: " << chebyquad(ch); - dlog << LINFO << "LM chebyquad 4 der: " << length(chebyquad_derivative(ch)); - dlog << LINFO << "LM chebyquad 4 error: " << length(ch - chebyquad_solution(4)); - - DLIB_TEST(length(ch - chebyquad_solution(4)) < 1e-5); - - } - - - print_spinner(); - { - matrix ch; - - ch = chebyquad_start(6); - - solve_least_squares(objective_delta_stop_strategy(1e-13, 80), - chebyquad_residual, - derivative(chebyquad_residual), - range(0,ch.size()-1), - ch); - - dlog << LINFO << "chebyquad 6 obj: " << chebyquad(ch); - dlog << LINFO << "chebyquad 6 der: " << length(chebyquad_derivative(ch)); - dlog << LINFO << "chebyquad 6 error: " << length(ch - chebyquad_solution(6)); - - // the ch variable contains a permutation of what is in chebyquad_solution(6). - // Apparently there is more than one minimum?. Just check that the objective - // goes to zero. - DLIB_TEST(chebyquad(ch) < 1e-10); - - } - print_spinner(); - { - matrix ch; - - ch = chebyquad_start(6); - - solve_least_squares_lm(objective_delta_stop_strategy(1e-13, 80), - chebyquad_residual, - derivative(chebyquad_residual), - range(0,ch.size()-1), - ch); - - dlog << LINFO << "LM chebyquad 6 obj: " << chebyquad(ch); - dlog << LINFO << "LM chebyquad 6 der: " << length(chebyquad_derivative(ch)); - dlog << LINFO << "LM chebyquad 6 error: " << length(ch - chebyquad_solution(6)); - - DLIB_TEST(chebyquad(ch) < 1e-10); - - } - - - print_spinner(); - { - matrix ch; - - ch = chebyquad_start(8); - - solve_least_squares(objective_delta_stop_strategy(1e-13, 80), - chebyquad_residual, - derivative(chebyquad_residual), - range(0,ch.size()-1), - ch); - - dlog << LINFO << "chebyquad 8 obj: " << chebyquad(ch); - dlog << LINFO << "chebyquad 8 der: " << length(chebyquad_derivative(ch)); - dlog << LINFO << "chebyquad 8 error: " << length(ch - chebyquad_solution(8)); - - DLIB_TEST(length(ch - chebyquad_solution(8)) < 1e-5); - - } - print_spinner(); - { - matrix ch; - - ch = chebyquad_start(8); - - solve_least_squares_lm(objective_delta_stop_strategy(1e-13, 80), - chebyquad_residual, - derivative(chebyquad_residual), - range(0,ch.size()-1), - ch); - - dlog << LINFO << "LM chebyquad 8 obj: " << chebyquad(ch); - dlog << LINFO << "LM chebyquad 8 der: " << length(chebyquad_derivative(ch)); - dlog << LINFO << "LM chebyquad 8 error: " << length(ch - chebyquad_solution(8)); - - DLIB_TEST(length(ch - chebyquad_solution(8)) < 1e-5); - - } - } - -// ---------------------------------------------------------------------------------------- - - void test_with_brown() - { - print_spinner(); - { - matrix ch; - - ch = brown_start(); - - solve_least_squares(objective_delta_stop_strategy(1e-13, 300), - brown_residual, - derivative(brown_residual), - range(1,20), - ch); - - dlog << LINFO << "brown obj: " << brown(ch); - dlog << LINFO << "brown der: " << length(brown_derivative(ch)); - dlog << LINFO << "brown error: " << length(ch - brown_solution()); - - DLIB_TEST_MSG(length(ch - brown_solution()) < 1e-5,length(ch - brown_solution()) ); - - } - print_spinner(); - { - matrix ch; - - ch = brown_start(); - - solve_least_squares_lm(objective_delta_stop_strategy(1e-13, 80), - brown_residual, - derivative(brown_residual), - range(1,20), - ch); - - dlog << LINFO << "LM brown obj: " << brown(ch); - dlog << LINFO << "LM brown der: " << length(brown_derivative(ch)); - dlog << LINFO << "LM brown error: " << length(ch - brown_solution()); - - DLIB_TEST(length(ch - brown_solution()) < 1e-5); - - } - } - -// ---------------------------------------------------------------------------------------- - -// These functions are declared here because wrapping the real rosen functions in this -// way avoids triggering a bug in visual studio 2005 which prevents this code from compiling. - double rosen_residual_double (int i, const matrix& m) - { return rosen_residual(i,m); } - float rosen_residual_float (int i, const matrix& m) - { return rosen_residual(i,m); } - - matrix rosen_residual_derivative_double (int i, const matrix& m) - { return rosen_residual_derivative(i,m); } - matrix rosen_residual_derivative_float (int i, const matrix& m) - { return rosen_residual_derivative(i,m); } - - double rosen_big_residual_double (int i, const matrix& m) - { return rosen_big_residual(i,m); } - -// ---------------------------------------------------------------------------------------- - - void test_with_rosen() - { - - print_spinner(); - { - matrix ch; - - ch = rosen_start(); - - solve_least_squares(objective_delta_stop_strategy(1e-13, 80), - rosen_residual_double, - rosen_residual_derivative_double, - range(1,20), - ch); - - dlog << LINFO << "rosen obj: " << rosen(ch); - dlog << LINFO << "rosen error: " << length(ch - rosen_solution()); - - DLIB_TEST(length(ch - rosen_solution()) < 1e-5); - - } - print_spinner(); - { - matrix ch; - - ch = rosen_start(); - - solve_least_squares_lm(objective_delta_stop_strategy(1e-13, 80), - rosen_residual_double, - rosen_residual_derivative_double, - range(1,20), - ch); - - dlog << LINFO << "lm rosen obj: " << rosen(ch); - dlog << LINFO << "lm rosen error: " << length(ch - rosen_solution()); - - DLIB_TEST(length(ch - rosen_solution()) < 1e-5); - - } - - - - print_spinner(); - { - matrix ch; - - ch = rosen_start(); - - solve_least_squares(objective_delta_stop_strategy(1e-13, 80), - rosen_residual_double, - derivative(rosen_residual_double), - range(1,20), - ch); - - dlog << LINFO << "rosen obj: " << rosen(ch); - dlog << LINFO << "rosen error: " << length(ch - rosen_solution()); - - DLIB_TEST(length(ch - rosen_solution()) < 1e-5); - - } - print_spinner(); - { - matrix ch; - - ch = rosen_start(); - - solve_least_squares(objective_delta_stop_strategy(1e-13, 80), - rosen_residual_float, - derivative(rosen_residual_float), - range(1,20), - ch); - - dlog << LINFO << "float rosen obj: " << rosen(ch); - dlog << LINFO << "float rosen error: " << length(ch - rosen_solution()); - - DLIB_TEST(length(ch - rosen_solution()) < 1e-5); - - } - print_spinner(); - { - matrix ch; - - ch = rosen_start(); - - solve_least_squares_lm(objective_delta_stop_strategy(1e-13, 80), - rosen_residual_float, - derivative(rosen_residual_float), - range(1,20), - ch); - - dlog << LINFO << "LM float rosen obj: " << rosen(ch); - dlog << LINFO << "LM float rosen error: " << length(ch - rosen_solution()); - - DLIB_TEST(length(ch - rosen_solution()) < 1e-5); - - } - print_spinner(); - { - matrix ch; - - ch = rosen_start(); - - solve_least_squares_lm(objective_delta_stop_strategy(1e-13, 80), - rosen_residual_double, - derivative(rosen_residual_double), - range(1,20), - ch); - - dlog << LINFO << "LM rosen obj: " << rosen(ch); - dlog << LINFO << "LM rosen error: " << length(ch - rosen_solution()); - - DLIB_TEST(length(ch - rosen_solution()) < 1e-5); - - } - print_spinner(); - { - matrix ch; - - ch = rosen_big_start(); - - solve_least_squares(objective_delta_stop_strategy(1e-13, 80), - rosen_big_residual_double, - derivative(rosen_big_residual_double), - range(1,2), - ch); - - dlog << LINFO << "rosen big obj: " << rosen_big(ch); - dlog << LINFO << "rosen big error: " << length(ch - rosen_big_solution()); - - DLIB_TEST(length(ch - rosen_big_solution()) < 1e-5); - - } - } - -// ---------------------------------------------------------------------------------------- - - class optimization_tester : public tester - { - public: - optimization_tester ( - ) : - tester ("test_least_squares", - "Runs tests on the least squares optimization component.") - {} - - void perform_test ( - ) - { - test_with_chebyquad(); - test_with_brown(); - test_with_rosen(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/linear_manifold_regularizer.cpp b/lib/3rdParty/dlib/include/dlib/test/linear_manifold_regularizer.cpp deleted file mode 100644 index e73b1c8d..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/linear_manifold_regularizer.cpp +++ /dev/null @@ -1,408 +0,0 @@ -// Copyright (C) 2010 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "tester.h" -#include -#include -#include -#include -#include -#include -#include -#include - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - dlib::logger dlog("test.linear_manifold_regularizer"); - - template - void test_find_k_nearest_neighbors_lsh( - const samples_type& samples - ) - { - std::vector edges1, edges2; - - find_k_nearest_neighbors(samples, cosine_distance(), 2, edges1); - find_k_nearest_neighbors_lsh(samples, cosine_distance(), hash_type(), 2, 6, edges2, 2); - - std::sort(edges1.begin(), edges1.end(), order_by_index); - std::sort(edges2.begin(), edges2.end(), order_by_index); - - DLIB_TEST_MSG(edges1.size() == edges2.size(), edges1.size() << " " << edges2.size()); - for (unsigned long i = 0; i < edges1.size(); ++i) - { - DLIB_TEST(edges1[i] == edges2[i]); - DLIB_TEST_MSG(std::abs(edges1[i].distance() - edges2[i].distance()) < 1e-7, - edges1[i].distance() - edges2[i].distance()); - } - } - - template - void test_knn_lsh_sparse() - { - dlib::rand rnd; - std::vector > samples; - samples.resize(20); - for (unsigned int i = 0; i < samples.size(); ++i) - { - samples[i][0] = rnd.get_random_gaussian(); - samples[i][2] = rnd.get_random_gaussian(); - } - - test_find_k_nearest_neighbors_lsh(samples); - test_find_k_nearest_neighbors_lsh(samples); - test_find_k_nearest_neighbors_lsh(samples); - test_find_k_nearest_neighbors_lsh(samples); - } - - template - void test_knn_lsh_dense() - { - dlib::rand rnd; - std::vector > samples; - samples.resize(20); - for (unsigned int i = 0; i < samples.size(); ++i) - { - samples[i].set_size(2); - samples[i](0) = rnd.get_random_gaussian(); - samples[i](1) = rnd.get_random_gaussian(); - } - - test_find_k_nearest_neighbors_lsh(samples); - test_find_k_nearest_neighbors_lsh(samples); - test_find_k_nearest_neighbors_lsh(samples); - test_find_k_nearest_neighbors_lsh(samples); - } - - - - class linear_manifold_regularizer_tester : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a unit test. When it is constructed - it adds itself into the testing framework. - !*/ - public: - linear_manifold_regularizer_tester ( - ) : - tester ( - "test_linear_manifold_regularizer", // the command line argument name for this test - "Run tests on the linear_manifold_regularizer object.", // the command line argument description - 0 // the number of command line arguments for this test - ) - { - seed = 1; - } - - dlib::rand rnd; - - unsigned long seed; - - typedef matrix sample_type; - typedef radial_basis_kernel kernel_type; - - void do_the_test() - { - print_spinner(); - std::vector samples; - - // Declare an instance of the kernel we will be using. - const kernel_type kern(0.1); - - const unsigned long num_points = 200; - - // create a large dataset with two concentric circles. - generate_circle(samples, 1, num_points); // circle of radius 1 - generate_circle(samples, 5, num_points); // circle of radius 5 - - std::vector edges; - find_percent_shortest_edges_randomly(samples, squared_euclidean_distance(0.1, 4), 1, 10000, "random seed", edges); - - dlog << LTRACE << "number of edges generated: " << edges.size(); - - empirical_kernel_map ekm; - - ekm.load(kern, randomly_subsample(samples, 100)); - - // Project all the samples into the span of our 50 basis samples - for (unsigned long i = 0; i < samples.size(); ++i) - samples[i] = ekm.project(samples[i]); - - - // Now create the manifold regularizer. The result is a transformation matrix that - // embodies the manifold assumption discussed above. - linear_manifold_regularizer lmr; - lmr.build(samples, edges, use_gaussian_weights(0.1)); - matrix T = lmr.get_transformation_matrix(10000); - - print_spinner(); - - // generate the T matrix manually and make sure it matches. The point of this test - // is to make sure that the more complex version of this that happens inside the linear_manifold_regularizer - // is correct. It uses a tedious block of loops to do it in a way that is a lot faster for sparse - // W matrices but isn't super straight forward. - matrix X(samples[0].size(), samples.size()); - for (unsigned long i = 0; i < samples.size(); ++i) - set_colm(X,i) = samples[i]; - - matrix W(samples.size(), samples.size()); - W = 0; - for (unsigned long i = 0; i < edges.size(); ++i) - { - W(edges[i].index1(), edges[i].index2()) = use_gaussian_weights(0.1)(edges[i]); - W(edges[i].index2(), edges[i].index1()) = use_gaussian_weights(0.1)(edges[i]); - } - matrix L = diagm(sum_rows(W)) - W; - matrix trueT = inv_lower_triangular(chol(identity_matrix(X.nr()) + (10000.0/sum(lowerm(W)))*X*L*trans(X))); - - dlog << LTRACE << "T error: "<< max(abs(T - trueT)); - DLIB_TEST(max(abs(T - trueT)) < 1e-7); - - - print_spinner(); - // Apply the transformation generated by the linear_manifold_regularizer to - // all our samples. - for (unsigned long i = 0; i < samples.size(); ++i) - samples[i] = T*samples[i]; - - - // For convenience, generate a projection_function and merge the transformation - // matrix T into it. - projection_function proj = ekm.get_projection_function(); - proj.weights = T*proj.weights; - - - // Pick 2 different labeled points. One on the inner circle and another on the outer. - // For each of these test points we will see if using the single plane that separates - // them is a good way to separate the concentric circles. Also do this a bunch - // of times with different randomly chosen points so we can see how robust the result is. - for (int itr = 0; itr < 10; ++itr) - { - print_spinner(); - std::vector test_points; - // generate a random point from the radius 1 circle - generate_circle(test_points, 1, 1); - // generate a random point from the radius 5 circle - generate_circle(test_points, 5, 1); - - // project the two test points into kernel space. Recall that this projection_function - // has the manifold regularizer incorporated into it. - const sample_type class1_point = proj(test_points[0]); - const sample_type class2_point = proj(test_points[1]); - - double num_wrong = 0; - - // Now attempt to classify all the data samples according to which point - // they are closest to. The output of this program shows that without manifold - // regularization this test will fail but with it it will perfectly classify - // all the points. - for (unsigned long i = 0; i < samples.size(); ++i) - { - double distance_to_class1 = length(samples[i] - class1_point); - double distance_to_class2 = length(samples[i] - class2_point); - - bool predicted_as_class_1 = (distance_to_class1 < distance_to_class2); - - bool really_is_class_1 = (i < num_points); - - // now count how many times we make a mistake - if (predicted_as_class_1 != really_is_class_1) - ++num_wrong; - } - - DLIB_TEST_MSG(num_wrong == 0, num_wrong); - } - - } - - void generate_circle ( - std::vector& samples, - double radius, - const long num - ) - { - sample_type m(2,1); - - for (long i = 0; i < num; ++i) - { - double sign = 1; - if (rnd.get_random_double() < 0.5) - sign = -1; - m(0) = 2*radius*rnd.get_random_double()-radius; - m(1) = sign*sqrt(radius*radius - m(0)*m(0)); - - samples.push_back(m); - } - } - - - void test_knn1() - { - std::vector > samples; - - matrix test; - - test = 0,0; samples.push_back(test); - test = 1,1; samples.push_back(test); - test = 1,-1; samples.push_back(test); - test = -1,1; samples.push_back(test); - test = -1,-1; samples.push_back(test); - - std::vector edges; - find_k_nearest_neighbors(samples, squared_euclidean_distance(), 1, edges); - DLIB_TEST(edges.size() == 4); - - std::sort(edges.begin(), edges.end(), &order_by_index); - - DLIB_TEST(edges[0] == sample_pair(0,1,0)); - DLIB_TEST(edges[1] == sample_pair(0,2,0)); - DLIB_TEST(edges[2] == sample_pair(0,3,0)); - DLIB_TEST(edges[3] == sample_pair(0,4,0)); - - find_k_nearest_neighbors(samples, squared_euclidean_distance(), 3, edges); - DLIB_TEST(edges.size() == 8); - - find_k_nearest_neighbors(samples, squared_euclidean_distance(3.9, 4.1), 3, edges); - DLIB_TEST(edges.size() == 4); - - std::sort(edges.begin(), edges.end(), &order_by_index); - - DLIB_TEST(edges[0] == sample_pair(1,2,0)); - DLIB_TEST(edges[1] == sample_pair(1,3,0)); - DLIB_TEST(edges[2] == sample_pair(2,4,0)); - DLIB_TEST(edges[3] == sample_pair(3,4,0)); - - find_k_nearest_neighbors(samples, squared_euclidean_distance(30000, 4.1), 3, edges); - DLIB_TEST(edges.size() == 0); - } - - void test_knn1_approx() - { - std::vector > samples; - - matrix test; - - test = 0,0; samples.push_back(test); - test = 1,1; samples.push_back(test); - test = 1,-1; samples.push_back(test); - test = -1,1; samples.push_back(test); - test = -1,-1; samples.push_back(test); - - std::vector edges; - find_approximate_k_nearest_neighbors(samples, squared_euclidean_distance(), 1, 10000, seed, edges); - DLIB_TEST(edges.size() == 4); - - std::sort(edges.begin(), edges.end(), &order_by_index); - - DLIB_TEST(edges[0] == sample_pair(0,1,0)); - DLIB_TEST(edges[1] == sample_pair(0,2,0)); - DLIB_TEST(edges[2] == sample_pair(0,3,0)); - DLIB_TEST(edges[3] == sample_pair(0,4,0)); - - find_approximate_k_nearest_neighbors(samples, squared_euclidean_distance(), 3, 10000, seed, edges); - DLIB_TEST(edges.size() == 8); - - find_approximate_k_nearest_neighbors(samples, squared_euclidean_distance(3.9, 4.1), 3, 10000, seed, edges); - DLIB_TEST(edges.size() == 4); - - std::sort(edges.begin(), edges.end(), &order_by_index); - - DLIB_TEST(edges[0] == sample_pair(1,2,0)); - DLIB_TEST(edges[1] == sample_pair(1,3,0)); - DLIB_TEST(edges[2] == sample_pair(2,4,0)); - DLIB_TEST(edges[3] == sample_pair(3,4,0)); - - find_approximate_k_nearest_neighbors(samples, squared_euclidean_distance(30000, 4.1), 3, 10000, seed, edges); - DLIB_TEST(edges.size() == 0); - } - - void test_knn2() - { - std::vector > samples; - - matrix test; - - test = 1,1; samples.push_back(test); - test = 1,-1; samples.push_back(test); - test = -1,1; samples.push_back(test); - test = -1,-1; samples.push_back(test); - - std::vector edges; - find_k_nearest_neighbors(samples, squared_euclidean_distance(), 2, edges); - DLIB_TEST(edges.size() == 4); - - std::sort(edges.begin(), edges.end(), &order_by_index); - - DLIB_TEST(edges[0] == sample_pair(0,1,0)); - DLIB_TEST(edges[1] == sample_pair(0,2,0)); - DLIB_TEST(edges[2] == sample_pair(1,3,0)); - DLIB_TEST(edges[3] == sample_pair(2,3,0)); - - find_k_nearest_neighbors(samples, squared_euclidean_distance(), 200, edges); - DLIB_TEST(edges.size() == 4*3/2); - } - - void test_knn2_approx() - { - std::vector > samples; - - matrix test; - - test = 1,1; samples.push_back(test); - test = 1,-1; samples.push_back(test); - test = -1,1; samples.push_back(test); - test = -1,-1; samples.push_back(test); - - std::vector edges; - // For this simple graph and high number of samples we will do we should obtain the exact - // knn solution. - find_approximate_k_nearest_neighbors(samples, squared_euclidean_distance(), 2, 10000, seed, edges); - DLIB_TEST(edges.size() == 4); - - std::sort(edges.begin(), edges.end(), &order_by_index); - - DLIB_TEST(edges[0] == sample_pair(0,1,0)); - DLIB_TEST(edges[1] == sample_pair(0,2,0)); - DLIB_TEST(edges[2] == sample_pair(1,3,0)); - DLIB_TEST(edges[3] == sample_pair(2,3,0)); - - - find_approximate_k_nearest_neighbors(samples, squared_euclidean_distance(), 200, 10000, seed, edges); - DLIB_TEST(edges.size() == 4*3/2); - } - - void perform_test ( - ) - { - for (int i = 0; i < 5; ++i) - { - do_the_test(); - - ++seed; - test_knn1_approx(); - test_knn2_approx(); - } - test_knn1(); - test_knn2(); - test_knn_lsh_sparse(); - test_knn_lsh_sparse(); - test_knn_lsh_dense(); - test_knn_lsh_dense(); - - } - }; - - // Create an instance of this object. Doing this causes this test - // to be automatically inserted into the testing framework whenever this cpp file - // is linked into the project. Note that since we are inside an unnamed-namespace - // we won't get any linker errors about the symbol a being defined multiple times. - linear_manifold_regularizer_tester a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/lz77_buffer.cpp b/lib/3rdParty/dlib/include/dlib/test/lz77_buffer.cpp deleted file mode 100644 index ccbb1a24..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/lz77_buffer.cpp +++ /dev/null @@ -1,569 +0,0 @@ -// Copyright (C) 2004 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include - -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace std; - using namespace dlib; - - logger dlog("test.lz77_buffer"); - - template < - typename buf - > - void lz77_buffer_kernel_test ( - ) - /*! - requires - - buf is an implementation of lz77_buffer/lz77_buffer_kernel_abstract.h - ensures - - runs tests on buf for compliance with the specs - !*/ - { - typedef dlib::sliding_buffer::kernel_1a sbuf; - - buf test(8,20); - srand(static_cast(time(0))); - - DLIB_TEST(test.get_lookahead_buffer_size() == 0); - DLIB_TEST(test.get_history_buffer_size() == 0); - DLIB_TEST_MSG(test.get_history_buffer_limit() == 256-20,test.get_history_buffer_limit()); - DLIB_TEST(test.get_lookahead_buffer_limit() == 20); - - - for (int g = 0; g < 2; ++g) - { - test.clear(); - - for (int i = 0; i < 1000; ++i) - { - test.add('a'); - } - DLIB_TEST(test.get_lookahead_buffer_size() == 20); - - - test.shift_buffers(5); - - DLIB_TEST(test.get_lookahead_buffer_size() == 15); - - - - unsigned long index, length, temp; - temp = test.get_lookahead_buffer_size(); - test.find_match(index,length,5); - - - DLIB_TEST_MSG(length <= temp, - "length: " << length << - "\ntemp: " << temp); - DLIB_TEST(test.get_lookahead_buffer_size() <= 15); - - - } - - - for (int g = 0; g < 2; ++g) - { - - - - test.clear(); - - - - DLIB_TEST(test.get_lookahead_buffer_size() == 0); - DLIB_TEST(test.get_history_buffer_size() == 0); - DLIB_TEST(test.get_history_buffer_limit() == 256-20); - DLIB_TEST(test.get_lookahead_buffer_limit() == 20); - - unsigned long a,b, temp = test.get_lookahead_buffer_size(); - test.find_match(a,b,0); - DLIB_TEST(b <= temp); - DLIB_TEST(b == 0); - - test.find_match(a,b,5); - DLIB_TEST(b == 0); - - DLIB_TEST(test.get_lookahead_buffer_size() == 0); - DLIB_TEST(test.get_history_buffer_size() == 0); - DLIB_TEST(test.get_history_buffer_limit() == 256-20); - DLIB_TEST(test.get_lookahead_buffer_limit() == 20); - - - - ostringstream sout; - sout << "DLIB_TEST_MSG(test.get_lookahead_buffer_size() == 0,);\n"; - sout << "DLIB_TEST_MSG(test.get_history_buffer_size() == 0,);\n"; - sout << "DLIB_TEST_MSG(test.get_history_buffer_limit() == 256-20,);\n"; - sout << "DLIB_TEST_MSG(test.get_lookahead_buffer_limit() == 20,);\n"; - sout << "DLIB_TEST_MSG(test.get_lookahead_buffer_size() == 0,);\n"; - sout << "DLIB_TEST_MSG(test.get_history_buffer_size() == 0,);\n"; - sout << "DLIB_TEST_MSG(test.get_history_buffer_limit() == 256-20,);\n"; - sout << "DLIB_TEST_MSG(test.get_lookahead_buffer_limit() == 20,);\n"; - istringstream sin(sout.str()); - - sout.str(""); - sout.clear(); - - unsigned char ch; - sbuf sbuffer; - sbuffer.set_size(8); - - - ch = sin.get(); - sbuffer[0] = ch; sbuffer.rotate_left(1); - test.add(ch); - DLIB_TEST(test.lookahead_buffer(test.get_lookahead_buffer_size()-1) == ch); - DLIB_TEST(test.get_lookahead_buffer_size() == 1); - DLIB_TEST(test.get_history_buffer_size() == 0); - DLIB_TEST(test.get_lookahead_buffer_limit() == 20); - - - - ch = sin.get(); - sbuffer[0] = ch; sbuffer.rotate_left(1); - test.add(ch); - DLIB_TEST(test.lookahead_buffer(test.get_lookahead_buffer_size()-1) == ch); - DLIB_TEST(test.get_lookahead_buffer_size() == 2); - DLIB_TEST(test.get_history_buffer_size() == 0); - DLIB_TEST(test.get_lookahead_buffer_limit() == 20); - - - - ch = sin.get(); - sbuffer[0] = ch; sbuffer.rotate_left(1); - test.add(ch); - DLIB_TEST(test.lookahead_buffer(test.get_lookahead_buffer_size()-1) == ch); - DLIB_TEST(test.get_lookahead_buffer_size() == 3); - DLIB_TEST(test.get_history_buffer_size() == 0); - - // add 17 chars to test so that the lookahead buffer will be full - for (int i = 0; i < 17; ++i) - { - ch = sin.get(); - sbuffer[0] = ch; sbuffer.rotate_left(1); - test.add(ch); - DLIB_TEST(test.lookahead_buffer(test.get_lookahead_buffer_size()-1) == ch); - } - - DLIB_TEST(test.get_lookahead_buffer_size() == 20); - DLIB_TEST(test.get_history_buffer_size() == 0); - DLIB_TEST(test.lookahead_buffer(0) == sbuffer[20]); - - - ch = sin.get(); - sbuffer[0] = ch; sbuffer.rotate_left(1); - test.add(ch); - DLIB_TEST(test.lookahead_buffer(test.get_lookahead_buffer_size()-1) == ch); - DLIB_TEST(test.get_lookahead_buffer_size() == 20); - DLIB_TEST(test.get_history_buffer_size() == 1); - - - - - - - // add the above text to test and make sure it gives the correct results - ch = sin.get(); - while (sin) - { - sbuffer[0] = ch; sbuffer.rotate_left(1); - test.add(ch); - DLIB_TEST(test.lookahead_buffer(test.get_lookahead_buffer_size()-1) == ch); - DLIB_TEST(test.history_buffer(0) == sbuffer[21]); - DLIB_TEST(test.history_buffer(1) == sbuffer[22]); - - ch = sin.get(); - } - - - - // make sure the contents of lookahead_buffer and history_buffer - // match what is in sbuffer - sbuffer.rotate_right(1); - for (unsigned int i = 0; i < test.get_history_buffer_size(); ++i) - { - DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()+i] == test.history_buffer(i)); - } - for (unsigned int i = 0; i < test.get_lookahead_buffer_size(); ++i) - { - DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()-1-i] == test.lookahead_buffer(i)); - } - sbuffer.rotate_left(1); - - - - - - - - - - - sbuffer.rotate_right(1); // do this because we never put anything in sbuffer[0] - - unsigned long match_index, match_length; - unsigned long ltemp = test.get_lookahead_buffer_size(); - test.find_match(match_index,match_length,0); - DLIB_TEST(match_length <= ltemp); - - - // verify the match with sbuffer - for (unsigned int i = 0; i < match_length; ++i) - { - DLIB_TEST_MSG(sbuffer[19-i] == sbuffer[match_index+20-i],i); - } - - - sin.str(""); - sin.clear(); - - } // for (int g = 0; g < 2; ++g) - - - for (int g = 0; g < 8; ++g) - { - test.clear(); - - - DLIB_TEST(test.get_lookahead_buffer_size() == 0); - DLIB_TEST(test.get_history_buffer_size() == 0); - DLIB_TEST(test.get_history_buffer_limit() == 256-20); - DLIB_TEST(test.get_lookahead_buffer_limit() == 20); - - - sbuf sbuffer; - sbuffer.set_size(8); - - ostringstream sout; - sout << "DLIB_TEST_MSG(test.get_lookahead_buffer_size() == 0,);\n"; - sout << "DLIB_TEST_MSG(test.get_history_buffer_size() == 0,);\n"; - sout << "DLIB_TEST_MSG(test.get_history_buffer_limit() == 256-20,);\n"; - sout << "DLIB_TEST_MSG(test.get_lookahead_buffer_limit() == 20,);\n"; - sout << "DLIB_TEST_MSG(test.get_lookahead_buffer_size() == 0,);\n"; - sout << "DLIB_TEST_MSG(test.get_history_buffer_limit() == 256-20,);\n"; - sout << "DLIB_TEST_MSG(test.get_lookahead_buffer_limit() == 20,);\n"; - sout << "DLIB_TEST_MSG(test.get_history_buffer_limit() == 256-20,);\n"; - sout << "DLIB_TEST_MSG(test.get_lookahead_buffer_size() == 0,);\n"; - sout << "DLIB_TEST_MSG(test.get_history_buffer_limit() == 256-20,);\n"; - sout << "DLIB_TEST_MSG(test.get_history_buffer_limit() == 256-20,);\n"; - istringstream sin(sout.str()); - - unsigned char ch; - for (int i = 0; i < 100; ++i) - { - ch = sin.get(); - sbuffer[0] = ch; sbuffer.rotate_left(1); - test.add(ch); - } - - // make sure the contents of lookahead_buffer and history_buffer - // match what is in sbuffer - sbuffer.rotate_right(1); - for (unsigned int i = 0; i < test.get_history_buffer_size(); ++i) - { - DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()+i] == test.history_buffer(i)); - } - for (unsigned int i = 0; i < test.get_lookahead_buffer_size(); ++i) - { - DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()-1-i] == test.lookahead_buffer(i)); - } - sbuffer.rotate_left(1); - - - - - unsigned long match_index, match_length; - unsigned long ltemp = test.get_lookahead_buffer_size(); - test.find_match(match_index,match_length,0); - DLIB_TEST(match_length <= ltemp); - - DLIB_TEST(test.get_lookahead_buffer_size() == 20-match_length); - - sbuffer.rotate_right(1); // do this because we never put anything in sbuffer[0] - // verify the match with sbuffer - for (unsigned int i = 0; i < match_length; ++i) - { - DLIB_TEST(sbuffer[i+20-match_length] == sbuffer[i+1+match_index+20-match_length]); - } - sbuffer.rotate_left(1); // free up sbuffer[0] for new data - - - - - for (int i = 0; i < 7+g*2; ++i) - { - ch = sin.get(); - sbuffer[0] = ch; sbuffer.rotate_left(1); - test.add(ch); - } - - ch = '?'; - sbuffer[0] = ch; sbuffer.rotate_left(1); - test.add(ch); - ch = 'a'; - sbuffer[0] = ch; sbuffer.rotate_left(1); - test.add(ch); - ch = 'v'; - sbuffer[0] = ch; sbuffer.rotate_left(1); - test.add(ch); - ch = 'i'; - sbuffer[0] = ch; sbuffer.rotate_left(1); - test.add(ch); - ch = 's'; - sbuffer[0] = ch; sbuffer.rotate_left(1); - test.add(ch); - - - // adjust sbuffer due to the last call to test.find_match() - // but only if we haven't already added enough (20 or more) chars - // to fill the lookahead buffer already. - if (match_length > static_cast(12+g*2)) - sbuffer.rotate_left(match_length-(12+g*2)); - - - - - - // make sure the contents of lookahead_buffer and history_buffer - // match what is in sbuffer - sbuffer.rotate_right(1); - for (unsigned int i = 0; i < test.get_history_buffer_size(); ++i) - { - DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()+i] == test.history_buffer(i)); - } - for (unsigned int i = 0; i < test.get_lookahead_buffer_size(); ++i) - { - DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()-1-i] == test.lookahead_buffer(i)); - } - sbuffer.rotate_left(1); - - - - - test.find_match(match_index,match_length,10+g); - - if (match_length > 0) - DLIB_TEST(match_length >= static_cast(10+g) ); - - - sbuffer.rotate_right(1); // do this because we never put anything in sbuffer[0] - // verify the match with sbuffer - for (unsigned int i = 0; i < match_length; ++i) - { - DLIB_TEST(sbuffer[i+20-match_length] == sbuffer[i+1+match_index+20-match_length]); - } - sbuffer.rotate_left(1); // free up sbuffer[0] for new data - - } // for (int g = 0; g < 8; ++g) - - - - - - - - srand(static_cast(time(0))); - - for (int g = 0; g < 200; ++g) - { - test.clear(); - - DLIB_TEST(test.get_lookahead_buffer_size() == 0); - DLIB_TEST(test.get_history_buffer_size() == 0); - DLIB_TEST(test.get_history_buffer_limit() == 256-20); - DLIB_TEST(test.get_lookahead_buffer_limit() == 20); - - - sbuf sbuffer; - sbuffer.set_size(8); - - ostringstream sout; - int l = ::rand()%500; - for (int i = 0; i < l; ++i) - { - char temp = static_cast(::rand()%256); - sout << temp; - } - istringstream sin(sout.str()); - - unsigned char ch; - for (int i = 0; i < l; ++i) - { - ch = sin.get(); - sbuffer[0] = ch; sbuffer.rotate_left(1); - test.add(ch); - } - - // make sure the contents of lookahead_buffer and history_buffer - // match what is in sbuffer - sbuffer.rotate_right(1); - - // adjust so that sbuffer[19] is the same as lookahead_buffer[0] - if (test.get_lookahead_buffer_size() < 20) - sbuffer.rotate_left(20-test.get_lookahead_buffer_size()); - - for (unsigned int i = 0; i < test.get_history_buffer_size(); ++i) - { - DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()+i] == test.history_buffer(i)); - } - for (unsigned int i = 0; i < test.get_lookahead_buffer_size(); ++i) - { - DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()-1-i] == test.lookahead_buffer(i)); - } - sbuffer.rotate_left(1); - - - - unsigned long match_index, match_length; - unsigned long lookahead_size_before = test.get_lookahead_buffer_size(); - test.find_match(match_index,match_length,0); - DLIB_TEST(match_length <= lookahead_size_before); - - - DLIB_TEST(test.get_lookahead_buffer_size() == lookahead_size_before-match_length); - - sbuffer.rotate_right(1); // do this because we never put anything in sbuffer[0] - // verify the match with sbuffer - for (unsigned int i = 0; i < match_length; ++i) - { - DLIB_TEST_MSG(sbuffer[19-i] == sbuffer[match_index+20-i],i); - } - sbuffer.rotate_left(1); // free up sbuffer[0] for new data - - } // for (int g = 0; g < 200; ++g) - - - - - - - - - srand(static_cast(time(0))); - - for (int g = 0; g < 300; ++g) - { - test.clear(); - - DLIB_TEST(test.get_lookahead_buffer_size() == 0); - DLIB_TEST(test.get_history_buffer_size() == 0); - DLIB_TEST(test.get_history_buffer_limit() == 256-20); - DLIB_TEST(test.get_lookahead_buffer_limit() == 20); - - - sbuf sbuffer; - sbuffer.set_size(8); - - ostringstream sout; - int l = ::rand()%500; - for (int i = 0; i < l; ++i) - { - char temp = static_cast(::rand()%20); - sout << temp; - sout << temp; - sout << temp; - sout << temp; - sout << temp; - sout << temp; - } - istringstream sin(sout.str()); - - unsigned char ch; - for (int i = 0; i < l; ++i) - { - ch = sin.get(); - sbuffer[0] = ch; sbuffer.rotate_left(1); - test.add(ch); - } - - // make sure the contents of lookahead_buffer and history_buffer - // match what is in sbuffer - sbuffer.rotate_right(1); - - // adjust so that sbuffer[19] is the same as lookahead_buffer[0] - if (test.get_lookahead_buffer_size() < 20) - sbuffer.rotate_left(20-test.get_lookahead_buffer_size()); - - for (unsigned int i = 0; i < test.get_history_buffer_size(); ++i) - { - DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()+i] == test.history_buffer(i)); - } - for (unsigned int i = 0; i < test.get_lookahead_buffer_size(); ++i) - { - DLIB_TEST(sbuffer[test.get_lookahead_buffer_limit()-1-i] == test.lookahead_buffer(i)); - } - sbuffer.rotate_left(1); - - - - unsigned long match_index = 0, match_length = 0; - unsigned long lookahead_size_before = test.get_lookahead_buffer_size(); - unsigned long history_size_before = test.get_history_buffer_size(); - test.find_match(match_index,match_length,2); - - if (match_length != 0) - { - DLIB_TEST_MSG(match_index < history_size_before, - "match_index: " << match_index << - "\nhistory_size_before: " << history_size_before); - - } - - - DLIB_TEST(test.get_lookahead_buffer_size() == lookahead_size_before-match_length); - - sbuffer.rotate_right(1); // do this because we never put anything in sbuffer[0] - // verify the match with sbuffer - for (unsigned int i = 0; i < match_length; ++i) - { - DLIB_TEST_MSG(sbuffer[19-i] == sbuffer[match_index+20-i],i); - } - sbuffer.rotate_left(1); // free up sbuffer[0] for new data - - - - } // for (int g = 0; g < 300; ++g) - - } - - - - - class lz77_buffer_tester : public tester - { - public: - lz77_buffer_tester ( - ) : - tester ("test_lz77_buffer", - "Runs tests on the lz77_buffer component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a"; - lz77_buffer_kernel_test (); - dlog << LINFO << "testing kernel_1a_c"; - lz77_buffer_kernel_test(); - dlog << LINFO << "testing kernel_2a"; - lz77_buffer_kernel_test (); - dlog << LINFO << "testing kernel_2a_c"; - lz77_buffer_kernel_test(); - } - } a; - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/main.cpp b/lib/3rdParty/dlib/include/dlib/test/main.cpp deleted file mode 100644 index 4800a721..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/main.cpp +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include "tester.h" -#include - - -using namespace std; -using namespace dlib; -using namespace test; - -typedef cmd_line_parser::check_1a_c clp; - -static logger dlog("test.main"); - -int main (int argc, char** argv) -{ - try - { - clp parser; - - parser.add_option("runall","Run all the tests that don't take any arguments."); - parser.add_option("h","Displays this information."); - parser.add_option("n","How many times to run the selected tests. The default is 1.",1); - parser.add_option("d","log debugging statements to file debug.txt."); - parser.add_option("l","Set the logging level (all, trace, debug, info, warn, error, or fatal), the default is all.",1); - parser.add_option("a","Append debugging messages to debug.txt rather than clearing the file at program startup."); - parser.add_option("q","Be quiet. Don't print the testing progress or results to standard out."); - - unsigned long num = 1; - - // add the options for all the different tests - testers().reset(); - while (testers().move_next()) - { - tester& test = *testers().element().value(); - parser.add_option(test.cmd_line_switch(), test.description(), test.num_of_args()); - } - - parser.parse(argc,argv); - - parser.check_option_arg_range("n",1,1000000000); - const char* singles[] = {"d","l","a","n","h","runall","q"}; - parser.check_one_time_options(singles); - const char* d_sub[] = {"l","a"}; - const char* l_args[] = {"all", "trace", "debug", "info", "warn", "error", "fatal"}; - parser.check_sub_options("d",d_sub); - parser.check_option_arg_range("l",l_args); - - - if (parser.option("n")) - { - num = string_cast(parser.option("n").argument()); - } - - if (parser.option("q")) - { - be_verbose = false; - } - - if (parser.option("h")) - { - cout << "Usage: test [options]\n"; - parser.print_options(cout); - cout << "\n\n"; - return 0; - } - - ofstream fout; - if (parser.option("d")) - { - if (parser.option("a")) - fout.open("debug.txt",ios::app); - else - fout.open("debug.txt"); - - set_all_logging_output_streams(fout); - - if (parser.option("l").count() == 0) - set_all_logging_levels(LALL); - else if (parser.option("l").argument() == "all") - set_all_logging_levels(LALL); - else if (parser.option("l").argument() == "trace") - set_all_logging_levels(LTRACE); - else if (parser.option("l").argument() == "debug") - set_all_logging_levels(LDEBUG); - else if (parser.option("l").argument() == "info") - set_all_logging_levels(LINFO); - else if (parser.option("l").argument() == "warn") - set_all_logging_levels(LWARN); - else if (parser.option("l").argument() == "error") - set_all_logging_levels(LERROR); - else if (parser.option("l").argument() == "fatal") - set_all_logging_levels(LFATAL); - } - else - { - set_all_logging_levels(LNONE); - } - - unsigned long num_of_failed_tests = 0; - unsigned long num_of_passed_tests = 0; - for (unsigned long i = 0; i < num; ++i) - { - dlog << LINFO << "************ Starting Test Run " << i+1 << " of " << num << ". ************"; - - // loop over all the testers and see if they are supposed to run - testers().reset(); - while (testers().move_next()) - { - tester& test= *testers().element().value(); - const clp::option_type& opt = parser.option(test.cmd_line_switch()); - // run the test for this option as many times as the user has requested. - for (unsigned long j = 0; j < parser.option("runall").count() + opt.count(); ++j) - { - // quit this loop if this option has arguments and this round through the loop is - // from the runall option being present. - if (test.num_of_args() > 0 && j == opt.count()) - break; - - if (be_verbose) - cout << "Running " << test.cmd_line_switch() << " " << flush; - - dlog << LINFO << "Running " << test.cmd_line_switch(); - try - { - switch (test.num_of_args()) - { - case 0: - test.perform_test(); - break; - case 1: - test.perform_test(opt.argument(0,j)); - break; - case 2: - test.perform_test(opt.argument(0,j), opt.argument(1,j)); - break; - default: - cerr << "\n\nThe test '" << test.cmd_line_switch() << "' requested " << test.num_of_args() - << " arguments but only 2 are supported." << endl; - dlog << LINFO << "The test '" << test.cmd_line_switch() << "' requested " << test.num_of_args() - << " arguments but only 2 are supported."; - break; - } - if (be_verbose) - cout << "\r \r"; - - ++num_of_passed_tests; - - } - catch (std::exception& e) - { - if (be_verbose) - { - cout << "\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"; - cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TEST FAILED: " << test.cmd_line_switch() - << " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; - cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n"; - cout << "Failure message from test: " << e.what() << endl; - } - - - dlog << LERROR << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; - dlog << LERROR << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TEST FAILED: " << test.cmd_line_switch() - << " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; - dlog << LERROR << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; - dlog << LERROR << "Failure message from test: " << e.what(); - ++num_of_failed_tests; - } - } - } - } - dlog << LINFO << "Testing Finished"; - if (num_of_passed_tests == 0 && num_of_failed_tests == 0) - { - cout << "You didn't select any tests to run.\n"; - cout << "Try the -h option for more information.\n"; - } - else if (num_of_failed_tests == 0) - { - if (be_verbose) - { - cout << "\n\nTesting Finished\n"; - cout << "Total number of individual testing statements executed: "<< number_of_testing_statements_executed() << endl; - cout << "All tests completed successfully\n\n"; - } - dlog << LINFO << "Total number of individual testing statements executed: "<< number_of_testing_statements_executed(); - dlog << LINFO << "All tests completed successfully"; - } - else - { - if (be_verbose) - { - cout << "\n\nTesting Finished\n"; - cout << "Total number of individual testing statements executed: "<< number_of_testing_statements_executed() << endl; - cout << "Number of failed tests: " << num_of_failed_tests << "\n"; - cout << "Number of passed tests: " << num_of_passed_tests << "\n\n"; - } - dlog << LINFO << "Total number of individual testing statements executed: "<< number_of_testing_statements_executed(); - dlog << LWARN << "Number of failed tests: " << num_of_failed_tests; - dlog << LWARN << "Number of passed tests: " << num_of_passed_tests; - } - - return num_of_failed_tests; - } - catch (exception& e) - { - cout << e.what() << endl; - cout << "\nTry the -h option for more information.\n"; - cout << endl; - } -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/makefile b/lib/3rdParty/dlib/include/dlib/test/makefile deleted file mode 100644 index e01e83d7..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/makefile +++ /dev/null @@ -1,187 +0,0 @@ -# This is the makefile used to build the dlib C++ library's regression test suite -# on Debian Linux using the gcc compiler. - -# this is the name of the output executable -TARGET = dtest - -# these are the compile time flags passed to gcc -CFLAGS = -ggdb -DDEBUG -DDLIB_NO_GUI_SUPPORT -I ../.. -Wall - -# These are the link time flags passed to gcc -LFLAGS = -lpthread -lnsl - -# The name of the compiler. If you only have one version of -# gcc installed then you probably want to change this to just g++ -CC = nice g++ - -#################################################### -#################################################### -# Here we list all the cpp files we want to compile - -SRC = main.cpp -SRC += tester.cpp -SRC += ../all/source.cpp - -SRC += example.cpp -SRC += example_args.cpp - -SRC += active_learning.cpp -SRC += any.cpp -SRC += any_function.cpp -SRC += array2d.cpp -SRC += array.cpp -SRC += assignment_learning.cpp -SRC += base64.cpp -SRC += bayes_nets.cpp -SRC += bigint.cpp -SRC += binary_search_tree_kernel_1a.cpp -SRC += binary_search_tree_kernel_2a.cpp -SRC += binary_search_tree_mm1.cpp -SRC += binary_search_tree_mm2.cpp -SRC += bridge.cpp -SRC += bsp.cpp -SRC += byte_orderer.cpp -SRC += cca.cpp -SRC += clustering.cpp -SRC += cmd_line_parser.cpp -SRC += cmd_line_parser_wchar_t.cpp -SRC += compress_stream.cpp -SRC += conditioning_class_c.cpp -SRC += conditioning_class.cpp -SRC += config_reader.cpp -SRC += crc32.cpp -SRC += create_iris_datafile.cpp -SRC += data_io.cpp -SRC += directed_graph.cpp -SRC += discriminant_pca.cpp -SRC += disjoint_subsets.cpp -SRC += ekm_and_lisf.cpp -SRC += empirical_kernel_map.cpp -SRC += entropy_coder.cpp -SRC += entropy_encoder_model.cpp -SRC += face.cpp -SRC += fft.cpp -SRC += fhog.cpp -SRC += filtering.cpp -SRC += find_max_factor_graph_nmplp.cpp -SRC += find_max_factor_graph_viterbi.cpp -SRC += geometry.cpp -SRC += graph.cpp -SRC += graph_cuts.cpp -SRC += graph_labeler.cpp -SRC += hash.cpp -SRC += hash_map.cpp -SRC += hash_set.cpp -SRC += hash_table.cpp -SRC += hog_image.cpp -SRC += image.cpp -SRC += iosockstream.cpp -SRC += is_same_object.cpp -SRC += kcentroid.cpp -SRC += kernel_matrix.cpp -SRC += kmeans.cpp -SRC += learning_to_track.cpp -SRC += least_squares.cpp -SRC += linear_manifold_regularizer.cpp -SRC += lz77_buffer.cpp -SRC += map.cpp -SRC += matrix2.cpp -SRC += matrix3.cpp -SRC += matrix4.cpp -SRC += matrix_chol.cpp -SRC += matrix.cpp -SRC += matrix_eig.cpp -SRC += matrix_lu.cpp -SRC += matrix_qr.cpp -SRC += max_cost_assignment.cpp -SRC += max_sum_submatrix.cpp -SRC += md5.cpp -SRC += member_function_pointer.cpp -SRC += metaprogramming.cpp -SRC += multithreaded_object.cpp -SRC += numerical_integration.cpp -SRC += object_detector.cpp -SRC += oca.cpp -SRC += one_vs_all_trainer.cpp -SRC += one_vs_one_trainer.cpp -SRC += optimization.cpp -SRC += optimization_test_functions.cpp -SRC += opt_qp_solver.cpp -SRC += parallel_for.cpp -SRC += parse.cpp -SRC += pipe.cpp -SRC += pixel.cpp -SRC += probabilistic.cpp -SRC += pyramid_down.cpp -SRC += queue.cpp -SRC += rand.cpp -SRC += ranking.cpp -SRC += read_write_mutex.cpp -SRC += reference_counter.cpp -SRC += rls.cpp -SRC += sammon.cpp -SRC += scan_image.cpp -SRC += sequence.cpp -SRC += sequence_labeler.cpp -SRC += sequence_segmenter.cpp -SRC += serialize.cpp -SRC += set.cpp -SRC += sldf.cpp -SRC += sliding_buffer.cpp -SRC += smart_pointers.cpp -SRC += sockets2.cpp -SRC += sockets.cpp -SRC += sockstreambuf.cpp -SRC += sparse_vector.cpp -SRC += stack.cpp -SRC += static_map.cpp -SRC += static_set.cpp -SRC += statistics.cpp -SRC += std_vector_c.cpp -SRC += string.cpp -SRC += svm_c_linear.cpp -SRC += svm_c_linear_dcd.cpp -SRC += svm.cpp -SRC += svm_multiclass_linear.cpp -SRC += svm_struct.cpp -SRC += svr_linear_trainer.cpp -SRC += symmetric_matrix_cache.cpp -SRC += thread_pool.cpp -SRC += threads.cpp -SRC += timer.cpp -SRC += tokenizer.cpp -SRC += trust_region.cpp -SRC += tuple.cpp -SRC += type_safe_union.cpp -SRC += vectorstream.cpp - - -#################################################### - -TMP = $(SRC:.cpp=.o) -OBJ = $(TMP:.c=.o) - -$(TARGET): $(OBJ) - @echo Linking $@ - @$(CC) $(OBJ) $(LFLAGS) -o $@ - @echo Build Complete - -.cpp.o: $< - @echo Compiling $< - @$(CC) -c $(CFLAGS) $< -o $@ - -clean: - @rm -f $(OBJ) $(TARGET) - @echo All object files and binaries removed - -dep: - @echo Running makedepend - @makedepend -- $(CFLAGS) -- $(SRC) 2> /dev/null - @echo Completed makedepend - -############################################################################### -########## Stuff from makedepend ##### -########## type make dep at the command line to rebuild the dependencies ##### -########## Also, DON'T edit the contents of this file beyond this line. ##### -############################################################################### - diff --git a/lib/3rdParty/dlib/include/dlib/test/map.cpp b/lib/3rdParty/dlib/include/dlib/test/map.cpp deleted file mode 100644 index 6901ddf0..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/map.cpp +++ /dev/null @@ -1,441 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include - -#include -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace std; - using namespace dlib; - - logger dlog("test.map"); - - template < - typename map - > - void map_kernel_test ( - ) - /*! - requires - - map is an implementation of map/map_kernel_abstract.h and - is instantiated to map int to int - ensures - - runs tests on map for compliance with the specs - !*/ - { - - print_spinner(); - - srand(static_cast(time(0))); - - - - map test, test2; - - enumerable >& e = test; - DLIB_TEST(e.at_start() == true); - - for (int j = 0; j < 4; ++j) - { - - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == false); - - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.is_in_domain(5) == false); - DLIB_TEST(test.is_in_domain(0) == false); - DLIB_TEST(test.is_in_domain(-999) == false); - DLIB_TEST(test.is_in_domain(4999) == false); - - - int a,b; - a = 8; - b = 94; - test.add(a,b); - DLIB_TEST(test.size() == 1); - DLIB_TEST(test.is_in_domain(8) == true); - DLIB_TEST(test.is_in_domain(5) == false); - DLIB_TEST(test.is_in_domain(0) == false); - DLIB_TEST(test.is_in_domain(-999) == false); - DLIB_TEST(test.is_in_domain(4999) == false); - DLIB_TEST(test[8] == 94); - a = 53; - b = 4; - test.add(a,b); - DLIB_TEST(test.size() == 2); - DLIB_TEST(test.is_in_domain(53) == true); - DLIB_TEST(test.is_in_domain(5) == false); - DLIB_TEST(test.is_in_domain(0) == false); - DLIB_TEST(test.is_in_domain(-999) == false); - DLIB_TEST(test.is_in_domain(4999) == false); - DLIB_TEST(test[53] == 4); - - - swap(test,test2); - - - DLIB_TEST(test2.size() == 2); - DLIB_TEST(test2.is_in_domain(8) == true); - DLIB_TEST(test2.is_in_domain(5) == false); - DLIB_TEST(test2.is_in_domain(0) == false); - DLIB_TEST(test2.is_in_domain(-999) == false); - DLIB_TEST(test2.is_in_domain(4999) == false); - DLIB_TEST(test2[8] == 94); - DLIB_TEST(test2.size() == 2); - DLIB_TEST(test2.is_in_domain(53) == true); - DLIB_TEST(test2.is_in_domain(5) == false); - DLIB_TEST(test2.is_in_domain(0) == false); - DLIB_TEST(test2.is_in_domain(-999) == false); - DLIB_TEST(test2.is_in_domain(4999) == false); - DLIB_TEST(test2[53] == 4); - - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.is_in_domain(8) == false); - DLIB_TEST(test.is_in_domain(5) == false); - DLIB_TEST(test.is_in_domain(0) == false); - DLIB_TEST(test.is_in_domain(-999) == false); - DLIB_TEST(test.is_in_domain(4999) == false); - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.is_in_domain(53) == false); - DLIB_TEST(test.is_in_domain(5) == false); - DLIB_TEST(test.is_in_domain(0) == false); - DLIB_TEST(test.is_in_domain(-999) == false); - DLIB_TEST(test.is_in_domain(4999) == false); - - - test.clear(); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.at_start() == false); - - - DLIB_TEST(test.size() == 0); - - while (test.size() < 10000) - { - a = ::rand(); - b = ::rand(); - if (!test.is_in_domain(a)) - test.add(a,b); - } - - DLIB_TEST(test.size() == 10000); - test.clear(); - DLIB_TEST(test.size() == 0); - - while (test.size() < 10000) - { - a = ::rand(); - b = ::rand(); - if (!test.is_in_domain(a)) - test.add(a,b); - } - - DLIB_TEST(test.size() == 10000); - - int count = 0; - a = -1; - while (test.move_next()) - { - DLIB_TEST(test.element().key() == test.element().key()); - DLIB_TEST(test.element().value() == test.element().value()); - DLIB_TEST(test.element().key() == test.element().key()); - DLIB_TEST(test.element().value() == test.element().value()); - - - DLIB_TEST(a < test.element().key()); - a = test.element().key(); - ++count; - } - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.move_next() == false); - - DLIB_TEST(count == 10000); - - test.swap(test2); - - DLIB_TEST(test.size() == 2); - DLIB_TEST(test2.size() == 10000); - count = 0; - a = -1; - test2.reset(); - - test2.move_next(); - test2.element().value() = 99; - DLIB_TEST(test2[test2.element().key()] == 99); - DLIB_TEST(test2.element().value() == 99); - - test2.reset(); - - while (test2.move_next()) - { - DLIB_TEST(test2[test2.element().key()] == test2.element().value()); - DLIB_TEST(test2.element().key() == test2.element().key()); - DLIB_TEST(test2.element().value() == test2.element().value()); - DLIB_TEST(test2.element().key() == test2.element().key()); - DLIB_TEST(test2.element().value() == test2.element().value()); - DLIB_TEST(a < test2.element().key()); - a = test2.element().key(); - ++count; - } - DLIB_TEST(test2.size() == 10000); - DLIB_TEST(count == 10000); - DLIB_TEST(test2.current_element_valid() == false); - DLIB_TEST(test2.at_start() == false); - DLIB_TEST(test2.move_next() == false); - DLIB_TEST(test2.current_element_valid() == false); - DLIB_TEST(test2.at_start() == false); - DLIB_TEST(test2.move_next() == false); - - - - test2.clear(); - DLIB_TEST(test2.size() == 0); - DLIB_TEST(test2.at_start() == true); - - while (test.size() < 20000) - { - a = ::rand(); - b = ::rand(); - if (!test.is_in_domain(a)) - test.add(a,b); - } - - // serialize the state of test, then clear test, then - // load the state back into test. - ostringstream sout; - serialize(test,sout); - istringstream sin(sout.str()); - test.clear(); - deserialize(test,sin); - - DLIB_TEST(test.at_start() == true); - - { - int* array1 = new int[test.size()]; - int* array2 = new int[test.size()]; - - int* tmp1 = array1; - int* tmp2 = array2; - - count = 0; - while (test.move_next()) - { - DLIB_TEST(test.element().key() == test.element().key()); - DLIB_TEST(test.element().value() == test.element().value()); - DLIB_TEST(test.element().key() == test.element().key()); - DLIB_TEST(test.current_element_valid() == true); - *tmp1 = test.element().key(); - *tmp2 = test.element().value(); - ++tmp1; - ++tmp2; - ++count; - } - DLIB_TEST(count == 20000); - - tmp1 = array1; - tmp2 = array2; - for (int i = 0; i < 20000; ++i) - { - DLIB_TEST(test.is_in_domain(*tmp1) == true); - DLIB_TEST(test[*tmp1] == *tmp2); - ++tmp1; - ++tmp2; - } - - DLIB_TEST(test.size() == 20000); - - tmp1 = array1; - tmp2 = array2; - count = 0; - while (test.size() > 10000) - { - test.remove(*tmp1,a,b); - DLIB_TEST(*tmp1 == a); - DLIB_TEST(*tmp2 == b); - ++tmp1; - ++tmp2; - ++count; - } - DLIB_TEST(count == 10000); - DLIB_TEST(test.size() == 10000); - - while (test.move_next()) - { - DLIB_TEST(test.element().key() == *tmp1); - DLIB_TEST(test.element().key() == *tmp1); - DLIB_TEST(test.element().key() == *tmp1); - DLIB_TEST(test.element().value() == *tmp2); - DLIB_TEST(test.element().value() == *tmp2); - DLIB_TEST(test.element().value() == *tmp2); - ++tmp1; - ++tmp2; - ++count; - } - DLIB_TEST(count == 20000); - DLIB_TEST(test.size() == 10000); - - while (test.size() < 20000) - { - a = ::rand(); - b = ::rand(); - if (!test.is_in_domain(a)) - test.add(a,b); - } - - test2.swap(test); - - count = 0; - a = -1; - while (test2.move_next()) - { - DLIB_TEST(test2.element().key() == test2.element().key()); - DLIB_TEST(test2.element().value() == test2.element().value()); - DLIB_TEST(test2.element().key() == test2.element().key()); - DLIB_TEST(a < test2.element().key()); - a = test2.element().key(); - ++count; - } - - DLIB_TEST(count == 20000); - DLIB_TEST(test2.size() == 20000); - - a = -1; - int c = 0; - while (test2.size()>0) - { - test2.remove_any(b,c); - DLIB_TEST( a < b); - a = b; - } - - DLIB_TEST(test2.size() == 0); - delete [] array1; - delete [] array2; - } - - test.clear(); - test2.clear(); - while (test.size() < 10000) - { - a = ::rand(); - b = ::rand(); - if (!test.is_in_domain(a)) - test.add(a,b); - } - - count = 0; - a = -1; - while (test.move_next()) - { - DLIB_TEST(a < test.element().key()); - DLIB_TEST(test[test.element().key()] == test.element().value()); - a = test.element().key(); - ++count; - if (count == 5000) - break; - DLIB_TEST(test.current_element_valid() == true); - } - - test.reset(); - - count = 0; - a = -1; - while (test.move_next()) - { - DLIB_TEST(a < test.element().key()); - a = test.element().key(); - ++count; - DLIB_TEST(test.current_element_valid() == true); - } - - DLIB_TEST(count == 10000); - - - test.clear(); - test2.clear(); - } - - - { - test.clear(); - DLIB_TEST(test.size() == 0); - int a = 5; - int b = 6; - test.add(a,b); - a = 7; - b = 8; - test.add(a,b); - DLIB_TEST(test.size() == 2); - DLIB_TEST(test[7] == 8); - DLIB_TEST(test[5] == 6); - DLIB_TEST(test.is_in_domain(7)); - DLIB_TEST(test.is_in_domain(5)); - test.destroy(7); - DLIB_TEST(test.size() == 1); - DLIB_TEST(!test.is_in_domain(7)); - DLIB_TEST(test.is_in_domain(5)); - test.destroy(5); - DLIB_TEST(test.size() == 0); - DLIB_TEST(!test.is_in_domain(7)); - DLIB_TEST(!test.is_in_domain(5)); - } - - } - - - - - class map_tester : public tester - { - public: - map_tester ( - ) : - tester ("test_map", - "Runs tests on the map component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a"; - map_kernel_test::kernel_1a> (); - dlog << LINFO << "testing kernel_1a_c"; - map_kernel_test::kernel_1a_c>(); - dlog << LINFO << "testing kernel_1b"; - map_kernel_test::kernel_1b> (); - dlog << LINFO << "testing kernel_1b_c"; - map_kernel_test::kernel_1b_c>(); - } - } a; - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/matrix.cpp b/lib/3rdParty/dlib/include/dlib/test/matrix.cpp deleted file mode 100644 index 52e2ce8a..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/matrix.cpp +++ /dev/null @@ -1,1348 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include "../stl_checked.h" -#include "../array.h" -#include "../rand.h" - -#include "tester.h" -#include -#include - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.matrix"); - - void matrix_test ( - ) - /*! - ensures - - runs tests on the matrix stuff compliance with the specs - !*/ - { - typedef memory_manager_stateless::kernel_2_2a MM; - print_spinner(); - - - { - matrix,2,2,MM> m; - set_all_elements(m,complex(1,2)); - DLIB_TEST((conj(m) == uniform_matrix,2,2>(conj(m(0,0))))); - DLIB_TEST((real(m) == uniform_matrix(1))); - DLIB_TEST((imag(m) == uniform_matrix(2))); - DLIB_TEST_MSG((sum(abs(norm(m) - uniform_matrix(5))) < 1e-10 ),norm(m)); - - } - - { - matrix m(5,5); - - for (long r = 0; r < m.nr(); ++r) - { - for (long c = 0; c < m.nc(); ++c) - { - m(r,c) = r*c; - } - } - - m = cos(exp(m)); - - - matrix mi = pinv(m ); - DLIB_TEST(mi.nr() == m.nc()); - DLIB_TEST(mi.nc() == m.nr()); - DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix()))); - DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix()))); - DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix(m)))); - DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix(m)))); - - mi = pinv(m,1e-12); - DLIB_TEST(mi.nr() == m.nc()); - DLIB_TEST(mi.nc() == m.nr()); - DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix()))); - DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix()))); - DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix(m)))); - DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix(m)))); - - m = diagm(diag(m)); - mi = pinv(diagm(diag(m)),1e-12); - DLIB_TEST(mi.nr() == m.nc()); - DLIB_TEST(mi.nc() == m.nr()); - DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix()))); - DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix()))); - DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix(m)))); - DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix(m)))); - - mi = pinv(m,0); - DLIB_TEST(mi.nr() == m.nc()); - DLIB_TEST(mi.nc() == m.nr()); - DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix()))); - DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix()))); - DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix(m)))); - DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix(m)))); - - m = diagm(diag(m)); - mi = pinv(diagm(diag(m)),0); - DLIB_TEST(mi.nr() == m.nc()); - DLIB_TEST(mi.nc() == m.nr()); - DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix()))); - DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix()))); - DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix(m)))); - DLIB_TEST((equal(round_zeros(m*mi,0.000001) , identity_matrix(m)))); - } - { - matrix m(5,5); - - for (long r = 0; r < m.nr(); ++r) - { - for (long c = 0; c < m.nc(); ++c) - { - m(r,c) = r*c; - } - } - - m = cos(exp(m)); - - - matrix mi = pinv(m ); - DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix()))); - } - - { - matrix m(5,5); - - for (long r = 0; r < m.nr(); ++r) - { - for (long c = 0; c < m.nc(); ++c) - { - m(r,c) = r*c; - } - } - - m = cos(exp(m)); - - - matrix mi = pinv(m ); - DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix()))); - } - - - { - matrix m(5,5); - - for (long r = 0; r < m.nr(); ++r) - { - for (long c = 0; c < m.nc(); ++c) - { - m(r,c) = r*c; - } - } - - m = cos(exp(m)); - - - matrix mi = pinv(m ); - DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix()))); - } - - { - matrix m; - - for (long r = 0; r < m.nr(); ++r) - { - for (long c = 0; c < m.nc(); ++c) - { - m(r,c) = r*c; - } - } - - m = cos(exp(m)); - - - matrix mi = pinv(m ); - DLIB_TEST(mi.nr() == m.nc()); - DLIB_TEST(mi.nc() == m.nr()); - DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix()))); - } - - { - matrix m(5,2); - - for (long r = 0; r < m.nr(); ++r) - { - for (long c = 0; c < m.nc(); ++c) - { - m(r,c) = r*c; - } - } - - m = cos(exp(m)); - - - matrix mi = pinv(m ); - DLIB_TEST(mi.nr() == m.nc()); - DLIB_TEST(mi.nc() == m.nr()); - DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix()))); - } - - { - matrix m; - - for (long r = 0; r < m.nr(); ++r) - { - for (long c = 0; c < m.nc(); ++c) - { - m(r,c) = r*c; - } - } - - m = cos(exp(m)); - - - matrix mi = trans(pinv(trans(m) )); - DLIB_TEST(mi.nr() == m.nc()); - DLIB_TEST(mi.nc() == m.nr()); - DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix()))); - } - - { - matrix m(5,2); - - for (long r = 0; r < m.nr(); ++r) - { - for (long c = 0; c < m.nc(); ++c) - { - m(r,c) = r*c; - } - } - - m = cos(exp(m)); - - - matrix mi = trans(pinv(trans(m) )); - DLIB_TEST(mi.nr() == m.nc()); - DLIB_TEST(mi.nc() == m.nr()); - DLIB_TEST((equal(round_zeros(mi*m,0.000001) , identity_matrix()))); - } - - { - matrix a1(5,1); - matrix a2(1,5); - matrix b1(5,1); - matrix b2(1,5); - matrix c1(5,1); - matrix c2(1,5); - matrix d1(5,1); - matrix d2(1,5); - - for (long i = 0; i < 5; ++i) - { - a1(i) = i; - a2(i) = i; - b1(i) = i; - b2(i) = i; - c1(i) = i; - c2(i) = i; - d1(i) = i; - d2(i) = i; - } - - DLIB_TEST(a1 == trans(a2)); - DLIB_TEST(a1 == trans(b2)); - DLIB_TEST(a1 == trans(c2)); - DLIB_TEST(a1 == trans(d2)); - - DLIB_TEST(a1 == b1); - DLIB_TEST(a1 == c1); - DLIB_TEST(a1 == d1); - - DLIB_TEST(trans(a1) == c2); - DLIB_TEST(trans(b1) == c2); - DLIB_TEST(trans(c1) == c2); - DLIB_TEST(trans(d1) == c2); - - DLIB_TEST(sum(a1) == 10); - DLIB_TEST(sum(a2) == 10); - DLIB_TEST(sum(b1) == 10); - DLIB_TEST(sum(b2) == 10); - DLIB_TEST(sum(c1) == 10); - DLIB_TEST(sum(c2) == 10); - DLIB_TEST(sum(d1) == 10); - DLIB_TEST(sum(d2) == 10); - - const matrix orig1 = a1; - const matrix orig2 = a2; - - ostringstream sout; - serialize(a1,sout); - serialize(a2,sout); - serialize(b1,sout); - serialize(b2,sout); - serialize(c1,sout); - serialize(c2,sout); - serialize(d1,sout); - serialize(d2,sout); - - DLIB_TEST(a1 == orig1); - DLIB_TEST(a2 == orig2); - DLIB_TEST(b1 == orig1); - DLIB_TEST(b2 == orig2); - DLIB_TEST(c1 == orig1); - DLIB_TEST(c2 == orig2); - DLIB_TEST(d1 == orig1); - DLIB_TEST(d2 == orig2); - - set_all_elements(a1,99); - set_all_elements(a2,99); - set_all_elements(b1,99); - set_all_elements(b2,99); - set_all_elements(c1,99); - set_all_elements(c2,99); - set_all_elements(d1,99); - set_all_elements(d2,99); - - DLIB_TEST(a1 != orig1); - DLIB_TEST(a2 != orig2); - DLIB_TEST(b1 != orig1); - DLIB_TEST(b2 != orig2); - DLIB_TEST(c1 != orig1); - DLIB_TEST(c2 != orig2); - DLIB_TEST(d1 != orig1); - DLIB_TEST(d2 != orig2); - - istringstream sin(sout.str()); - - deserialize(a1,sin); - deserialize(a2,sin); - deserialize(b1,sin); - deserialize(b2,sin); - deserialize(c1,sin); - deserialize(c2,sin); - deserialize(d1,sin); - deserialize(d2,sin); - - DLIB_TEST(a1 == orig1); - DLIB_TEST(a2 == orig2); - DLIB_TEST(b1 == orig1); - DLIB_TEST(b2 == orig2); - DLIB_TEST(c1 == orig1); - DLIB_TEST(c2 == orig2); - DLIB_TEST(d1 == orig1); - DLIB_TEST(d2 == orig2); - - - } - - { - matrix a(5); - matrix b(5); - matrix c(5); - matrix d(5); - DLIB_TEST(a.nr() == 1); - DLIB_TEST(a.nc() == 5); - DLIB_TEST(c.nr() == 1); - DLIB_TEST(c.nc() == 5); - - DLIB_TEST(b.nc() == 1); - DLIB_TEST(b.nr() == 5); - DLIB_TEST(d.nc() == 1); - DLIB_TEST(d.nr() == 5); - } - - { - matrix a; - matrix b; - matrix c; - matrix d; - - a.set_size(5); - b.set_size(5); - c.set_size(5); - d.set_size(5); - - DLIB_TEST(a.nr() == 1); - DLIB_TEST(a.nc() == 5); - DLIB_TEST(c.nr() == 1); - DLIB_TEST(c.nc() == 5); - - DLIB_TEST(b.nc() == 1); - DLIB_TEST(b.nr() == 5); - DLIB_TEST(d.nc() == 1); - DLIB_TEST(d.nr() == 5); - } - - { - matrix a(1,5); - matrix b(5,1); - - set_all_elements(a,1); - set_all_elements(b,1); - - - a = a*b; - - DLIB_TEST(a(0) == 5); - } - - { - matrix a(6,7); - - for (long r = 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - a(r,c) = r*a.nc() + c; - } - } - - - - DLIB_TEST(rowm(a,1).nr() == 1); - DLIB_TEST(rowm(a,1).nc() == a.nc()); - DLIB_TEST(colm(a,1).nr() == a.nr()); - DLIB_TEST(colm(a,1).nc() == 1); - - for (long c = 0; c < a.nc(); ++c) - { - DLIB_TEST( rowm(a,1)(c) == 1*a.nc() + c); - } - - for (long r = 0; r < a.nr(); ++r) - { - DLIB_TEST( colm(a,1)(r) == r*a.nc() + 1); - } - - rectangle rect(2, 1, 3+2-1, 2+1-1); - DLIB_TEST(get_rect(a).contains(get_rect(a))); - DLIB_TEST(get_rect(a).contains(rect)); - for (long r = 0; r < 2; ++r) - { - for (long c = 0; c < 3; ++c) - { - DLIB_TEST(subm(a,1,2,2,3)(r,c) == (r+1)*a.nc() + c+2); - DLIB_TEST(subm(a,1,2,2,3) == subm(a,rect)); - } - } - - DLIB_TEST(subm(a,rectangle()).nr() == 0); - DLIB_TEST(subm(a,rectangle()).nc() == 0); - - } - - { - array2d a; - a.set_size(6,7); - - - for (long r = 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - a[r][c] = r*a.nc() + c; - } - } - - - - DLIB_TEST(rowm(mat(a),1).nr() == 1); - DLIB_TEST(rowm(mat(a),1).nc() == a.nc()); - DLIB_TEST(colm(mat(a),1).nr() == a.nr()); - DLIB_TEST(colm(mat(a),1).nc() == 1); - - for (long c = 0; c < a.nc(); ++c) - { - DLIB_TEST( rowm(mat(a),1)(c) == 1*a.nc() + c); - } - - for (long r = 0; r < a.nr(); ++r) - { - DLIB_TEST( colm(mat(a),1)(r) == r*a.nc() + 1); - } - - for (long r = 0; r < 2; ++r) - { - for (long c = 0; c < 3; ++c) - { - DLIB_TEST(subm(mat(a),1,2,2,3)(r,c) == (r+1)*a.nc() + c+2); - } - } - - - } - - { - array2d m; - m.set_size(5,5); - - for (long r = 0; r < m.nr(); ++r) - { - for (long c = 0; c < m.nc(); ++c) - { - m[r][c] = r*c; - } - } - - - matrix mi = pinv(cos(exp(mat(m))) ); - DLIB_TEST(mi.nr() == m.nc()); - DLIB_TEST(mi.nc() == m.nr()); - DLIB_TEST((equal(round_zeros(mi*cos(exp(mat(m))),0.000001) , identity_matrix()))); - DLIB_TEST((equal(round_zeros(cos(exp(mat(m)))*mi,0.000001) , identity_matrix()))); - } - - { - matrix m1, res; - matrix m2; - - set_all_elements(m1,0); - - - long res_vals[] = { - 9, 9, 9, 9, 9, - 0, 1, 1, 0, 0, - 0, 1, 1, 0, 2, - 0, 0, 2, 2, 2, - 0, 0, 2, 2, 0 - }; - - res = res_vals; - - set_all_elements(m2, 1); - set_subm(m1, range(1,2), range(1,2)) = subm(m2,0,0,2,2); - set_all_elements(m2, 2); - set_subm(m1, 3,2,2,2) = m2; - - set_colm(m1,4) = trans(rowm(m1,4)); - set_rowm(m1,0) = 9; - - DLIB_TEST_MSG(m1 == res, "m1: \n" << m1 << "\nres: \n" << res); - - set_subm(m1,0,0,5,5) = m1*m1; - DLIB_TEST_MSG(m1 == res*res, "m1: \n" << m1 << "\nres*res: \n" << res*res); - - m1 = res; - set_subm(m1,1,1,2,2) = subm(m1,0,0,2,2); - - long res_vals2[] = { - 9, 9, 9, 9, 9, - 0, 9, 9, 0, 0, - 0, 0, 1, 0, 2, - 0, 0, 2, 2, 2, - 0, 0, 2, 2, 0 - }; - - res = res_vals2; - DLIB_TEST_MSG(m1 == res, "m1: \n" << m1 << "\nres: \n" << res); - - - } - - { - matrix m1, res; - matrix m2; - - set_all_elements(m1,0); - - - long res_vals[] = { - 9, 9, 9, 9, 9, - 0, 1, 1, 0, 0, - 0, 1, 1, 0, 2, - 0, 0, 2, 2, 2, - 0, 0, 2, 2, 0 - }; - - res = res_vals; - - set_all_elements(m2, 1); - set_subm(m1, rectangle(1,1,2,2)) = subm(m2,0,0,2,2); - set_all_elements(m2, 2); - set_subm(m1, 3,2,2,2) = m2; - - set_colm(m1,4) = trans(rowm(m1,4)); - set_rowm(m1,0) = 9; - - DLIB_TEST_MSG(m1 == res, "m1: \n" << m1 << "\nres: \n" << res); - - set_subm(m1,0,0,5,5) = m1*m1; - DLIB_TEST_MSG(m1 == res*res, "m1: \n" << m1 << "\nres*res: \n" << res*res); - - m1 = res; - set_subm(m1,1,1,2,2) = subm(m1,0,0,2,2); - - long res_vals2[] = { - 9, 9, 9, 9, 9, - 0, 9, 9, 0, 0, - 0, 0, 1, 0, 2, - 0, 0, 2, 2, 2, - 0, 0, 2, 2, 0 - }; - - res = res_vals2; - DLIB_TEST_MSG(m1 == res, "m1: \n" << m1 << "\nres: \n" << res); - - - } - - { - matrix m1, res; - matrix m2; - - set_all_elements(m1,0); - - - long res_vals[] = { - 9, 0, 3, 3, 0, - 9, 2, 2, 2, 0, - 9, 2, 2, 2, 0, - 4, 4, 4, 4, 4, - 9, 0, 3, 3, 0 - }; - long res_vals_c3[] = { - 9, 0, 3, 0, - 9, 2, 2, 0, - 9, 2, 2, 0, - 4, 4, 4, 4, - 9, 0, 3, 0 - }; - long res_vals_r2[] = { - 9, 0, 3, 3, 0, - 9, 2, 2, 2, 0, - 4, 4, 4, 4, 4, - 9, 0, 3, 3, 0 - }; - - matrix temp; - - res = res_vals; - - temp = matrix(res_vals_r2); - DLIB_TEST(remove_row<2>(res) == temp); - DLIB_TEST(remove_row<2>(res)(3,3) == 3); - DLIB_TEST(remove_row<2>(res).nr() == 4); - DLIB_TEST(remove_row<2>(res).nc() == 5); - DLIB_TEST(remove_row(res,2) == temp); - DLIB_TEST(remove_row(res,2)(3,3) == 3); - DLIB_TEST(remove_row(res,2).nr() == 4); - DLIB_TEST(remove_row(res,2).nc() == 5); - - temp = matrix(res_vals); - temp = remove_row(res,2); - DLIB_TEST((temp == matrix(res_vals_r2))); - temp = matrix(res_vals); - temp = remove_col(res,3); - DLIB_TEST((temp == matrix(res_vals_c3))); - - matrix vect; - set_all_elements(vect,1); - temp = identity_matrix(3); - temp = temp*vect; - DLIB_TEST(temp == vect); - - temp = matrix(res_vals_c3); - DLIB_TEST(remove_col(res,3) == temp); - DLIB_TEST(remove_col(res,3)(2,3) == 0); - DLIB_TEST(remove_col(res,3).nr() == 5); - DLIB_TEST(remove_col(res,3).nc() == 4); - - set_all_elements(m2, 1); - set_subm(m1, rectangle(1,1,3,2)) = 2; - set_all_elements(m2, 2); - set_subm(m1, 3,2,2,2) = 3; - - set_colm(m1,0) = 9; - set_rowm(m1,0) = rowm(m1,4); - set_rowm(m1,3) = 4; - - DLIB_TEST_MSG(m1 == res, "m1: \n" << m1 << "\nres: \n" << res); - - } - - - { - - const double stuff[] = { - 1, 2, 3, - 6, 3, 3, - 7, 3, 9}; - - matrix m(stuff); - - // make m be symmetric - m = m*trans(m); - - matrix L = chol(m); - DLIB_TEST(equal(L*trans(L), m)); - - DLIB_TEST_MSG(equal(inv(m), inv_upper_triangular(trans(L))*inv_lower_triangular((L))), "") - DLIB_TEST(equal(round_zeros(inv_upper_triangular(trans(L))*trans(L),1e-10), identity_matrix(3), 1e-10)); - DLIB_TEST(equal(round_zeros(inv_lower_triangular((L))*(L),1e-10) ,identity_matrix(3),1e-10)); - - } - - { - - const double stuff[] = { - 1, 2, 3, 6, 3, 4, - 6, 3, 3, 1, 2, 3, - 7, 3, 9, 54.3, 5, 3, - -6, 3, -3, 1, 2, 3, - 1, 2, 3, 5, -3, 3, - 7, 3, -9, 54.3, 5, 3 - }; - - matrix m(stuff); - - // make m be symmetric - m = m*trans(m); - - matrix L = chol(m); - DLIB_TEST_MSG(equal(L*trans(L), m, 1e-10), L*trans(L)-m); - - DLIB_TEST_MSG(equal(inv(m), inv_upper_triangular(trans(L))*inv_lower_triangular((L))), "") - DLIB_TEST_MSG(equal(inv(m), trans(inv_lower_triangular(L))*inv_lower_triangular((L))), "") - DLIB_TEST_MSG(equal(inv(m), trans(inv_lower_triangular(L))*trans(inv_upper_triangular(trans(L)))), "") - DLIB_TEST_MSG(equal(round_zeros(inv_upper_triangular(trans(L))*trans(L),1e-10) , identity_matrix(6), 1e-10), - round_zeros(inv_upper_triangular(trans(L))*trans(L),1e-10)); - DLIB_TEST_MSG(equal(round_zeros(inv_lower_triangular((L))*(L),1e-10) ,identity_matrix(6), 1e-10), - round_zeros(inv_lower_triangular((L))*(L),1e-10)); - - } - - { - matrix m(3,4), m2; - m = 1,2,3,4, - 4,5,6,6, - 6,1,8,0; - m2 = m; - DLIB_TEST(round(m) == m2); - DLIB_TEST(round_zeros(m) == m2); - - m2 = 0,2,3,4, - 4,5,6,6, - 6,0,8,0; - - DLIB_TEST(round_zeros(m,2) == m2); - } - - - { - - matrix m(identity_matrix(6)*4.5); - - matrix L = chol(m); - DLIB_TEST_MSG(equal(L*trans(L), m, 1e-10), L*trans(L)-m); - - DLIB_TEST_MSG(equal(inv(m), inv_upper_triangular(trans(L))*inv_lower_triangular((L))), "") - DLIB_TEST_MSG(equal(round_zeros(inv_upper_triangular(trans(L))*trans(L),1e-10) , identity_matrix(6), 1e-10), - round_zeros(inv_upper_triangular(trans(L))*trans(L),1e-10)); - DLIB_TEST_MSG(equal(round_zeros(inv_lower_triangular((L))*(L),1e-10) ,identity_matrix(6), 1e-10), - round_zeros(inv_lower_triangular((L))*(L),1e-10)); - - } - - { - - matrix m(identity_matrix(6)*4.5); - m(1,4) = 2; - - DLIB_TEST_MSG(dlib::equal(inv_upper_triangular(m), inv(m),1e-10), inv_upper_triangular(m)-inv(m)); - DLIB_TEST_MSG(dlib::equal(inv_lower_triangular(trans(m)), inv(trans(m)),1e-10), inv_lower_triangular(trans(m))-inv(trans(m))); - - } - - { - matrix a; - matrix b; - matrix i; - a.set_size(1000,10); - b.set_size(1000,10); - i.set_size(1000,10); - dlib::rand rnd; - for (long r = 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - a(r,c) = rnd.get_random_double(); - b(r,c) = rnd.get_random_float(); - i(r,c) = r+c*r; - } - } - - // make sure the multiply optimizations aren't messing things up - DLIB_TEST(trans(i)*i == tmp(trans(i)*i)); - DLIB_TEST_MSG(equal(trans(a)*a , tmp(trans(a)*a), 1e-11),max(abs(trans(a)*a - tmp(trans(a)*a)))); - DLIB_TEST_MSG(equal(trans(b)*b , tmp(trans(b)*b), 1e-3f),max(abs(trans(b)*b - tmp(trans(b)*b)))); - } - - { - matrix i(4,1); - i(0) = 1; - i(1) = 2; - i(2) = 3; - i(3) = 4; - matrix m; - set_all_elements(m,0); - m(0,0) = 1; - m(1,1) = 2; - m(2,2) = 3; - m(3,3) = 4; - - DLIB_TEST(diagm(i) == m); - } - - { - matrix i; - i(0) = 1; - i(1) = 2; - i(2) = 3; - i(3) = 4; - matrix m; - set_all_elements(m,0); - m(0,0) = 1; - m(1,1) = 2; - m(2,2) = 3; - m(3,3) = 4; - - DLIB_TEST(diagm(i) == m); - } - - { - matrix i(4,1); - i(0) = 1; - i(1) = 2; - i(2) = 3; - i(3) = 4; - matrix m(4,4); - set_all_elements(m,0); - m(0,0) = 1; - m(1,1) = 2; - m(2,2) = 3; - m(3,3) = 4; - - DLIB_TEST(diagm(i) == m); - } - - { - matrix i(1,4); - i(0) = 1; - i(1) = 2; - i(2) = 3; - i(3) = 4; - matrix m(4,4); - set_all_elements(m,0); - m(0,0) = 1; - m(1,1) = 2; - m(2,2) = 3; - m(3,3) = 4; - - DLIB_TEST(diagm(i) == m); - } - - { - DLIB_TEST(range(0,5).nc() == 6); - DLIB_TEST(range(1,5).nc() == 5); - DLIB_TEST(range(0,5).nr() == 1); - DLIB_TEST(range(1,5).nr() == 1); - DLIB_TEST(trans(range(0,5)).nr() == 6); - DLIB_TEST(trans(range(1,5)).nr() == 5); - DLIB_TEST(trans(range(0,5)).nc() == 1); - DLIB_TEST(trans(range(1,5)).nc() == 1); - - DLIB_TEST(range(0,2,5).nc() == 3); - DLIB_TEST(range(1,2,5).nc() == 3); - DLIB_TEST(range(0,2,5).nr() == 1); - DLIB_TEST(range(1,2,5).nr() == 1); - DLIB_TEST(trans(range(0,2,5)).nr() == 3); - DLIB_TEST(trans(range(1,2,5)).nr() == 3); - DLIB_TEST(trans(range(0,2,5)).nc() == 1); - DLIB_TEST(trans(range(1,2,5)).nc() == 1); - - DLIB_TEST(range(0,3,6).nc() == 3); - DLIB_TEST(range(1,3,5).nc() == 2); - DLIB_TEST(range(0,3,5).nr() == 1); - DLIB_TEST(range(1,3,5).nr() == 1); - DLIB_TEST(trans(range(0,3,6)).nr() == 3); - DLIB_TEST(trans(range(1,3,5)).nr() == 2); - DLIB_TEST(trans(range(0,3,5)).nc() == 1); - DLIB_TEST(trans(range(1,3,5)).nc() == 1); - - DLIB_TEST(range(1,9,5).nc() == 1); - DLIB_TEST(range(1,9,5).nr() == 1); - - DLIB_TEST(range(0,0).nc() == 1); - DLIB_TEST(range(0,0).nr() == 1); - - DLIB_TEST(range(1,1)(0) == 1); - - DLIB_TEST(range(0,5)(0) == 0 && range(0,5)(1) == 1 && range(0,5)(5) == 5); - DLIB_TEST(range(1,2,5)(0) == 1 && range(1,2,5)(1) == 3 && range(1,2,5)(2) == 5); - DLIB_TEST((range<0,5>()(0) == 0 && range<0,5>()(1) == 1 && range<0,5>()(5) == 5)); - DLIB_TEST((range<1,2,5>()(0) == 1 && range<1,2,5>()(1) == 3 && range<1,2,5>()(2) == 5)); - - - DLIB_TEST((range<0,5>().nc() == 6)); - DLIB_TEST((range<1,5>().nc() == 5)); - DLIB_TEST((range<0,5>().nr() == 1)); - DLIB_TEST((range<1,5>().nr() == 1)); - DLIB_TEST((trans(range<0,5>()).nr() == 6)); - DLIB_TEST((trans(range<1,5>()).nr() == 5)); - DLIB_TEST((trans(range<0,5>()).nc() == 1)); - DLIB_TEST((trans(range<1,5>()).nc() == 1)); - - DLIB_TEST((range<0,2,5>().nc() == 3)); - DLIB_TEST((range<1,2,5>().nc() == 3)); - DLIB_TEST((range<0,2,5>().nr() == 1)); - DLIB_TEST((range<1,2,5>().nr() == 1)); - DLIB_TEST((trans(range<0,2,5>()).nr() == 3)); - DLIB_TEST((trans(range<1,2,5>()).nr() == 3)); - DLIB_TEST((trans(range<0,2,5>()).nc() == 1)); - DLIB_TEST((trans(range<1,2,5>()).nc() == 1)); - - DLIB_TEST((range<0,3,6>().nc() == 3)); - DLIB_TEST((range<1,3,5>().nc() == 2)); - DLIB_TEST((range<0,3,5>().nr() == 1)); - DLIB_TEST((range<1,3,5>().nr() == 1)); - DLIB_TEST((trans(range<0,3,6>()).nr() == 3)); - DLIB_TEST((trans(range<1,3,5>()).nr() == 2)); - DLIB_TEST((trans(range<0,3,5>()).nc() == 1)); - DLIB_TEST((trans(range<1,3,5>()).nc() == 1)); - } - - { - DLIB_TEST(range(5,0).nc() == 6); - DLIB_TEST(range(5,1).nc() == 5); - DLIB_TEST(range(5,0).nr() == 1); - DLIB_TEST(range(5,1).nr() == 1); - DLIB_TEST(trans(range(5,0)).nr() == 6); - DLIB_TEST(trans(range(5,1)).nr() == 5); - DLIB_TEST(trans(range(5,0)).nc() == 1); - DLIB_TEST(trans(range(5,1)).nc() == 1); - - DLIB_TEST(range(5,2,0).nc() == 3); - DLIB_TEST(range(5,2,1).nc() == 3); - DLIB_TEST(range(5,2,0).nr() == 1); - DLIB_TEST(range(5,2,1).nr() == 1); - DLIB_TEST(trans(range(5,2,0)).nr() == 3); - DLIB_TEST(trans(range(5,2,1)).nr() == 3); - DLIB_TEST(trans(range(5,2,0)).nc() == 1); - DLIB_TEST(trans(range(5,2,1)).nc() == 1); - - DLIB_TEST(range(6,3,0).nc() == 3); - DLIB_TEST(range(5,3,1).nc() == 2); - DLIB_TEST(range(5,3,0).nr() == 1); - DLIB_TEST(range(5,3,1).nr() == 1); - DLIB_TEST(trans(range(6,3,0)).nr() == 3); - DLIB_TEST(trans(range(5,3,1)).nr() == 2); - DLIB_TEST(trans(range(5,3,0)).nc() == 1); - DLIB_TEST(trans(range(5,3,1)).nc() == 1); - - DLIB_TEST(range(5,9,1).nc() == 1); - DLIB_TEST(range(5,9,1).nr() == 1); - - DLIB_TEST(range(0,0).nc() == 1); - DLIB_TEST(range(0,0).nr() == 1); - - DLIB_TEST(range(1,1)(0) == 1); - - DLIB_TEST(range(5,0)(0) == 5 && range(5,0)(1) == 4 && range(5,0)(5) == 0); - DLIB_TEST(range(5,2,1)(0) == 5 && range(5,2,1)(1) == 3 && range(5,2,1)(2) == 1); - DLIB_TEST((range<5,0>()(0) == 5 && range<5,0>()(1) == 4 && range<5,0>()(5) == 0)); - DLIB_TEST((range<5,2,1>()(0) == 5 && range<5,2,1>()(1) == 3 && range<5,2,1>()(2) == 1)); - - - DLIB_TEST((range<5,0>().nc() == 6)); - DLIB_TEST((range<5,1>().nc() == 5)); - DLIB_TEST((range<5,0>().nr() == 1)); - DLIB_TEST((range<5,1>().nr() == 1)); - DLIB_TEST((trans(range<5,0>()).nr() == 6)); - DLIB_TEST((trans(range<5,1>()).nr() == 5)); - DLIB_TEST((trans(range<5,0>()).nc() == 1)); - DLIB_TEST((trans(range<5,1>()).nc() == 1)); - - DLIB_TEST((range<5,2,0>().nc() == 3)); - DLIB_TEST((range<5,2,1>().nc() == 3)); - DLIB_TEST((range<5,2,0>().nr() == 1)); - DLIB_TEST((range<5,2,1>().nr() == 1)); - DLIB_TEST((trans(range<5,2,0>()).nr() == 3)); - DLIB_TEST((trans(range<5,2,1>()).nr() == 3)); - DLIB_TEST((trans(range<5,2,0>()).nc() == 1)); - DLIB_TEST((trans(range<5,2,1>()).nc() == 1)); - - DLIB_TEST((range<6,3,0>().nc() == 3)); - DLIB_TEST((range<5,3,1>().nc() == 2)); - DLIB_TEST((range<5,3,0>().nr() == 1)); - DLIB_TEST((range<5,3,1>().nr() == 1)); - DLIB_TEST((trans(range<6,3,0>()).nr() == 3)); - DLIB_TEST((trans(range<5,3,1>()).nr() == 2)); - DLIB_TEST((trans(range<5,3,0>()).nc() == 1)); - DLIB_TEST((trans(range<5,3,1>()).nc() == 1)); - } - - { - matrix m(4,3); - for (long r = 0; r < m.nr(); ++r) - { - for (long c = 0; c < m.nc(); ++c) - { - m(r,c) = r*c; - } - } - - DLIB_TEST(subm(m,range(0,3),range(0,0)) == colm(m,0)); - DLIB_TEST(subm(m,range(0,3),range(1,1)) == colm(m,1)); - DLIB_TEST(subm(m,range(0,3),range(2,2)) == colm(m,2)); - - DLIB_TEST(subm(m,range(0,0),range(0,2)) == rowm(m,0)); - DLIB_TEST(subm(m,range(1,1),range(0,2)) == rowm(m,1)); - DLIB_TEST(subm(m,range(2,2),range(0,2)) == rowm(m,2)); - DLIB_TEST(subm(m,range(3,3),range(0,2)) == rowm(m,3)); - - DLIB_TEST(subm(m,0,0,2,2) == subm(m,range(0,1),range(0,1))); - DLIB_TEST(subm(m,1,1,2,2) == subm(m,range(1,2),range(1,2))); - - matrix m2 = subm(m,range(0,2,2),range(0,2,2)); - - DLIB_TEST(m2(0,0) == m(0,0)); - DLIB_TEST(m2(0,1) == m(0,2)); - DLIB_TEST(m2(1,0) == m(2,0)); - DLIB_TEST(m2(1,1) == m(2,2)); - - - } - { - matrix m(4,3); - for (long r = 0; r < m.nr(); ++r) - { - for (long c = 0; c < m.nc(); ++c) - { - m(r,c) = r*c; - } - } - - DLIB_TEST(subm(m,range<0,3>(),range<0,0>()) == colm(m,0)); - DLIB_TEST(subm(m,range<0,3>(),range<1,1>()) == colm(m,1)); - DLIB_TEST(subm(m,range<0,3>(),range<2,2>()) == colm(m,2)); - - DLIB_TEST(subm(m,range<0,0>(),range<0,2>()) == rowm(m,0)); - DLIB_TEST(subm(m,range<1,1>(),range<0,2>()) == rowm(m,1)); - DLIB_TEST(subm(m,range<2,2>(),range<0,2>()) == rowm(m,2)); - DLIB_TEST(subm(m,range<3,3>(),range<0,2>()) == rowm(m,3)); - - DLIB_TEST(subm(m,0,0,2,2) == subm(m,range<0,1>(),range<0,1>())); - DLIB_TEST(subm(m,1,1,2,2) == subm(m,range<1,2>(),range<1,2>())); - - matrix m2 = subm(m,range<0,2,2>(),range<0,2,2>()); - - DLIB_TEST(m2(0,0) == m(0,0)); - DLIB_TEST(m2(0,1) == m(0,2)); - DLIB_TEST(m2(1,0) == m(2,0)); - DLIB_TEST(m2(1,1) == m(2,2)); - - - } - - { - matrix m; - set_subm(m, range(0,3), range(0,4)) = 4; - DLIB_TEST(min(m) == max(m) && min(m) == 4); - - set_subm(m,range(1,1),range(0,4)) = 7; - DLIB_TEST((rowm(m,0) == uniform_matrix(1,5, 4))); - DLIB_TEST((rowm(m,1) == uniform_matrix(1,5, 7))); - DLIB_TEST((rowm(m,2) == uniform_matrix(1,5, 4))); - DLIB_TEST((rowm(m,3) == uniform_matrix(1,5, 4))); - - - set_subm(m, range(0,2,3), range(0,2,4)) = trans(subm(m,0,0,3,2)); - - - DLIB_TEST(m(0,2) == 7); - DLIB_TEST(m(2,2) == 7); - - DLIB_TEST(sum(m) == 7*5+ 7+7 + 4*(4*5 - 7)); - - } - - { - matrix mat(4,5); - DLIB_TEST((uniform_matrix(4,5,1) == ones_matrix(4,5))); - DLIB_TEST((uniform_matrix(4,5,1) == ones_matrix(mat))); - DLIB_TEST((uniform_matrix(4,5,0) == zeros_matrix(4,5))); - DLIB_TEST((uniform_matrix(4,5,0) == zeros_matrix(mat))); - DLIB_TEST((uniform_matrix(4,5,1) == ones_matrix(4,5))); - DLIB_TEST((uniform_matrix(4,5,0) == zeros_matrix(4,5))); - DLIB_TEST((uniform_matrix >(4,5,1) == ones_matrix >(4,5))); - DLIB_TEST((uniform_matrix >(4,5,0) == zeros_matrix >(4,5))); - DLIB_TEST((uniform_matrix >(4,5,1) == ones_matrix >(4,5))); - DLIB_TEST((uniform_matrix >(4,5,0) == zeros_matrix >(4,5))); - DLIB_TEST((complex_matrix(ones_matrix(3,3), zeros_matrix(3,3)) == complex_matrix(ones_matrix(3,3)))); - DLIB_TEST((pointwise_multiply(complex_matrix(ones_matrix(3,3)), ones_matrix(3,3)*2) == - complex_matrix(2*ones_matrix(3,3)))); - } - - { - DLIB_TEST(( uniform_matrix(303,303, 3)*identity_matrix(303) == uniform_matrix(3) ) ); - DLIB_TEST(( uniform_matrix(3)*identity_matrix() == uniform_matrix(3) )); - } - - { - matrix m(2,3); - m = 1,2,3, - 5,6,7; - - DLIB_TEST_MSG(m(0,0) == 1 && m(0,1) == 2 && m(0,2) == 3 && - m(1,0) == 5 && m(1,1) == 6 && m(1,2) == 7,""); - - m = 4; - DLIB_TEST((m == uniform_matrix(4))); - - matrix m2; - m2 = 1,2,3, - 5,6,7; - DLIB_TEST_MSG(m2(0,0) == 1 && m2(0,1) == 2 && m2(0,2) == 3 && - m2(1,0) == 5 && m2(1,1) == 6 && m2(1,2) == 7,""); - - matrix m3; - m3 = 1, - 5; - DLIB_TEST(m3(0) == 1 && m3(1) == 5 ); - - matrix m4; - m4 = 1, 5; - DLIB_TEST(m3(0) == 1 && m3(1) == 5 ); - } - - { - matrix m(4,1); - m = 3, 1, 5, 2; - DLIB_TEST(index_of_min(m) == 1); - DLIB_TEST(index_of_max(m) == 2); - DLIB_TEST(index_of_min(trans(m)) == 1); - DLIB_TEST(index_of_max(trans(m)) == 2); - } - - { - matrix m1(1,5), m2; - - m1 = 3.0000, 3.7500, 4.5000, 5.2500, 6.0000; - m2 = linspace(3, 6, 5); - - DLIB_TEST(equal(m1, m2)); - - m1 = pow(10, m1); - m2 = logspace(3, 6, 5); - - DLIB_TEST(equal(m1, m2)); - } - - { - matrix m = cartesian_product(range(1,3), range(0,1)); - - matrix c0, c1, c2, c3, c4, c5; - c0 = 1, 0; - c1 = 1, 1; - c2 = 2, 0; - c3 = 2, 1; - c4 = 3, 0; - c5 = 3, 1; - - DLIB_TEST_MSG(colm(m,0) == c0, colm(m,0) << "\n\n" << c0); - DLIB_TEST(colm(m,1) == c1); - DLIB_TEST(colm(m,2) == c2); - DLIB_TEST(colm(m,3) == c3); - DLIB_TEST(colm(m,4) == c4); - DLIB_TEST(colm(m,5) == c5); - } - - - { - matrix m(2,2), mr(2,2), mr_max(2,2); - - m = 1, 2, - 0, 4; - - mr = 1, 1.0/2.0, - 0, 1.0/4.0; - - mr_max = 1, 1.0/2.0, - std::numeric_limits::max(), 1.0/4.0; - - DLIB_TEST(equal(reciprocal(m), mr)); - DLIB_TEST(equal(reciprocal_max(m), mr_max)); - - } - - { - matrix m1, m2; - m1.set_size(3,1); - m2.set_size(1,3); - - m1 = 1,2,3; - m2 = 4,5,6; - DLIB_TEST(dot(m1, m2) == 1*4 + 2*5 + 3*6); - DLIB_TEST(dot(m1, trans(m2)) == 1*4 + 2*5 + 3*6); - DLIB_TEST(dot(trans(m1), m2) == 1*4 + 2*5 + 3*6); - DLIB_TEST(dot(trans(m1), trans(m2)) == 1*4 + 2*5 + 3*6); - } - - { - matrix m1, m2; - m1.set_size(3,1); - m2.set_size(3,1); - - m1 = 1,2,3; - m2 = 4,5,6; - DLIB_TEST(dot(m1, m2) == 1*4 + 2*5 + 3*6); - DLIB_TEST(dot(m1, trans(m2)) == 1*4 + 2*5 + 3*6); - DLIB_TEST(dot(trans(m1), m2) == 1*4 + 2*5 + 3*6); - DLIB_TEST(dot(trans(m1), trans(m2)) == 1*4 + 2*5 + 3*6); - } - { - matrix m1, m2; - m1.set_size(1,3); - m2.set_size(1,3); - - m1 = 1,2,3; - m2 = 4,5,6; - DLIB_TEST(dot(m1, m2) == 1*4 + 2*5 + 3*6); - DLIB_TEST(dot(m1, trans(m2)) == 1*4 + 2*5 + 3*6); - DLIB_TEST(dot(trans(m1), m2) == 1*4 + 2*5 + 3*6); - DLIB_TEST(dot(trans(m1), trans(m2)) == 1*4 + 2*5 + 3*6); - } - { - matrix m1; - matrix m2; - m1.set_size(1,3); - m2.set_size(3,1); - - m1 = 1,2,3; - m2 = 4,5,6; - DLIB_TEST(dot(m1, m2) == 1*4 + 2*5 + 3*6); - DLIB_TEST(dot(m1, trans(m2)) == 1*4 + 2*5 + 3*6); - DLIB_TEST(dot(trans(m1), m2) == 1*4 + 2*5 + 3*6); - DLIB_TEST(dot(trans(m1), trans(m2)) == 1*4 + 2*5 + 3*6); - } - - { - matrix m1(3,3), m2(3,3); - - m1 = 1; - m2 = 1; - m1 = m1*subm(m2,0,0,3,3); - DLIB_TEST(is_finite(m1)); - } - { - matrix m1; - matrix m2(3,3); - - m1 = 1; - m2 = 1; - m1 = subm(m2,0,0,3,3)*m1; - } - - { - matrix m(2,1); - - m = 3,3; - m /= m(0); - - DLIB_TEST(m(0) == 1); - DLIB_TEST(m(1) == 1); - } - { - matrix m(2,1); - - m = 3,3; - m *= m(0); - - DLIB_TEST(m(0) == 9); - DLIB_TEST(m(1) == 9); - } - { - matrix m(2,1); - - m = 3,3; - m -= m(0); - - DLIB_TEST(m(0) == 0); - DLIB_TEST(m(1) == 0); - } - { - matrix m(2,1); - - m = 3,3; - m += m(0); - - DLIB_TEST(m(0) == 6); - DLIB_TEST(m(1) == 6); - DLIB_TEST(is_finite(m)); - } - - - { - matrix m(3,3); - m = 3; - m(1,1) = std::numeric_limits::infinity(); - DLIB_TEST(is_finite(m) == false); - m(1,1) = -std::numeric_limits::infinity(); - DLIB_TEST(is_finite(m) == false); - m(1,1) = 2; - DLIB_TEST(is_finite(m)); - } - - { - matrix m(4,1), mm, mmm; - - mmm = mm = (m = 1,2,3,4); - DLIB_TEST(m(0) == 1); - DLIB_TEST(m(1) == 2); - DLIB_TEST(m(2) == 3); - DLIB_TEST(m(3) == 4); - DLIB_TEST(mm == m); - DLIB_TEST(mmm == m); - DLIB_TEST(mm(0) == 1); - DLIB_TEST(mm(1) == 2); - DLIB_TEST(mm(2) == 3); - DLIB_TEST(mm(3) == 4); - } - - - } - - - - - - - class matrix_tester : public tester - { - public: - matrix_tester ( - ) : - tester ("test_matrix", - "Runs tests on the matrix component.") - {} - - void perform_test ( - ) - { - matrix_test(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/matrix2.cpp b/lib/3rdParty/dlib/include/dlib/test/matrix2.cpp deleted file mode 100644 index bf9abae7..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/matrix2.cpp +++ /dev/null @@ -1,1152 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include "../stl_checked.h" -#include "../array.h" -#include "../rand.h" - -#include "tester.h" -#include -#include - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.matrix2"); - - dlib::rand rnd; - - void matrix_test ( - ) - /*! - ensures - - runs tests on the matrix stuff compliance with the specs - !*/ - { - typedef memory_manager_stateless::kernel_2_2a MM; - print_spinner(); - - const double ident[] = { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 }; - - const double uniform3[] = { - 3, 3, 3, 3, - 3, 3, 3, 3, - 3, 3, 3, 3, - 3, 3, 3, 3 - }; - - const double uniform1[] = { - 1, 1, 1, 1, - 1, 1, 1, 1, - 1, 1, 1, 1, - 1, 1, 1, 1 - }; - - const double uniform0[] = { - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0 - }; - - const int array[] = { - 42, 58, 9, 1, - 9, 5, 8, 2, - 98, 28, 4, 77, - 9, 2, 44, 88 }; - - const int array2[] = { - 1, 22, 3, - 4, 52, 6, - 7, 8, 9 }; - - const int array2_r[] = { - 52, 6, 4, - 8, 9, 7, - 22, 3, 1 - }; - - const double array_f[] = { - -0.99, - 0.99}; - - - matrix fm(array_f); - - DLIB_TEST(fm.size() == 2); - matrix dfm(fm); - DLIB_TEST(round(fm)(0) == -1); - DLIB_TEST(round(fm)(1) == 1); - DLIB_TEST(round(dfm)(0) == -1); - DLIB_TEST(round(dfm)(1) == 1); - DLIB_TEST(round(dfm).size() == dfm.size()); - - - const int array3[] = { 1, 2, 3, 4 }; - - matrix m3(array2); - matrix dm3; - DLIB_TEST(dm3.size() == 0); - DLIB_TEST(dm3.nr() == 0); - DLIB_TEST(dm3.nc() == 0); - dm3.set_size(3,4); - DLIB_TEST(dm3.nr() == 3); - DLIB_TEST(dm3.nc() == 4); - DLIB_TEST(dm3.size() == 3*4); - dm3.set_size(3,3); - DLIB_TEST(dm3.nr() == 3); - DLIB_TEST(dm3.nc() == 3); - dm3 = m3; - dm3(0,0)++; - DLIB_TEST( dm3 != m3); - dm3 = m3; - DLIB_TEST( dm3 == m3); - DLIB_TEST( abs(sum(squared(normalize(dm3))) - 1.0) < 1e-10); - - matrix mrc; - mrc.set_size(3,4); - - set_all_elements(mrc,1); - - DLIB_TEST(diag(mrc) == uniform_matrix(3,1,1)); - DLIB_TEST(diag(matrix(mrc)) == uniform_matrix(3,1,1)); - - matrix mrc2; - set_all_elements(mrc2,1); - DLIB_TEST((removerc<1,1>(mrc) == mrc2)); - DLIB_TEST((removerc(mrc,1,1) == mrc2)); - - matrix m4, m5, m6; - set_all_elements(m4, 4); - set_all_elements(m5, 4); - set_all_elements(m6, 1); - - DLIB_TEST(squared(m4) == pointwise_multiply(m4,m4)); - DLIB_TEST(cubed(m4) == pointwise_multiply(m4,m4,m4)); - DLIB_TEST(pow(matrix_cast(m4),2) == squared(matrix_cast(m4))); - DLIB_TEST(pow(matrix_cast(m4),3) == cubed(matrix_cast(m4))); - - matrix dm4; - matrix::kernel_2_2a> dm5; - dm4 = dm4; - dm4 = dm5; - DLIB_TEST(dm4.nr() == 0); - dm4 = m4; - dm5 = m5; - DLIB_TEST(dm4 == dm5); - - - DLIB_TEST(m4 == m5); - DLIB_TEST(m6 != m5); - m4.swap(m6); - DLIB_TEST(m6 == m5); - DLIB_TEST(m4 != m5); - - DLIB_TEST(m3.nr() == 3); - DLIB_TEST(m3.nc() == 3); - - matrix v(array3), v2; - DLIB_TEST(v.nr() == 4); - DLIB_TEST(v.nc() == 1); - - std::vector stdv(4); - std_vector_c stdv_c(4); - dlib::array arr; - arr.resize(4); - for (long i = 0; i < 4; ++i) - stdv[i] = stdv_c[i] = arr[i] = i+1; - - DLIB_TEST(mat(stdv)(0) == 1); - DLIB_TEST(mat(stdv)(1) == 2); - DLIB_TEST(mat(stdv)(2) == 3); - DLIB_TEST(mat(stdv)(3) == 4); - DLIB_TEST(mat(stdv).nr() == 4); - DLIB_TEST(mat(stdv).nc() == 1); - DLIB_TEST(mat(stdv).size() == 4); - DLIB_TEST(equal(trans(mat(stdv))*mat(stdv), trans(v)*v)); - DLIB_TEST(equal(trans(mat(stdv))*mat(stdv), tmp(trans(v)*v))); - - DLIB_TEST(mat(stdv_c)(0) == 1); - DLIB_TEST(mat(stdv_c)(1) == 2); - DLIB_TEST(mat(stdv_c)(2) == 3); - DLIB_TEST(mat(stdv_c)(3) == 4); - DLIB_TEST(mat(stdv_c).nr() == 4); - DLIB_TEST(mat(stdv_c).nc() == 1); - DLIB_TEST(mat(stdv_c).size() == 4); - DLIB_TEST(equal(trans(mat(stdv_c))*mat(stdv_c), trans(v)*v)); - - DLIB_TEST(mat(arr)(0) == 1); - DLIB_TEST(mat(arr)(1) == 2); - DLIB_TEST(mat(arr)(2) == 3); - DLIB_TEST(mat(arr)(3) == 4); - DLIB_TEST(mat(arr).nr() == 4); - DLIB_TEST(mat(arr).nc() == 1); - DLIB_TEST(mat(arr).size() == 4); - DLIB_TEST(equal(trans(mat(arr))*mat(arr), trans(v)*v)); - - DLIB_TEST(v(0) == 1); - DLIB_TEST(v(1) == 2); - DLIB_TEST(v(2) == 3); - DLIB_TEST(v(3) == 4); - matrix dv = v; - DLIB_TEST((trans(v)*v).size() == 1); - DLIB_TEST((trans(v)*v).nr() == 1); - DLIB_TEST((trans(v)*dv).nr() == 1); - DLIB_TEST((trans(dv)*dv).nr() == 1); - DLIB_TEST((trans(dv)*v).nr() == 1); - DLIB_TEST((trans(v)*v).nc() == 1); - DLIB_TEST((trans(v)*dv).nc() == 1); - DLIB_TEST((trans(dv)*dv).nc() == 1); - DLIB_TEST((trans(dv)*v).nc() == 1); - DLIB_TEST((trans(v)*v)(0) == 1*1 + 2*2 + 3*3 + 4*4); - DLIB_TEST((trans(dv)*v)(0) == 1*1 + 2*2 + 3*3 + 4*4); - DLIB_TEST((trans(dv)*dv)(0) == 1*1 + 2*2 + 3*3 + 4*4); - DLIB_TEST((trans(v)*dv)(0) == 1*1 + 2*2 + 3*3 + 4*4); - - dv = trans(dv)*v; - DLIB_TEST(dv.nr() == 1); - DLIB_TEST(dv.nc() == 1); - - dm3 = m3; - DLIB_TEST(floor(det(m3)+0.01) == -444); - DLIB_TEST(floor(det(dm3)+0.01) == -444); - DLIB_TEST(min(m3) == 1); - DLIB_TEST(min(dm3) == 1); - DLIB_TEST(max(m3) == 52); - DLIB_TEST(max(dm3) == 52); - DLIB_TEST(sum(m3) == 112); - DLIB_TEST(sum(dm3) == 112); - DLIB_TEST(prod(m3) == 41513472); - DLIB_TEST(prod(dm3) == 41513472); - DLIB_TEST(prod(diag(m3)) == 1*52*9); - DLIB_TEST(prod(diag(dm3)) == 1*52*9); - DLIB_TEST(sum(diag(m3)) == 1+52+9); - DLIB_TEST(sum(diag(dm3)) == 1+52+9); - DLIB_TEST(equal(round(10000*m3*inv(m3))/10000 , identity_matrix())); - DLIB_TEST(equal(round(10000*dm3*inv(m3))/10000 , identity_matrix())); - DLIB_TEST(equal(round(10000*dm3*inv(dm3))/10000 , identity_matrix())); - DLIB_TEST(equal(round(10000*m3*inv(dm3))/10000 , identity_matrix())); - DLIB_TEST(equal(round(10000*tmp(m3*inv(m3)))/10000 , identity_matrix())); - DLIB_TEST(equal(round(10000*tmp(dm3*inv(m3)))/10000 , identity_matrix())); - DLIB_TEST(equal(round(10000*tmp(dm3*inv(dm3)))/10000 , identity_matrix())); - DLIB_TEST(equal(round(10000*tmp(m3*inv(dm3)))/10000 , identity_matrix())); - DLIB_TEST(-1*m3 == -m3); - DLIB_TEST(-1*dm3 == -m3); - DLIB_TEST(-1*m3 == -dm3); - DLIB_TEST(-1*dm3 == -dm3); - - DLIB_TEST(m3 == dm3); - m3(1,1) = 99; - DLIB_TEST(m3 != dm3); - m3 = dm3; - DLIB_TEST(m3 == dm3); - - matrix mident(ident); - matrix muniform0(uniform0); - matrix muniform1(uniform1); - matrix muniform3(uniform3); - matrix m1(array), m2; - DLIB_TEST(m1.nr() == 4); - DLIB_TEST(m1.nc() == 4); - - DLIB_TEST(muniform1 + muniform1 + muniform1 == muniform3); - DLIB_TEST(muniform1*2 + muniform1 + muniform1 - muniform1 == muniform3); - DLIB_TEST(2*muniform1 + muniform1 + muniform1 - muniform1 == muniform3); - DLIB_TEST(muniform1 + muniform1 + muniform1 - muniform3 == muniform0); - DLIB_TEST(equal(muniform3/3 , muniform1)); - DLIB_TEST(v != m1); - DLIB_TEST(v == v); - DLIB_TEST(m1 == m1); - - muniform0.swap(muniform1); - DLIB_TEST((muniform1 == matrix_cast(uniform_matrix()))); - DLIB_TEST((muniform0 == matrix_cast(uniform_matrix()))); - DLIB_TEST((muniform1 == matrix_cast(uniform_matrix(4,4,0)))); - DLIB_TEST((muniform0 == matrix_cast(uniform_matrix(4,4,1)))); - swap(muniform0,muniform1); - - DLIB_TEST((mident == identity_matrix())); - DLIB_TEST((muniform0 == matrix_cast(uniform_matrix()))); - DLIB_TEST((muniform1 == matrix_cast(uniform_matrix()))); - DLIB_TEST((muniform3 == matrix_cast(uniform_matrix()))); - DLIB_TEST((muniform1*8 == matrix_cast(uniform_matrix()))); - - set_all_elements(m2,7); - DLIB_TEST(m2 == muniform1*7); - m2 = array; - DLIB_TEST(m2 == m1); - - const double m1inv[] = { - -0.00946427624, 0.0593272941, 0.00970564379, -0.00973323731, - 0.0249312057, -0.0590122427, -0.00583102756, 0.00616002729, - -0.00575431149, 0.110081189, -0.00806792253, 0.00462297692, - 0.00327847478, -0.0597669712, 0.00317386196, 0.00990759201 - }; - - m2 = m1inv; - DLIB_TEST((round(m2*m1) == identity_matrix())); - DLIB_TEST((round(tmp(m2*m1)) == identity_matrix())); - - DLIB_TEST_MSG(round(m2*10000) == round(inv(m1)*10000), - round(m2*10000) - round(inv(m1)*10000) - << "\n\n" << round(m2*10000) - << "\n\n" << round(inv(m1)*10000) - << "\n\n" << m2 - << "\n\n" << inv(m1) - ); - DLIB_TEST(m1 == abs(-1*m1)); - DLIB_TEST(abs(m2) == abs(-1*m2)); - - DLIB_TEST_MSG(floor(det(m1)+0.01) == 3297875,"\nm1: \n" << m1 << "\ndet(m1): " << det(m1)); - - - ostringstream sout; - m1 = m2; - serialize(m1,sout); - set_all_elements(m1,0); - istringstream sin(sout.str()); - deserialize(m1,sin); - DLIB_TEST_MSG(round(100000*m1) == round(100000*m2),"m1: \n" << m1 << endl << "m2: \n" << m2); - - - set_all_elements(v,2); - v2 = pointwise_multiply(v, v*2); - set_all_elements(v,8); - DLIB_TEST(v == v2); - DLIB_TEST(v == tmp(v2)); - DLIB_TEST((v == rotate<2,0>(v))); - - m4 = array2; - m5 = array2_r; - DLIB_TEST((m5 == rotate<1,1>(m4))); - - m5 = array2; - DLIB_TEST((m5*2 == pointwise_multiply(m5,uniform_matrix()))); - DLIB_TEST((tmp(m5*2) == tmp(pointwise_multiply(m5,uniform_matrix())))); - - v = tmp(v); - - - - - matrix dm10(10,5); - DLIB_TEST(dm10.nr() == 10); - DLIB_TEST(dm10.nc() == 5); - set_all_elements(dm10,4); - DLIB_TEST(dm10.nr() == 10); - DLIB_TEST(dm10.nc() == 5); - matrix m10; - DLIB_TEST(m10.nr() == 10); - DLIB_TEST(m10.nc() == 5); - set_all_elements(m10,4); - DLIB_TEST(dm10 == m10); - DLIB_TEST((clamp<0,3>(dm10) == clamp<0,3>(m10))); - DLIB_TEST((clamp<0,3>(dm10)(0,2) == 3)); - - set_all_elements(dm10,1); - set_all_elements(m10,4); - DLIB_TEST(4*dm10 == m10); - DLIB_TEST(5*dm10 - dm10 == m10); - DLIB_TEST((16*dm10)/4 == m10); - DLIB_TEST(dm10+dm10+2*dm10 == m10); - DLIB_TEST(dm10+tmp(dm10+2*dm10) == m10); - set_all_elements(dm10,4); - DLIB_TEST(dm10 == m10); - DLIB_TEST_MSG(sum(abs(sigmoid(dm10) -sigmoid(m10))) < 1e-10,sum(abs(sigmoid(dm10) -sigmoid(m10))) ); - - { - matrix x, l, u, out; - x = 3,4; - - l = 1,1; - u = 2,2.2; - - out = 2, 2.2; - DLIB_TEST(equal(clamp(x, l, u) , out)); - out = 3, 2.2; - DLIB_TEST(!equal(clamp(x, l, u) , out)); - out = 2, 4.2; - DLIB_TEST(!equal(clamp(x, l, u) , out)); - - x = 1.5, 1.5; - out = x; - DLIB_TEST(equal(clamp(x, l, u) , out)); - - x = 0.5, 1.5; - out = 1, 1.5; - DLIB_TEST(equal(clamp(x, l, u) , out)); - - x = 1.5, 0.5; - out = 1.5, 1.0; - DLIB_TEST(equal(clamp(x, l, u) , out)); - - } - - matrix m7; - matrix dm7(7,7); - dm7 = randm(7,7, rnd); - m7 = dm7; - - DLIB_TEST_MSG(max(abs(dm7*inv(dm7) - identity_matrix(7))) < 1e-12, max(abs(dm7*inv(dm7) - identity_matrix(7)))); - DLIB_TEST(equal(inv(dm7), inv(m7))); - DLIB_TEST(abs(det(dm7) - det(m7)) < 1e-14); - DLIB_TEST(abs(min(dm7) - min(m7)) < 1e-14); - DLIB_TEST(abs(max(dm7) - max(m7)) < 1e-14); - DLIB_TEST_MSG(abs(sum(dm7) - sum(m7)) < 1e-14,sum(dm7) - sum(m7)); - DLIB_TEST(abs(prod(dm7) -prod(m7)) < 1e-14); - DLIB_TEST(equal(diag(dm7) , diag(m7))); - DLIB_TEST(equal(trans(dm7) , trans(m7))); - DLIB_TEST(equal(abs(dm7) , abs(m7))); - DLIB_TEST(equal(round(dm7) , round(m7))); - DLIB_TEST(matrix_cast(dm7) == matrix_cast(m7)); - DLIB_TEST((rotate<2,3>(dm7) == rotate<2,3>(m7))); - DLIB_TEST((sum(pointwise_multiply(dm7,dm7) - pointwise_multiply(m7,m7))) < 1e-10); - DLIB_TEST((sum(pointwise_multiply(dm7,dm7,dm7) - pointwise_multiply(m7,m7,m7))) < 1e-10); - DLIB_TEST_MSG((sum(pointwise_multiply(dm7,dm7,dm7,dm7) - pointwise_multiply(m7,m7,m7,m7))) < 1e-10, - (sum(pointwise_multiply(dm7,dm7,dm7,dm7) - pointwise_multiply(m7,m7,m7,m7))) - ); - - - matrix temp(5,5); - matrix dsm(5,5); - matrix sm; - - set_all_elements(dsm,1); - set_all_elements(sm,1); - set_all_elements(temp,1); - - dsm += dsm; - sm += sm; - DLIB_TEST(dsm == 2*temp); - DLIB_TEST(sm == 2*temp); - temp = dsm*sm + dsm; - dsm += dsm*sm; - DLIB_TEST_MSG(temp == dsm,temp - dsm); - - set_all_elements(dsm,1); - set_all_elements(sm,1); - set_all_elements(temp,1); - - dsm += dsm; - sm += sm; - DLIB_TEST(dsm == 2*temp); - DLIB_TEST(sm == 2*temp); - temp = dsm*sm + dsm; - sm += dsm*sm; - DLIB_TEST_MSG(temp == sm,temp - sm); - - set_all_elements(dsm,1); - set_all_elements(sm,1); - set_all_elements(temp,1); - - dsm += dsm; - sm += sm; - DLIB_TEST(dsm == 2*temp); - DLIB_TEST(sm == 2*temp); - temp = sm - dsm*sm ; - sm -= dsm*sm; - DLIB_TEST_MSG(temp == sm,temp - sm); - - set_all_elements(dsm,1); - set_all_elements(sm,1); - set_all_elements(temp,1); - - dsm += dsm; - sm += sm; - DLIB_TEST(dsm == 2*temp); - DLIB_TEST(sm == 2*temp); - temp = dsm - dsm*sm ; - dsm -= dsm*sm; - DLIB_TEST_MSG(temp == dsm,temp - dsm); - - set_all_elements(dsm,1); - set_all_elements(sm,1); - set_all_elements(temp,2); - - dsm *= 2; - sm *= 2; - DLIB_TEST(dsm == temp); - DLIB_TEST(sm == temp); - dsm /= 2; - sm /= 2; - DLIB_TEST(dsm == temp/2); - DLIB_TEST(sm == temp/2); - - dsm += dsm; - sm += sm; - DLIB_TEST(dsm == temp); - DLIB_TEST(sm == temp); - dsm += sm; - sm += dsm; - DLIB_TEST(dsm == 2*temp); - DLIB_TEST(sm == temp*3); - dsm -= sm; - sm -= dsm; - DLIB_TEST(dsm == -temp); - DLIB_TEST(sm == 4*temp); - sm -= sm; - dsm -= dsm; - DLIB_TEST(dsm == 0*temp); - DLIB_TEST(sm == 0*temp); - - set_all_elements(dsm,1); - set_all_elements(sm,1); - set_all_elements(temp,3); - dsm += sm+sm; - DLIB_TEST(dsm == temp); - - set_all_elements(dsm,1); - set_all_elements(sm,1); - set_all_elements(temp,-1); - dsm -= sm+sm; - DLIB_TEST(dsm == temp); - - set_all_elements(dsm,1); - set_all_elements(sm,1); - set_all_elements(temp,-1); - sm -= dsm+dsm; - DLIB_TEST(sm == temp); - - set_all_elements(dsm,1); - set_all_elements(sm,1); - set_all_elements(temp,3); - sm += dsm+dsm; - DLIB_TEST(sm == temp); - - - - // test the implicit conversion to bool stuff - { - matrix bt1(3,1); - matrix bt2; - set_all_elements(bt1,2); - set_all_elements(bt2,3); - - float val = trans(bt1)*bt2; - DLIB_TEST((float)(trans(bt1)*bt2) == 18); - DLIB_TEST((float)(trans(bt1)*bt2) != 19); - DLIB_TEST(val == 18); - } - { - matrix bt1; - matrix bt2(3,1); - set_all_elements(bt1,2); - set_all_elements(bt2,3); - - float val = trans(bt1)*bt2; - DLIB_TEST((float)(trans(bt1)*bt2) == 18); - DLIB_TEST((float)(trans(bt1)*bt2) != 19); - DLIB_TEST(val == 18); - } - { - matrix bt1(3,1); - matrix bt2(3,1); - set_all_elements(bt1,2); - set_all_elements(bt2,3); - - float val = trans(bt1)*bt2; - DLIB_TEST((float)(trans(bt1)*bt2) == 18); - DLIB_TEST((float)(trans(bt1)*bt2) != 19); - DLIB_TEST(val == 18); - } - { - matrix bt1; - matrix bt2; - set_all_elements(bt1,2); - set_all_elements(bt2,3); - - float val = trans(bt1)*bt2; - DLIB_TEST((float)(trans(bt1)*bt2) == 18); - DLIB_TEST((float)(trans(bt1)*bt2) != 19); - DLIB_TEST(val == 18); - } - - - - - { - srand(423452); - const long M = 50; - const long N = 40; - - matrix a(M,N); - for (long r = 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - a(r,c) = 10*((double)::rand())/RAND_MAX; - } - } - - matrix u, u2; - matrix q, q2; - matrix v, v2; - - matrix a2; - a2 = tmp(a/2); - - - svd2(true,true,a2+a2,u,q,v); - - double err = max(abs(a - subm(u,get_rect(a2+a2))*diagm(q)*trans(v))); - DLIB_TEST_MSG( err < 1e-11,"err: " << err); - using dlib::equal; - DLIB_TEST((equal(trans(u)*u , identity_matrix(), 1e-10))); - DLIB_TEST((equal(trans(v)*v , identity_matrix(), 1e-10))); - - svd2(false,true,a2+a2,u,q,v2); - svd2(true,false,a2+a2,u2,q,v); - svd2(false,false,a2+a2,u,q2,v); - - err = max(abs(a - subm(u2,get_rect(a2+a2))*diagm(q2)*trans(v2))); - DLIB_TEST_MSG( err < 1e-11,"err: " << err); - DLIB_TEST((equal(trans(u2)*u2 , identity_matrix(), 1e-10))); - DLIB_TEST((equal(trans(v2)*v2 , identity_matrix(), 1e-10))); - - } - - - { - srand(423452); - const long M = 3; - const long N = 3; - - matrix a(M,N); - for (long r = 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - a(r,c) = 10*((double)::rand())/RAND_MAX; - } - } - - matrix u, u2; - matrix q, q2; - matrix v, v2; - - matrix a2; - a2 = tmp(a/2); - - - svd2(true,true,a2+a2,u,q,v); - - double err = max(abs(a - subm(u,get_rect(a2+a2))*diagm(q)*trans(v))); - DLIB_TEST_MSG( err < 1e-11,"err: " << err); - using dlib::equal; - DLIB_TEST((equal(trans(u)*u , identity_matrix(), 1e-10))); - DLIB_TEST((equal(trans(v)*v , identity_matrix(), 1e-10))); - - svd2(false,true,a2+a2,u,q,v2); - svd2(true,false,a2+a2,u2,q,v); - svd2(false,false,a2+a2,u,q2,v); - - err = max(abs(a - subm(u2,get_rect(a2+a2))*diagm(q2)*trans(v2))); - DLIB_TEST_MSG( err < 1e-11,"err: " << err); - DLIB_TEST((equal(trans(u2)*u2 , identity_matrix(), 1e-10))); - DLIB_TEST((equal(trans(v2)*v2 , identity_matrix(), 1e-10))); - - } - - { - srand(423452); - const long M = 3; - const long N = 3; - - - matrix a(M,N); - for (long r = 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - a(r,c) = 10*((double)::rand())/RAND_MAX; - } - } - - matrix u, u2; - matrix q, q2; - matrix v, v2; - - matrix a2; - a2 = tmp(a/2); - - - svd2(true,true,a2+a2,u,q,v); - - double err = max(abs(a - subm(u,get_rect(a2+a2))*diagm(q)*trans(v))); - DLIB_TEST_MSG( err < 1e-11,"err: " << err); - using dlib::equal; - DLIB_TEST((equal(trans(u)*u , identity_matrix(), 1e-10))); - DLIB_TEST((equal(trans(v)*v , identity_matrix(), 1e-10))); - - svd2(false,true,a2+a2,u,q,v2); - svd2(true,false,a2+a2,u2,q,v); - svd2(false,false,a2+a2,u,q2,v); - - err = max(abs(a - subm(u2,get_rect(a2+a2))*diagm(q2)*trans(v2))); - DLIB_TEST_MSG( err < 1e-11,"err: " << err); - DLIB_TEST((equal(trans(u2)*u2 , identity_matrix(), 1e-10))); - DLIB_TEST((equal(trans(v2)*v2 , identity_matrix(), 1e-10))); - - } - - - - { - srand(423452); - const long M = 10; - const long N = 7; - - matrix a(M,N); - for (long r = 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - a(r,c) = 10*((double)::rand())/RAND_MAX; - } - } - - matrix u; - matrix q; - matrix v; - - matrix a2; - a2 = tmp(a/2); - - - svd2(true,true,a2+a2,u,q,v); - - double err = sum(round(1e10*(a - subm(u,get_rect(a2+a2))*diagm(q)*trans(v)))); - DLIB_TEST_MSG( err == 0,"err: " << err); - DLIB_TEST((round(1e10*trans(u)*u) == 1e10*identity_matrix())); - DLIB_TEST((round(1e10*trans(v)*v) == 1e10*identity_matrix())); - } - - - { - srand(423452); - const long M = 10; - const long N = 7; - - matrix a(M,N); - for (long r = 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - a(r,c) = 10*((double)::rand())/RAND_MAX; - } - } - - matrix u(M,N); - matrix w; - matrix v(N,N); - - matrix a2; - a2 = tmp(a/2); - - - svd(a2+a2,u,w,v); - - DLIB_TEST( sum(round(1e10*(a - u*w*trans(v)))) == 0); - DLIB_TEST((round(1e10*trans(u)*u) == 1e10*identity_matrix())); - DLIB_TEST((round(1e10*trans(v)*v) == 1e10*identity_matrix())); - } - - { - srand(423452); - const long M = 1; - const long N = 1; - - matrix a(M,N); - for (long r = 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - a(r,c) = 10*((double)::rand())/RAND_MAX; - } - } - - matrix u; - matrix w; - matrix v; - - matrix a2; - a2 = 0; - a2 = tmp(a/2); - - - svd(a2+a2,u,w,v); - - DLIB_TEST( sum(round(1e10*(a - u*w*trans(v)))) == 0); - DLIB_TEST((round(1e10*trans(u)*u) == 1e10*identity_matrix())); - DLIB_TEST((round(1e10*trans(v)*v) == 1e10*identity_matrix())); - } - - - { - srand(53434); - const long M = 5; - const long N = 5; - - matrix a(M,N); - for (long r = 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - a(r,c) = 10*((double)::rand())/RAND_MAX; - } - } - - matrix u(M,N); - matrix w; - matrix v; - - svd(a,u,w,v); - - DLIB_TEST( sum(round(1e10*(a - u*w*trans(v)))) == 0); - DLIB_TEST((round(1e10*trans(u)*u) == 1e10*identity_matrix())); - DLIB_TEST((round(1e10*trans(v)*v) == 1e10*identity_matrix())); - } - - - { - srand(11234); - const long M = 9; - const long N = 4; - - matrix a(M,N); - for (long r = 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - a(r,c) = 10*((double)::rand())/RAND_MAX; - } - } - - matrix u; - matrix w; - matrix v; - - svd(a,u,w,v); - - DLIB_TEST( sum(round(1e10*(a - u*w*trans(v)))) == 0); - DLIB_TEST((round(1e10*trans(u)*u) == 1e10*identity_matrix())); - DLIB_TEST((round(1e10*trans(v)*v) == 1e10*identity_matrix())); - } - - - - { - srand(53934); - const long M = 2; - const long N = 4; - - matrix a(M,N); - for (long r = 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - a(r,c) = 10*((double)::rand())/RAND_MAX; - } - } - - matrix u; - matrix w; - matrix v; - - svd(a,u,w,v); - - DLIB_TEST( sum(round(1e10*(a - u*w*trans(v)))) == 0); - } - - - { - srand(53234); - const long M = 9; - const long N = 40; - - matrix a(M,N); - for (long r = 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - a(r,c) = 10*((double)::rand())/RAND_MAX; - } - } - - matrix u; - matrix w; - matrix v; - - svd(a,u,w,v); - - DLIB_TEST( sum(round(1e10*(a - u*w*trans(v)))) == 0); - } - - { - srand(53234); - const long M = 9; - const long N = 40; - - typedef matrix mat; - mat a(M,N); - for (long r = 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - a(r,c) = 10*((double)::rand())/RAND_MAX; - } - } - - mat u; - mat w; - mat v; - - svd(a,u,w,v); - - DLIB_TEST( sum(round(1e10*(a - u*w*trans(v)))) == 0); - } - - - { - matrix a(3,3); - matrix b; - set_all_elements(a,0); - - a(0,0) = 1; - a(1,1) = 2; - a(2,2) = 3; - b = a; - - DLIB_TEST(diag(a)(0) == 1); - DLIB_TEST(diag(a)(1) == 2); - DLIB_TEST(diag(a)(2) == 3); - DLIB_TEST(diag(a).nr() == 3); - DLIB_TEST(diag(a).nc() == 1); - - DLIB_TEST(diag(b)(0) == 1); - DLIB_TEST(diag(b)(1) == 2); - DLIB_TEST(diag(b)(2) == 3); - DLIB_TEST(diag(b).nr() == 3); - DLIB_TEST(diag(b).nc() == 1); - - DLIB_TEST(pointwise_multiply(a,b)(0,0) == 1); - DLIB_TEST(pointwise_multiply(a,b)(1,1) == 4); - DLIB_TEST(pointwise_multiply(a,b)(2,2) == 9); - DLIB_TEST(pointwise_multiply(a,b)(1,0) == 0); - DLIB_TEST(pointwise_multiply(a,b,a)(1,0) == 0); - DLIB_TEST(pointwise_multiply(a,b,a,b)(1,0) == 0); - - - DLIB_TEST(complex_matrix(a,b)(0,0) == std::complex(1,1)); - DLIB_TEST(complex_matrix(a,b)(2,2) == std::complex(3,3)); - DLIB_TEST(complex_matrix(a,b)(2,1) == std::complex(0,0)); - } - - { - matrix > m(2,2), m2(2,2); - complex val1(1,2), val2(1.0/complex(1,2)); - m = val1; - m2 = val2; - - DLIB_TEST(equal(reciprocal(m) , m2)); - } - { - matrix > m(2,2), m2(2,2); - complex val1(1,2), val2(1.0f/complex(1,2)); - m = val1; - m2 = val2; - - DLIB_TEST(equal(reciprocal(m) , m2)); - } - - { - matrix m1, m2; - set_all_elements(m1,2.0); - set_all_elements(m2,1.0/2.0); - DLIB_TEST(reciprocal(m1) == m2); - DLIB_TEST((reciprocal(uniform_matrix(2.0)) == m2)); - DLIB_TEST((round_zeros(uniform_matrix(1e-8f)) == uniform_matrix(0)) ); - set_all_elements(m1,2.0); - m2 = m1; - m1(1,0) = static_cast(1e-8); - m2(1,0) = 0; - DLIB_TEST(round_zeros(m1) == m2); - m1 = round_zeros(m1); - DLIB_TEST(m1 == m2); - } - - { - matrix > m; - m.set_size(3,3); - set_all_elements(m,uniform_matrix(1)); - DLIB_TEST((sum(m) == uniform_matrix(9))); - DLIB_TEST((round_zeros(sqrt(sum(m)) - uniform_matrix(3)) == uniform_matrix(0))); - } - - { - matrix m1; - matrix m2; - m2.set_size(2,2); - - set_all_elements(m1,2); - m2 = uniform_matrix(2); - - m1 = m1 + m2; - DLIB_TEST((m1 == uniform_matrix(4))); - - set_all_elements(m1,2); - set_all_elements(m2,2); - m1 = m1*m1; - DLIB_TEST((m1 == uniform_matrix(8))); - - m1(1,0) = 1; - set_all_elements(m2,8); - m2(0,1) = 1; - m1 = trans(m1); - DLIB_TEST(m1 == m2); - } - - { - matrix m; - matrix m2(2,3); - - set_all_elements(m,1); - DLIB_TEST(mean(m) == 1); - set_all_elements(m,2); - DLIB_TEST(mean(m) == 2); - m(0,0) = 1; - m(0,1) = 1; - m(0,2) = 1; - DLIB_TEST(abs(mean(m) - 1.5) < 1e-10); - DLIB_TEST(abs(variance(m) - 0.3) < 1e-10); - - set_all_elements(m2,1); - DLIB_TEST(mean(m2) == 1); - set_all_elements(m2,2); - DLIB_TEST(mean(m2) == 2); - m2(0,0) = 1; - m2(0,1) = 1; - m2(0,2) = 1; - DLIB_TEST(abs(mean(m2) - 1.5) < 1e-10); - DLIB_TEST(abs(variance(m2) - 0.3) < 1e-10); - - set_all_elements(m,0); - DLIB_TEST(abs(variance(m)) < 1e-10); - set_all_elements(m,1); - DLIB_TEST(abs(variance(m)) < 1e-10); - set_all_elements(m,23.4); - DLIB_TEST(abs(variance(m)) < 1e-10); - } - - { - matrix,2,2,MM> m; - set_all_elements(m,uniform_matrix(1)); - DLIB_TEST((round_zeros(variance(m)) == uniform_matrix(0))); - DLIB_TEST((round_zeros(mean(m)) == uniform_matrix(1))); - m(0,0) = uniform_matrix(9); - DLIB_TEST((round_zeros(variance(m)) == uniform_matrix(16))); - DLIB_TEST((round_zeros(mean(m)) == uniform_matrix(3))); - - matrix > m2(2,2); - set_all_elements(m2,uniform_matrix(1)); - DLIB_TEST((round_zeros(variance(m2)) == uniform_matrix(0))); - DLIB_TEST((round_zeros(mean(m2)) == uniform_matrix(1))); - m2(0,0) = uniform_matrix(9); - DLIB_TEST((round_zeros(variance(m2)) == uniform_matrix(16))); - DLIB_TEST((round_zeros(mean(m2)) == uniform_matrix(3))); - } - - - { - matrix m(4,4), m2; - m = 1,2,3,4, - 1,2,3,4, - 4,6,8,10, - 4,6,8,10; - m2 = m; - - DLIB_TEST(colm(m,range(0,3)) == m); - DLIB_TEST(rowm(m,range(0,3)) == m); - DLIB_TEST(colm(m,range(0,0)) == colm(m,0)); - DLIB_TEST(rowm(m,range(0,0)) == rowm(m,0)); - DLIB_TEST(colm(m,range(1,1)) == colm(m,1)); - DLIB_TEST(rowm(m,range(1,1)) == rowm(m,1)); - - DLIB_TEST(colm(m,range(2,2)) == colm(m,2)); - DLIB_TEST(rowm(m,range(2,2)) == rowm(m,2)); - - DLIB_TEST(colm(m,range(1,2)) == subm(m,0,1,4,2)); - DLIB_TEST(rowm(m,range(1,2)) == subm(m,1,0,2,4)); - - set_colm(m,range(1,2)) = 9; - set_subm(m2,0,1,4,2) = 9; - DLIB_TEST(m == m2); - - set_colm(m,range(1,2)) = 11; - set_subm(m2,0,1,4,2) = 11; - DLIB_TEST(m == m2); - } - - { - print_spinner(); - matrix m1; - matrix m2; - matrix m3; - matrix m4; - - dlib::rand rnd; - for (int i = 0; i < 50; ++i) - { - m1 = randm(1,1,rnd); - m2 = randm(2,2,rnd); - m3 = randm(3,3,rnd); - m4 = randm(4,4,rnd); - - DLIB_TEST(max(abs(m1*inv(m1) - identity_matrix(m1))) < 1e-13); - DLIB_TEST(max(abs(m2*inv(m2) - identity_matrix(m2))) < 1e-13); - DLIB_TEST(max(abs(m3*inv(m3) - identity_matrix(m3))) < 1e-13); - DLIB_TEST(max(abs(m4*inv(m4) - identity_matrix(m4))) < 1e-13); - } - } - - } - - - - - - - class matrix_tester : public tester - { - public: - matrix_tester ( - ) : - tester ("test_matrix2", - "Runs tests on the matrix component.") - {} - - void perform_test ( - ) - { - matrix_test(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/matrix3.cpp b/lib/3rdParty/dlib/include/dlib/test/matrix3.cpp deleted file mode 100644 index 46dde12a..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/matrix3.cpp +++ /dev/null @@ -1,1098 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include "../stl_checked.h" -#include "../array.h" -#include "../rand.h" - -#include "tester.h" -#include -#include - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.matrix3"); - - - const double eps_mul = 200; - - template - void check_equal ( - const T& a, - const U& b - ) - { - DLIB_TEST(a.nr() == b.nr()); - DLIB_TEST(a.nc() == b.nc()); - typedef typename T::type type; - for (long r = 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - type error = std::abs(a(r,c) - b(r,c)); - DLIB_TEST_MSG(error < std::sqrt(std::numeric_limits::epsilon())*eps_mul, "error: " << error << - " eps: " << std::sqrt(std::numeric_limits::epsilon())*eps_mul); - } - } - } - - template - void c_check_equal ( - const T& a, - const U& b - ) - { - DLIB_TEST(a.nr() == b.nr()); - DLIB_TEST(a.nc() == b.nc()); - typedef typename T::type type; - for (long r = 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - typename type::value_type error = std::abs(a(r,c) - b(r,c)); - DLIB_TEST_MSG(error < std::sqrt(std::numeric_limits::epsilon())*eps_mul, "error: " << error << - " eps: " << std::sqrt(std::numeric_limits::epsilon())*eps_mul); - } - } - } - - template - void assign_no_blas ( - const T& a_, - const U& b - ) - { - T& a = const_cast(a_); - DLIB_TEST(a.nr() == b.nr()); - DLIB_TEST(a.nc() == b.nc()); - for (long r = 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - a(r,c) = b(r,c); - } - } - } - - template - type rnd_num (dlib::rand& rnd) - { - return static_cast(10*rnd.get_random_double()); - } - - template - void test_blas( long rows, long cols) - { - // The tests in this function exercise the BLAS bindings located in the matrix/matrix_blas_bindings.h file. - // It does this by performing an assignment that is subject to BLAS bindings and comparing the - // results directly to an unevaluated matrix_exp that should be equal. - - dlib::rand rnd; - - matrix a(rows,cols), temp, temp2, temp3; - - for (int k = 0; k < 6; ++k) - { - for (long r= 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - a(r,c) = rnd_num(rnd); - } - } - matrix at; - at = trans(a); - - matrix > c_a(rows,cols), c_at, c_sqr; - for (long r= 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - c_a(r,c) = complex(rnd_num(rnd),rnd_num(rnd)); - } - } - c_at = trans(c_a); - const int size = max(rows,cols); - c_sqr = 10*matrix_cast >(complex_matrix(randm(size,size,rnd), randm(size,size,rnd))); - - - matrix > c_temp(cols,cols), c_temp2(cols,cols); - const complex i(0,1); - - const type one = 1; - const type two = 1; - const type num1 = static_cast(3.6); - const type num2 = static_cast(6.6); - const type num3 = static_cast(8.6); - - matrix,0,1> c_cv4(cols), c_cv3(rows); - matrix,1,0> c_rv4(cols), c_rv3(rows); - - matrix cv4(cols); - - for (long idx = 0; idx < cv4.size(); ++idx) - cv4(idx) = rnd_num(rnd); - - for (long idx = 0; idx < c_cv4.size(); ++idx) - c_cv4(idx) = complex(rnd_num(rnd),rnd_num(rnd)); - - matrix rv3(rows); - - for (long idx = 0; idx < rv3.size(); ++idx) - rv3(idx) = rnd_num(rnd); - - for (long idx = 0; idx < c_rv3.size(); ++idx) - c_rv3(idx) = complex(rnd_num(rnd),rnd_num(rnd)); - - matrix cv3(rows); - - for (long idx = 0; idx < cv3.size(); ++idx) - cv3(idx) = rnd_num(rnd); - - for (long idx = 0; idx < c_cv3.size(); ++idx) - c_cv3(idx) = complex(rnd_num(rnd),rnd_num(rnd)); - - matrix rv4(cols); - for (long idx = 0; idx < rv4.size(); ++idx) - rv4(idx) = rnd_num(rnd); - - for (long idx = 0; idx < c_rv4.size(); ++idx) - c_rv4(idx) = complex(rnd_num(rnd),rnd_num(rnd)); - - - - // GEMM tests - dlog << LTRACE << "1.1"; - check_equal(tmp(at*a), at*a); - check_equal(tmp(trans(at*a)), trans(at*a)); - check_equal(tmp(2.4*trans(4*trans(at*a) + at*3*a)), 2.4*trans(4*trans(at*a) + at*3*a)); - dlog << LTRACE << "1.2"; - check_equal(tmp(trans(a)*a), trans(a)*a); - check_equal(tmp(trans(trans(a)*a)), trans(trans(a)*a)); - dlog << LTRACE << "1.3"; - check_equal(tmp(at*trans(at)), at*trans(at)); - check_equal(tmp(trans(at*trans(at))), trans(at*trans(at))); - dlog << LTRACE << "1.4"; - check_equal(tmp(trans(at)*trans(a)), a*at); - check_equal(tmp(trans(trans(at)*trans(a))), trans(a*at)); - dlog << LTRACE << "1.5"; - - print_spinner(); - c_check_equal(tmp(conj(trans(c_a))*c_a), trans(conj(c_a))*c_a); - dlog << LTRACE << "1.5.1"; - c_check_equal(tmp(trans(conj(trans(c_a))*c_a)), trans(trans(conj(c_a))*c_a)); - dlog << LTRACE << "1.5.2"; - c_check_equal(tmp((conj(trans(c_sqr))*trans(c_sqr))), (trans(conj(c_sqr))*trans(c_sqr))); - dlog << LTRACE << "1.5.3"; - c_check_equal(tmp(trans(conj(trans(c_sqr))*trans(c_sqr))), trans(trans(conj(c_sqr))*trans(c_sqr))); - dlog << LTRACE << "1.6"; - c_check_equal(tmp(c_at*trans(conj(c_at))), c_at*conj(trans(c_at))); - dlog << LTRACE << "1.6.1"; - c_check_equal(tmp(trans(c_at*trans(conj(c_at)))), trans(c_at*conj(trans(c_at)))); - dlog << LTRACE << "1.6.2"; - c_check_equal(tmp((c_sqr)*trans(conj(c_sqr))), (c_sqr)*conj(trans(c_sqr))); - dlog << LTRACE << "1.6.2.1"; - c_check_equal(tmp(trans(c_sqr)*trans(conj(c_sqr))), trans(c_sqr)*conj(trans(c_sqr))); - dlog << LTRACE << "1.6.3"; - c_check_equal(tmp(trans(trans(c_sqr)*trans(conj(c_sqr)))), trans(trans(c_sqr)*conj(trans(c_sqr)))); - dlog << LTRACE << "1.7"; - c_check_equal(tmp(conj(trans(c_at))*trans(conj(c_a))), conj(trans(c_at))*trans(conj(c_a))); - c_check_equal(tmp(trans(conj(trans(c_at))*trans(conj(c_a)))), trans(conj(trans(c_at))*trans(conj(c_a)))); - dlog << LTRACE << "1.8"; - - check_equal(tmp(a*trans(rowm(a,1))) , a*trans(rowm(a,1))); - check_equal(tmp(a*colm(at,1)) , a*colm(at,1)); - check_equal(tmp(subm(a,1,1,2,2)*subm(a,1,2,2,2)), subm(a,1,1,2,2)*subm(a,1,2,2,2)); - - dlog << LTRACE << "1.9"; - check_equal(tmp(trans(a*trans(rowm(a,1)))) , trans(a*trans(rowm(a,1)))); - dlog << LTRACE << "1.10"; - check_equal(tmp(trans(a*colm(at,1))) , trans(a*colm(at,1))); - dlog << LTRACE << "1.11"; - check_equal(tmp(trans(subm(a,1,1,2,2)*subm(a,1,2,2,2))), trans(subm(a,1,1,2,2)*subm(a,1,2,2,2))); - dlog << LTRACE << "1.12"; - - { - temp = at*a; - temp2 = temp; - - temp += 3.5*at*a; - assign_no_blas(temp2, temp2 + 3.5*at*a); - check_equal(temp, temp2); - - temp -= at*3.5*a; - assign_no_blas(temp2, temp2 - at*3.5*a); - check_equal(temp, temp2); - - temp = temp + 4*at*a; - assign_no_blas(temp2, temp2 + 4*at*a); - check_equal(temp, temp2); - - temp = temp - 2.4*at*a; - assign_no_blas(temp2, temp2 - 2.4*at*a); - check_equal(temp, temp2); - } - dlog << LTRACE << "1.13"; - { - temp = trans(at*a); - temp2 = temp; - temp3 = temp; - - dlog << LTRACE << "1.14"; - temp += trans(3.5*at*a); - assign_no_blas(temp2, temp2 + trans(3.5*at*a)); - check_equal(temp, temp2); - - dlog << LTRACE << "1.15"; - temp -= trans(at*3.5*a); - assign_no_blas(temp2, temp2 - trans(at*3.5*a)); - check_equal(temp, temp2); - - dlog << LTRACE << "1.16"; - temp = trans(temp + 4*at*a); - assign_no_blas(temp3, trans(temp2 + 4*at*a)); - check_equal(temp, temp3); - - temp2 = temp; - dlog << LTRACE << "1.17"; - temp = trans(temp - 2.4*at*a); - assign_no_blas(temp3, trans(temp2 - 2.4*at*a)); - check_equal(temp, temp3); - } - - dlog << LTRACE << "1.17.1"; - { - matrix m1, m2; - - m1 = matrix_cast(randm(rows, cols, rnd)); - m2 = matrix_cast(randm(cols, rows + 8, rnd)); - check_equal(tmp(m1*m2), m1*m2); - check_equal(tmp(trans(m1*m2)), trans(m1*m2)); - - m1 = trans(m1); - check_equal(tmp(trans(m1)*m2), trans(m1)*m2); - check_equal(tmp(trans(trans(m1)*m2)), trans(trans(m1)*m2)); - - m2 = trans(m2); - check_equal(tmp(trans(m1)*trans(m2)), trans(m1)*trans(m2)); - check_equal(tmp(trans(trans(m1)*trans(m2))), trans(trans(m1)*trans(m2))); - - m1 = trans(m1); - check_equal(tmp(m1*trans(m2)), m1*trans(m2)); - check_equal(tmp(trans(m1*trans(m2))), trans(m1*trans(m2))); - } - - dlog << LTRACE << "1.17.5"; - { - matrix r; - matrix c; - - r = matrix_cast(randm(1, rows+9, rnd)); - c = matrix_cast(randm(rows, 1, rnd)); - - check_equal(tmp(c*r), c*r); - check_equal(tmp(trans(c*r)), trans(c*r)); - - check_equal(tmp(trans(r)*trans(c)), trans(r)*trans(c)); - check_equal(tmp(trans(trans(r)*trans(c))), trans(trans(r)*trans(c))); - } - - dlog << LTRACE << "1.18"; - - // GEMV tests - check_equal(tmp(a*cv4), a*cv4); - check_equal(tmp(trans(a*cv4)), trans(a*cv4)); - check_equal(tmp(rv3*a), rv3*a); - check_equal(tmp(trans(cv4)*at), trans(cv4)*at); - check_equal(tmp(a*trans(rv4)), a*trans(rv4)); - check_equal(tmp(trans(a*trans(rv4))), trans(a*trans(rv4))); - - check_equal(tmp(trans(a)*cv3), trans(a)*cv3); - check_equal(tmp(rv4*trans(a)), rv4*trans(a)); - check_equal(tmp(trans(cv3)*trans(at)), trans(cv3)*trans(at)); - check_equal(tmp(trans(cv3)*a), trans(cv3)*a); - check_equal(tmp(trans(a)*trans(rv3)), trans(a)*trans(rv3)); - - - c_check_equal(tmp(trans(conj(c_a))*c_cv3), trans(conj(c_a))*c_cv3); - c_check_equal(tmp(c_rv4*trans(conj(c_a))), c_rv4*trans(conj(c_a))); - c_check_equal(tmp(trans(c_cv3)*trans(conj(c_at))), trans(c_cv3)*trans(conj(c_at))); - c_check_equal(tmp(conj(trans(c_a))*trans(c_rv3)), trans(conj(c_a))*trans(c_rv3)); - c_check_equal(tmp(c_rv4*conj(c_at)), c_rv4*conj(c_at)); - c_check_equal(tmp(trans(c_cv4)*conj(c_at)), trans(c_cv4)*conj(c_at)); - - dlog << LTRACE << "2.00"; - - c_check_equal(tmp(trans(trans(conj(c_a))*c_cv3)), trans(trans(conj(c_a))*c_cv3)); - c_check_equal(tmp(trans(c_rv4*trans(conj(c_a)))), trans(c_rv4*trans(conj(c_a)))); - c_check_equal(tmp(trans(trans(c_cv3)*trans(conj(c_at)))), trans(trans(c_cv3)*trans(conj(c_at)))); - dlog << LTRACE << "2.20"; - c_check_equal(tmp(trans(conj(trans(c_a))*trans(c_rv3))), trans(trans(conj(c_a))*trans(c_rv3))); - c_check_equal(tmp(trans(c_rv4*conj(c_at))), trans(c_rv4*conj(c_at))); - c_check_equal(tmp(trans(trans(c_cv4)*conj(c_at))), trans(trans(c_cv4)*conj(c_at))); - - - - dlog << LTRACE << "6"; - temp = a*at; - check_equal(temp, a*at); - temp = temp + a*at + trans(at)*at + trans(at)*sin(at); - check_equal(temp, a*at + a*at+ trans(at)*at + trans(at)*sin(at)); - - dlog << LTRACE << "6.1"; - temp = a*at; - check_equal(temp, a*at); - temp = a*at + temp; - check_equal(temp, a*at + a*at); - - print_spinner(); - dlog << LTRACE << "6.2"; - temp = a*at; - check_equal(temp, a*at); - dlog << LTRACE << "6.2.3"; - temp = temp - a*at; - dlog << LTRACE << "6.2.4"; - check_equal(temp, a*at-a*at); - - dlog << LTRACE << "6.3"; - temp = a*at; - dlog << LTRACE << "6.3.5"; - check_equal(temp, a*at); - dlog << LTRACE << "6.3.6"; - temp = a*at - temp; - dlog << LTRACE << "6.4"; - check_equal(temp, a*at-a*at); - - - - const long d = min(rows,cols); - rectangle rect(1,1,d,d); - temp.set_size(max(rows,cols)+4,max(rows,cols)+4); - set_all_elements(temp,4); - temp2 = temp; - - dlog << LTRACE << "7"; - set_subm(temp,rect) = a*at; - assign_no_blas( set_subm(temp2,rect) , a*at); - check_equal(temp, temp2); - - temp = a; - temp2 = a; - - set_colm(temp,1) = a*cv4; - assign_no_blas( set_colm(temp2,1) , a*cv4); - check_equal(temp, temp2); - - set_rowm(temp,1) = rv3*a; - assign_no_blas( set_rowm(temp2,1) , rv3*a); - check_equal(temp, temp2); - - - // Test BLAS GER - { - temp.set_size(cols,cols); - set_all_elements(temp,3); - temp2 = temp; - - - dlog << LTRACE << "8"; - temp += cv4*rv4; - assign_no_blas(temp2, temp2 + cv4*rv4); - check_equal(temp, temp2); - - dlog << LTRACE << "8.3"; - temp = temp + cv4*rv4; - assign_no_blas(temp2, temp2 + cv4*rv4); - check_equal(temp, temp2); - dlog << LTRACE << "8.9"; - } - { - temp.set_size(cols,cols); - set_all_elements(temp,3); - temp2 = temp; - temp3 = 0; - - dlog << LTRACE << "8.10"; - - temp += trans(cv4*rv4); - assign_no_blas(temp3, temp2 + trans(cv4*rv4)); - check_equal(temp, temp3); - temp3 = 0; - - dlog << LTRACE << "8.11"; - temp2 = temp; - temp = trans(temp + cv4*rv4); - assign_no_blas(temp3, trans(temp2 + cv4*rv4)); - check_equal(temp, temp3); - dlog << LTRACE << "8.12"; - } - { - matrix > temp, temp2, temp3; - matrix,0,1 > cv4; - matrix,1,0 > rv4; - cv4.set_size(cols); - rv4.set_size(cols); - temp.set_size(cols,cols); - set_all_elements(temp,complex(3,5)); - temp(cols-1, cols-4) = 9; - temp2 = temp; - temp3.set_size(cols,cols); - temp3 = 0; - - for (long i = 0; i < rv4.size(); ++i) - { - rv4(i) = complex(rnd_num(rnd),rnd_num(rnd)); - cv4(i) = complex(rnd_num(rnd),rnd_num(rnd)); - } - - dlog << LTRACE << "8.13"; - - temp += trans(cv4*rv4); - assign_no_blas(temp3, temp2 + trans(cv4*rv4)); - c_check_equal(temp, temp3); - temp3 = 0; - - dlog << LTRACE << "8.14"; - temp2 = temp; - temp = trans(temp + cv4*rv4); - assign_no_blas(temp3, trans(temp2 + cv4*rv4)); - c_check_equal(temp, temp3); - dlog << LTRACE << "8.15"; - } - - - - - set_all_elements(c_temp, one + num1*i); - c_temp2 = c_temp; - set_all_elements(c_rv4, one + num2*i); - set_all_elements(c_cv4, two + num3*i); - - - dlog << LTRACE << "9"; - c_temp += c_cv4*c_rv4; - assign_no_blas(c_temp2, c_temp2 + c_cv4*c_rv4); - c_check_equal(c_temp, c_temp2); - dlog << LTRACE << "9.1"; - c_temp += c_cv4*conj(c_rv4); - assign_no_blas(c_temp2, c_temp2 + c_cv4*conj(c_rv4)); - c_check_equal(c_temp, c_temp2); - dlog << LTRACE << "9.2"; - c_temp = c_cv4*conj(c_rv4) + c_temp; - assign_no_blas(c_temp2, c_temp2 + c_cv4*conj(c_rv4)); - c_check_equal(c_temp, c_temp2); - dlog << LTRACE << "9.3"; - c_temp = trans(c_rv4)*trans(conj(c_cv4)) + c_temp; - assign_no_blas(c_temp2, c_temp2 + trans(c_rv4)*trans(conj(c_cv4))); - c_check_equal(c_temp, c_temp2); - - - dlog << LTRACE << "9.4"; - c_temp += conj(c_cv4)*c_rv4; - assign_no_blas(c_temp2, c_temp2 + conj(c_cv4)*c_rv4); - c_check_equal(c_temp, c_temp2); - dlog << LTRACE << "9.5"; - c_temp += conj(c_cv4)*conj(c_rv4); - assign_no_blas(c_temp2, c_temp2 + conj(c_cv4)*conj(c_rv4)); - c_check_equal(c_temp, c_temp2); - dlog << LTRACE << "9.6"; - c_temp = conj(c_cv4)*conj(c_rv4) + c_temp; - assign_no_blas(c_temp2, c_temp2 + conj(c_cv4)*conj(c_rv4)); - c_check_equal(c_temp, c_temp2); - dlog << LTRACE << "9.7"; - c_temp = conj(trans(c_rv4))*trans(conj(c_cv4)) + c_temp; - assign_no_blas(c_temp2, c_temp2 + conj(trans(c_rv4))*trans(conj(c_cv4))); - c_check_equal(c_temp, c_temp2); - - - dlog << LTRACE << "10"; - c_temp += trans(c_cv4*c_rv4); - assign_no_blas(c_temp2, c_temp2 + trans(c_cv4*c_rv4)); - c_check_equal(c_temp, c_temp2); - dlog << LTRACE << "10.1"; - c_temp += trans(c_cv4*conj(c_rv4)); - assign_no_blas(c_temp2, c_temp2 + trans(c_cv4*conj(c_rv4))); - c_check_equal(c_temp, c_temp2); - dlog << LTRACE << "10.2"; - c_temp = trans(c_cv4*conj(c_rv4)) + c_temp; - assign_no_blas(c_temp2, c_temp2 + trans(c_cv4*conj(c_rv4))); - c_check_equal(c_temp, c_temp2); - dlog << LTRACE << "10.3"; - c_temp = trans(trans(c_rv4)*trans(conj(c_cv4))) + c_temp; - assign_no_blas(c_temp2, c_temp2 + trans(trans(c_rv4)*trans(conj(c_cv4)))); - c_check_equal(c_temp, c_temp2); - - - dlog << LTRACE << "10.4"; - c_temp += trans(conj(c_cv4)*c_rv4); - assign_no_blas(c_temp2, c_temp2 + trans(conj(c_cv4)*c_rv4)); - c_check_equal(c_temp, c_temp2); - dlog << LTRACE << "10.5"; - c_temp += trans(conj(c_cv4)*conj(c_rv4)); - assign_no_blas(c_temp2, c_temp2 + trans(conj(c_cv4)*conj(c_rv4))); - c_check_equal(c_temp, c_temp2); - dlog << LTRACE << "10.6"; - c_temp = trans(conj(c_cv4)*conj(c_rv4)) + c_temp; - assign_no_blas(c_temp2, c_temp2 + trans(conj(c_cv4)*conj(c_rv4))); - c_check_equal(c_temp, c_temp2); - dlog << LTRACE << "10.7"; - c_temp = trans(conj(trans(c_rv4))*trans(conj(c_cv4))) + c_temp; - assign_no_blas(c_temp2, c_temp2 + trans(conj(trans(c_rv4))*trans(conj(c_cv4)))); - c_check_equal(c_temp, c_temp2); - - dlog << LTRACE << "10.8"; - - - print_spinner(); - - // Test DOT - check_equal( tmp(rv4*cv4), rv4*cv4); - check_equal( tmp(trans(rv4*cv4)), trans(rv4*cv4)); - check_equal( tmp(trans(cv4)*trans(rv4)), trans(cv4)*trans(rv4)); - check_equal( tmp(rv4*3.9*cv4), rv4*3.9*cv4); - check_equal( tmp(trans(cv4)*3.9*trans(rv4)), trans(cv4)*3.9*trans(rv4)); - check_equal( tmp(rv4*cv4*3.9), rv4*3.9*cv4); - check_equal( tmp(trans(cv4)*trans(rv4)*3.9), trans(cv4)*3.9*trans(rv4)); - - - check_equal( tmp(trans(rv4*cv4)), trans(rv4*cv4)); - check_equal( tmp(trans(trans(rv4*cv4))), trans(trans(rv4*cv4))); - check_equal( tmp(trans(trans(cv4)*trans(rv4))), trans(trans(cv4)*trans(rv4))); - check_equal( tmp(trans(rv4*3.9*cv4)), trans(rv4*3.9*cv4)); - check_equal( tmp(trans(trans(cv4)*3.9*trans(rv4))), trans(trans(cv4)*3.9*trans(rv4))); - check_equal( tmp(trans(rv4*cv4*3.9)), trans(rv4*3.9*cv4)); - check_equal( tmp(trans(trans(cv4)*trans(rv4)*3.9)), trans(trans(cv4)*3.9*trans(rv4))); - - - temp.set_size(1,1); - temp = 4; - check_equal( tmp(temp + rv4*cv4), temp + rv4*cv4); - check_equal( tmp(temp + trans(cv4)*trans(rv4)), temp + trans(cv4)*trans(rv4)); - - dlog << LTRACE << "11"; - - - - c_check_equal( tmp(conj(c_rv4)*c_cv4), conj(c_rv4)*c_cv4); - c_check_equal( tmp(conj(trans(c_cv4))*trans(c_rv4)), trans(conj(c_cv4))*trans(c_rv4)); - - c_check_equal( tmp(conj(c_rv4)*i*c_cv4), conj(c_rv4)*i*c_cv4); - c_check_equal( tmp(conj(trans(c_cv4))*i*trans(c_rv4)), trans(conj(c_cv4))*i*trans(c_rv4)); - - c_temp.set_size(1,1); - c_temp = 4; - c_check_equal( tmp(c_temp + conj(c_rv4)*c_cv4), c_temp + conj(c_rv4)*c_cv4); - c_check_equal( tmp(c_temp + trans(conj(c_cv4))*trans(c_rv4)), c_temp + trans(conj(c_cv4))*trans(c_rv4)); - - DLIB_TEST(abs((static_cast >(c_rv4*c_cv4) + i) - ((c_rv4*c_cv4)(0) + i)) < std::sqrt(std::numeric_limits::epsilon())*eps_mul ); - DLIB_TEST(max(abs((rv4*cv4 + 1.0) - ((rv4*cv4)(0) + 1.0))) < std::sqrt(std::numeric_limits::epsilon())*eps_mul); - - } - - { - matrix m(2,3), m2(6,1); - - m = 1,2,3, - 4,5,6; - - m2 = 1,2,3,4,5,6; - - DLIB_TEST(reshape_to_column_vector(m) == m2); - DLIB_TEST(reshape_to_column_vector(m+m) == m2+m2); - - } - { - matrix m(2,3); - matrix m2(6,1); - - m = 1,2,3, - 4,5,6; - - m2 = 1,2,3,4,5,6; - - DLIB_TEST(reshape_to_column_vector(m) == m2); - DLIB_TEST(reshape_to_column_vector(m+m) == m2+m2); - - } - } - - - void matrix_test ( - ) - /*! - ensures - - runs tests on the matrix stuff compliance with the specs - !*/ - { - print_spinner(); - - - { - matrix m1(2,2), m2(2,2); - - m1 = 1, 2, - 3, 4; - - m2 = 4, 5, - 6, 7; - - - DLIB_TEST(subm(tensor_product(m1,m2),range(0,1), range(0,1)) == 1*m2); - DLIB_TEST(subm(tensor_product(m1,m2),range(0,1), range(2,3)) == 2*m2); - DLIB_TEST(subm(tensor_product(m1,m2),range(2,3), range(0,1)) == 3*m2); - DLIB_TEST(subm(tensor_product(m1,m2),range(2,3), range(2,3)) == 4*m2); - } - - { - print_spinner(); - dlog << LTRACE << "testing blas stuff"; - dlog << LTRACE << " \nsmall double"; - test_blas(3,4); - print_spinner(); - dlog << LTRACE << " \nsmall float"; - test_blas(3,4); - print_spinner(); - dlog << LTRACE << " \nbig double"; - test_blas(120,131); - print_spinner(); - dlog << LTRACE << " \nbig float"; - test_blas(120,131); - print_spinner(); - dlog << LTRACE << "testing done"; - } - - - { - matrix m(3,4), ml(3,4), mu(3,4); - m = 1,2,3,4, - 4,5,6,7, - 7,8,9,0; - - ml = 1,0,0,0, - 4,5,0,0, - 7,8,9,0; - - mu = 1,2,3,4, - 0,5,6,7, - 0,0,9,0; - - - DLIB_TEST(lowerm(m) == ml); - DLIB_TEST(upperm(m) == mu); - - ml = 3,0,0,0, - 4,3,0,0, - 7,8,3,0; - - mu = 4,2,3,4, - 0,4,6,7, - 0,0,4,0; - - DLIB_TEST(lowerm(m,3) == ml); - DLIB_TEST(upperm(m,4) == mu); - - } - - { - matrix m(3,4), row(1,3), col(2,1); - m = 1,2,3,4, - 4,5,6,7, - 7,8,9,0; - - row = 4,5,6; - col = 3,6; - - DLIB_TEST(rowm(m, 1, 3) == row); - DLIB_TEST(colm(m, 2, 2) == col); - - } - - - { - std::vector v(34, 8); - std::vector v2(34, 9); - - DLIB_TEST(mat(&v[0], v.size()) == mat(v)); - DLIB_TEST(mat(&v2[0], v.size()) != mat(v)); - } - - { - std::vector v(1, 3); - std::vector v2(1, 2); - - DLIB_TEST(mat(&v[0], v.size()) == mat(v)); - DLIB_TEST(mat(&v2[0], v.size()) != mat(v)); - } - - { - matrix a(3,3), b(3,3); - a = 1, 2.5, 1, - 3, 4, 5, - 0.5, 2.2, 3; - - b = 0, 1, 0, - 1, 1, 1, - 0, 1, 1; - - DLIB_TEST((a>1) == b); - DLIB_TEST((1=1) == b); - DLIB_TEST((1<=a) == b); - - b = 0, 0, 0, - 0, 0, 0, - 0, 1, 0; - DLIB_TEST((a==2.2) == b); - DLIB_TEST((a!=2.2) == (b==0)); - DLIB_TEST((2.2==a) == b); - DLIB_TEST((2.2!=a) == (0==b)); - - b = 0, 0, 0, - 0, 0, 0, - 1, 0, 0; - DLIB_TEST((a<1) == b); - DLIB_TEST((1>a) == b); - - b = 1, 0, 1, - 0, 0, 0, - 1, 0, 0; - DLIB_TEST((a<=1) == b); - DLIB_TEST((1>=a) == b); - } - - { - matrix a, b, c; - a = randm(4,2); - - b += a; - c -= a; - - DLIB_TEST(equal(a, b)); - DLIB_TEST(equal(-a, c)); - - b += a; - c -= a; - - DLIB_TEST(equal(2*a, b)); - DLIB_TEST(equal(-2*a, c)); - - b += a + a; - c -= a + a; - - DLIB_TEST(equal(4*a, b)); - DLIB_TEST(equal(-4*a, c)); - - b.set_size(0,0); - c.set_size(0,0); - - - b += a + a; - c -= a + a; - - DLIB_TEST(equal(2*a, b)); - DLIB_TEST(equal(-2*a, c)); - } - - { - matrix a, b, c; - - a.set_size(2, 3); - b.set_size(2, 6); - c.set_size(4, 3); - - a = 1, 2, 3, - 4, 5, 6; - - b = 1, 2, 3, 1, 2, 3, - 4, 5, 6, 4, 5, 6; - - c = 1, 2, 3, - 4, 5, 6, - 1, 2, 3, - 4, 5, 6; - - DLIB_TEST(join_rows(a,a) == b); - DLIB_TEST(join_rows(a,abs(a)) == b); - DLIB_TEST(join_cols(trans(a), trans(a)) == trans(b)); - DLIB_TEST(join_cols(a,a) == c) - DLIB_TEST(join_cols(a,abs(a)) == c) - DLIB_TEST(join_rows(trans(a),trans(a)) == trans(c)) - } - - { - matrix a; - matrix b; - matrix c; - - a = 1, 2, 3, - 4, 5, 6; - - b = 1, 2, 3, 1, 2, 3, - 4, 5, 6, 4, 5, 6; - - c = 1, 2, 3, - 4, 5, 6, - 1, 2, 3, - 4, 5, 6; - - DLIB_TEST(join_rows(a,a) == b); - DLIB_TEST(join_rows(a,abs(a)) == b); - DLIB_TEST(join_cols(trans(a), trans(a)) == trans(b)); - DLIB_TEST(join_cols(a,a) == c) - DLIB_TEST(join_cols(a,abs(a)) == c) - DLIB_TEST(join_rows(trans(a),trans(a)) == trans(c)) - } - - { - matrix a; - matrix a2; - matrix b; - matrix c; - - a = 1, 2, 3, - 4, 5, 6; - - a2 = a; - - b = 1, 2, 3, 1, 2, 3, - 4, 5, 6, 4, 5, 6; - - c = 1, 2, 3, - 4, 5, 6, - 1, 2, 3, - 4, 5, 6; - - DLIB_TEST(join_rows(a,a2) == b); - DLIB_TEST(join_rows(a2,a) == b); - DLIB_TEST(join_cols(trans(a2), trans(a)) == trans(b)); - DLIB_TEST(join_cols(a2,a) == c) - DLIB_TEST(join_cols(a,a2) == c) - DLIB_TEST(join_rows(trans(a2),trans(a)) == trans(c)) - } - - { - matrix a, b; - - a.set_size(2,3); - - a = 1, 2, 3, - 4, 5, 6; - - b.set_size(3,2); - b = 1, 2, - 3, 4, - 5, 6; - - DLIB_TEST(reshape(a, 3, 2) == b); - - b.set_size(2,3); - b = 1, 4, 2, - 5, 3, 6; - - DLIB_TEST(reshape(trans(a), 2, 3) == b); - - } - - { - matrix a; - matrix b; - - a = 1, 2, 3, - 4, 5, 6; - - b.set_size(3,2); - b = 1, 2, - 3, 4, - 5, 6; - - DLIB_TEST(reshape(a, 3, 2) == b); - - b.set_size(2,3); - b = 1, 4, 2, - 5, 3, 6; - - DLIB_TEST(reshape(trans(a), 2, 3) == b); - - } - - { - std::vector v(6); - for (unsigned long i = 0; i < v.size(); ++i) - v[i] = i; - - matrix a; - a = 0, 1, 2, - 3, 4, 5; - - DLIB_TEST(mat(&v[0], 2, 3) == a); - } - - { - matrix a(3,4); - matrix b(3,1), c(1,4); - - a = 1, 2, 3, 6, - 4, 5, 6, 9, - 1, 1, 1, 3; - - b(0) = sum(rowm(a,0)); - b(1) = sum(rowm(a,1)); - b(2) = sum(rowm(a,2)); - - c(0) = sum(colm(a,0)); - c(1) = sum(colm(a,1)); - c(2) = sum(colm(a,2)); - c(3) = sum(colm(a,3)); - - DLIB_TEST(sum_cols(a) == b); - DLIB_TEST(sum_rows(a) == c); - - } - - { - matrix m(3,3); - - m = 1, 2, 3, - 4, 5, 6, - 7, 8, 9; - - DLIB_TEST(make_symmetric(m) == trans(make_symmetric(m))); - DLIB_TEST(lowerm(make_symmetric(m)) == lowerm(m)); - DLIB_TEST(upperm(make_symmetric(m)) == trans(lowerm(m))); - } - - { - matrix a; - matrix b(3,1), c(1,4); - - a = 1, 2, 3, 6, - 4, 5, 6, 9, - 1, 1, 1, 3; - - b(0) = sum(rowm(a,0)); - b(1) = sum(rowm(a,1)); - b(2) = sum(rowm(a,2)); - - c(0) = sum(colm(a,0)); - c(1) = sum(colm(a,1)); - c(2) = sum(colm(a,2)); - c(3) = sum(colm(a,3)); - - DLIB_TEST(sum_cols(a) == b); - DLIB_TEST(sum_rows(a) == c); - - } - - { - matrix m(3,4), s(3,4); - m = -2, 1, 5, -5, - 5, 5, 5, 5, - 9, 0, -4, -2; - - s = -1, 1, 1, -1, - 1, 1, 1, 1, - 1, 1, -1, -1; - - DLIB_TEST(sign(m) == s); - DLIB_TEST(sign(matrix_cast(m)) == matrix_cast(s)); - } - - } - - - void test_matrix_IO() - { - dlib::rand rnd; - print_spinner(); - - for (int i = 0; i < 400; ++i) - { - ostringstream sout; - sout.precision(20); - - matrix m1, m2, m3; - - const long r = rnd.get_random_32bit_number()%7+1; - const long c = rnd.get_random_32bit_number()%7+1; - const long num = rnd.get_random_32bit_number()%2+1; - - m1 = randm(r,c,rnd); - sout << m1; - if (num != 1) - sout << "\n" << m1; - - if (rnd.get_random_double() < 0.3) - sout << " \n"; - else if (rnd.get_random_double() < 0.3) - sout << " \n\n 3 3 3 3"; - else if (rnd.get_random_double() < 0.3) - sout << " \n \n v 3 3 3 3 3"; - - istringstream sin(sout.str()); - sin >> m2; - DLIB_TEST_MSG(equal(m1,m2), m1 << "\n***********\n" << m2); - - if (num != 1) - { - sin >> m3; - DLIB_TEST_MSG(equal(m1,m3), m1 << "\n***********\n" << m3); - } - } - - - { - istringstream sin(" 1 2\n3"); - matrix m; - DLIB_TEST(sin.good()); - sin >> m; - DLIB_TEST(!sin.good()); - } - { - istringstream sin(""); - matrix m; - DLIB_TEST(sin.good()); - sin >> m; - DLIB_TEST(!sin.good()); - } - } - - - - - class matrix_tester : public tester - { - public: - matrix_tester ( - ) : - tester ("test_matrix3", - "Runs tests on the matrix component.") - {} - - void perform_test ( - ) - { - test_matrix_IO(); - matrix_test(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/matrix4.cpp b/lib/3rdParty/dlib/include/dlib/test/matrix4.cpp deleted file mode 100644 index dd63940e..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/matrix4.cpp +++ /dev/null @@ -1,1095 +0,0 @@ -// Copyright (C) 2010 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include "../stl_checked.h" -#include "../array.h" -#include "../rand.h" - -#include "tester.h" -#include -#include - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.matrix4"); - - void matrix_test ( - ) - /*! - ensures - - runs tests on the matrix stuff compliance with the specs - !*/ - { - print_spinner(); - - { - matrix m = round(10*randm(3,3)); - matrix v = round(10*randm(3,1)); - - DLIB_TEST(equal( m*diagm(v) , m*tmp(diagm(v)) )); - DLIB_TEST(equal( scale_columns(m,v) , m*tmp(diagm(v)) )); - - DLIB_TEST(equal( diagm(v)*m , tmp(diagm(v))*m )); - DLIB_TEST(equal( scale_rows(m,v) , tmp(diagm(v))*m )); - } - - { - matrix m = round(10*randm(3,3)); - matrix v = round(10*randm(1,3)); - - DLIB_TEST(equal( m*diagm(v) , m*tmp(diagm(v)) )); - DLIB_TEST(equal( scale_columns(m,v) , m*tmp(diagm(v)) )); - - DLIB_TEST(equal( diagm(v)*m , tmp(diagm(v))*m )); - DLIB_TEST(equal( scale_rows(m,v) , tmp(diagm(v))*m )); - } - - { - matrix m = round(10*randm(3,3)); - matrix v = round(10*randm(1,3)); - - DLIB_TEST(equal( m*diagm(v) , m*tmp(diagm(v)) )); - DLIB_TEST(equal( scale_columns(m,v) , m*tmp(diagm(v)) )); - - DLIB_TEST(equal( diagm(v)*m , tmp(diagm(v))*m )); - DLIB_TEST(equal( scale_rows(m,v) , tmp(diagm(v))*m )); - } - - { - matrix m = round(10*randm(3,3)); - matrix v = round(10*randm(1,3)); - - DLIB_TEST(equal( m*diagm(v) , m*tmp(diagm(v)) )); - DLIB_TEST(equal( scale_columns(m,v) , m*tmp(diagm(v)) )); - - DLIB_TEST(equal( diagm(v)*m , tmp(diagm(v))*m )); - DLIB_TEST(equal( scale_rows(m,v) , tmp(diagm(v))*m )); - } - - - { - matrix m = round(10*randm(3,3)); - matrix v = round(10*randm(1,3)); - - DLIB_TEST(equal( m*diagm(v) , m*tmp(diagm(v)) )); - DLIB_TEST(equal( scale_columns(m,v) , m*tmp(diagm(v)) )); - - DLIB_TEST(equal( diagm(v)*m , tmp(diagm(v))*m )); - DLIB_TEST(equal( scale_rows(m,v) , tmp(diagm(v))*m )); - } - - { - matrix m = round(10*randm(3,3)); - matrix v = round(10*randm(3,1)); - - DLIB_TEST(equal( m*diagm(v) , m*tmp(diagm(v)) )); - DLIB_TEST(equal( scale_columns(m,v) , m*tmp(diagm(v)) )); - - DLIB_TEST(equal( diagm(v)*m , tmp(diagm(v))*m )); - DLIB_TEST(equal( scale_rows(m,v) , tmp(diagm(v))*m )); - } - - - { - matrix m = round(10*randm(3,3)); - matrix v = round(10*randm(3,1)); - - DLIB_TEST(equal( m*diagm(v) , m*tmp(diagm(v)) )); - DLIB_TEST(equal( scale_columns(m,v) , m*tmp(diagm(v)) )); - - DLIB_TEST(equal( diagm(v)*m , tmp(diagm(v))*m )); - DLIB_TEST(equal( scale_rows(m,v) , tmp(diagm(v))*m )); - } - - { - matrix m = round(10*randm(3,3)); - matrix v = round(10*randm(3,1)); - - DLIB_TEST(equal( m*diagm(v) , m*tmp(diagm(v)) )); - DLIB_TEST(equal( scale_columns(m,v) , m*tmp(diagm(v)) )); - - DLIB_TEST(equal( diagm(v)*m , tmp(diagm(v))*m )); - DLIB_TEST(equal( scale_rows(m,v) , tmp(diagm(v))*m )); - } - - - { - matrix m = round(10*randm(3,3)); - matrix v = round(10*randm(3,1)); - - DLIB_TEST(equal( m*diagm(v) , m*tmp(diagm(v)) )); - DLIB_TEST(equal( scale_columns(m,v) , m*tmp(diagm(v)) )); - - DLIB_TEST(equal( diagm(v)*m , tmp(diagm(v))*m )); - DLIB_TEST(equal( scale_rows(m,v) , tmp(diagm(v))*m )); - } - - { - matrix m = round(10*randm(3,5)); - matrix v1 = round(10*randm(5,1)); - matrix v2 = round(10*randm(3,1)); - - DLIB_TEST(equal( m*diagm(v1) , m*tmp(diagm(v1)) )); - DLIB_TEST(equal( scale_columns(m,v1) , m*tmp(diagm(v1)) )); - - DLIB_TEST(equal( diagm(v2)*m , tmp(diagm(v2))*m )); - DLIB_TEST(equal( scale_rows(m,v2) , tmp(diagm(v2))*m )); - } - - { - matrix m = round(10*randm(3,5)); - matrix v1 = round(10*randm(5,1)); - matrix v2 = round(10*randm(3,1)); - - DLIB_TEST(equal( m*diagm(v1) , m*tmp(diagm(v1)) )); - DLIB_TEST(equal( scale_columns(m,v1) , m*tmp(diagm(v1)) )); - - DLIB_TEST(equal( diagm(v2)*m , tmp(diagm(v2))*m )); - DLIB_TEST(equal( scale_rows(m,v2) , tmp(diagm(v2))*m )); - } - - } - - void test_stuff() - { - print_spinner(); - - { - matrix m(3,3), lr(3,3), ud(3,3); - - m = 1,2,3, - 4,5,6, - 7,8,9; - - - lr = 3,2,1, - 6,5,4, - 9,8,7; - - ud = 7,8,9, - 4,5,6, - 1,2,3; - - DLIB_TEST(lr == fliplr(m)); - DLIB_TEST(ud == flipud(m)); - } - { - matrix m(3,2), lr(3,2), ud(3,2); - - m = 1,2, - 3,4, - 5,6; - - lr = 2,1, - 4,3, - 6,5; - - ud = 5,6, - 3,4, - 1,2; - - DLIB_TEST(lr == fliplr(m)); - DLIB_TEST(ud == flipud(m)); - } - - { - matrix a, b; - - a = matrix_cast(round(10*randm(3,3))); - b = a; - - b *= b; - DLIB_TEST(b == a*a); - } - - { - matrix m(2,3), m2(2,3); - - m = 1,2,3, - 4,5,6; - - - m2 = 3,4,5, - 6,7,8; - - DLIB_TEST(m + 2 == m2); - DLIB_TEST(2 + m == m2); - - m += 2; - DLIB_TEST(m == m2); - m -= 2; - - m2 = 0,1,2, - 3,4,5; - - DLIB_TEST(m - 1 == m2); - - m -= 1; - DLIB_TEST(m == m2); - m += 1; - - - m2 = 5,4,3, - 2,1,0; - - DLIB_TEST(6 - m == m2); - } - - { - matrix m(2,3), m2(2,3); - - m = 1,2,3, - 4,5,6; - - - m2 = 3,4,5, - 6,7,8; - - DLIB_TEST(m + 2 == m2); - DLIB_TEST(2 + m == m2); - - m += 2; - DLIB_TEST(m == m2); - m -= 2; - - m2 = 0,1,2, - 3,4,5; - - DLIB_TEST(m - 1 == m2); - - m -= 1; - DLIB_TEST(m == m2); - m += 1; - - - m2 = 5,4,3, - 2,1,0; - - DLIB_TEST(6 - m == m2); - } - - { - matrix m(2,3), m2(2,3); - - m = 1,2,3, - 4,5,6; - - - m2 = 3,4,5, - 6,7,8; - - DLIB_TEST(m + 2 == m2); - DLIB_TEST(2 + m == m2); - - m += 2; - DLIB_TEST(m == m2); - m -= 2; - - m2 = 0,1,2, - 3,4,5; - - DLIB_TEST(m - 1 == m2); - - m -= 1; - DLIB_TEST(m == m2); - m += 1; - - - m2 = 5,4,3, - 2,1,0; - - DLIB_TEST(6 - m == m2); - } - - { - matrix m, m2; - - m = 1,2,3, - 4,5,6; - - - m2 = 3,4,5, - 6,7,8; - - DLIB_TEST(m + 2 == m2); - DLIB_TEST(2 + m == m2); - - m += 2; - DLIB_TEST(m == m2); - m -= 2; - - m2 = 0,1,2, - 3,4,5; - - DLIB_TEST(m - 1 == m2); - - m -= 1; - DLIB_TEST(m == m2); - m += 1; - - - m2 = 5,4,3, - 2,1,0; - - DLIB_TEST(6 - m == m2); - } - - { - matrix m(2,3), m2(3,2); - - m = 1,2,3, - 4,5,6; - - m2 = 2,5, - 3,6, - 4,7; - - DLIB_TEST(trans(m+1) == m2); - DLIB_TEST(trans(m)+1 == m2); - DLIB_TEST(1+trans(m) == m2); - DLIB_TEST(1+m-1 == m); - - m = trans(m+1); - DLIB_TEST(m == m2); - m = trans(m-1); - DLIB_TEST(trans(m+1) == m2); - m = trans(m)+1; - DLIB_TEST(m == m2); - } - - { - matrix d(3,1), di(3,1); - matrix m(3,3); - - m = 1,2,3, - 4,5,6, - 7,8,9; - - d = 1,2,3; - - di = 1, 1/2.0, 1/3.0; - - DLIB_TEST(inv(diagm(d)) == diagm(di)); - DLIB_TEST(pinv(diagm(d)) == diagm(di)); - DLIB_TEST(inv(diagm(d))*m == tmp(diagm(di))*m); - DLIB_TEST(m*inv(diagm(d)) == m*tmp(diagm(di))); - - DLIB_TEST(equal(inv(diagm(d)) + m , tmp(diagm(di)) + m)); - DLIB_TEST(equal(m + inv(diagm(d)) , tmp(diagm(di)) + m)); - - DLIB_TEST((m + identity_matrix(3) == m + tmp(identity_matrix(3)))); - DLIB_TEST((m + identity_matrix() == m + tmp(identity_matrix()))); - DLIB_TEST((m + 2*identity_matrix(3) == m + 2*tmp(identity_matrix(3)))); - DLIB_TEST((m + 2*identity_matrix() == m + 2*tmp(identity_matrix()))); - DLIB_TEST((m + identity_matrix(3)*2 == m + 2*tmp(identity_matrix(3)))); - DLIB_TEST((m + identity_matrix()*2 == m + 2*tmp(identity_matrix()))); - - DLIB_TEST((identity_matrix(3) + m == m + tmp(identity_matrix(3)))); - DLIB_TEST((identity_matrix() + m == m + tmp(identity_matrix()))); - DLIB_TEST((2*identity_matrix(3) + m == m + 2*tmp(identity_matrix(3)))); - DLIB_TEST((2*identity_matrix() + m == m + 2*tmp(identity_matrix()))); - - } - { - matrix d(3,1), di(3,1); - matrix m(3,3); - - m = 1,2,3, - 4,5,6, - 7,8,9; - - d = 1,2,3; - - di = 1, 1/2.0, 1/3.0; - - DLIB_TEST(equal(inv(diagm(d)) , diagm(di))); - DLIB_TEST(equal(inv(diagm(d)) , diagm(di))); - DLIB_TEST(equal(inv(diagm(d))*m , tmp(diagm(di))*m)); - DLIB_TEST(equal(m*inv(diagm(d)) , m*tmp(diagm(di)))); - - DLIB_TEST_MSG(equal(inv(diagm(d)) + m , tmp(diagm(di)) + m), - (inv(diagm(d)) + m) - (tmp(diagm(di)) + m) ); - DLIB_TEST(equal(m + inv(diagm(d)) , tmp(diagm(di)) + m)); - - - DLIB_TEST((m + identity_matrix(3) == m + tmp(identity_matrix(3)))); - DLIB_TEST((m + identity_matrix() == m + tmp(identity_matrix()))); - DLIB_TEST((m + 2*identity_matrix(3) == m + 2*tmp(identity_matrix(3)))); - DLIB_TEST((m + 2*identity_matrix() == m + 2*tmp(identity_matrix()))); - DLIB_TEST((m + identity_matrix(3)*2 == m + 2*tmp(identity_matrix(3)))); - DLIB_TEST((m + identity_matrix()*2 == m + 2*tmp(identity_matrix()))); - - DLIB_TEST((identity_matrix(3) + m == m + tmp(identity_matrix(3)))); - DLIB_TEST((identity_matrix() + m == m + tmp(identity_matrix()))); - DLIB_TEST((2*identity_matrix(3) + m == m + 2*tmp(identity_matrix(3)))); - DLIB_TEST((2*identity_matrix() + m == m + 2*tmp(identity_matrix()))); - } - - { - matrix d(1,3), di(1,3); - matrix m(3,3); - - m = 1,2,3, - 4,5,6, - 7,8,9; - - d = 1,2,3; - - di = 1, 1/2.0, 1/3.0; - - DLIB_TEST(equal(inv(diagm(d)) , diagm(di))); - DLIB_TEST(equal(inv(diagm(d)) , diagm(di))); - DLIB_TEST(equal(inv(diagm(d))*m , tmp(diagm(di))*m)); - DLIB_TEST(equal(m*inv(diagm(d)) , m*tmp(diagm(di)))); - - DLIB_TEST(equal(inv(diagm(d)) + m , tmp(diagm(di)) + m)); - DLIB_TEST(equal(m + inv(diagm(d)) , tmp(diagm(di)) + m)); - - - DLIB_TEST((m + identity_matrix(3) == m + tmp(identity_matrix(3)))); - DLIB_TEST((m + identity_matrix() == m + tmp(identity_matrix()))); - DLIB_TEST((m + 2*identity_matrix(3) == m + 2*tmp(identity_matrix(3)))); - DLIB_TEST((m + 2*identity_matrix() == m + 2*tmp(identity_matrix()))); - DLIB_TEST((m + identity_matrix(3)*2 == m + 2*tmp(identity_matrix(3)))); - DLIB_TEST((m + identity_matrix()*2 == m + 2*tmp(identity_matrix()))); - - DLIB_TEST((identity_matrix(3) + m == m + tmp(identity_matrix(3)))); - DLIB_TEST((identity_matrix() + m == m + tmp(identity_matrix()))); - DLIB_TEST((2*identity_matrix(3) + m == m + 2*tmp(identity_matrix(3)))); - DLIB_TEST((2*identity_matrix() + m == m + 2*tmp(identity_matrix()))); - } - - { - matrix d(1,3), di(1,3); - matrix m(3,3); - - m = 1,2,3, - 4,5,6, - 7,8,9; - - d = 1,2,3; - - di = 1, 1/2.0, 1/3.0; - - DLIB_TEST(equal(inv(diagm(d)) , diagm(di))); - DLIB_TEST(equal(inv(diagm(d)) , diagm(di))); - DLIB_TEST(equal(inv(diagm(d))*m , tmp(diagm(di))*m)); - DLIB_TEST(equal(m*inv(diagm(d)) , m*tmp(diagm(di)))); - - DLIB_TEST(equal(inv(diagm(d)) + m , tmp(diagm(di)) + m)); - DLIB_TEST(equal(m + inv(diagm(d)) , tmp(diagm(di)) + m)); - - - DLIB_TEST((m + identity_matrix(3) == m + tmp(identity_matrix(3)))); - DLIB_TEST((m + identity_matrix() == m + tmp(identity_matrix()))); - DLIB_TEST((m + 2*identity_matrix(3) == m + 2*tmp(identity_matrix(3)))); - DLIB_TEST((m + 2*identity_matrix() == m + 2*tmp(identity_matrix()))); - DLIB_TEST((m + identity_matrix(3)*2 == m + 2*tmp(identity_matrix(3)))); - DLIB_TEST((m + identity_matrix()*2 == m + 2*tmp(identity_matrix()))); - - DLIB_TEST((identity_matrix(3) + m == m + tmp(identity_matrix(3)))); - DLIB_TEST((identity_matrix() + m == m + tmp(identity_matrix()))); - DLIB_TEST((2*identity_matrix(3) + m == m + 2*tmp(identity_matrix(3)))); - DLIB_TEST((2*identity_matrix() + m == m + 2*tmp(identity_matrix()))); - } - - - { - matrix d1, d2; - - d1 = 1,2,3; - - d2 = 2,3,4; - - matrix ans; - ans = 2, 0, 0, - 0, 6, 0, - 0, 0, 12; - - DLIB_TEST(ans == diagm(d1)*diagm(d2)); - } - - - dlib::rand rnd; - for (int i = 0; i < 1; ++i) - { - matrix d1 = randm(4,1,rnd); - matrix d2 = randm(5,1,rnd); - - matrix m = randm(4,5,rnd); - - DLIB_TEST_MSG(equal(pointwise_multiply(d1*trans(d2), m) , diagm(d1)*m*diagm(d2)), - pointwise_multiply(d1*trans(d2), m) - diagm(d1)*m*diagm(d2) - ); - DLIB_TEST(equal(pointwise_multiply(d1*trans(d2), m) , diagm(d1)*(m*diagm(d2)))); - DLIB_TEST(equal(pointwise_multiply(d1*trans(d2), m) , (diagm(d1)*m)*diagm(d2))); - - DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans(reciprocal(d2)), m) , inv(diagm(d1))*m*inv(diagm(d2)))); - DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans(reciprocal(d2)), m) , inv(diagm(d1))*(m*inv(diagm(d2))))); - DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans(reciprocal(d2)), m) , (inv(diagm(d1))*m)*inv(diagm(d2)))); - - DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans((d2)), m) , inv(diagm(d1))*m*(diagm(d2)))); - DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans((d2)), m) , inv(diagm(d1))*(m*(diagm(d2))))); - DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans((d2)), m) , (inv(diagm(d1))*m)*(diagm(d2)))); - - DLIB_TEST(equal(pointwise_multiply((d1)*trans(reciprocal(d2)), m) , (diagm(d1))*m*inv(diagm(d2)))); - DLIB_TEST(equal(pointwise_multiply((d1)*trans(reciprocal(d2)), m) , (diagm(d1))*(m*inv(diagm(d2))))); - DLIB_TEST(equal(pointwise_multiply((d1)*trans(reciprocal(d2)), m) , ((diagm(d1))*m)*inv(diagm(d2)))); - } - for (int i = 0; i < 1; ++i) - { - matrix d1 = randm(4,1,rnd); - matrix d2 = randm(5,1,rnd); - - matrix m = randm(4,5,rnd); - - DLIB_TEST(equal(pointwise_multiply(d1*trans(d2), m) , diagm(d1)*m*diagm(d2))); - DLIB_TEST(equal(pointwise_multiply(d1*trans(d2), m) , diagm(d1)*(m*diagm(d2)))); - DLIB_TEST(equal(pointwise_multiply(d1*trans(d2), m) , (diagm(d1)*m)*diagm(d2))); - - DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans(reciprocal(d2)), m) , inv(diagm(d1))*m*inv(diagm(d2)))); - DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans(reciprocal(d2)), m) , inv(diagm(d1))*(m*inv(diagm(d2))))); - DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans(reciprocal(d2)), m) , (inv(diagm(d1))*m)*inv(diagm(d2)))); - - DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans((d2)), m) , inv(diagm(d1))*m*(diagm(d2)))); - DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans((d2)), m) , inv(diagm(d1))*(m*(diagm(d2))))); - DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans((d2)), m) , (inv(diagm(d1))*m)*(diagm(d2)))); - - DLIB_TEST(equal(pointwise_multiply((d1)*trans(reciprocal(d2)), m) , (diagm(d1))*m*inv(diagm(d2)))); - DLIB_TEST(equal(pointwise_multiply((d1)*trans(reciprocal(d2)), m) , (diagm(d1))*(m*inv(diagm(d2))))); - DLIB_TEST(equal(pointwise_multiply((d1)*trans(reciprocal(d2)), m) , ((diagm(d1))*m)*inv(diagm(d2)))); - } - for (int i = 0; i < 1; ++i) - { - matrix d1 = randm(4,1,rnd); - matrix d2 = randm(5,1,rnd); - - matrix m = randm(4,5,rnd); - - DLIB_TEST(equal(pointwise_multiply(d1*trans(d2), m) , diagm(d1)*m*diagm(d2))); - DLIB_TEST(equal(pointwise_multiply(d1*trans(d2), m) , diagm(d1)*(m*diagm(d2)))); - DLIB_TEST(equal(pointwise_multiply(d1*trans(d2), m) , (diagm(d1)*m)*diagm(d2))); - - DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans(reciprocal(d2)), m) , inv(diagm(d1))*m*inv(diagm(d2)))); - DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans(reciprocal(d2)), m) , inv(diagm(d1))*(m*inv(diagm(d2))))); - DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans(reciprocal(d2)), m) , (inv(diagm(d1))*m)*inv(diagm(d2)))); - - DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans((d2)), m) , inv(diagm(d1))*m*(diagm(d2)))); - DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans((d2)), m) , inv(diagm(d1))*(m*(diagm(d2))))); - DLIB_TEST(equal(pointwise_multiply(reciprocal(d1)*trans((d2)), m) , (inv(diagm(d1))*m)*(diagm(d2)))); - - DLIB_TEST(equal(pointwise_multiply((d1)*trans(reciprocal(d2)), m) , (diagm(d1))*m*inv(diagm(d2)))); - DLIB_TEST(equal(pointwise_multiply((d1)*trans(reciprocal(d2)), m) , (diagm(d1))*(m*inv(diagm(d2))))); - DLIB_TEST(equal(pointwise_multiply((d1)*trans(reciprocal(d2)), m) , ((diagm(d1))*m)*inv(diagm(d2)))); - } - - - - { - for (int i = 0; i < 5; ++i) - { - matrix m = randm(3,4) + 1; - - DLIB_TEST(equal(1.0/m , reciprocal(m))); - DLIB_TEST(equal(0.0/m , zeros_matrix(3,4))); - } - } - - { - matrix m(2,3); - m = 1,2,3, - 4,5,6; - matrix M(2,3); - M = m; - - DLIB_TEST(upperbound(m,6) == M); - DLIB_TEST(upperbound(m,60) == M); - DLIB_TEST(lowerbound(m,-2) == M); - DLIB_TEST(lowerbound(m,0) == M); - - M = 2,2,3, - 4,5,6; - DLIB_TEST(lowerbound(m,2) == M); - - M = 0,0,0, - 0,0,0; - DLIB_TEST(upperbound(m,0) == M); - - M = 1,2,3, - 3,3,3; - DLIB_TEST(upperbound(m,3) == M); - } - } - - - - template < - long D1, - long D2, - long D3, - long D4 - > - void test_conv() - { - dlog << LINFO << D1 << " " << D2 << " " << D3 << " " << D4; - matrix a(1,1); - matrix b(2,2); - matrix c(3,3); - matrix d(4,1); - - a = 4; - - b = 1,2, - 3,4; - - c = 1,2,3, - 4,5,6, - 7,8,9; - - d = 1, - 2, - 3, - 4; - - matrix temp(4,4), temp2; - temp = 1, 4, 7, 6, - 7, 23, 33, 24, - 19, 53, 63, 42, - 21, 52, 59, 36; - - DLIB_TEST(conv(b,c) == temp); - DLIB_TEST(conv(c,b) == temp); - DLIB_TEST(xcorr(c,flip(b)) == temp); - - temp.set_size(2,2); - temp = 23, 33, - 53, 63; - DLIB_TEST(conv_same(b,c) == temp); - DLIB_TEST(xcorr_same(b,flip(c)) == temp); - - temp2.set_size(2,2); - temp2 = 63, 53, - 33, 23; - DLIB_TEST(flip(temp) == temp2); - DLIB_TEST(flip(temp) == fliplr(flipud(temp))); - - DLIB_TEST(conv_valid(b,c).nr() == 0); - DLIB_TEST(conv_valid(b,c).nc() == 0); - - DLIB_TEST(conv_valid(c,b) == temp); - DLIB_TEST(xcorr_valid(c,flip(b)) == temp); - - temp.set_size(1,1); - temp = 16; - - DLIB_TEST(conv(a,a) == temp); - DLIB_TEST(conv_same(a,a) == temp); - DLIB_TEST(conv_valid(a,a) == temp); - DLIB_TEST(xcorr(a,a) == temp); - DLIB_TEST(xcorr_same(a,a) == temp); - DLIB_TEST(xcorr_valid(a,a) == temp); - - temp.set_size(0,0); - DLIB_TEST(conv(temp,temp).nr() == 0); - DLIB_TEST(conv(temp,temp).nc() == 0); - DLIB_TEST(conv_same(temp,temp).nr() == 0); - DLIB_TEST(conv_same(temp,temp).nc() == 0); - DLIB_TEST_MSG(conv_valid(temp,temp).nr() == 0, conv_valid(temp,temp).nr()); - DLIB_TEST(conv_valid(temp,temp).nc() == 0); - DLIB_TEST(conv(c,temp).nr() == 0); - DLIB_TEST(conv(c,temp).nc() == 0); - DLIB_TEST(conv_same(c,temp).nr() == 0); - DLIB_TEST(conv_same(c,temp).nc() == 0); - DLIB_TEST(conv_valid(c,temp).nr() == 0); - DLIB_TEST(conv_valid(c,temp).nc() == 0); - DLIB_TEST(conv(temp,c).nr() == 0); - DLIB_TEST(conv(temp,c).nc() == 0); - DLIB_TEST(conv_same(temp,c).nr() == 0); - DLIB_TEST(conv_same(temp,c).nc() == 0); - DLIB_TEST(conv_valid(temp,c).nr() == 0); - DLIB_TEST(conv_valid(temp,c).nc() == 0); - - temp.set_size(5,2); - temp = 1, 2, - 5, 8, - 9, 14, - 13, 20, - 12, 16; - DLIB_TEST(conv(b,d) == temp); - DLIB_TEST(xcorr(b,flip(d)) == temp); - - temp.set_size(2,2); - temp = 9, 14, - 13, 20; - DLIB_TEST(conv_same(b,d) == temp); - DLIB_TEST(xcorr_same(b,flip(d)) == temp); - - DLIB_TEST(conv_valid(b,d).nr() == 0); - DLIB_TEST(xcorr_valid(b,flip(d)).nr() == 0); - DLIB_TEST_MSG(conv_valid(b,d).nc() == 0, conv_valid(b,d).nc()); - DLIB_TEST(xcorr_valid(b,flip(d)).nc() == 0); - - temp.set_size(5,5); - temp = 1, 4, 10, 12, 9, - 8, 26, 56, 54, 36, - 30, 84, 165, 144, 90, - 56, 134, 236, 186, 108, - 49, 112, 190, 144, 81; - - DLIB_TEST(conv(c,c) == temp); - DLIB_TEST(xcorr(c,flip(c)) == temp); - matrix temp3 = c; - temp3 = conv(temp3,c); - DLIB_TEST(temp3 == temp); - - temp3 = c; - temp3 = conv(c,temp3); - DLIB_TEST(temp3 == temp); - - - temp.set_size(3,3); - temp = 26, 56, 54, - 84, 165, 144, - 134, 236, 186; - DLIB_TEST(conv_same(c,c) == temp); - DLIB_TEST(xcorr_same(c,flip(c)) == temp); - temp3 = c; - temp3 = conv_same(c,temp3); - DLIB_TEST(temp3 == temp); - temp3 = c; - temp3 = conv_same(temp3,c); - DLIB_TEST(temp3 == temp); - - temp.set_size(1,1); - temp = 165; - DLIB_TEST(conv_valid(c,c) == temp); - DLIB_TEST(xcorr_valid(c,flip(c)) == temp); - temp3 = c; - temp3 = conv_valid(c,temp3); - DLIB_TEST(temp3 == temp); - temp3 = c; - temp3 = conv_valid(temp3,c); - DLIB_TEST(temp3 == temp); - - - for (int i = 0; i < 3; ++i) - { - dlib::rand rnd; - matrix > a, b; - a = complex_matrix(matrix_cast(round(20*randm(2,7,rnd))), - matrix_cast(round(20*randm(2,7,rnd)))); - b = complex_matrix(matrix_cast(round(20*randm(3,2,rnd))), - matrix_cast(round(20*randm(3,2,rnd)))); - - DLIB_TEST(xcorr(a,b) == conv(a, flip(conj(b)))); - DLIB_TEST(xcorr_valid(a,b) == conv_valid(a, flip(conj(b)))); - DLIB_TEST(xcorr_same(a,b) == conv_same(a, flip(conj(b)))); - } - } - - void test_complex() - { - matrix > a, b; - - a = complex_matrix(linspace(1,7,7), linspace(2,8,7)); - b = complex_matrix(linspace(4,10,7), linspace(2,8,7)); - - DLIB_TEST(mean(a) == complex(4, 5)); - } - - void test_setsubs() - { - { - matrix m(3,3); - m = 0; - - set_colm(m,0) += 1; - set_rowm(m,0) += 1; - set_subm(m,1,1,2,2) += 5; - - matrix m2(3,3); - m2 = 2, 1, 1, - 1, 5, 5, - 1, 5, 5; - - DLIB_TEST(m == m2); - - set_colm(m,0) -= 1; - set_rowm(m,0) -= 1; - set_subm(m,1,1,2,2) -= 5; - - m2 = 0; - DLIB_TEST(m == m2); - - matrix r; - matrix c; - matrix b; - r = 1,2,3; - - c = 2, - 3, - 4; - - b = 2,3, - 4,5; - - set_colm(m,1) += c; - set_rowm(m,1) += r; - set_subm(m,1,1,2,2) += b; - - m2 = 0, 2, 0, - 1, 7, 6, - 0, 8, 5; - - DLIB_TEST(m2 == m); - - set_colm(m,1) -= c; - set_rowm(m,1) -= r; - set_subm(m,1,1,2,2) -= b; - - m2 = 0; - DLIB_TEST(m2 == m); - - - // check that the code path for destructive aliasing works right. - m = 2*identity_matrix(3); - set_colm(m,1) += m*c; - m2 = 2, 4, 0, - 0, 8, 0, - 0, 8, 2; - DLIB_TEST(m == m2); - - m = 2*identity_matrix(3); - set_colm(m,1) -= m*c; - m2 = 2, -4, 0, - 0, -4, 0, - 0, -8, 2; - DLIB_TEST(m == m2); - - m = 2*identity_matrix(3); - set_rowm(m,1) += r*m; - m2 = 2, 0, 0, - 2, 6, 6, - 0, 0, 2; - DLIB_TEST(m == m2); - - m = 2*identity_matrix(3); - set_rowm(m,1) -= r*m; - m2 = 2, 0, 0, - -2, -2, -6, - 0, 0, 2; - DLIB_TEST(m == m2); - - m = identity_matrix(3); - const rectangle rect(0,0,1,1); - set_subm(m,rect) += subm(m,rect)*b; - m2 = 3, 3, 0, - 4, 6, 0, - 0, 0, 1; - DLIB_TEST(m == m2); - - m = identity_matrix(3); - set_subm(m,rect) -= subm(m,rect)*b; - m2 = -1, -3, 0, - -4, -4, 0, - 0, 0, 1; - DLIB_TEST(m == m2); - - } - - { - matrix a, b; - a = 2; - b = 3; - DLIB_TEST(dot(a,b) == 6); - } - { - matrix a; - matrix b(1); - a = 2; - b = 3; - DLIB_TEST(dot(a,b) == 6); - DLIB_TEST(dot(b,a) == 6); - } - { - matrix a; - matrix b(1); - a = 2; - b = 3; - DLIB_TEST(dot(a,b) == 6); - DLIB_TEST(dot(b,a) == 6); - } - } - - template - std::vector tovect1(const T& m) - { - std::vector temp; - for (typename T::const_iterator i = m.begin(); i != m.end(); ++i) - { - temp.push_back(*i); - } - return temp; - } - - template - std::vector tovect2(const T& m) - { - std::vector temp; - for (typename T::const_iterator i = m.begin(); i != m.end(); i++) - { - temp.push_back(*i); - } - return temp; - } - - template - std::vector tovect3(const T& m_) - { - matrix m(m_); - std::vector temp; - for (matrix::iterator i = m.begin(); i != m.end(); ++i) - { - temp.push_back(*i); - } - return temp; - } - - template - std::vector tovect4(const T& m_) - { - matrix m(m_); - std::vector temp; - for (matrix::iterator i = m.begin(); i != m.end(); i++) - { - temp.push_back(*i); - } - return temp; - } - - void test_iterators() - { - matrix m(3,2); - m = 1,2,3, - 4,5,6; - - std::vector v1 = tovect1(m); - std::vector v2 = tovect2(m); - std::vector v3 = tovect3(m); - std::vector v4 = tovect4(m); - - std::vector v5 = tovect1(m+m); - std::vector v6 = tovect2(m+m); - std::vector v7 = tovect3(m+m); - std::vector v8 = tovect4(m+m); - - - std::vector a1, a2; - for (int i = 1; i <= 6; ++i) - { - a1.push_back(i); - a2.push_back(i*2); - } - - DLIB_TEST(max(abs(mat(v1) - mat(a1))) == 0); - DLIB_TEST(max(abs(mat(v2) - mat(a1))) == 0); - DLIB_TEST(max(abs(mat(v3) - mat(a1))) == 0); - DLIB_TEST(max(abs(mat(v4) - mat(a1))) == 0); - - DLIB_TEST(max(abs(mat(v5) - mat(a2))) == 0); - DLIB_TEST(max(abs(mat(v6) - mat(a2))) == 0); - DLIB_TEST(max(abs(mat(v7) - mat(a2))) == 0); - DLIB_TEST(max(abs(mat(v8) - mat(a2))) == 0); - } - - void test_linpiece() - { - matrix temp = linpiece(5, linspace(-1, 9, 2)); - DLIB_CASSERT(temp.size() == 1,""); - DLIB_CASSERT(std::abs(temp(0) - 6) < 1e-13,""); - - temp = linpiece(5, linspace(-1, 9, 6)); - DLIB_CASSERT(temp.size() == 5,""); - DLIB_CASSERT(std::abs(temp(0) - 2) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(1) - 2) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(2) - 2) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(3) - 0) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(4) - 0) < 1e-13,""); - - temp = linpiece(4, linspace(-1, 9, 6)); - DLIB_CASSERT(temp.size() == 5,""); - DLIB_CASSERT(std::abs(temp(0) - 2) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(1) - 2) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(2) - 1) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(3) - 0) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(4) - 0) < 1e-13,""); - - temp = linpiece(40, linspace(-1, 9, 6)); - DLIB_CASSERT(temp.size() == 5,""); - DLIB_CASSERT(std::abs(temp(0) - 2) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(1) - 2) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(2) - 2) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(3) - 2) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(4) - 2) < 1e-13,""); - - temp = linpiece(-40, linspace(-1, 9, 6)); - DLIB_CASSERT(temp.size() == 5,""); - DLIB_CASSERT(std::abs(temp(0) - 0) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(1) - 0) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(2) - 0) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(3) - 0) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(4) - 0) < 1e-13,""); - - temp = linpiece(0, linspace(-1, 9, 6)); - DLIB_CASSERT(temp.size() == 5,""); - DLIB_CASSERT(std::abs(temp(0) - 1) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(1) - 0) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(2) - 0) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(3) - 0) < 1e-13,""); - DLIB_CASSERT(std::abs(temp(4) - 0) < 1e-13,""); - - } - - class matrix_tester : public tester - { - public: - matrix_tester ( - ) : - tester ("test_matrix4", - "Runs tests on the scale_rows and scale_columns functions.") - {} - - void perform_test ( - ) - { - test_iterators(); - test_setsubs(); - - test_conv<0,0,0,0>(); - test_conv<1,2,3,4>(); - - test_stuff(); - for (int i = 0; i < 10; ++i) - matrix_test(); - - test_complex(); - test_linpiece(); - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/matrix_chol.cpp b/lib/3rdParty/dlib/include/dlib/test/matrix_chol.cpp deleted file mode 100644 index b46c4866..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/matrix_chol.cpp +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (C) 2009 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include "../stl_checked.h" -#include "../array.h" -#include "../rand.h" -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.matrix_chol"); - - dlib::rand rnd; - -// ---------------------------------------------------------------------------------------- - - template - const matrix symm(const mat_type& m) { return m*trans(m); } - -// ---------------------------------------------------------------------------------------- - - template - const matrix randmat(long r, long c) - { - matrix m(r,c); - for (long row = 0; row < m.nr(); ++row) - { - for (long col = 0; col < m.nc(); ++col) - { - m(row,col) = static_cast(rnd.get_random_double()); - } - } - - return m; - } - - template - const matrix randmat() - { - matrix m; - for (long row = 0; row < m.nr(); ++row) - { - for (long col = 0; col < m.nc(); ++col) - { - m(row,col) = static_cast(rnd.get_random_double()); - } - } - - return m; - } - -// ---------------------------------------------------------------------------------------- - - template - void test_cholesky ( const matrix_type& m) - { - typedef typename matrix_type::type type; - const type eps = 10*max(abs(m))*sqrt(std::numeric_limits::epsilon()); - dlog << LDEBUG << "test_cholesky(): " << m.nr() << " x " << m.nc() << " eps: " << eps; - print_spinner(); - - - cholesky_decomposition test(m); - - // none of the matrices we should be passing in to test_cholesky() should be non-spd. - DLIB_TEST(test.is_spd() == true); - - type temp; - DLIB_TEST_MSG( (temp= max(abs(test.get_l()*trans(test.get_l()) - m))) < eps,temp); - - { - matrix mat = chol(m); - DLIB_TEST_MSG( (temp= max(abs(mat*trans(mat) - m))) < eps,temp); - } - - - matrix m2; - matrix col; - - m2 = identity_matrix(m.nr()); - DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2))); - m2 = randmat(m.nr(),5); - DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2))); - m2 = randmat(m.nr(),1); - DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2))); - col = randmat(m.nr(),1); - DLIB_TEST_MSG(equal(m*test.solve(col), col,eps),max(abs(m*test.solve(m2)- m2))); - - // now make us a non-spd matrix - if (m.nr() > 2) - { - matrix sm(lowerm(m)); - sm(1,1) = 0; - - cholesky_decomposition test2(sm); - DLIB_TEST_MSG(test2.is_spd() == false, test2.get_l()); - - - cholesky_decomposition test3(sm*trans(sm)); - DLIB_TEST_MSG(test3.is_spd() == false, test3.get_l()); - - sm = sm*trans(sm); - sm(1,1) = 5; - sm(1,0) -= 1; - cholesky_decomposition test4(sm); - DLIB_TEST_MSG(test4.is_spd() == false, test4.get_l()); - } - - } - -// ---------------------------------------------------------------------------------------- - - void matrix_test_double() - { - - test_cholesky(uniform_matrix(1,1,1) + 10*symm(randmat(1,1))); - test_cholesky(uniform_matrix(2,2,1) + 10*symm(randmat(2,2))); - test_cholesky(uniform_matrix(3,3,1) + 10*symm(randmat(3,3))); - test_cholesky(uniform_matrix(4,4,1) + 10*symm(randmat(4,4))); - test_cholesky(uniform_matrix(15,15,1) + 10*symm(randmat(15,15))); - test_cholesky(uniform_matrix(101,101,1) + 10*symm(randmat(101,101))); - - typedef matrix mat; - test_cholesky(mat(uniform_matrix(101,101,1) + 10*symm(randmat(101,101)))); - } - -// ---------------------------------------------------------------------------------------- - - void matrix_test_float() - { - - test_cholesky(uniform_matrix(1,1,1) + 2*symm(randmat(1,1))); - test_cholesky(uniform_matrix(2,2,1) + 2*symm(randmat(2,2))); - test_cholesky(uniform_matrix(3,3,1) + 2*symm(randmat(3,3))); - - typedef matrix mat; - test_cholesky(mat(uniform_matrix(3,3,1) + 2*symm(randmat(3,3)))); - } - -// ---------------------------------------------------------------------------------------- - - class matrix_tester : public tester - { - public: - matrix_tester ( - ) : - tester ("test_matrix_chol", - "Runs tests on the matrix cholesky component.") - { - rnd.set_seed(cast_to_string(time(0))); - } - - void perform_test ( - ) - { - dlog << LINFO << "seed string: " << rnd.get_seed(); - - dlog << LINFO << "begin testing with double"; - matrix_test_double(); - dlog << LINFO << "begin testing with float"; - matrix_test_float(); - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/matrix_eig.cpp b/lib/3rdParty/dlib/include/dlib/test/matrix_eig.cpp deleted file mode 100644 index c86f90f7..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/matrix_eig.cpp +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (C) 2009 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include "../stl_checked.h" -#include "../array.h" -#include "../rand.h" -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.matrix_eig"); - - dlib::rand rnd; - -// ---------------------------------------------------------------------------------------- - - template - const matrix randm(long r, long c) - { - matrix m(r,c); - for (long row = 0; row < m.nr(); ++row) - { - for (long col = 0; col < m.nc(); ++col) - { - m(row,col) = static_cast(rnd.get_random_double()); - } - } - - return m; - } - - template - const matrix randm() - { - matrix m; - for (long row = 0; row < m.nr(); ++row) - { - for (long col = 0; col < m.nc(); ++col) - { - m(row,col) = static_cast(rnd.get_random_double()); - } - } - - return m; - } - -// ---------------------------------------------------------------------------------------- - - template - void test_eigenvalue_impl ( const matrix_type& m, const eigenvalue_decomposition& test ) - { - typedef typename matrix_type::type type; - const type eps = 10*max(abs(m))*sqrt(std::numeric_limits::epsilon()); - dlog << LDEBUG << "test_eigenvalue(): " << m.nr() << " x " << m.nc() << " eps: " << eps; - print_spinner(); - - - DLIB_TEST(test.dim() == m.nr()); - - // make sure all the various ways of asking for the eigenvalues are actually returning a - // consistent set of eigenvalues. - DLIB_TEST(equal(real(test.get_eigenvalues()), test.get_real_eigenvalues(), eps)); - DLIB_TEST(equal(imag(test.get_eigenvalues()), test.get_imag_eigenvalues(), eps)); - DLIB_TEST(equal(real(diag(test.get_d())), test.get_real_eigenvalues(), eps)); - DLIB_TEST(equal(imag(diag(test.get_d())), test.get_imag_eigenvalues(), eps)); - - matrix eig1 ( real_eigenvalues(m)); - matrix eig2 ( test.get_real_eigenvalues()); - sort(&eig1(0), &eig1(0) + eig1.size()); - sort(&eig2(0), &eig2(0) + eig2.size()); - DLIB_TEST(max(abs(eig1 - eig2)) < eps); - - const matrix V = test.get_pseudo_v(); - const matrix D = test.get_pseudo_d(); - const matrix > CV = test.get_v(); - const matrix > CD = test.get_d(); - const matrix > CM = complex_matrix(m, uniform_matrix(m.nr(),m.nc(),0)); - - DLIB_TEST(V.nr() == test.dim()); - DLIB_TEST(V.nc() == test.dim()); - DLIB_TEST(D.nr() == test.dim()); - DLIB_TEST(D.nc() == test.dim()); - - // CD is a diagonal matrix - DLIB_TEST(diagm(diag(CD)) == CD); - - // verify that these things are actually eigenvalues and eigenvectors of m - DLIB_TEST_MSG(max(abs(m*V - V*D)) < eps, max(abs(m*V - V*D)) << " " << eps); - DLIB_TEST(max(norm(CM*CV - CV*CD)) < eps); - - // if m is a symmetric matrix - if (max(abs(m-trans(m))) < 1e-5) - { - dlog << LTRACE << "m is symmetric"; - // there aren't any imaginary eigenvalues - DLIB_TEST(max(abs(test.get_imag_eigenvalues())) < eps); - DLIB_TEST(diagm(diag(D)) == D); - - // only check the determinant against the eigenvalues for small matrices - // because for huge ones the determinant might be so big it overflows a floating point number. - if (m.nr() < 50) - { - const type mdet = det(m); - DLIB_TEST_MSG(std::abs(prod(test.get_real_eigenvalues()) - mdet) < std::abs(mdet)*sqrt(std::numeric_limits::epsilon()), - std::abs(prod(test.get_real_eigenvalues()) - mdet) <<" eps: " << std::abs(mdet)*sqrt(std::numeric_limits::epsilon()) - << " mdet: "<< mdet << " prod(eig): " << prod(test.get_real_eigenvalues()) - ); - } - - // V is orthogonal - DLIB_TEST(equal(V*trans(V), identity_matrix(test.dim()), eps)); - DLIB_TEST(equal(m , V*D*trans(V), eps)); - } - else - { - dlog << LTRACE << "m is NOT symmetric"; - DLIB_TEST_MSG(equal(m , V*D*inv(V), eps), max(abs(m - V*D*inv(V)))); - } - } - -// ---------------------------------------------------------------------------------------- - - template - void test_eigenvalue ( const matrix_type& m ) - { - typedef typename matrix_type::type type; - typedef typename matrix_type::mem_manager_type MM; - matrix mr(m); - matrix mc(m); - - { - eigenvalue_decomposition test(mr); - test_eigenvalue_impl(mr, test); - - eigenvalue_decomposition test_symm(make_symmetric(mr)); - test_eigenvalue_impl(make_symmetric(mr), test_symm); - } - - { - eigenvalue_decomposition test(mc); - test_eigenvalue_impl(mc, test); - - eigenvalue_decomposition test_symm(make_symmetric(mc)); - test_eigenvalue_impl(make_symmetric(mc), test_symm); - } - } - -// ---------------------------------------------------------------------------------------- - - void matrix_test_double() - { - - test_eigenvalue(10*randm(1,1)); - test_eigenvalue(10*randm(2,2)); - test_eigenvalue(10*randm(3,3)); - test_eigenvalue(10*randm(4,4)); - test_eigenvalue(10*randm(15,15)); - test_eigenvalue(10*randm(150,150)); - - test_eigenvalue(10*randm()); - test_eigenvalue(10*randm()); - test_eigenvalue(10*randm()); - } - -// ---------------------------------------------------------------------------------------- - - void matrix_test_float() - { - - test_eigenvalue(10*randm(1,1)); - test_eigenvalue(10*randm(2,2)); - test_eigenvalue(10*randm(3,3)); - test_eigenvalue(10*randm(4,4)); - test_eigenvalue(10*randm(15,15)); - test_eigenvalue(10*randm(50,50)); - - test_eigenvalue(10*randm()); - test_eigenvalue(10*randm()); - test_eigenvalue(10*randm()); - } - -// ---------------------------------------------------------------------------------------- - - class matrix_tester : public tester - { - public: - matrix_tester ( - ) : - tester ("test_matrix_eig", - "Runs tests on the matrix eigen decomp component.") - { - //rnd.set_seed(cast_to_string(time(0))); - } - - void perform_test ( - ) - { - dlog << LINFO << "seed string: " << rnd.get_seed(); - - dlog << LINFO << "begin testing with double"; - matrix_test_double(); - dlog << LINFO << "begin testing with float"; - matrix_test_float(); - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/matrix_lu.cpp b/lib/3rdParty/dlib/include/dlib/test/matrix_lu.cpp deleted file mode 100644 index 01b56760..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/matrix_lu.cpp +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright (C) 2009 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include "../stl_checked.h" -#include "../array.h" -#include "../rand.h" -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.matrix_lu"); - - dlib::rand rnd; - -// ---------------------------------------------------------------------------------------- - - template - const matrix symm(const mat_type& m) { return m*trans(m); } - -// ---------------------------------------------------------------------------------------- - - template - const matrix randmat(long r, long c) - { - matrix m(r,c); - for (long row = 0; row < m.nr(); ++row) - { - for (long col = 0; col < m.nc(); ++col) - { - m(row,col) = static_cast(rnd.get_random_double()); - } - } - - return m; - } - - template - const matrix randmat() - { - matrix m; - for (long row = 0; row < m.nr(); ++row) - { - for (long col = 0; col < m.nc(); ++col) - { - m(row,col) = static_cast(rnd.get_random_double()); - } - } - - return m; - } - -// ---------------------------------------------------------------------------------------- - - template - void test_lu ( const matrix_type& m) - { - typedef typename matrix_type::type type; - const type eps = 10*max(abs(m))*sqrt(std::numeric_limits::epsilon()); - dlog << LDEBUG << "test_lu(): " << m.nr() << " x " << m.nc() << " eps: " << eps; - print_spinner(); - - - lu_decomposition test(m); - - DLIB_TEST(test.is_square() == (m.nr() == m.nc())); - - DLIB_TEST(test.nr() == m.nr()); - DLIB_TEST(test.nc() == m.nc()); - - dlog << LDEBUG << "m.nr(): " << m.nr() << " m.nc(): " << m.nc(); - - type temp; - DLIB_TEST_MSG( (temp= max(abs(test.get_l()*test.get_u() - rowm(m,test.get_pivot())))) < eps,temp); - - if (test.is_square()) - { - // none of the matrices we should be passing in to test_lu() should be singular. - DLIB_TEST_MSG (abs(test.det()) > eps/100, "det: " << test.det() ); - dlog << LDEBUG << "big det: " << test.det(); - - DLIB_TEST(test.is_singular() == false); - - matrix m2; - matrix col; - - m2 = identity_matrix(m.nr()); - DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2))); - m2 = randmat(m.nr(),5); - DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2))); - m2 = randmat(m.nr(),1); - DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2))); - col = randmat(m.nr(),1); - DLIB_TEST_MSG(equal(m*test.solve(col), col,eps),max(abs(m*test.solve(m2)- m2))); - - // now make us a singular matrix - if (m.nr() > 1) - { - matrix sm(m); - set_colm(sm,0) = colm(sm,1); - - lu_decomposition test2(sm); - DLIB_TEST_MSG( (temp= max(abs(test2.get_l()*test2.get_u() - rowm(sm,test2.get_pivot())))) < eps,temp); - - // these checks are only accurate for small matrices - if (test2.nr() < 100) - { - DLIB_TEST_MSG(test2.is_singular() == true,"det: " << test2.det()); - DLIB_TEST_MSG(abs(test2.det()) < eps,"det: " << test2.det()); - } - - } - } - - } - -// ---------------------------------------------------------------------------------------- - - void matrix_test_double() - { - - - test_lu(10*randmat(2,2)); - test_lu(10*randmat(1,1)); - test_lu(10*symm(randmat(2,2))); - test_lu(10*randmat(4,4)); - test_lu(10*randmat(9,4)); - test_lu(10*randmat(3,8)); - test_lu(10*randmat(15,15)); - test_lu(2*symm(randmat(15,15))); - test_lu(10*randmat(100,100)); - test_lu(10*randmat(137,200)); - test_lu(10*randmat(200,101)); - - test_lu(10*randmat()); - test_lu(10*randmat()); - test_lu(10*randmat()); - test_lu(10*randmat()); - test_lu(10*randmat()); - test_lu(10*randmat()); - test_lu(10*randmat()); - test_lu(10*randmat()); - test_lu(10*randmat()); - test_lu(10*randmat()); - - typedef matrix mat; - test_lu(mat(3*randmat(4,4))); - test_lu(mat(3*randmat(9,4))); - test_lu(mat(3*randmat(3,8))); - } - -// ---------------------------------------------------------------------------------------- - - void matrix_test_float() - { - - // ------------------------------- - - test_lu(3*randmat(1,1)); - test_lu(3*randmat(2,2)); - test_lu(3*randmat(4,4)); - test_lu(3*randmat(9,4)); - test_lu(3*randmat(3,8)); - test_lu(3*randmat(137,200)); - test_lu(3*randmat(200,101)); - - test_lu(3*randmat()); - test_lu(3*randmat()); - test_lu(3*randmat()); - test_lu(3*randmat()); - test_lu(3*randmat()); - test_lu(3*randmat()); - test_lu(3*randmat()); - test_lu(3*randmat()); - - typedef matrix mat; - test_lu(mat(3*randmat(4,4))); - test_lu(mat(3*randmat(9,4))); - test_lu(mat(3*randmat(3,8))); - } - -// ---------------------------------------------------------------------------------------- - - class matrix_tester : public tester - { - public: - matrix_tester ( - ) : - tester ("test_matrix_lu", - "Runs tests on the matrix LU component.") - { - rnd.set_seed(cast_to_string(time(0))); - } - - void perform_test ( - ) - { - dlog << LINFO << "seed string: " << rnd.get_seed(); - - dlog << LINFO << "begin testing with double"; - matrix_test_double(); - dlog << LINFO << "begin testing with float"; - matrix_test_float(); - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/matrix_qr.cpp b/lib/3rdParty/dlib/include/dlib/test/matrix_qr.cpp deleted file mode 100644 index c1101b6c..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/matrix_qr.cpp +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright (C) 2009 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include "../stl_checked.h" -#include "../array.h" -#include "../rand.h" -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.matrix_qr"); - - dlib::rand rnd; - -// ---------------------------------------------------------------------------------------- - - template - const matrix symm(const mat_type& m) { return m*trans(m); } - -// ---------------------------------------------------------------------------------------- - - template - const matrix randmat(long r, long c) - { - matrix m(r,c); - for (long row = 0; row < m.nr(); ++row) - { - for (long col = 0; col < m.nc(); ++col) - { - m(row,col) = static_cast(rnd.get_random_double()); - } - } - - return m; - } - - template - const matrix randmat() - { - matrix m; - for (long row = 0; row < m.nr(); ++row) - { - for (long col = 0; col < m.nc(); ++col) - { - m(row,col) = static_cast(rnd.get_random_double()); - } - } - - return m; - } - -// ---------------------------------------------------------------------------------------- - - template - void test_qr ( const matrix_type& m) - { - typedef typename matrix_type::type type; - const type eps = 10*max(abs(m))*sqrt(std::numeric_limits::epsilon()); - dlog << LDEBUG << "test_qr(): " << m.nr() << " x " << m.nc() << " eps: " << eps; - print_spinner(); - - - qr_decomposition test(m); - - - DLIB_TEST(test.nr() == m.nr()); - DLIB_TEST(test.nc() == m.nc()); - - - type temp; - DLIB_TEST_MSG( (temp= max(abs(test.get_q()*test.get_r() - m))) < eps,temp); - - // none of the matrices we should be passing in to test_qr() should be non-full rank. - DLIB_TEST(test.is_full_rank() == true); - - if (m.nr() == m.nc()) - { - matrix m2; - matrix col; - - m2 = identity_matrix(m.nr()); - DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2))); - m2 = randmat(m.nr(),5); - DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2))); - m2 = randmat(m.nr(),1); - DLIB_TEST_MSG(equal(m*test.solve(m2), m2,eps),max(abs(m*test.solve(m2)- m2))); - col = randmat(m.nr(),1); - DLIB_TEST_MSG(equal(m*test.solve(col), col,eps),max(abs(m*test.solve(m2)- m2))); - } - else - { - DLIB_TEST_MSG(dlib::equal(pinv(m), test.solve(identity_matrix(m.nr())), eps), - max(abs(pinv(m) - test.solve(identity_matrix(m.nr())))) ); - } - - // now make us a non-full rank matrix - if (m.nc() > 1) - { - matrix sm(m); - set_colm(sm,0) = colm(sm,1); - - qr_decomposition test2(sm); - DLIB_TEST_MSG( (temp= max(abs(test.get_q()*test.get_r() - m))) < eps,temp); - - if (test2.nc() < 100) - { - DLIB_TEST_MSG(test2.is_full_rank() == false,"eps: " << eps); - } - - } - - } - -// ---------------------------------------------------------------------------------------- - - void matrix_test_double() - { - - test_qr(10*randmat(1,1)); - test_qr(10*randmat(2,2)); - test_qr(10*symm(randmat(2,2))); - test_qr(10*randmat(4,4)); - test_qr(10*randmat(9,4)); - test_qr(10*randmat(15,15)); - test_qr(2*symm(randmat(15,15))); - test_qr(10*randmat(100,100)); - test_qr(10*randmat(237,200)); - test_qr(10*randmat(200,101)); - - test_qr(10*randmat()); - test_qr(10*randmat()); - test_qr(10*randmat()); - test_qr(10*randmat()); - test_qr(10*randmat()); - test_qr(10*randmat()); - test_qr(10*randmat()); - - typedef matrix mat; - test_qr(mat(3*randmat(9,4))); - test_qr(mat(3*randmat(9,9))); - } - -// ---------------------------------------------------------------------------------------- - - void matrix_test_float() - { - - - test_qr(3*randmat(1,1)); - test_qr(3*randmat(2,2)); - test_qr(3*randmat(4,4)); - test_qr(3*randmat(9,4)); - test_qr(3*randmat(237,200)); - - test_qr(3*randmat()); - test_qr(3*randmat()); - test_qr(3*randmat()); - test_qr(3*randmat()); - test_qr(3*randmat()); - - typedef matrix mat; - test_qr(mat(3*randmat(9,4))); - test_qr(mat(3*randmat(9,9))); - } - -// ---------------------------------------------------------------------------------------- - - class matrix_tester : public tester - { - public: - matrix_tester ( - ) : - tester ("test_matrix_qr", - "Runs tests on the matrix QR component.") - { - //rnd.set_seed(cast_to_string(time(0))); - } - - void perform_test ( - ) - { - dlog << LINFO << "seed string: " << rnd.get_seed(); - - dlog << LINFO << "begin testing with double"; - matrix_test_double(); - dlog << LINFO << "begin testing with float"; - matrix_test_float(); - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/max_cost_assignment.cpp b/lib/3rdParty/dlib/include/dlib/test/max_cost_assignment.cpp deleted file mode 100644 index 9a62be41..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/max_cost_assignment.cpp +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include "../rand.h" - -#include "tester.h" - - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.max_cost_assignment"); - -// ---------------------------------------------------------------------------------------- - - std::vector > permutations ( - matrix vals - ) - { - if (vals.size() == 0) - { - return std::vector >(); - } - else if (vals.size() == 1) - { - return std::vector >(1,std::vector(1,vals(0))); - } - - - std::vector > temp; - - - for (long i = 0; i < vals.size(); ++i) - { - const std::vector >& res = permutations(remove_col(vals,i)); - - for (unsigned long j = 0; j < res.size(); ++j) - { - temp.resize(temp.size()+1); - std::vector& part = temp.back(); - part.push_back(vals(i)); - part.insert(part.end(), res[j].begin(), res[j].end()); - } - } - - - return temp; - } - -// ---------------------------------------------------------------------------------------- - - template - std::vector brute_force_max_cost_assignment ( - matrix cost - ) - { - if (cost.size() == 0) - return std::vector(); - - const std::vector >& perms = permutations(range(0,cost.nc()-1)); - - T best_cost = std::numeric_limits::min(); - unsigned long best_idx = 0; - for (unsigned long i = 0; i < perms.size(); ++i) - { - const T temp = assignment_cost(cost, perms[i]); - if (temp > best_cost) - { - best_idx = i; - best_cost = temp; - } - } - - return perms[best_idx]; - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - class test_max_cost_assignment : public tester - { - public: - test_max_cost_assignment ( - ) : - tester ("test_max_cost_assignment", - "Runs tests on the max_cost_assignment function.") - {} - - dlib::rand rnd; - - template - void test_hungarian() - { - long size = rnd.get_random_32bit_number()%7; - long range = rnd.get_random_32bit_number()%100; - matrix cost = matrix_cast(randm(size,size,rnd)*range) - range/2; - - // use a uniform cost matrix sometimes - if ((rnd.get_random_32bit_number()%100) == 0) - cost = rnd.get_random_32bit_number()%100; - - // negate the cost matrix every now and then - if ((rnd.get_random_32bit_number()%100) == 0) - cost = -cost; - - - std::vector assign = brute_force_max_cost_assignment(cost); - T true_eval = assignment_cost(cost, assign); - assign = max_cost_assignment(cost); - DLIB_TEST(assignment_cost(cost,assign) == true_eval); - assign = max_cost_assignment(matrix_cast(cost)); - DLIB_TEST(assignment_cost(cost,assign) == true_eval); - - - cost = matrix_cast(randm(size,size,rnd)*range); - assign = brute_force_max_cost_assignment(cost); - true_eval = assignment_cost(cost, assign); - assign = max_cost_assignment(cost); - DLIB_TEST(assignment_cost(cost,assign) == true_eval); - assign = max_cost_assignment(matrix_cast(cost)); - DLIB_TEST(assignment_cost(cost,assign) == true_eval); - assign = max_cost_assignment(matrix_cast::type>(cost)); - DLIB_TEST(assignment_cost(cost,assign) == true_eval); - } - - void perform_test ( - ) - { - for (long i = 0; i < 1000; ++i) - { - if ((i%100) == 0) - print_spinner(); - - test_hungarian(); - test_hungarian(); - test_hungarian(); - test_hungarian(); - } - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/max_sum_submatrix.cpp b/lib/3rdParty/dlib/include/dlib/test/max_sum_submatrix.cpp deleted file mode 100644 index 34b4756f..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/max_sum_submatrix.cpp +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.max_sum_submatrix"); - -// ---------------------------------------------------------------------------------------- - - bool order_rects ( - const rectangle& a, - const rectangle& b - ) - { - if (a.left() < b.left()) return true; - else if (a.left() > b.left()) return false; - - if (a.right() < b.right()) return true; - else if (a.right() > b.right()) return false; - - if (a.top() < b.top()) return true; - else if (a.top() > b.top()) return false; - - if (a.bottom() < b.bottom()) return true; - else if (a.bottom() > b.bottom()) return false; - - return false; - } - - void run_test( - const int num - ) - { - static dlib::rand rnd; - - matrix mat, mask; - - mat.set_size(rnd.get_random_32bit_number()%1000 + 1, - rnd.get_random_32bit_number()%1000 + 1); - mask.set_size(mat.nr(), mat.nc()); - mask = 0; - - mat = -10000; - - std::vector true_rects; - - for (int i = 0; i < num; ++i) - { - const int width = rnd.get_random_32bit_number()%100 + 1; - const int height = rnd.get_random_32bit_number()%100 + 1; - - rectangle rect = centered_rect(rnd.get_random_16bit_number()%mat.nc(), - rnd.get_random_16bit_number()%mat.nr(), - width,height); - rect = get_rect(mat).intersect(rect); - - // make sure this new rectangle doesn't overlap or abut any others - if (sum(subm(mask,grow_rect(rect,1).intersect(get_rect(mask)))) == 0) - { - set_subm(mat, rect) = rnd.get_random_8bit_number()%100 + 1; - set_subm(mask, rect) = 1; - true_rects.push_back(rect); - } - } - - - std::vector res; - res = max_sum_submatrix(mat, true_rects.size()+10, 0); - - DLIB_TEST(res.size() == true_rects.size()); - - // make sure big rectangles come first - for (unsigned long i = 0; i+1 < res.size(); ++i) - { - DLIB_TEST(sum(subm(mat,res[i])) >= sum(subm(mat,res[i+1]))); - } - - // make sure rectangles match - sort(true_rects.begin(), true_rects.end(), order_rects); - sort(res.begin(), res.end(), order_rects); - for (unsigned long i = 0; i < res.size(); ++i) - { - DLIB_TEST_MSG(res[i] == true_rects[i], - "i: " << i << " res[i]: " << res[i] << " true_rects[i]: " << true_rects[i]); - } - - } - -// ---------------------------------------------------------------------------------------- - - template - void run_test2() - { - matrix mat(100,100); - mat = 1; - std::vector res = max_sum_submatrix(mat, 0, 0); - - DLIB_TEST(res.size() == 0); - res = max_sum_submatrix(mat, 1, 0); - DLIB_TEST(res.size() == 1); - DLIB_TEST(res[0] == get_rect(mat)); - res = max_sum_submatrix(mat, 3, 0); - DLIB_TEST(res.size() == 1); - DLIB_TEST(res[0] == get_rect(mat)); - res = max_sum_submatrix(mat, 3, 10); - DLIB_TEST(res.size() == 1); - DLIB_TEST(res[0] == get_rect(mat)); - - res = max_sum_submatrix(mat, 3, mat.size()); - DLIB_TEST(res.size() == 0); - - mat = -1; - res = max_sum_submatrix(mat, 1, 0); - DLIB_TEST(res.size() == 0); - - const rectangle rect1 = rectangle(10,10,40,40); - const rectangle rect2 = rectangle(35,35,80,80); - - set_subm(mat, rect1) = 2; - set_subm(mat, rect2) = 1; - res = max_sum_submatrix(mat, 3, 0); - DLIB_TEST(res.size() == 2); - DLIB_TEST(res[0] == rect2); - DLIB_TEST(res[1] == rect1); - - res = max_sum_submatrix(mat, 3, 2*rect1.area() - 2*(rect1.intersect(rect2)).area()); - DLIB_TEST(res.size() == 1); - DLIB_TEST(res[0] == rect2); - } - -// ---------------------------------------------------------------------------------------- - - - class test_max_sum_submatrix : public tester - { - public: - test_max_sum_submatrix ( - ) : - tester ("test_max_sum_submatrix", - "Runs tests on the max_sum_submatrix() function.") - {} - - void perform_test ( - ) - { - for (int j = 0; j < 5; ++j) - { - print_spinner(); - for (int i = 0; i < 40; ++i) - run_test(i); - } - - run_test2(); - run_test2(); - run_test2(); - run_test2(); - run_test2(); - } - } a; - -} - - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/md5.cpp b/lib/3rdParty/dlib/include/dlib/test/md5.cpp deleted file mode 100644 index 15fafac3..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/md5.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (C) 2007 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.md5"); - - void md5_test ( - ) - /*! - ensures - - runs tests on the md5 stuff compliance with the specs - !*/ - { - - DLIB_TEST(md5 ("") == "d41d8cd98f00b204e9800998ecf8427e"); - DLIB_TEST(md5 ("a") == "0cc175b9c0f1b6a831c399e269772661"); - DLIB_TEST(md5 ("abc") == "900150983cd24fb0d6963f7d28e17f72"); - DLIB_TEST(md5 ("message digest") == "f96b697d7cb7938d525a2f31aaf161d0"); - DLIB_TEST(md5 ("abcdefghijklmnopqrstuvwxyz") == "c3fcd3d76192e4007dfb496cca67e13b"); - DLIB_TEST(md5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") == "d174ab98d277d9f5a5611c2c9f419d9f"); - DLIB_TEST(md5 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") == "57edf4a22be3c955ac49da2e2107b67a"); - - // make sure the two versions of md5() always agree - for (int num = 0; num < 2000; ++num) - { - std::string temp; - for (int i = 0; i < num; ++i) - temp += 'a'; - - istringstream str(temp); - DLIB_TEST(md5(temp) == md5(str)); - } - - } - - - class md5_tester : public tester - { - public: - md5_tester ( - ) : - tester ("test_md5", - "Runs tests on the md5 component.") - {} - - void perform_test ( - ) - { - md5_test(); - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/member_function_pointer.cpp b/lib/3rdParty/dlib/include/dlib/test/member_function_pointer.cpp deleted file mode 100644 index 72aa3aa3..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/member_function_pointer.cpp +++ /dev/null @@ -1,553 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include - -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace std; - using namespace dlib; - - logger dlog("test.member_function_pointer"); - - class mfp_test_helper_other - { - public: - mfp_test_helper_other ( - ): i(-1) {} - - - mutable int i; - - - void go0 ( - ) { i = 0; } - void go1 ( - int v1 - ) { i = 1*v1; } - void go2 ( - int v1,int v2 - ) { i = 2*v1*v2; } - void go3 ( - int v1,int v2,int v3 - ) { i = 3*v1*v2*v3; } - void go4 ( - int v1,int v2,int v3,int v4 - ) { i = 4*v1*v2*v3*v4; } - - }; - - - class mfp_test_helper - { - public: - mfp_test_helper ( - ): i(-1) {} - - - mutable int i; - - - void go0 ( - ) { i = 0; } - void go1 ( - int v1 - ) { i = 1*v1; } - void go2 ( - int v1,int v2 - ) { i = 2*v1*v2; } - void go3 ( - int v1,int v2,int v3 - ) { i = 3*v1*v2*v3; } - void go4 ( - int v1,int v2,int v3,int v4 - ) { i = 4*v1*v2*v3*v4; } - - }; - - class mfp_test_helper_const - { - public: - mfp_test_helper_const ( - ): i(-1) {} - - - mutable int i; - - void go0 ( - ) const { i = 0; } - void go1 ( - int v1 - ) const { i = 1*v1; } - void go2 ( - int v1,int v2 - ) const { i = 2*v1*v2; } - void go3 ( - int v1,int v2,int v3 - ) const { i = 3*v1*v2*v3; } - void go4 ( - int v1,int v2,int v3,int v4 - ) const { i = 4*v1*v2*v3*v4; } - }; - - template < - template class mfp, - typename test_helper - > - void member_function_pointer_kernel_test ( - ) - /*! - requires - - mfp is an implementation of member_function_pointer/member_function_pointer_kernel_abstract.h - ensures - - runs tests on mfp for compliance with the specs - !*/ - { - - - test_helper helper; - - mfp<> a0, b0; - mfp a1, b1; - mfp a2, b2; - mfp a3, b3; - mfp a4, b4; - - mfp<> a0c, b0c; - mfp a1c, b1c; - mfp a2c, b2c; - mfp a3c, b3c; - mfp a4c, b4c; - - DLIB_TEST(a0c == b0c); - DLIB_TEST(a1c == b1c); - DLIB_TEST(a2c == b2c); - DLIB_TEST(a3c == b3c); - DLIB_TEST(a4c == b4c); - DLIB_TEST((a0c != b0c) == false); - DLIB_TEST((a1c != b1c) == false); - DLIB_TEST((a2c != b2c) == false); - DLIB_TEST((a3c != b3c) == false); - DLIB_TEST((a4c != b4c) == false); - - DLIB_TEST(a0.is_set() == false); - DLIB_TEST(b0.is_set() == false); - DLIB_TEST(a0c.is_set() == false); - DLIB_TEST(b0c.is_set() == false); - - DLIB_TEST(!a0 ); - DLIB_TEST(!b0 ); - DLIB_TEST(!a0c); - DLIB_TEST(!b0c); - - DLIB_TEST(a1.is_set() == false); - DLIB_TEST(b1.is_set() == false); - DLIB_TEST(a1c.is_set() == false); - DLIB_TEST(b1c.is_set() == false); - - DLIB_TEST(!a1 ); - DLIB_TEST(!b1 ); - DLIB_TEST(!a1c); - DLIB_TEST(!b1c); - - - DLIB_TEST(a2.is_set() == false); - DLIB_TEST(b2.is_set() == false); - DLIB_TEST(a2c.is_set() == false); - DLIB_TEST(b2c.is_set() == false); - - DLIB_TEST(!a2); - DLIB_TEST(!b2); - DLIB_TEST(!a2c); - DLIB_TEST(!b2c); - - DLIB_TEST(a3.is_set() == false); - DLIB_TEST(b3.is_set() == false); - DLIB_TEST(a3c.is_set() == false); - DLIB_TEST(b3c.is_set() == false); - - DLIB_TEST(!a3); - DLIB_TEST(!b3); - DLIB_TEST(!a3c); - DLIB_TEST(!b3c); - - DLIB_TEST(a4.is_set() == false); - DLIB_TEST(b4.is_set() == false); - DLIB_TEST(a4c.is_set() == false); - DLIB_TEST(b4c.is_set() == false); - - DLIB_TEST(!a4); - DLIB_TEST(!b4); - DLIB_TEST(!a4c); - DLIB_TEST(!b4c); - - a0.set(helper,&test_helper::go0); - a0c.set(helper,&test_helper::go0); - DLIB_TEST(a0.is_set() == true); - DLIB_TEST(a0c.is_set() == true); - DLIB_TEST(b0.is_set() == false); - DLIB_TEST(b0c.is_set() == false); - - DLIB_TEST(a0); - DLIB_TEST(a0c); - DLIB_TEST(!b0); - DLIB_TEST(!b0c); - - a0 = a0; - DLIB_TEST(a0 == a0); - DLIB_TEST(!(a0 != a0)); - DLIB_TEST(a0.is_set() == true); - DLIB_TEST(a0c.is_set() == true); - DLIB_TEST(b0.is_set() == false); - DLIB_TEST(b0c.is_set() == false); - - DLIB_TEST(a0); - DLIB_TEST(a0c); - DLIB_TEST(!b0); - DLIB_TEST(!b0c); - - swap(a0,b0); - swap(a0c,b0c); - DLIB_TEST(a0.is_set() == false); - DLIB_TEST(a0c.is_set() == false); - DLIB_TEST(b0.is_set() == true); - DLIB_TEST(b0c.is_set() == true); - - DLIB_TEST(!a0); - DLIB_TEST(!a0c); - DLIB_TEST(b0); - DLIB_TEST(b0c); - - a0 = b0; - DLIB_TEST(a0 == a0); - DLIB_TEST(a0 == b0); - DLIB_TEST(!(a0 != b0)); - DLIB_TEST(a0.is_set() == true); - DLIB_TEST(a0c.is_set() == false); - DLIB_TEST(b0.is_set() == true); - DLIB_TEST(b0c.is_set() == true); - - DLIB_TEST(a0 ); - DLIB_TEST(!a0c); - DLIB_TEST(b0); - DLIB_TEST(b0c); - - - a0.clear(); - a0c.clear(); - b0.clear(); - b0c.clear(); - DLIB_TEST(a0.is_set() == false); - DLIB_TEST(a0c.is_set() == false); - DLIB_TEST(b0.is_set() == false); - DLIB_TEST(b0c.is_set() == false); - - - a1.set(helper,&test_helper::go1); - a1c.set(helper,&test_helper::go1); - DLIB_TEST(a1.is_set() == true); - DLIB_TEST(a1c.is_set() == true); - DLIB_TEST(b1.is_set() == false); - DLIB_TEST(b1c.is_set() == false); - swap(a1,b1); - swap(a1c,b1c); - DLIB_TEST(a1.is_set() == false); - DLIB_TEST(a1c.is_set() == false); - DLIB_TEST(b1.is_set() == true); - DLIB_TEST(b1c.is_set() == true); - - DLIB_TEST(!a1); - DLIB_TEST(!a1c); - DLIB_TEST(b1); - DLIB_TEST(b1c); - - - a1 = b1; - DLIB_TEST(a1 == a1); - DLIB_TEST(a1 == b1); - DLIB_TEST(!(a1 != b1)); - DLIB_TEST(a1.is_set() == true); - DLIB_TEST(a1c.is_set() == false); - DLIB_TEST(b1.is_set() == true); - DLIB_TEST(b1c.is_set() == true); - - - a1.clear(); - a1c.clear(); - b1.clear(); - b1c.clear(); - DLIB_TEST(a1.is_set() == false); - DLIB_TEST(a1c.is_set() == false); - DLIB_TEST(b1.is_set() == false); - DLIB_TEST(b1c.is_set() == false); - - - a2.set(helper,&test_helper::go2); - a2c.set(helper,&test_helper::go2); - DLIB_TEST(a2.is_set() == true); - DLIB_TEST(a2c.is_set() == true); - DLIB_TEST(b2.is_set() == false); - DLIB_TEST(b2c.is_set() == false); - swap(a2,b2); - swap(a2c,b2c); - DLIB_TEST(a2.is_set() == false); - DLIB_TEST(a2c.is_set() == false); - DLIB_TEST(b2.is_set() == true); - DLIB_TEST(b2c.is_set() == true); - - DLIB_TEST(!a2); - DLIB_TEST(!a2c); - DLIB_TEST(b2); - DLIB_TEST(b2c); - if (b2) - { - } - else - { - DLIB_TEST(false); - } - - if (a2c) - { - DLIB_TEST(false); - } - else - { - DLIB_TEST(true); - } - - a2 = b2; - DLIB_TEST(a2 == a2); - DLIB_TEST(a2 == b2); - DLIB_TEST(!(a2 != b2)); - DLIB_TEST(a2.is_set() == true); - DLIB_TEST(a2c.is_set() == false); - DLIB_TEST(b2.is_set() == true); - DLIB_TEST(b2c.is_set() == true); - - a2.clear(); - a2c.clear(); - b2.clear(); - b2c.clear(); - DLIB_TEST(a2.is_set() == false); - DLIB_TEST(a2c.is_set() == false); - DLIB_TEST(b2.is_set() == false); - DLIB_TEST(b2c.is_set() == false); - - - a3.set(helper,&test_helper::go3); - a3c.set(helper,&test_helper::go3); - DLIB_TEST(a3.is_set() == true); - DLIB_TEST(a3c.is_set() == true); - DLIB_TEST(b3.is_set() == false); - DLIB_TEST(b3c.is_set() == false); - swap(a3,b3); - swap(a3c,b3c); - DLIB_TEST(a3.is_set() == false); - DLIB_TEST(a3c.is_set() == false); - DLIB_TEST(b3.is_set() == true); - DLIB_TEST(b3c.is_set() == true); - - a3 = b3; - DLIB_TEST(a3 == a3); - DLIB_TEST(a3 == b3); - DLIB_TEST(!(a3 != b3)); - DLIB_TEST(a3.is_set() == true); - DLIB_TEST(a3c.is_set() == false); - DLIB_TEST(b3.is_set() == true); - DLIB_TEST(b3c.is_set() == true); - - - a3.clear(); - a3c.clear(); - b3.clear(); - b3c.clear(); - DLIB_TEST(a3.is_set() == false); - DLIB_TEST(a3c.is_set() == false); - DLIB_TEST(b3.is_set() == false); - DLIB_TEST(b3c.is_set() == false); - - - a4.set(helper,&test_helper::go4); - a4c.set(helper,&test_helper::go4); - DLIB_TEST(a4.is_set() == true); - DLIB_TEST(a4c.is_set() == true); - DLIB_TEST(b4.is_set() == false); - DLIB_TEST(b4c.is_set() == false); - swap(a4,b4); - swap(a4c,b4c); - DLIB_TEST(a4.is_set() == false); - DLIB_TEST(a4c.is_set() == false); - DLIB_TEST(b4.is_set() == true); - DLIB_TEST(b4c.is_set() == true); - - a4 = b4; - a4 = b4; - a4 = b4; - a4 = b4; - DLIB_TEST(a4 == a4); - DLIB_TEST(a4 == b4); - DLIB_TEST(!(a4 != b4)); - DLIB_TEST(a4.is_set() == true); - DLIB_TEST(a4c.is_set() == false); - DLIB_TEST(b4.is_set() == true); - DLIB_TEST(b4c.is_set() == true); - - - a4.clear(); - a4c.clear(); - b4.clear(); - b4c.clear(); - DLIB_TEST(a4.is_set() == false); - DLIB_TEST(a4c.is_set() == false); - DLIB_TEST(b4.is_set() == false); - DLIB_TEST(b4c.is_set() == false); - - - a0.set(helper,&test_helper::go0); - a0c.set(helper,&test_helper::go0); - b0 = a0; - b0c = a0c; - helper.i = -1; - a0(); - DLIB_TEST(helper.i == 0); - helper.i = -1; - b0(); - DLIB_TEST(helper.i == 0); - helper.i = -1; - a0c(); - DLIB_TEST(helper.i == 0); - helper.i = -1; - b0c(); - DLIB_TEST(helper.i == 0); - - - a1.set(helper,&test_helper::go1); - a1c.set(helper,&test_helper::go1); - b1 = a1; - b1c = a1c; - helper.i = -1; - a1(1); - DLIB_TEST(helper.i == 1); - helper.i = -1; - b1(10); - DLIB_TEST(helper.i == 1*10); - helper.i = -1; - a1c(20); - DLIB_TEST(helper.i == 1*20); - helper.i = -1; - b1c(30); - DLIB_TEST(helper.i == 1*30); - - - a2.set(helper,&test_helper::go2); - a2c.set(helper,&test_helper::go2); - b2 = a2; - b2c = a2c; - helper.i = -1; - a2(1,2); - DLIB_TEST(helper.i == 2*1*2); - helper.i = -1; - b2(3,4); - DLIB_TEST(helper.i == 2*3*4); - helper.i = -1; - a2c(5,6); - DLIB_TEST(helper.i == 2*5*6); - helper.i = -1; - b2c(7,8); - DLIB_TEST(helper.i == 2*7*8); - - - a3.set(helper,&test_helper::go3); - a3c.set(helper,&test_helper::go3); - b3 = a3; - b3c = a3c; - helper.i = -1; - a3(1,2,3); - DLIB_TEST(helper.i == 3*1*2*3); - helper.i = -1; - b3(4,5,6); - DLIB_TEST(helper.i == 3*4*5*6); - helper.i = -1; - a3c(7,8,9); - DLIB_TEST(helper.i == 3*7*8*9); - helper.i = -1; - b3c(1,2,3); - DLIB_TEST(helper.i == 3*1*2*3); - - - a4.set(helper,&test_helper::go4); - a4c.set(helper,&test_helper::go4); - DLIB_TEST(a4 == a4c); - b4 = a4; - b4c = a4c; - helper.i = -1; - a4(1,2,3,4); - DLIB_TEST(helper.i == 4*1*2*3*4); - helper.i = -1; - b4(5,6,7,8); - DLIB_TEST(helper.i == 4*5*6*7*8); - helper.i = -1; - a4c(9,1,2,3); - DLIB_TEST(helper.i == 4*9*1*2*3); - helper.i = -1; - b4c(4,5,6,7); - DLIB_TEST(helper.i == 4*4*5*6*7); - - DLIB_TEST(a4 == b4); - DLIB_TEST(a4); - DLIB_TEST(a4 == b4); - a4.clear(); - DLIB_TEST(a4 != b4); - DLIB_TEST(!a4); - DLIB_TEST(a4 == 0); - DLIB_TEST(a4 == a4); - a4 = a4; - DLIB_TEST(a4 != b4); - DLIB_TEST(!a4); - DLIB_TEST(a4 == a4); - mfp_test_helper_other other; - a4.set(other,&mfp_test_helper_other::go4); - DLIB_TEST(a4 != b4); - DLIB_TEST(a4); - DLIB_TEST(a4 == a4); - a4.set(helper,&test_helper::go4); - DLIB_TEST(a4 == b4); - DLIB_TEST(a4); - DLIB_TEST(a4 == a4); - - - - } - - - - class member_function_pointer_tester : public tester - { - public: - member_function_pointer_tester ( - ) : - tester ("test_member_function_pointer", - "Runs tests on the member_function_pointer component.") - {} - - void perform_test ( - ) - { - member_function_pointer_kernel_test(); - member_function_pointer_kernel_test(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/metaprogramming.cpp b/lib/3rdParty/dlib/include/dlib/test/metaprogramming.cpp deleted file mode 100644 index 344d5ca3..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/metaprogramming.cpp +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (C) 2008 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.metaprogramming"); - - - void metaprogramming_test ( - ) - /*! - ensures - - runs tests on template metaprogramming objects and functions for compliance with the specs - !*/ - { - - print_spinner(); - - DLIB_TEST(is_signed_type::value == true); - DLIB_TEST(is_signed_type::value == true); - DLIB_TEST(is_signed_type::value == true); - DLIB_TEST(is_signed_type::value == true); - DLIB_TEST(is_unsigned_type::value == false); - DLIB_TEST(is_unsigned_type::value == false); - DLIB_TEST(is_unsigned_type::value == false); - DLIB_TEST(is_unsigned_type::value == false); - - DLIB_TEST(is_unsigned_type::value == true); - DLIB_TEST(is_unsigned_type::value == true); - DLIB_TEST(is_unsigned_type::value == true); - DLIB_TEST(is_unsigned_type::value == true); - DLIB_TEST(is_signed_type::value == false); - DLIB_TEST(is_signed_type::value == false); - DLIB_TEST(is_signed_type::value == false); - DLIB_TEST(is_signed_type::value == false); - - - COMPILE_TIME_ASSERT(is_signed_type::value == true); - COMPILE_TIME_ASSERT(is_signed_type::value == true); - COMPILE_TIME_ASSERT(is_signed_type::value == true); - COMPILE_TIME_ASSERT(is_signed_type::value == true); - COMPILE_TIME_ASSERT(is_unsigned_type::value == false); - COMPILE_TIME_ASSERT(is_unsigned_type::value == false); - COMPILE_TIME_ASSERT(is_unsigned_type::value == false); - COMPILE_TIME_ASSERT(is_unsigned_type::value == false); - - COMPILE_TIME_ASSERT(is_unsigned_type::value == true); - COMPILE_TIME_ASSERT(is_unsigned_type::value == true); - COMPILE_TIME_ASSERT(is_unsigned_type::value == true); - COMPILE_TIME_ASSERT(is_unsigned_type::value == true); - COMPILE_TIME_ASSERT(is_signed_type::value == false); - COMPILE_TIME_ASSERT(is_signed_type::value == false); - COMPILE_TIME_ASSERT(is_signed_type::value == false); - COMPILE_TIME_ASSERT(is_signed_type::value == false); - - - } - - - - - class metaprogramming_tester : public tester - { - public: - metaprogramming_tester ( - ) : - tester ("test_metaprogramming", - "Runs tests on the metaprogramming objects and functions.") - {} - - void perform_test ( - ) - { - metaprogramming_test(); - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/multithreaded_object.cpp b/lib/3rdParty/dlib/include/dlib/test/multithreaded_object.cpp deleted file mode 100644 index 044523a9..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/multithreaded_object.cpp +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright (C) 2007 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include - -#include -#include "tester.h" - -namespace -{ - using namespace test; - using namespace std; - using namespace dlib; - - logger dlog("test.multithreaded_object"); - - dlib::mutex cm; - int count; - - class test1 : multithreaded_object - { - public: - test1 () - { - DLIB_TEST(number_of_threads_registered() == 0); - DLIB_TEST(number_of_threads_alive() == 0); - DLIB_TEST(is_running() == false); - clear(); - DLIB_TEST(number_of_threads_registered() == 0); - DLIB_TEST(number_of_threads_alive() == 0); - DLIB_TEST(is_running() == false); - } - - ~test1 () - { - DLIB_TEST(number_of_threads_registered() == 0); - DLIB_TEST(number_of_threads_alive() == 0); - DLIB_TEST(is_running() == false); - stop(); - DLIB_TEST(number_of_threads_registered() == 0); - DLIB_TEST(number_of_threads_alive() == 0); - DLIB_TEST(is_running() == false); - wait(); - DLIB_TEST(number_of_threads_registered() == 0); - DLIB_TEST(number_of_threads_alive() == 0); - DLIB_TEST(is_running() == false); - } - - private: - }; - - class test2 : private multithreaded_object - { - public: - test2() - { - DLIB_TEST(number_of_threads_registered() == 0); - DLIB_TEST(number_of_threads_alive() == 0); - DLIB_TEST(is_running() == false); - register_thread(*this,&test2::thread); - DLIB_TEST(number_of_threads_registered() == 1); - DLIB_TEST(number_of_threads_alive() == 0); - DLIB_TEST(is_running() == false); - clear(); - DLIB_TEST(number_of_threads_registered() == 0); - DLIB_TEST(number_of_threads_alive() == 0); - DLIB_TEST(is_running() == false); - register_thread(*this,&test2::thread); - DLIB_TEST(number_of_threads_registered() == 1); - DLIB_TEST(number_of_threads_alive() == 0); - DLIB_TEST(is_running() == false); - } - - ~test2() - { - DLIB_TEST(number_of_threads_registered() == 1); - DLIB_TEST(number_of_threads_alive() == 0); - DLIB_TEST(is_running() == false); - stop(); - DLIB_TEST(number_of_threads_registered() == 1); - DLIB_TEST(number_of_threads_alive() == 0); - DLIB_TEST(is_running() == false); - wait(); - DLIB_TEST(number_of_threads_registered() == 1); - DLIB_TEST(number_of_threads_alive() == 0); - DLIB_TEST(is_running() == false); - } - - private: - - void thread() - { - auto_mutex M(cm); - ++count; - } - - }; - - class test3_c1 : private multithreaded_object - { - public: - test3_c1() - { - DLIB_TEST(number_of_threads_registered() == 0); - DLIB_TEST(number_of_threads_alive() == 0); - DLIB_TEST(is_running() == false); - register_thread(*this,&test3_c1::thread); - DLIB_TEST(number_of_threads_registered() == 1); - DLIB_TEST(number_of_threads_alive() == 0); - DLIB_TEST(is_running() == false); - start(); - DLIB_TEST(number_of_threads_registered() == 1); - DLIB_TEST(is_running() == true); - } - - ~test3_c1() - { - DLIB_TEST(number_of_threads_registered() == 1); - stop(); - DLIB_TEST(is_running() == false); - DLIB_TEST(number_of_threads_registered() == 1); - wait(); - DLIB_TEST(number_of_threads_registered() == 1); - DLIB_TEST(number_of_threads_alive() == 0); - DLIB_TEST(is_running() == false); - } - - private: - - void thread() - { - cm.lock(); - ++count; - cm.unlock(); - // wait until we are supposed to stop - while (!should_stop()) - dlib::sleep(1); - } - - }; - - class test4_c2 : private multithreaded_object - { - public: - test4_c2() - { - DLIB_TEST(number_of_threads_registered() == 0); - DLIB_TEST(number_of_threads_alive() == 0); - DLIB_TEST(is_running() == false); - register_thread(*this,&test4_c2::thread); - DLIB_TEST(number_of_threads_registered() == 1); - DLIB_TEST(number_of_threads_alive() == 0); - DLIB_TEST(is_running() == false); - start(); - DLIB_TEST(number_of_threads_registered() == 1); - DLIB_TEST(number_of_threads_alive() == 1); - DLIB_TEST(is_running() == true); - register_thread(*this,&test4_c2::thread); - DLIB_TEST(number_of_threads_registered() == 2); - DLIB_TEST(number_of_threads_alive() == 2); - DLIB_TEST(is_running() == true); - start(); - DLIB_TEST(number_of_threads_registered() == 2); - DLIB_TEST(number_of_threads_alive() == 2); - DLIB_TEST(is_running() == true); - start(); - DLIB_TEST(number_of_threads_registered() == 2); - DLIB_TEST(number_of_threads_alive() == 2); - DLIB_TEST(is_running() == true); - start(); - DLIB_TEST(number_of_threads_registered() == 2); - DLIB_TEST(number_of_threads_alive() == 2); - DLIB_TEST(is_running() == true); - start(); - DLIB_TEST(number_of_threads_registered() == 2); - DLIB_TEST(number_of_threads_alive() == 2); - DLIB_TEST(is_running() == true); - pause(); - DLIB_TEST(number_of_threads_registered() == 2); - DLIB_TEST(number_of_threads_alive() == 2); - DLIB_TEST(is_running() == false); - } - - ~test4_c2() - { - DLIB_TEST(number_of_threads_registered() == 2); - DLIB_TEST(number_of_threads_alive() == 2); - DLIB_TEST_MSG(is_running() == false,"is_running(): " << is_running()); - stop(); - DLIB_TEST(number_of_threads_registered() == 2); - DLIB_TEST(is_running() == false); - wait(); - DLIB_TEST(number_of_threads_registered() == 2); - DLIB_TEST(number_of_threads_alive() == 0); - DLIB_TEST(is_running() == false); - } - - private: - - void thread() - { - auto_mutex M(cm); - ++count; - while (!should_stop()) - dlib::sleep(10); - } - - }; - - - class test5 : private multithreaded_object - { - public: - test5() - { - register_thread(*this,&test5::thread1); - register_thread(*this,&test5::thread2); - register_thread(*this,&test5::thread3); - register_thread(*this,&test5::thread3); - start(); - } - - ~test5() - { - stop(); - wait(); - } - - private: - - void thread1() - { - while (!should_stop()) - dlib::sleep(10); - } - - void thread2() - { - while (!should_stop()) - dlib::sleep(10); - } - - void thread3() - { - while (!should_stop()) - dlib::sleep(10); - } - - }; - - - void multithreaded_object_test ( - ) - /*! - ensures - - runs tests on dlib::multithreaded_object for compliance with the specs - !*/ - { - - count = 0; - - for (int i = 0; i < 5; ++i) - { - { - test1 a1; - test2 a2; - test3_c1 a3; - test4_c2 a4; - test5 a5; - } - DLIB_TEST(count == (i+1)*3); - print_spinner(); - } - count = 0; - - for (int i = 0; i < 5; ++i) - { - { - test1 a1; - test2 a2; - test3_c1 a3; - test4_c2 a4; - test5 a5; - dlib::sleep(50); - } - DLIB_TEST(count == (i+1)*3); - print_spinner(); - } - } - - - class multithreaded_object_tester : public tester - { - public: - multithreaded_object_tester ( - ) : - tester ("test_multithreaded_object", - "Runs tests on the multithreaded_object component.") - {} - - void perform_test ( - ) - { - multithreaded_object_test(); - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/numerical_integration.cpp b/lib/3rdParty/dlib/include/dlib/test/numerical_integration.cpp deleted file mode 100644 index d0e24762..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/numerical_integration.cpp +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright (C) 2013 Steve Taylor (steve98654@gmail.com) -// License: Boost Software License See LICENSE.txt for the full license. - -// This function test battery is given in: -// -// Test functions taken from Pedro Gonnet's dissertation at ETH: -// Adaptive Quadrature Re-Revisited -// http://e-collection.library.ethz.ch/eserv/eth:65/eth-65-02.pdf - -#include -#include -#include -#include -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.numerical_integration"); - - class numerical_integration_tester : public tester - { - public: - numerical_integration_tester ( - ) : - tester ("test_numerical_integration", - "Runs tests on the numerical integration function.", - 0 - ) - {} - - void perform_test() - { - - dlog < m; - double tol = 1e-10; - double eps = 1e-8; - - m(0) = integrate_function_adapt_simp(&gg1, 0.0, 1.0, tol); - m(1) = integrate_function_adapt_simp(&gg2, 0.0, 1.0, tol); - m(2) = integrate_function_adapt_simp(&gg3, 0.0, 1.0, tol); - m(3) = integrate_function_adapt_simp(&gg4, 0.0, 1.0, tol); - m(4) = integrate_function_adapt_simp(&gg5, -1.0, 1.0, tol); - m(5) = integrate_function_adapt_simp(&gg6, 0.0, 1.0, tol); - m(6) = integrate_function_adapt_simp(&gg7, 0.0, 1.0, tol); - m(7) = integrate_function_adapt_simp(&gg8, 0.0, 1.0, tol); - m(8) = integrate_function_adapt_simp(&gg9, 0.0, 1.0, tol); - m(9) = integrate_function_adapt_simp(&gg10, 0.0, 1.0, tol); - m(10) = integrate_function_adapt_simp(&gg11, 0.0, 1.0, tol); - m(11) = integrate_function_adapt_simp(&gg12, 1e-6, 1.0, tol); - m(12) = integrate_function_adapt_simp(&gg13, 0.0, 10.0, tol); - m(13) = integrate_function_adapt_simp(&gg14, 0.0, 10.0, tol); - m(14) = integrate_function_adapt_simp(&gg15, 0.0, 10.0, tol); - m(15) = integrate_function_adapt_simp(&gg16, 0.01, 1.0, tol); - m(16) = integrate_function_adapt_simp(&gg17, 0.0, pi, tol); - m(17) = integrate_function_adapt_simp(&gg18, 0.0, 1.0, tol); - m(18) = integrate_function_adapt_simp(&gg19, -1.0, 1.0, tol); - m(19) = integrate_function_adapt_simp(&gg20, 0.0, 1.0, tol); - m(20) = integrate_function_adapt_simp(&gg21, 0.0, 1.0, tol); - m(21) = integrate_function_adapt_simp(&gg22, 0.0, 5.0, tol); - - // Here we compare the approximated integrals against - // highly accurate approximations generated either from - // the exact integral values or Mathematica's NIntegrate - // function using a working precision of 20. - - DLIB_TEST(abs(m(0) - 1.7182818284590452354) < 1e-11); - DLIB_TEST(abs(m(1) - 0.7000000000000000000) < eps); - DLIB_TEST(abs(m(2) - 0.6666666666666666667) < eps); - DLIB_TEST(abs(m(3) - 0.2397141133444008336) < eps); - DLIB_TEST(abs(m(4) - 1.5822329637296729331) < 1e-11); - DLIB_TEST(abs(m(5) - 0.4000000000000000000) < eps); - DLIB_TEST(abs(m(6) - 2.0000000000000000000) < 1e-4); - DLIB_TEST(abs(m(7) - 0.8669729873399110375) < eps); - DLIB_TEST(abs(m(8) - 1.1547005383792515290) < eps); - DLIB_TEST(abs(m(9) - 0.6931471805599453094) < eps); - DLIB_TEST(abs(m(10) - 0.3798854930417224753) < eps); - DLIB_TEST(abs(m(11) - 0.7775036341124982763) < eps); - DLIB_TEST(abs(m(12) - 0.5000000000000000000) < eps); - DLIB_TEST(abs(m(13) - 1.0000000000000000000) < eps); - DLIB_TEST(abs(m(14) - 0.4993633810764567446) < eps); - DLIB_TEST(abs(m(15) - 0.1121393035410217 ) < eps); - DLIB_TEST(abs(m(16) - 0.2910187828600526985) < eps); - DLIB_TEST(abs(m(17) + 0.4342944819032518276) < 1e-5); - DLIB_TEST(abs(m(18) - 1.56439644406905 ) < eps); - DLIB_TEST(abs(m(19) - 0.1634949430186372261) < eps); - DLIB_TEST(abs(m(20) - 0.0134924856494677726) < eps); - } - - static double gg1(double x) - { - return pow(e,x); - } - - static double gg2(double x) - { - if(x > 0.3) - { - return 1.0; - } - else - { - return 0; - } - } - - static double gg3(double x) - { - return pow(x,0.5); - } - - static double gg4(double x) - { - return 23.0/25.0*cosh(x)-cos(x); - } - - static double gg5(double x) - { - return 1/(pow(x,4) + pow(x,2) + 0.9); - } - - static double gg6(double x) - { - return pow(x,1.5); - } - - static double gg7(double x) - { - return pow(x,-0.5); - } - - static double gg8(double x) - { - return 1/(1 + pow(x,4)); - } - - static double gg9(double x) - { - return 2/(2 + sin(10*pi*x)); - } - - static double gg10(double x) - { - return 1/(1+x); - } - - static double gg11(double x) - { - return 1.0/(1 + pow(e,x)); - } - - static double gg12(double x) - { - return x/(pow(e,x)-1.0); - } - - static double gg13(double x) - { - return sqrt(50.0)*pow(e,-50.0*pi*x*x); - } - - static double gg14(double x) - { - return 25.0*pow(e,-25.0*x); - } - - static double gg15(double x) - { - return 50.0/(pi*(2500.0*x*x+1)); - } - - static double gg16(double x) - { - return 50.0*pow((sin(50.0*pi*x)/(50.0*pi*x)),2); - } - - static double gg17(double x) - { - return cos(cos(x)+3*sin(x)+2*cos(2*x)+3*cos(3*x)); - } - - static double gg18(double x) - { - return log10(x); - } - - static double gg19(double x) - { - return 1/(1.005+x*x); - } - - static double gg20(double x) - { - return 1/cosh(20.0*(x-1.0/5.0)) + 1/cosh(400.0*(x-2.0/5.0)) - + 1/cosh(8000.0*(x-3.0/5.0)); - } - - static double gg21(double x) - { - return 1.0/(1.0+(230.0*x-30.0)*(230.0*x-30.0)); - } - - static double gg22(double x) - { - if(x < 1) - { - return (x + 1.0); - } - else if(x >= 1 && x <= 3) - { - return (3.0 - x); - } - else - { - return 2.0; - } - } - - }; - - numerical_integration_tester a; -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/object_detector.cpp b/lib/3rdParty/dlib/include/dlib/test/object_detector.cpp deleted file mode 100644 index c145dbf6..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/object_detector.cpp +++ /dev/null @@ -1,1028 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include "tester.h" -#include -#include -#include -#include -#include -#include -#include -#include - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.object_detector"); - -// ---------------------------------------------------------------------------------------- - - struct funny_image - { - array2d img; - long nr() const { return img.nr(); } - long nc() const { return img.nc(); } - }; - - void swap(funny_image& a, funny_image& b) - { - a.img.swap(b.img); - } - -// ---------------------------------------------------------------------------------------- - - template < - typename image_array_type, - typename detector_type - > - void validate_some_object_detector_stuff ( - const image_array_type& images, - detector_type& detector, - double eps = 1e-10 - ) - { - for (unsigned long i = 0; i < images.size(); ++i) - { - std::vector dets = detector(images[i]); - std::vector > dets2; - - detector(images[i], dets2); - - matrix psi(detector.get_w().size()); - matrix psi2(detector.get_w().size()); - const double thresh = detector.get_w()(detector.get_w().size()-1); - - DLIB_TEST(dets.size() == dets2.size()); - for (unsigned long j = 0; j < dets.size(); ++j) - { - DLIB_TEST(dets[j] == dets2[j].second); - - const full_object_detection fdet = detector.get_scanner().get_full_object_detection(dets[j], detector.get_w()); - psi = 0; - detector.get_scanner().get_feature_vector(fdet, psi); - - double check_score = dot(psi,detector.get_w()) - thresh; - DLIB_TEST_MSG(std::abs(check_score - dets2[j].first) < eps, std::abs(check_score - dets2[j].first) << " check_score: "<< check_score); - } - - } - } - -// ---------------------------------------------------------------------------------------- - - class very_simple_feature_extractor : noncopyable - { - /*! - WHAT THIS OBJECT REPRESENTS - This object is a feature extractor which goes to every pixel in an image and - produces a 32 dimensional feature vector. This vector is an indicator vector - which records the pattern of pixel values in a 4-connected region. So it should - be able to distinguish basic things like whether or not a location falls on the - corner of a white box, on an edge, in the middle, etc. - - - Note that this object also implements the interface defined in dlib/image_keypoint/hashed_feature_image_abstract.h. - This means all the member functions in this object are supposed to behave as - described in the hashed_feature_image specification. So when you define your own - feature extractor objects you should probably refer yourself to that documentation - in addition to reading this example program. - !*/ - - - public: - - inline void load ( - const funny_image& img_ - ) - { - const array2d& img = img_.img; - - feat_image.set_size(img.nr(), img.nc()); - assign_all_pixels(feat_image,0); - for (long r = 1; r+1 < img.nr(); ++r) - { - for (long c = 1; c+1 < img.nc(); ++c) - { - unsigned char f = 0; - if (img[r][c]) f |= 0x1; - if (img[r][c+1]) f |= 0x2; - if (img[r][c-1]) f |= 0x4; - if (img[r+1][c]) f |= 0x8; - if (img[r-1][c]) f |= 0x10; - - // Store the code value for the pattern of pixel values in the 4-connected - // neighborhood around this row and column. - feat_image[r][c] = f; - } - } - } - - inline void load ( - const array2d& img - ) - { - feat_image.set_size(img.nr(), img.nc()); - assign_all_pixels(feat_image,0); - for (long r = 1; r+1 < img.nr(); ++r) - { - for (long c = 1; c+1 < img.nc(); ++c) - { - unsigned char f = 0; - if (img[r][c]) f |= 0x1; - if (img[r][c+1]) f |= 0x2; - if (img[r][c-1]) f |= 0x4; - if (img[r+1][c]) f |= 0x8; - if (img[r-1][c]) f |= 0x10; - - // Store the code value for the pattern of pixel values in the 4-connected - // neighborhood around this row and column. - feat_image[r][c] = f; - } - } - } - - inline unsigned long size () const { return feat_image.size(); } - inline long nr () const { return feat_image.nr(); } - inline long nc () const { return feat_image.nc(); } - - inline long get_num_dimensions ( - ) const - { - // Return the dimensionality of the vectors produced by operator() - return 32; - } - - typedef std::vector > descriptor_type; - - inline const descriptor_type& operator() ( - long row, - long col - ) const - /*! - requires - - 0 <= row < nr() - - 0 <= col < nc() - ensures - - returns a sparse vector which describes the image at the given row and column. - In particular, this is a vector that is 0 everywhere except for one element. - !*/ - { - feat.clear(); - const unsigned long only_nonzero_element_index = feat_image[row][col]; - feat.push_back(make_pair(only_nonzero_element_index,1.0)); - return feat; - } - - // This block of functions is meant to provide a way to map between the row/col space taken by - // this object's operator() function and the images supplied to load(). In this example it's trivial. - // However, in general, you might create feature extractors which don't perform extraction at every - // possible image location (e.g. the hog_image) and thus result in some more complex mapping. - inline const rectangle get_block_rect ( long row, long col) const { return centered_rect(col,row,3,3); } - inline const point image_to_feat_space ( const point& p) const { return p; } - inline const rectangle image_to_feat_space ( const rectangle& rect) const { return rect; } - inline const point feat_to_image_space ( const point& p) const { return p; } - inline const rectangle feat_to_image_space ( const rectangle& rect) const { return rect; } - - inline friend void serialize ( const very_simple_feature_extractor& item, std::ostream& out) { serialize(item.feat_image, out); } - inline friend void deserialize ( very_simple_feature_extractor& item, std::istream& in ) { deserialize(item.feat_image, in); } - - void copy_configuration ( const very_simple_feature_extractor& ){} - - private: - array2d feat_image; - - // This variable doesn't logically contribute to the state of this object. It is here - // only to avoid returning a descriptor_type object by value inside the operator() method. - mutable descriptor_type feat; - }; - -// ---------------------------------------------------------------------------------------- - - template < - typename image_array_type - > - void make_simple_test_data ( - image_array_type& images, - std::vector >& object_locations - ) - { - images.clear(); - object_locations.clear(); - - images.resize(3); - images[0].set_size(400,400); - images[1].set_size(400,400); - images[2].set_size(400,400); - - // set all the pixel values to black - assign_all_pixels(images[0], 0); - assign_all_pixels(images[1], 0); - assign_all_pixels(images[2], 0); - - // Now make some squares and draw them onto our black images. All the - // squares will be 70 pixels wide and tall. - - std::vector temp; - temp.push_back(centered_rect(point(100,100), 70,70)); - fill_rect(images[0],temp.back(),255); // Paint the square white - temp.push_back(centered_rect(point(200,300), 70,70)); - fill_rect(images[0],temp.back(),255); // Paint the square white - object_locations.push_back(temp); - - temp.clear(); - temp.push_back(centered_rect(point(140,200), 70,70)); - fill_rect(images[1],temp.back(),255); // Paint the square white - temp.push_back(centered_rect(point(303,200), 70,70)); - fill_rect(images[1],temp.back(),255); // Paint the square white - object_locations.push_back(temp); - - temp.clear(); - temp.push_back(centered_rect(point(123,121), 70,70)); - fill_rect(images[2],temp.back(),255); // Paint the square white - object_locations.push_back(temp); - - // corrupt each image with random noise just to make this a little more - // challenging - dlib::rand rnd; - for (unsigned long i = 0; i < images.size(); ++i) - { - for (long r = 0; r < images[i].nr(); ++r) - { - for (long c = 0; c < images[i].nc(); ++c) - { - typedef typename image_array_type::type image_type; - typedef typename image_type::type type; - images[i][r][c] = (type)put_in_range(0,255,images[i][r][c] + 10*rnd.get_random_gaussian()); - } - } - } - } - - template < - typename image_array_type - > - void make_simple_test_data ( - image_array_type& images, - std::vector >& object_locations - ) - { - images.clear(); - object_locations.clear(); - - - images.resize(3); - images[0].set_size(400,400); - images[1].set_size(400,400); - images[2].set_size(400,400); - - // set all the pixel values to black - assign_all_pixels(images[0], 0); - assign_all_pixels(images[1], 0); - assign_all_pixels(images[2], 0); - - // Now make some squares and draw them onto our black images. All the - // squares will be 70 pixels wide and tall. - const int shrink = 0; - std::vector temp; - - rectangle rect = centered_rect(point(100,100), 70,71); - std::vector movable_parts; - movable_parts.push_back(shrink_rect(rect,shrink).tl_corner()); - movable_parts.push_back(shrink_rect(rect,shrink).tr_corner()); - movable_parts.push_back(shrink_rect(rect,shrink).bl_corner()); - movable_parts.push_back(shrink_rect(rect,shrink).br_corner()); - temp.push_back(full_object_detection(rect, movable_parts)); - fill_rect(images[0],rect,255); // Paint the square white - - rect = centered_rect(point(200,200), 70,71); - movable_parts.clear(); - movable_parts.push_back(shrink_rect(rect,shrink).tl_corner()); - movable_parts.push_back(shrink_rect(rect,shrink).tr_corner()); - movable_parts.push_back(shrink_rect(rect,shrink).bl_corner()); - movable_parts.push_back(shrink_rect(rect,shrink).br_corner()); - temp.push_back(full_object_detection(rect, movable_parts)); - fill_rect(images[0],rect,255); // Paint the square white - - object_locations.push_back(temp); - // ------------------------------------ - temp.clear(); - - rect = centered_rect(point(140,200), 70,71); - movable_parts.clear(); - movable_parts.push_back(shrink_rect(rect,shrink).tl_corner()); - movable_parts.push_back(shrink_rect(rect,shrink).tr_corner()); - movable_parts.push_back(shrink_rect(rect,shrink).bl_corner()); - movable_parts.push_back(shrink_rect(rect,shrink).br_corner()); - temp.push_back(full_object_detection(rect, movable_parts)); - fill_rect(images[1],rect,255); // Paint the square white - - - rect = centered_rect(point(303,200), 70,71); - movable_parts.clear(); - movable_parts.push_back(shrink_rect(rect,shrink).tl_corner()); - movable_parts.push_back(shrink_rect(rect,shrink).tr_corner()); - movable_parts.push_back(shrink_rect(rect,shrink).bl_corner()); - movable_parts.push_back(shrink_rect(rect,shrink).br_corner()); - temp.push_back(full_object_detection(rect, movable_parts)); - fill_rect(images[1],rect,255); // Paint the square white - - object_locations.push_back(temp); - // ------------------------------------ - temp.clear(); - - rect = centered_rect(point(123,121), 70,71); - movable_parts.clear(); - movable_parts.push_back(shrink_rect(rect,shrink).tl_corner()); - movable_parts.push_back(shrink_rect(rect,shrink).tr_corner()); - movable_parts.push_back(shrink_rect(rect,shrink).bl_corner()); - movable_parts.push_back(shrink_rect(rect,shrink).br_corner()); - temp.push_back(full_object_detection(rect, movable_parts)); - fill_rect(images[2],rect,255); // Paint the square white - - object_locations.push_back(temp); - - // corrupt each image with random noise just to make this a little more - // challenging - dlib::rand rnd; - for (unsigned long i = 0; i < images.size(); ++i) - { - for (long r = 0; r < images[i].nr(); ++r) - { - for (long c = 0; c < images[i].nc(); ++c) - { - typedef typename image_array_type::type image_type; - typedef typename image_type::type type; - images[i][r][c] = (type)put_in_range(0,255,images[i][r][c] + 40*rnd.get_random_gaussian()); - } - } - } - } - -// ---------------------------------------------------------------------------------------- - - void test_fhog_pyramid ( - ) - { - print_spinner(); - dlog << LINFO << "test_fhog_pyramid()"; - - typedef dlib::array > grayscale_image_array_type; - grayscale_image_array_type images; - std::vector > object_locations; - make_simple_test_data(images, object_locations); - - typedef scan_fhog_pyramid > image_scanner_type; - image_scanner_type scanner; - scanner.set_detection_window_size(35,35); - structural_object_detection_trainer trainer(scanner); - trainer.set_num_threads(4); - trainer.set_overlap_tester(test_box_overlap(0,0)); - object_detector detector = trainer.train(images, object_locations); - - matrix res = test_object_detection_function(detector, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - { - ostringstream sout; - serialize(detector, sout); - istringstream sin(sout.str()); - object_detector d2; - deserialize(d2, sin); - matrix res = test_object_detection_function(d2, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - validate_some_object_detector_stuff(images, detector, 1e-6); - } - - { - std::vector > detectors; - detectors.push_back(detector); - detectors.push_back(detector); - detectors.push_back(detector); - - std::vector dets1 = evaluate_detectors(detectors, images[0]); - std::vector dets2 = detector(images[0]); - DLIB_TEST(dets1.size() > 0); - DLIB_TEST(dets2.size()*3 == dets1.size()); - dlib::set::kernel_1a_c d1, d2; - for (unsigned long i = 0; i < dets1.size(); ++i) - { - if (!d1.is_member(dets1[i])) - d1.add(dets1[i]); - } - for (unsigned long i = 0; i < dets2.size(); ++i) - { - if (!d2.is_member(dets2[i])) - d2.add(dets2[i]); - } - DLIB_TEST(d1.size() == d2.size()); - DLIB_TEST(set_intersection_size(d1,d2) == d1.size()); - } - } - -// ---------------------------------------------------------------------------------------- - - void test_1 ( - ) - { - print_spinner(); - dlog << LINFO << "test_1()"; - - typedef dlib::array > grayscale_image_array_type; - grayscale_image_array_type images; - std::vector > object_locations; - make_simple_test_data(images, object_locations); - - typedef hashed_feature_image > feature_extractor_type; - typedef scan_image_pyramid, feature_extractor_type> image_scanner_type; - image_scanner_type scanner; - const rectangle object_box = compute_box_dimensions(1,35*35); - scanner.add_detection_template(object_box, create_grid_detection_template(object_box,2,2)); - setup_hashed_features(scanner, images, 9); - use_uniform_feature_weights(scanner); - structural_object_detection_trainer trainer(scanner); - trainer.set_num_threads(4); - trainer.set_overlap_tester(test_box_overlap(0,0)); - object_detector detector = trainer.train(images, object_locations); - - matrix res = test_object_detection_function(detector, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - { - ostringstream sout; - serialize(detector, sout); - istringstream sin(sout.str()); - object_detector d2; - deserialize(d2, sin); - matrix res = test_object_detection_function(d2, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - validate_some_object_detector_stuff(images, detector); - } - } - -// ---------------------------------------------------------------------------------------- - - void test_1_boxes ( - ) - { - print_spinner(); - dlog << LINFO << "test_1_boxes()"; - - typedef dlib::array > grayscale_image_array_type; - grayscale_image_array_type images; - std::vector > object_locations; - make_simple_test_data(images, object_locations); - - typedef hashed_feature_image > feature_extractor_type; - typedef scan_image_boxes image_scanner_type; - image_scanner_type scanner; - setup_hashed_features(scanner, images, 9); - use_uniform_feature_weights(scanner); - structural_object_detection_trainer trainer(scanner); - trainer.set_num_threads(4); - trainer.set_overlap_tester(test_box_overlap(0,0)); - object_detector detector = trainer.train(images, object_locations); - - matrix res = test_object_detection_function(detector, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - { - ostringstream sout; - serialize(detector, sout); - istringstream sin(sout.str()); - object_detector d2; - deserialize(d2, sin); - matrix res = test_object_detection_function(d2, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - validate_some_object_detector_stuff(images, detector); - } - } - -// ---------------------------------------------------------------------------------------- - - void test_1m ( - ) - { - print_spinner(); - dlog << LINFO << "test_1m()"; - - typedef dlib::array > grayscale_image_array_type; - grayscale_image_array_type images; - std::vector > object_locations; - make_simple_test_data(images, object_locations); - - typedef hashed_feature_image > feature_extractor_type; - typedef scan_image_pyramid, feature_extractor_type> image_scanner_type; - image_scanner_type scanner; - const rectangle object_box = compute_box_dimensions(1,35*35); - std::vector mboxes; - const int mbox_size = 20; - mboxes.push_back(centered_rect(0,0, mbox_size,mbox_size)); - mboxes.push_back(centered_rect(0,0, mbox_size,mbox_size)); - mboxes.push_back(centered_rect(0,0, mbox_size,mbox_size)); - mboxes.push_back(centered_rect(0,0, mbox_size,mbox_size)); - scanner.add_detection_template(object_box, create_grid_detection_template(object_box,1,1), mboxes); - setup_hashed_features(scanner, images, 9); - use_uniform_feature_weights(scanner); - structural_object_detection_trainer trainer(scanner); - trainer.set_num_threads(4); - trainer.set_overlap_tester(test_box_overlap(0,0)); - object_detector detector = trainer.train(images, object_locations); - - matrix res = test_object_detection_function(detector, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - { - ostringstream sout; - serialize(detector, sout); - istringstream sin(sout.str()); - object_detector d2; - deserialize(d2, sin); - matrix res = test_object_detection_function(d2, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - validate_some_object_detector_stuff(images, detector); - } - } - -// ---------------------------------------------------------------------------------------- - - void test_1_fine_hog ( - ) - { - print_spinner(); - dlog << LINFO << "test_1_fine_hog()"; - - typedef dlib::array > grayscale_image_array_type; - grayscale_image_array_type images; - std::vector > object_locations; - make_simple_test_data(images, object_locations); - - typedef hashed_feature_image > feature_extractor_type; - typedef scan_image_pyramid, feature_extractor_type> image_scanner_type; - image_scanner_type scanner; - const rectangle object_box = compute_box_dimensions(1,35*35); - scanner.add_detection_template(object_box, create_grid_detection_template(object_box,2,2)); - setup_hashed_features(scanner, images, 9); - use_uniform_feature_weights(scanner); - structural_object_detection_trainer trainer(scanner); - trainer.set_num_threads(4); - trainer.set_overlap_tester(test_box_overlap(0,0)); - object_detector detector = trainer.train(images, object_locations); - - matrix res = test_object_detection_function(detector, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - { - ostringstream sout; - serialize(detector, sout); - istringstream sin(sout.str()); - object_detector d2; - deserialize(d2, sin); - matrix res = test_object_detection_function(d2, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - validate_some_object_detector_stuff(images, detector); - } - } - -// ---------------------------------------------------------------------------------------- - - void test_1_poly ( - ) - { - print_spinner(); - dlog << LINFO << "test_1_poly()"; - - typedef dlib::array > grayscale_image_array_type; - grayscale_image_array_type images; - std::vector > object_locations; - make_simple_test_data(images, object_locations); - - typedef hashed_feature_image > feature_extractor_type; - typedef scan_image_pyramid, feature_extractor_type> image_scanner_type; - image_scanner_type scanner; - const rectangle object_box = compute_box_dimensions(1,35*35); - scanner.add_detection_template(object_box, create_grid_detection_template(object_box,2,2)); - setup_hashed_features(scanner, images, 9); - use_uniform_feature_weights(scanner); - structural_object_detection_trainer trainer(scanner); - trainer.set_num_threads(4); - trainer.set_overlap_tester(test_box_overlap(0,0)); - object_detector detector = trainer.train(images, object_locations); - - matrix res = test_object_detection_function(detector, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - { - ostringstream sout; - serialize(detector, sout); - istringstream sin(sout.str()); - object_detector d2; - deserialize(d2, sin); - matrix res = test_object_detection_function(d2, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - validate_some_object_detector_stuff(images, detector); - } - } - -// ---------------------------------------------------------------------------------------- - - void test_1m_poly ( - ) - { - print_spinner(); - dlog << LINFO << "test_1_poly()"; - - typedef dlib::array > grayscale_image_array_type; - grayscale_image_array_type images; - std::vector > object_locations; - make_simple_test_data(images, object_locations); - - typedef hashed_feature_image > feature_extractor_type; - typedef scan_image_pyramid, feature_extractor_type> image_scanner_type; - image_scanner_type scanner; - const rectangle object_box = compute_box_dimensions(1,35*35); - std::vector mboxes; - const int mbox_size = 20; - mboxes.push_back(centered_rect(0,0, mbox_size,mbox_size)); - mboxes.push_back(centered_rect(0,0, mbox_size,mbox_size)); - mboxes.push_back(centered_rect(0,0, mbox_size,mbox_size)); - mboxes.push_back(centered_rect(0,0, mbox_size,mbox_size)); - scanner.add_detection_template(object_box, create_grid_detection_template(object_box,2,2), mboxes); - setup_hashed_features(scanner, images, 9); - use_uniform_feature_weights(scanner); - structural_object_detection_trainer trainer(scanner); - trainer.set_num_threads(4); - trainer.set_overlap_tester(test_box_overlap(0,0)); - object_detector detector = trainer.train(images, object_locations); - - matrix res = test_object_detection_function(detector, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - { - ostringstream sout; - serialize(detector, sout); - istringstream sin(sout.str()); - object_detector d2; - deserialize(d2, sin); - matrix res = test_object_detection_function(d2, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - validate_some_object_detector_stuff(images, detector); - } - } - -// ---------------------------------------------------------------------------------------- - - void test_1_poly_nn ( - ) - { - print_spinner(); - dlog << LINFO << "test_1_poly_nn()"; - - typedef dlib::array > grayscale_image_array_type; - grayscale_image_array_type images; - std::vector > object_locations; - make_simple_test_data(images, object_locations); - - typedef nearest_neighbor_feature_image > feature_extractor_type; - typedef scan_image_pyramid, feature_extractor_type> image_scanner_type; - image_scanner_type scanner; - - setup_grid_detection_templates(scanner, object_locations, 2, 2); - feature_extractor_type nnfe; - pyramid_down<2> pyr_down; - poly_image<5> polyi; - nnfe.set_basis(randomly_sample_image_features(images, pyr_down, polyi, 80)); - scanner.copy_configuration(nnfe); - - structural_object_detection_trainer trainer(scanner); - trainer.set_num_threads(4); - object_detector detector = trainer.train(images, object_locations); - - matrix res = test_object_detection_function(detector, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - { - ostringstream sout; - serialize(detector, sout); - istringstream sin(sout.str()); - object_detector d2; - deserialize(d2, sin); - matrix res = test_object_detection_function(d2, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - validate_some_object_detector_stuff(images, detector); - } - } - -// ---------------------------------------------------------------------------------------- - - void test_1_poly_nn_boxes ( - ) - { - print_spinner(); - dlog << LINFO << "test_1_poly_nn_boxes()"; - - typedef dlib::array > grayscale_image_array_type; - grayscale_image_array_type images; - std::vector > object_locations; - make_simple_test_data(images, object_locations); - - typedef nearest_neighbor_feature_image > feature_extractor_type; - typedef scan_image_boxes image_scanner_type; - image_scanner_type scanner; - - feature_extractor_type nnfe; - pyramid_down<2> pyr_down; - poly_image<5> polyi; - nnfe.set_basis(randomly_sample_image_features(images, pyr_down, polyi, 80)); - scanner.copy_configuration(nnfe); - - structural_object_detection_trainer trainer(scanner); - trainer.set_num_threads(4); - object_detector detector = trainer.train(images, object_locations); - - matrix res = test_object_detection_function(detector, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - { - ostringstream sout; - serialize(detector, sout); - istringstream sin(sout.str()); - object_detector d2; - deserialize(d2, sin); - matrix res = test_object_detection_function(d2, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - validate_some_object_detector_stuff(images, detector); - } - } - -// ---------------------------------------------------------------------------------------- - - void test_2 ( - ) - { - print_spinner(); - dlog << LINFO << "test_2()"; - - typedef dlib::array > grayscale_image_array_type; - grayscale_image_array_type images; - std::vector > object_locations; - make_simple_test_data(images, object_locations); - - typedef scan_image_pyramid, very_simple_feature_extractor> image_scanner_type; - image_scanner_type scanner; - const rectangle object_box = compute_box_dimensions(1,70*70); - scanner.add_detection_template(object_box, create_grid_detection_template(object_box,2,2)); - scanner.set_max_pyramid_levels(1); - structural_object_detection_trainer trainer(scanner); - trainer.set_num_threads(0); - object_detector detector = trainer.train(images, object_locations); - - matrix res = test_object_detection_function(detector, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - res = cross_validate_object_detection_trainer(trainer, images, object_locations, 3); - dlog << LINFO << "3-fold cross validation (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - { - ostringstream sout; - serialize(detector, sout); - istringstream sin(sout.str()); - object_detector d2; - deserialize(d2, sin); - matrix res = test_object_detection_function(d2, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - validate_some_object_detector_stuff(images, detector); - } - } - -// ---------------------------------------------------------------------------------------- - - class pyramid_down_funny : noncopyable - { - pyramid_down<2> pyr; - public: - - template - dlib::vector point_down ( const dlib::vector& p) const { return pyr.point_down(p); } - - template - dlib::vector point_up ( const dlib::vector& p) const { return pyr.point_up(p); } - - template - dlib::vector point_down ( const dlib::vector& p, unsigned int levels) const { return pyr.point_down(p,levels); } - - template - dlib::vector point_up ( const dlib::vector& p, unsigned int levels) const { return pyr.point_up(p,levels); } - - rectangle rect_up ( const rectangle& rect) const { return pyr.rect_up(rect); } - - rectangle rect_up ( const rectangle& rect, unsigned int levels) const { return pyr.rect_up(rect,levels); } - - rectangle rect_down ( const rectangle& rect) const { return pyr.rect_down(rect); } - - rectangle rect_down ( const rectangle& rect, unsigned int levels) const { return pyr.rect_down(rect,levels); } - - template < - typename in_image_type, - typename out_image_type - > - void operator() ( - const in_image_type& original, - out_image_type& down - ) const - { - pyr(original.img, down.img); - } - - }; - - // make sure everything works even when the image isn't a dlib::array2d. - // So test with funny_image. - void test_3 ( - ) - { - print_spinner(); - dlog << LINFO << "test_3()"; - - - typedef dlib::array > grayscale_image_array_type; - typedef dlib::array funny_image_array_type; - grayscale_image_array_type images_temp; - funny_image_array_type images; - std::vector > object_locations; - make_simple_test_data(images_temp, object_locations); - images.resize(images_temp.size()); - for (unsigned long i = 0; i < images_temp.size(); ++i) - { - images[i].img.swap(images_temp[i]); - } - - typedef scan_image_pyramid image_scanner_type; - image_scanner_type scanner; - const rectangle object_box = compute_box_dimensions(1,70*70); - scanner.add_detection_template(object_box, create_grid_detection_template(object_box,2,2)); - scanner.set_max_pyramid_levels(1); - structural_object_detection_trainer trainer(scanner); - trainer.set_num_threads(4); - object_detector detector = trainer.train(images, object_locations); - - matrix res = test_object_detection_function(detector, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - res = cross_validate_object_detection_trainer(trainer, images, object_locations, 3); - dlog << LINFO << "3-fold cross validation (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - { - ostringstream sout; - serialize(detector, sout); - istringstream sin(sout.str()); - object_detector d2; - deserialize(d2, sin); - matrix res = test_object_detection_function(d2, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - } - } - -// ---------------------------------------------------------------------------------------- - - class funny_box_generator - { - public: - template - void operator() ( - const image_type& img, - std::vector& rects - ) const - { - rects.clear(); - find_candidate_object_locations(img.img, rects); - dlog << LINFO << "funny_box_generator, rects.size(): "<< rects.size(); - } - }; - - inline void serialize(const funny_box_generator&, std::ostream& ) {} - inline void deserialize(funny_box_generator&, std::istream& ) {} - - - // make sure everything works even when the image isn't a dlib::array2d. - // So test with funny_image. - void test_3_boxes ( - ) - { - print_spinner(); - dlog << LINFO << "test_3_boxes()"; - - - typedef dlib::array > grayscale_image_array_type; - typedef dlib::array funny_image_array_type; - grayscale_image_array_type images_temp; - funny_image_array_type images; - std::vector > object_locations; - make_simple_test_data(images_temp, object_locations); - images.resize(images_temp.size()); - for (unsigned long i = 0; i < images_temp.size(); ++i) - { - images[i].img.swap(images_temp[i]); - } - - typedef scan_image_boxes image_scanner_type; - image_scanner_type scanner; - structural_object_detection_trainer trainer(scanner); - trainer.set_num_threads(4); - object_detector detector = trainer.train(images, object_locations); - - matrix res = test_object_detection_function(detector, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - res = cross_validate_object_detection_trainer(trainer, images, object_locations, 3); - dlog << LINFO << "3-fold cross validation (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - - { - ostringstream sout; - serialize(detector, sout); - istringstream sin(sout.str()); - object_detector d2; - deserialize(d2, sin); - matrix res = test_object_detection_function(d2, images, object_locations); - dlog << LINFO << "Test detector (precision,recall): " << res; - DLIB_TEST(sum(res) == 3); - } - } - -// ---------------------------------------------------------------------------------------- - - class object_detector_tester : public tester - { - public: - object_detector_tester ( - ) : - tester ("test_object_detector", - "Runs tests on the structural object detection stuff.") - {} - - void perform_test ( - ) - { - test_fhog_pyramid(); - test_1_boxes(); - test_1_poly_nn_boxes(); - test_3_boxes(); - - test_1(); - test_1m(); - test_1_fine_hog(); - test_1_poly(); - test_1m_poly(); - test_1_poly_nn(); - test_2(); - test_3(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/oca.cpp b/lib/3rdParty/dlib/include/dlib/test/oca.cpp deleted file mode 100644 index 7d856e5b..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/oca.cpp +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright (C) 2012 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.oca"); - -// ---------------------------------------------------------------------------------------- - - class test_oca : public tester - { - - public: - test_oca ( - ) : - tester ("test_oca", - "Runs tests on the oca component.") - { - } - - void perform_test( - ) - { - print_spinner(); - - typedef matrix w_type; - w_type w; - - decision_function > df; - svm_c_linear_trainer > trainer; - trainer.set_c_class1(2); - trainer.set_c_class1(3); - trainer.set_learns_nonnegative_weights(true); - trainer.set_epsilon(1e-12); - - std::vector x; - w_type temp(2); - temp = -1, 1; - x.push_back(temp); - temp = 1, -1; - x.push_back(temp); - - std::vector y; - y.push_back(+1); - y.push_back(-1); - - w_type true_w(3); - - oca solver; - - // test the version without a non-negativity constraint on w. - solver(make_oca_problem_c_svm(2.0, 3.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, 0); - dlog << LINFO << trans(w); - true_w = -0.5, 0.5, 0; - dlog << LINFO << "error: "<< max(abs(w-true_w)); - DLIB_TEST(max(abs(w-true_w)) < 1e-10); - - w_type prior = true_w; - solver(make_oca_problem_c_svm(20.0, 30.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, prior); - dlog << LINFO << trans(w); - true_w = -0.5, 0.5, 0; - dlog << LINFO << "error: "<< max(abs(w-true_w)); - DLIB_TEST(max(abs(w-true_w)) < 1e-10); - - prior = 0,0,0; - solver(make_oca_problem_c_svm(20.0, 30.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, prior); - dlog << LINFO << trans(w); - true_w = -0.5, 0.5, 0; - dlog << LINFO << "error: "<< max(abs(w-true_w)); - DLIB_TEST(max(abs(w-true_w)) < 1e-10); - - prior = -1,1,0; - solver(make_oca_problem_c_svm(20.0, 30.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, prior); - dlog << LINFO << trans(w); - true_w = -1.0, 1.0, 0; - dlog << LINFO << "error: "<< max(abs(w-true_w)); - DLIB_TEST(max(abs(w-true_w)) < 1e-10); - - prior = -0.2,0.2,0; - solver(make_oca_problem_c_svm(20.0, 30.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, prior); - dlog << LINFO << trans(w); - true_w = -0.5, 0.5, 0; - dlog << LINFO << "error: "<< max(abs(w-true_w)); - DLIB_TEST(max(abs(w-true_w)) < 1e-10); - - prior = -10.2,-1,0; - solver(make_oca_problem_c_svm(20.0, 30.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, prior); - dlog << LINFO << trans(w); - true_w = -10.2, -1.0, 0; - dlog << LINFO << "error: "<< max(abs(w-true_w)); - DLIB_TEST(max(abs(w-true_w)) < 1e-10); - - print_spinner(); - - // test the version with a non-negativity constraint on w. - solver(make_oca_problem_c_svm(2.0, 3.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, 9999); - dlog << LINFO << trans(w); - true_w = 0, 1, 0; - dlog << LINFO << "error: "<< max(abs(w-true_w)); - DLIB_TEST(max(abs(w-true_w)) < 1e-10); - - df = trainer.train(x,y); - w = join_cols(df.basis_vectors(0), uniform_matrix(1,1,-df.b)); - true_w = 0, 1, 0; - dlog << LINFO << "error: "<< max(abs(w-true_w)); - DLIB_TEST(max(abs(w-true_w)) < 1e-10); - - - print_spinner(); - - // test the version with a non-negativity constraint on w. - solver(make_oca_problem_c_svm(2.0, 3.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, 2); - dlog << LINFO << trans(w); - true_w = 0, 1, 0; - dlog << LINFO << "error: "<< max(abs(w-true_w)); - DLIB_TEST(max(abs(w-true_w)) < 1e-10); - - print_spinner(); - - - // test the version with a non-negativity constraint on w. - solver(make_oca_problem_c_svm(2.0, 3.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, 1); - dlog << LINFO << trans(w); - true_w = 0, 1, 0; - dlog << LINFO << "error: "<< max(abs(w-true_w)); - DLIB_TEST(max(abs(w-true_w)) < 1e-10); - - print_spinner(); - - - // switching the labels should change which w weight goes negative. - y.clear(); - y.push_back(-1); - y.push_back(+1); - - - solver(make_oca_problem_c_svm(2.0, 3.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, 0); - dlog << LINFO << trans(w); - true_w = 0.5, -0.5, 0; - dlog << LINFO << "error: "<< max(abs(w-true_w)); - DLIB_TEST(max(abs(w-true_w)) < 1e-10); - - print_spinner(); - - solver(make_oca_problem_c_svm(2.0, 3.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, 1); - dlog << LINFO << trans(w); - true_w = 0.5, -0.5, 0; - dlog << LINFO << "error: "<< max(abs(w-true_w)); - DLIB_TEST(max(abs(w-true_w)) < 1e-10); - - print_spinner(); - - solver(make_oca_problem_c_svm(2.0, 3.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, 2); - dlog << LINFO << trans(w); - true_w = 1, 0, 0; - dlog << LINFO << "error: "<< max(abs(w-true_w)); - DLIB_TEST(max(abs(w-true_w)) < 1e-10); - - print_spinner(); - - solver(make_oca_problem_c_svm(2.0, 3.0, mat(x), mat(y), false, 1e-12, 40, max_index_plus_one(x)), w, 5); - dlog << LINFO << trans(w); - true_w = 1, 0, 0; - dlog << LINFO << "error: "<< max(abs(w-true_w)); - DLIB_TEST(max(abs(w-true_w)) < 1e-10); - - df = trainer.train(x,y); - w = join_cols(df.basis_vectors(0), uniform_matrix(1,1,-df.b)); - true_w = 1, 0, 0; - dlog << LINFO << "error: "<< max(abs(w-true_w)); - DLIB_TEST(max(abs(w-true_w)) < 1e-10); - - - - x.clear(); - y.clear(); - temp = -2, 2; - x.push_back(temp); - temp = 0, -0; - x.push_back(temp); - - y.push_back(+1); - y.push_back(-1); - - trainer.set_c(10); - df = trainer.train(x,y); - w = join_cols(df.basis_vectors(0), uniform_matrix(1,1,-df.b)); - true_w = 0, 1, -1; - dlog << LINFO << "w: " << trans(w); - dlog << LINFO << "error: "<< max(abs(w-true_w)); - DLIB_TEST(max(abs(w-true_w)) < 1e-10); - - - x.clear(); - y.clear(); - temp = -2, 2; - x.push_back(temp); - temp = 0, -0; - x.push_back(temp); - - y.push_back(-1); - y.push_back(+1); - - trainer.set_c(10); - df = trainer.train(x,y); - w = join_cols(df.basis_vectors(0), uniform_matrix(1,1,-df.b)); - true_w = 1, 0, 1; - dlog << LINFO << "w: " << trans(w); - dlog << LINFO << "error: "<< max(abs(w-true_w)); - DLIB_TEST(max(abs(w-true_w)) < 1e-10); - - } - - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/one_vs_all_trainer.cpp b/lib/3rdParty/dlib/include/dlib/test/one_vs_all_trainer.cpp deleted file mode 100644 index 6ff9693a..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/one_vs_all_trainer.cpp +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright (C) 2010 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "tester.h" -#include -#include -#include - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - dlib::logger dlog("test.one_vs_all_trainer"); - - - class test_one_vs_all_trainer : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a unit test. When it is constructed - it adds itself into the testing framework. - !*/ - public: - test_one_vs_all_trainer ( - ) : - tester ( - "test_one_vs_all_trainer", // the command line argument name for this test - "Run tests on the one_vs_all_trainer stuff.", // the command line argument description - 0 // the number of command line arguments for this test - ) - { - } - - - - template - void generate_data ( - std::vector& samples, - std::vector& labels - ) - { - const long num = 50; - - sample_type m; - - dlib::rand rnd; - - - // make some samples near the origin - double radius = 0.5; - for (long i = 0; i < num+10; ++i) - { - double sign = 1; - if (rnd.get_random_double() < 0.5) - sign = -1; - m(0) = 2*radius*rnd.get_random_double()-radius; - m(1) = sign*sqrt(radius*radius - m(0)*m(0)); - - // add this sample to our set of samples we will run k-means - samples.push_back(m); - labels.push_back(1); - } - - // make some samples in a circle around the origin but far away - radius = 10.0; - for (long i = 0; i < num+20; ++i) - { - double sign = 1; - if (rnd.get_random_double() < 0.5) - sign = -1; - m(0) = 2*radius*rnd.get_random_double()-radius; - m(1) = sign*sqrt(radius*radius - m(0)*m(0)); - - // add this sample to our set of samples we will run k-means - samples.push_back(m); - labels.push_back(2); - } - - // make some samples in a circle around the point (25,25) - radius = 4.0; - for (long i = 0; i < num+30; ++i) - { - double sign = 1; - if (rnd.get_random_double() < 0.5) - sign = -1; - m(0) = 2*radius*rnd.get_random_double()-radius; - m(1) = sign*sqrt(radius*radius - m(0)*m(0)); - - // translate this point away from the origin - m(0) += 25; - m(1) += 25; - - // add this sample to our set of samples we will run k-means - samples.push_back(m); - labels.push_back(3); - } - } - - template - void run_test ( - ) - { - print_spinner(); - typedef matrix sample_type; - - std::vector samples, norm_samples; - std::vector labels; - - // First, get our labeled set of training data - generate_data(samples, labels); - - typedef one_vs_all_trainer,label_type > ova_trainer; - - - ova_trainer trainer; - - typedef polynomial_kernel poly_kernel; - typedef radial_basis_kernel rbf_kernel; - - // make the binary trainers and set some parameters - krr_trainer rbf_trainer; - svm_nu_trainer poly_trainer; - poly_trainer.set_kernel(poly_kernel(0.1, 1, 2)); - rbf_trainer.set_kernel(rbf_kernel(0.1)); - - - trainer.set_trainer(rbf_trainer); - trainer.set_trainer(poly_trainer, 1); - - randomize_samples(samples, labels); - matrix res = cross_validate_multiclass_trainer(trainer, samples, labels, 2); - - print_spinner(); - - matrix ans(3,3); - ans = 60, 0, 0, - 0, 70, 0, - 0, 0, 80; - - DLIB_TEST_MSG(ans == res, "res: \n" << res); - - // test using a normalized_function with a one_vs_all_decision_function - { - poly_trainer.set_kernel(poly_kernel(1.1, 1, 2)); - trainer.set_trainer(poly_trainer, 1); - vector_normalizer normalizer; - normalizer.train(samples); - for (unsigned long i = 0; i < samples.size(); ++i) - norm_samples.push_back(normalizer(samples[i])); - normalized_function > ndf; - ndf.function = trainer.train(norm_samples, labels); - ndf.normalizer = normalizer; - DLIB_TEST(ndf(samples[0]) == labels[0]); - DLIB_TEST(ndf(samples[40]) == labels[40]); - DLIB_TEST(ndf(samples[90]) == labels[90]); - DLIB_TEST(ndf(samples[120]) == labels[120]); - poly_trainer.set_kernel(poly_kernel(0.1, 1, 2)); - trainer.set_trainer(poly_trainer, 1); - print_spinner(); - } - - one_vs_all_decision_function df = trainer.train(samples, labels); - - DLIB_TEST(df.number_of_classes() == 3); - - DLIB_TEST(df(samples[0]) == labels[0]) - DLIB_TEST(df(samples[90]) == labels[90]) - - - one_vs_all_decision_function, // This is the output of the poly_trainer - decision_function // This is the output of the rbf_trainer - > df2, df3; - - - df2 = df; - ofstream fout("df.dat", ios::binary); - serialize(df2, fout); - fout.close(); - - // load the function back in from disk and store it in df3. - ifstream fin("df.dat", ios::binary); - deserialize(df3, fin); - - - DLIB_TEST(df3(samples[0]) == labels[0]) - DLIB_TEST(df3(samples[90]) == labels[90]) - res = test_multiclass_decision_function(df3, samples, labels); - - DLIB_TEST(res == ans); - - - } - - template - void run_probabilistic_test ( - ) - { - print_spinner(); - typedef matrix sample_type; - - std::vector samples; - std::vector labels; - - // First, get our labeled set of training data - generate_data(samples, labels); - - typedef one_vs_all_trainer,label_type > ova_trainer; - - - ova_trainer trainer; - - typedef polynomial_kernel poly_kernel; - typedef radial_basis_kernel rbf_kernel; - - // make the binary trainers and set some parameters - krr_trainer rbf_trainer; - svm_nu_trainer poly_trainer; - poly_trainer.set_kernel(poly_kernel(0.1, 1, 2)); - rbf_trainer.set_kernel(rbf_kernel(0.1)); - - - trainer.set_trainer(probabilistic(rbf_trainer, 3)); - trainer.set_trainer(probabilistic(poly_trainer, 3), 1); - - randomize_samples(samples, labels); - matrix res = cross_validate_multiclass_trainer(trainer, samples, labels, 2); - - print_spinner(); - - matrix ans(3,3); - ans = 60, 0, 0, - 0, 70, 0, - 0, 0, 80; - - DLIB_TEST_MSG(ans == res, "res: \n" << res); - - one_vs_all_decision_function df = trainer.train(samples, labels); - - DLIB_TEST(df.number_of_classes() == 3); - - DLIB_TEST(df(samples[0]) == labels[0]) - DLIB_TEST(df(samples[90]) == labels[90]) - - - one_vs_all_decision_function >, // This is the output of the poly_trainer - probabilistic_function > // This is the output of the rbf_trainer - > df2, df3; - - - df2 = df; - ofstream fout("df.dat", ios::binary); - serialize(df2, fout); - fout.close(); - - // load the function back in from disk and store it in df3. - ifstream fin("df.dat", ios::binary); - deserialize(df3, fin); - - - DLIB_TEST(df3(samples[0]) == labels[0]) - DLIB_TEST(df3(samples[90]) == labels[90]) - res = test_multiclass_decision_function(df3, samples, labels); - - DLIB_TEST(res == ans); - - - } - - void perform_test ( - ) - { - dlog << LINFO << "run_test()"; - run_test(); - - dlog << LINFO << "run_test()"; - run_test(); - - dlog << LINFO << "run_test()"; - run_test(); - - dlog << LINFO << "run_test()"; - run_test(); - - dlog << LINFO << "run_probabilistic_test()"; - run_probabilistic_test(); - - dlog << LINFO << "run_probabilistic_test()"; - run_probabilistic_test(); - - dlog << LINFO << "run_probabilistic_test()"; - run_probabilistic_test(); - - dlog << LINFO << "run_probabilistic_test()"; - run_probabilistic_test(); - } - }; - - test_one_vs_all_trainer a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/one_vs_one_trainer.cpp b/lib/3rdParty/dlib/include/dlib/test/one_vs_one_trainer.cpp deleted file mode 100644 index 32dc64ea..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/one_vs_one_trainer.cpp +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright (C) 2010 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "tester.h" -#include -#include -#include -#include - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - dlib::logger dlog("test.one_vs_one_trainer"); - - - class test_one_vs_one_trainer : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a unit test. When it is constructed - it adds itself into the testing framework. - !*/ - public: - test_one_vs_one_trainer ( - ) : - tester ( - "test_one_vs_one_trainer", // the command line argument name for this test - "Run tests on the one_vs_one_trainer stuff.", // the command line argument description - 0 // the number of command line arguments for this test - ) - { - } - - - - template - void generate_data ( - std::vector& samples, - std::vector& labels - ) - { - const long num = 50; - - sample_type m; - - dlib::rand rnd; - - - // make some samples near the origin - double radius = 0.5; - for (long i = 0; i < num+10; ++i) - { - double sign = 1; - if (rnd.get_random_double() < 0.5) - sign = -1; - m(0) = 2*radius*rnd.get_random_double()-radius; - m(1) = sign*sqrt(radius*radius - m(0)*m(0)); - - // add this sample to our set of samples we will run k-means - samples.push_back(m); - labels.push_back(1); - } - - // make some samples in a circle around the origin but far away - radius = 10.0; - for (long i = 0; i < num+20; ++i) - { - double sign = 1; - if (rnd.get_random_double() < 0.5) - sign = -1; - m(0) = 2*radius*rnd.get_random_double()-radius; - m(1) = sign*sqrt(radius*radius - m(0)*m(0)); - - // add this sample to our set of samples we will run k-means - samples.push_back(m); - labels.push_back(2); - } - - // make some samples in a circle around the point (25,25) - radius = 4.0; - for (long i = 0; i < num+30; ++i) - { - double sign = 1; - if (rnd.get_random_double() < 0.5) - sign = -1; - m(0) = 2*radius*rnd.get_random_double()-radius; - m(1) = sign*sqrt(radius*radius - m(0)*m(0)); - - // translate this point away from the origin - m(0) += 25; - m(1) += 25; - - // add this sample to our set of samples we will run k-means - samples.push_back(m); - labels.push_back(3); - } - } - - template - void run_test ( - ) - { - print_spinner(); - typedef matrix sample_type; - - std::vector samples, norm_samples; - std::vector labels; - - // First, get our labeled set of training data - generate_data(samples, labels); - - typedef one_vs_one_trainer,label_type > ovo_trainer; - - - ovo_trainer trainer; - - typedef histogram_intersection_kernel hist_kernel; - typedef radial_basis_kernel rbf_kernel; - - // make the binary trainers and set some parameters - krr_trainer rbf_trainer; - svm_nu_trainer hist_trainer; - rbf_trainer.set_kernel(rbf_kernel(0.1)); - - - trainer.set_trainer(rbf_trainer); - trainer.set_trainer(hist_trainer, 1, 2); - - randomize_samples(samples, labels); - matrix res = cross_validate_multiclass_trainer(trainer, samples, labels, 2); - - print_spinner(); - - matrix ans(3,3); - ans = 60, 0, 0, - 0, 70, 0, - 0, 0, 80; - - DLIB_TEST_MSG(ans == res, "res: \n" << res); - - // test using a normalized_function with a one_vs_one_decision_function - { - trainer.set_trainer(hist_trainer, 1, 2); - vector_normalizer normalizer; - normalizer.train(samples); - for (unsigned long i = 0; i < samples.size(); ++i) - norm_samples.push_back(normalizer(samples[i])); - normalized_function > ndf; - ndf.function = trainer.train(norm_samples, labels); - ndf.normalizer = normalizer; - DLIB_TEST(ndf(samples[0]) == labels[0]); - DLIB_TEST(ndf(samples[40]) == labels[40]); - DLIB_TEST(ndf(samples[90]) == labels[90]); - DLIB_TEST(ndf(samples[120]) == labels[120]); - trainer.set_trainer(hist_trainer, 1, 2); - print_spinner(); - } - - - - - one_vs_one_decision_function df = trainer.train(samples, labels); - - DLIB_TEST(df.number_of_classes() == 3); - - DLIB_TEST(df(samples[0]) == labels[0]) - DLIB_TEST(df(samples[90]) == labels[90]) - - - one_vs_one_decision_function, // This is the output of the hist_trainer - decision_function // This is the output of the rbf_trainer - > df2, df3; - - - df2 = df; - ofstream fout("df.dat", ios::binary); - serialize(df2, fout); - fout.close(); - - // load the function back in from disk and store it in df3. - ifstream fin("df.dat", ios::binary); - deserialize(df3, fin); - - - DLIB_TEST(df3(samples[0]) == labels[0]) - DLIB_TEST(df3(samples[90]) == labels[90]) - res = test_multiclass_decision_function(df3, samples, labels); - - DLIB_TEST(res == ans); - - - } - - void perform_test ( - ) - { - dlog << LINFO << "run_test()"; - run_test(); - - dlog << LINFO << "run_test()"; - run_test(); - - dlog << LINFO << "run_test()"; - run_test(); - - dlog << LINFO << "run_test()"; - run_test(); - } - }; - - test_one_vs_one_trainer a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/opt_qp_solver.cpp b/lib/3rdParty/dlib/include/dlib/test/opt_qp_solver.cpp deleted file mode 100644 index 104da557..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/opt_qp_solver.cpp +++ /dev/null @@ -1,476 +0,0 @@ -// Copyright (C) 2010 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.opt_qp_solver"); - -// ---------------------------------------------------------------------------------------- - - class test_smo - { - public: - double penalty; - double C; - - double operator() ( - const matrix& alpha - ) const - { - - double obj = 0.5* trans(alpha)*Q*alpha - trans(alpha)*b; - double c1 = pow(sum(alpha)-C,2); - double c2 = sum(pow(pointwise_multiply(alpha, alpha<0), 2)); - - obj += penalty*(c1 + c2); - - return obj; - } - - matrix Q, b; - }; - -// ---------------------------------------------------------------------------------------- - - class test_smo_derivative - { - public: - double penalty; - double C; - - matrix operator() ( - const matrix& alpha - ) const - { - - matrix obj = Q*alpha - b; - matrix c1 = uniform_matrix(alpha.size(),1, 2*(sum(alpha)-C)); - matrix c2 = 2*pointwise_multiply(alpha, alpha<0); - - return obj + penalty*(c1 + c2); - } - - matrix Q, b; - }; - -// ---------------------------------------------------------------------------------------- - - double compute_objective_value ( - const matrix& w, - const matrix& A, - const matrix& b, - const double C - ) - { - return 0.5*dot(w,w) + C*max(trans(A)*w + b); - } - -// ---------------------------------------------------------------------------------------- - - void test_qp4_test1() - { - matrix A(3,2); - A = 1,2, - -3,1, - 6,7; - - matrix b(2); - b = 1, - 2; - - const double C = 2; - - matrix alpha(2), true_alpha(2); - alpha = C/2, C/2; - - solve_qp4_using_smo(A, tmp(trans(A)*A), b, alpha, 1e-9, 800); - matrix w = lowerbound(-A*alpha, 0); - - dlog << LINFO << "*******************************************************"; - - dlog << LINFO << "w: " << trans(w); - - dlog << LINFO << "computed obj: "<< compute_objective_value(w,A,b,C); - w = 0; - dlog << LINFO << "with true w obj: "<< compute_objective_value(w,A,b,C); - - dlog << LINFO << "alpha: " << trans(alpha); - true_alpha = 0, 2; - dlog << LINFO << "true alpha: "<< trans(true_alpha); - - dlog << LINFO << "alpha error: "<< max(abs(alpha-true_alpha)); - DLIB_TEST(max(abs(alpha-true_alpha)) < 1e-9); - } - -// ---------------------------------------------------------------------------------------- - - void test_qp4_test2() - { - matrix A(3,2); - A = 1,2, - 3,-1, - 6,7; - - matrix b(2); - b = 1, - 2; - - const double C = 2; - - matrix alpha(2), true_alpha(2); - alpha = C/2, C/2; - - solve_qp4_using_smo(A, tmp(trans(A)*A), b, alpha, 1e-9, 800); - matrix w = lowerbound(-A*alpha, 0); - - dlog << LINFO << "*******************************************************"; - - dlog << LINFO << "w: " << trans(w); - - dlog << LINFO << "computed obj: "<< compute_objective_value(w,A,b,C); - w = 0, 0.25, 0; - dlog << LINFO << "with true w obj: "<< compute_objective_value(w,A,b,C); - - dlog << LINFO << "alpha: " << trans(alpha); - true_alpha = 0.43750, 1.56250; - dlog << LINFO << "true alpha: "<< trans(true_alpha); - - dlog << LINFO << "alpha error: "<< max(abs(alpha-true_alpha)); - DLIB_TEST(max(abs(alpha-true_alpha)) < 1e-9); - } - -// ---------------------------------------------------------------------------------------- - - void test_qp4_test3() - { - matrix A(3,2); - A = 1,2, - -3,-1, - 6,7; - - matrix b(2); - b = 1, - 2; - - const double C = 2; - - matrix alpha(2), true_alpha(2); - alpha = C/2, C/2; - - solve_qp4_using_smo(A, tmp(trans(A)*A), b, alpha, 1e-9, 800); - matrix w = lowerbound(-A*alpha, 0); - - dlog << LINFO << "*******************************************************"; - - dlog << LINFO << "w: " << trans(w); - - dlog << LINFO << "computed obj: "<< compute_objective_value(w,A,b,C); - w = 0, 2, 0; - dlog << LINFO << "with true w obj: "<< compute_objective_value(w,A,b,C); - - dlog << LINFO << "alpha: " << trans(alpha); - true_alpha = 0, 2; - dlog << LINFO << "true alpha: "<< trans(true_alpha); - - dlog << LINFO << "alpha error: "<< max(abs(alpha-true_alpha)); - DLIB_TEST(max(abs(alpha-true_alpha)) < 1e-9); - } - -// ---------------------------------------------------------------------------------------- - - void test_qp4_test5() - { - matrix A(3,3); - A = 1,2,4, - 3,1,6, - 6,7,-2; - - matrix b(3); - b = 1, - 2, - 3; - - const double C = 2; - - matrix alpha(3), true_alpha(3); - alpha = C/2, C/2, 0; - - solve_qp4_using_smo(A, tmp(trans(A)*A), b, alpha, 1e-9, 800); - matrix w = lowerbound(-A*alpha, 0); - - - dlog << LINFO << "*******************************************************"; - - dlog << LINFO << "w: " << trans(w); - - dlog << LINFO << "computed obj: "<< compute_objective_value(w,A,b,C); - w = 0, 0, 0.11111111111111111111; - dlog << LINFO << "with true w obj: "<< compute_objective_value(w,A,b,C); - - dlog << LINFO << "alpha: " << trans(alpha); - true_alpha = 0, 0.432098765432099, 1.567901234567901; - dlog << LINFO << "true alpha: "<< trans(true_alpha); - - dlog << LINFO << "alpha error: "<< max(abs(alpha-true_alpha)); - DLIB_TEST(max(abs(alpha-true_alpha)) < 1e-9); - } - -// ---------------------------------------------------------------------------------------- - - void test_qp4_test4() - { - matrix A(3,2); - A = 1,2, - 3,1, - 6,7; - - matrix b(2); - b = 1, - 2; - - const double C = 2; - - matrix alpha(2), true_alpha(2); - alpha = C/2, C/2; - - solve_qp4_using_smo(A, tmp(trans(A)*A), b, alpha, 1e-9, 800); - matrix w = lowerbound(-A*alpha, 0); - - dlog << LINFO << "*******************************************************"; - - dlog << LINFO << "w: " << trans(w); - - dlog << LINFO << "computed obj: "<< compute_objective_value(w,A,b,C); - w = 0, 0, 0; - dlog << LINFO << "with true w obj: "<< compute_objective_value(w,A,b,C); - - dlog << LINFO << "alpha: " << trans(alpha); - true_alpha = 0, 2; - dlog << LINFO << "true alpha: "<< trans(true_alpha); - - dlog << LINFO << "alpha error: "<< max(abs(alpha-true_alpha)); - DLIB_TEST(max(abs(alpha-true_alpha)) < 1e-9); - } - - void test_qp4_test6() - { - matrix A(3,3); - A = 1,2,4, - 3,1,6, - 6,7,-2; - - matrix b(3); - b = -1, - -2, - -3; - - const double C = 2; - - matrix alpha(3), true_alpha(3); - alpha = C/2, C/2, 0; - - solve_qp4_using_smo(A, tmp(trans(A)*A), b, alpha, 1e-9, 800); - matrix w = lowerbound(-A*alpha, 0); - - dlog << LINFO << "*******************************************************"; - - dlog << LINFO << "w: " << trans(w); - - dlog << LINFO << "computed obj: "<< compute_objective_value(w,A,b,C); - w = 0, 0, 0; - dlog << LINFO << "with true w obj: "<< compute_objective_value(w,A,b,C); - - dlog << LINFO << "alpha: " << trans(alpha); - true_alpha = 2, 0, 0; - dlog << LINFO << "true alpha: "<< trans(true_alpha); - - dlog << LINFO << "alpha error: "<< max(abs(alpha-true_alpha)); - DLIB_TEST(max(abs(alpha-true_alpha)) < 1e-9); - } - - void test_qp4_test7() - { - matrix A(3,3); - A = -1,2,4, - -3,1,6, - -6,7,-2; - - matrix b(3); - b = -1, - -2, - 3; - - matrix Q(3,3); - Q = 4,-5,6, - 1,-4,2, - -9,-4,5; - Q = Q*trans(Q); - - const double C = 2; - - matrix alpha(3), true_alpha(3); - alpha = C/2, C/2, 0; - - solve_qp4_using_smo(A, Q, b, alpha, 1e-9, 800); - - dlog << LINFO << "*******************************************************"; - - dlog << LINFO << "alpha: " << trans(alpha); - true_alpha = 0, 2, 0; - dlog << LINFO << "true alpha: "<< trans(true_alpha); - - dlog << LINFO << "alpha error: "<< max(abs(alpha-true_alpha)); - DLIB_TEST(max(abs(alpha-true_alpha)) < 1e-9); - - } - -// ---------------------------------------------------------------------------------------- - - void test_solve_qp4_using_smo() - { - test_qp4_test1(); - test_qp4_test2(); - test_qp4_test3(); - test_qp4_test4(); - test_qp4_test5(); - test_qp4_test6(); - test_qp4_test7(); - } - -// ---------------------------------------------------------------------------------------- - - class opt_qp_solver_tester : public tester - { - /* - The idea here is just to solve the same problem with two different - methods and check that they basically agree. The SMO solver should be - very accurate but for this problem the BFGS solver is relatively - inaccurate. So this test is really just a sanity check on the SMO - solver. - */ - public: - opt_qp_solver_tester ( - ) : - tester ("test_opt_qp_solver", - "Runs tests on the solve_qp_using_smo component.") - { - thetime = time(0); - } - - time_t thetime; - dlib::rand rnd; - - void perform_test( - ) - { - print_spinner(); - test_solve_qp4_using_smo(); - print_spinner(); - - ++thetime; - //dlog << LINFO << "time seed: " << thetime; - //rnd.set_seed(cast_to_string(thetime)); - - running_stats rs; - - for (int i = 0; i < 40; ++i) - { - for (long dims = 1; dims < 6; ++dims) - { - rs.add(do_the_test(dims, 1.0)); - } - } - - for (int i = 0; i < 40; ++i) - { - for (long dims = 1; dims < 6; ++dims) - { - rs.add(do_the_test(dims, 5.0)); - } - } - - dlog << LINFO << "disagreement mean: " << rs.mean(); - dlog << LINFO << "disagreement stddev: " << rs.stddev(); - DLIB_TEST_MSG(rs.mean() < 0.001, rs.mean()); - DLIB_TEST_MSG(rs.stddev() < 0.001, rs.stddev()); - } - - double do_the_test ( - const long dims, - double C - ) - { - print_spinner(); - dlog << LINFO << "dims: " << dims; - dlog << LINFO << "testing with C == " << C; - test_smo test; - - test.Q = randm(dims, dims, rnd); - test.Q = trans(test.Q)*test.Q; - test.b = randm(dims,1, rnd); - test.C = C; - - test_smo_derivative der; - der.Q = test.Q; - der.b = test.b; - der.C = test.C; - - - matrix x(dims), alpha(dims); - - - test.penalty = 20000; - der.penalty = test.penalty; - - alpha = C/alpha.size(); - x = alpha; - - const unsigned long max_iter = 400000; - solve_qp_using_smo(test.Q, test.b, alpha, 0.00000001, max_iter); - DLIB_TEST_MSG(abs(sum(alpha) - C) < 1e-13, abs(sum(alpha) - C) ); - dlog << LTRACE << "alpha: " << alpha; - dlog << LINFO << "SMO: true objective: "<< 0.5*trans(alpha)*test.Q*alpha - trans(alpha)*test.b; - - - double obj = find_min(bfgs_search_strategy(), - objective_delta_stop_strategy(1e-13, 5000), - test, - der, - x, - -10); - - - dlog << LINFO << "BFGS: objective: " << obj; - dlog << LINFO << "BFGS: true objective: "<< 0.5*trans(x)*test.Q*x - trans(x)*test.b; - dlog << LINFO << "sum(x): " << sum(x); - dlog << LINFO << x; - - double disagreement = max(abs(x-alpha)); - dlog << LINFO << "Disagreement: " << disagreement; - return disagreement; - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/optimization.cpp b/lib/3rdParty/dlib/include/dlib/test/optimization.cpp deleted file mode 100644 index 512156ab..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/optimization.cpp +++ /dev/null @@ -1,1208 +0,0 @@ -// Copyright (C) 2008 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include "optimization_test_functions.h" -#include -#include -#include -#include -#include -#include -#include -#include "../stl_checked.h" -#include "../array.h" -#include "../rand.h" - -#include "tester.h" - - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.optimization"); - -// ---------------------------------------------------------------------------------------- - - bool approx_equal ( - double a, - double b - ) - { - return std::abs(a - b) < 100*std::numeric_limits::epsilon(); - } - -// ---------------------------------------------------------------------------------------- - - long total_count = 0; - - - template - double apq ( const T& x) - { - DLIB_ASSERT(x.nr() > 1 && x.nc() == 1,""); - COMPILE_TIME_ASSERT(is_matrix::value); - double temp = 0; - for (long r = 0; r < x.nr(); ++r) - { - temp += (r+1)*x(r)*x(r); - } - - ++total_count; - - return temp + 1/100.0*(x(0) + x(x.nr()-1))*(x(0) + x(x.nr()-1)); - } - - template - T der_apq ( const T& x) - { - DLIB_ASSERT(x.nr() > 1 && x.nc() == 1,""); - COMPILE_TIME_ASSERT(is_matrix::value); - T temp(x.nr()); - for (long r = 0; r < x.nr(); ++r) - { - temp(r) = 2*(r+1)*x(r) ; - } - - temp(0) += 1/50.0*(x(0) + x(x.nr()-1)); - temp(x.nr()-1) += 1/50.0*(x(0) + x(x.nr()-1)); - - ++total_count; - - return temp; - } - -// ---------------------------------------------------------------------------------------- - - // Rosenbrock's function. minimum at (1,1) - double rosen ( const matrix& x) - { - ++total_count; - return 100*pow(x(1) - x(0)*x(0),2) + pow(1 - x(0),2); - } - - matrix der_rosen ( const matrix& x) - { - ++total_count; - matrix res; - res(0) = -400*x(0)*(x(1)-x(0)*x(0)) - 2*(1-x(0)); - res(1) = 200*(x(1)-x(0)*x(0)); - return res; - } - -// ---------------------------------------------------------------------------------------- - - // negative of Rosenbrock's function. minimum at (1,1) - double neg_rosen ( const matrix& x) - { - ++total_count; - return -(100*pow(x(1) - x(0)*x(0),2) + pow(1 - x(0),2)); - } - - matrix der_neg_rosen ( const matrix& x) - { - ++total_count; - matrix res; - res(0) = -400*x(0)*(x(1)-x(0)*x(0)) - 2*(1-x(0)); - res(1) = 200*(x(1)-x(0)*x(0)); - return -res; - } - -// ---------------------------------------------------------------------------------------- - - double simple ( const matrix& x) - { - ++total_count; - return 10*x(0)*x(0) + x(1)*x(1); - } - - matrix der_simple ( const matrix& x) - { - ++total_count; - matrix res; - res(0) = 20*x(0); - res(1) = 2*x(1); - return res; - } - -// ---------------------------------------------------------------------------------------- - - double powell ( const matrix& x) - { - ++total_count; - return pow(x(0) + 10*x(1),2) + - pow(std::sqrt(5.0)*(x(2) - x(3)),2) + - pow((x(1) - 2*x(2))*(x(1) - 2*x(2)),2) + - pow(std::sqrt(10.0)*(x(0) - x(3))*(x(0) - x(3)),2); - } - -// ---------------------------------------------------------------------------------------- - -// a simple function with a minimum at zero - double single_variable_function ( double x) - { - ++total_count; - return 3*x*x + 5; - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - void test_apq ( - const matrix p - ) - { - typedef matrix T; - const double eps = 1e-12; - const double minf = -10; - matrix x(p.nr()), opt(p.nr()); - set_all_elements(opt, 0); - double val = 0; - - if (p.size() < 20) - dlog << LINFO << "testing with apq and the start point: " << trans(p); - else - dlog << LINFO << "testing with apq and a big vector with " << p.size() << " components."; - - // don't use bfgs on really large vectors - if (p.size() < 20) - { - total_count = 0; - x = p; - val = find_min(bfgs_search_strategy(), - objective_delta_stop_strategy(eps), - wrap_function(apq), wrap_function(der_apq), x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , apq(x))); - dlog << LINFO << "find_min() bgfs: got apq in " << total_count; - - total_count = 0; - x = p; - find_min(bfgs_search_strategy(), - gradient_norm_stop_strategy(), - wrap_function(apq), wrap_function(der_apq), x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - dlog << LINFO << "find_min() bgfs(gn): got apq in " << total_count; - } - - - if (p.size() < 100) - { - total_count = 0; - x = p; - val=find_min_bobyqa(wrap_function(apq), x, 2*x.size()+1, - uniform_matrix(x.size(),1,-1e100), - uniform_matrix(x.size(),1,1e100), - (max(abs(x))+1)/10, - 1e-6, - 10000); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , apq(x))); - dlog << LINFO << "find_min_bobyqa(): got apq in " << total_count; - } - - total_count = 0; - x = p; - val=find_min(lbfgs_search_strategy(10), - objective_delta_stop_strategy(eps), - wrap_function(apq), wrap_function(der_apq), x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , apq(x))); - dlog << LINFO << "find_min() lbgfs-10: got apq in " << total_count; - - - total_count = 0; - x = p; - val=find_min(lbfgs_search_strategy(1), - objective_delta_stop_strategy(eps), - wrap_function(apq), wrap_function(der_apq), x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , apq(x))); - dlog << LINFO << "find_min() lbgfs-1: got apq in " << total_count; - - - total_count = 0; - x = p; - val=find_min(cg_search_strategy(), - objective_delta_stop_strategy(eps), - wrap_function(apq), wrap_function(der_apq), x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , apq(x))); - dlog << LINFO << "find_min() cg: got apq in " << total_count; - - - // don't do approximate derivative tests if the input point is really long - if (p.size() < 20) - { - total_count = 0; - x = p; - val=find_min(bfgs_search_strategy(), - objective_delta_stop_strategy(eps), - wrap_function(apq), derivative(wrap_function(apq)), x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , apq(x))); - dlog << LINFO << "find_min() bfgs: got apq/noder in " << total_count; - - - total_count = 0; - x = p; - val=find_min(cg_search_strategy(), - objective_delta_stop_strategy(eps), - wrap_function(apq), derivative(wrap_function(apq)), x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , apq(x))); - dlog << LINFO << "find_min() cg: got apq/noder in " << total_count; - - - total_count = 0; - x = p; - val=find_min_using_approximate_derivatives(bfgs_search_strategy(), - objective_delta_stop_strategy(eps), - wrap_function(apq), x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , apq(x))); - dlog << LINFO << "find_min() bfgs: got apq/noder2 in " << total_count; - - - total_count = 0; - x = p; - val=find_min_using_approximate_derivatives(lbfgs_search_strategy(10), - objective_delta_stop_strategy(eps), - wrap_function(apq), x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - dlog << LINFO << "find_min() lbfgs-10: got apq/noder2 in " << total_count; - - - total_count = 0; - x = p; - val=find_min_using_approximate_derivatives(cg_search_strategy(), - objective_delta_stop_strategy(eps), - wrap_function(apq), x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , apq(x))); - dlog << LINFO << "find_min() cg: got apq/noder2 in " << total_count; - } - } - - void test_powell ( - const matrix p - ) - { - const double eps = 1e-15; - const double minf = -1; - matrix x, opt; - opt(0) = 0; - opt(1) = 0; - opt(2) = 0; - opt(3) = 0; - - double val = 0; - - dlog << LINFO << "testing with powell and the start point: " << trans(p); - - /* - total_count = 0; - x = p; - val=find_min(bfgs_search_strategy(), - objective_delta_stop_strategy(eps), - powell, derivative(powell,1e-8), x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-2),opt-x); - DLIB_TEST(approx_equal(val , powell(x))); - dlog << LINFO << "find_min() bfgs: got powell/noder in " << total_count; - - - total_count = 0; - x = p; - val=find_min(cg_search_strategy(), - objective_delta_stop_strategy(eps), - powell, derivative(powell,1e-9), x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-2),opt-x); - DLIB_TEST(approx_equal(val , powell(x))); - dlog << LINFO << "find_min() cg: got powell/noder in " << total_count; - */ - - total_count = 0; - x = p; - val=find_min_using_approximate_derivatives(bfgs_search_strategy(), - objective_delta_stop_strategy(eps), - powell, x, minf, 1e-10); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-1),opt-x); - DLIB_TEST(approx_equal(val , powell(x))); - dlog << LINFO << "find_min() bfgs: got powell/noder2 in " << total_count; - - - total_count = 0; - x = p; - val=find_min_using_approximate_derivatives(lbfgs_search_strategy(4), - objective_delta_stop_strategy(eps), - powell, x, minf, 1e-10); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-1),opt-x); - DLIB_TEST(approx_equal(val , powell(x))); - dlog << LINFO << "find_min() lbfgs-4: got powell/noder2 in " << total_count; - - - total_count = 0; - x = p; - val=find_min_using_approximate_derivatives(lbfgs_search_strategy(4), - gradient_norm_stop_strategy(), - powell, x, minf, 1e-10); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-1),opt-x); - DLIB_TEST(approx_equal(val , powell(x))); - dlog << LINFO << "find_min() lbfgs-4(gn): got powell/noder2 in " << total_count; - - - total_count = 0; - x = p; - val=find_min_using_approximate_derivatives(cg_search_strategy(), - objective_delta_stop_strategy(eps), - powell, x, minf, 1e-10); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-1),opt-x); - DLIB_TEST(approx_equal(val , powell(x))); - dlog << LINFO << "find_min() cg: got powell/noder2 in " << total_count; - - - total_count = 0; - x = p; - val=find_min_bobyqa(powell, x, 2*x.size()+1, - uniform_matrix(x.size(),1,-1e100), - uniform_matrix(x.size(),1,1e100), - (max(abs(x))+1)/10, - 1e-7, - 10000); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-3),opt-x); - DLIB_TEST(approx_equal(val , powell(x))); - dlog << LINFO << "find_min_bobyqa(): got powell in " << total_count; - - } - - - - void test_simple ( - const matrix p - ) - { - const double eps = 1e-12; - const double minf = -10000; - matrix x, opt; - opt(0) = 0; - opt(1) = 0; - double val = 0; - - dlog << LINFO << "testing with simple and the start point: " << trans(p); - - total_count = 0; - x = p; - val=find_min(bfgs_search_strategy(), - objective_delta_stop_strategy(eps), - simple, der_simple, x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , simple(x))); - dlog << LINFO << "find_min() bfgs: got simple in " << total_count; - - - total_count = 0; - x = p; - val=find_min(bfgs_search_strategy(), - gradient_norm_stop_strategy(), - simple, der_simple, x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , simple(x))); - dlog << LINFO << "find_min() bfgs(gn): got simple in " << total_count; - - - total_count = 0; - x = p; - val=find_min(lbfgs_search_strategy(3), - objective_delta_stop_strategy(eps), - simple, der_simple, x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , simple(x))); - dlog << LINFO << "find_min() lbfgs-3: got simple in " << total_count; - - - total_count = 0; - x = p; - val=find_min(cg_search_strategy(), - objective_delta_stop_strategy(eps), - simple, der_simple, x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , simple(x))); - dlog << LINFO << "find_min() cg: got simple in " << total_count; - - - - total_count = 0; - x = p; - val=find_min(bfgs_search_strategy(), - objective_delta_stop_strategy(eps), - simple, derivative(simple), x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , simple(x))); - dlog << LINFO << "find_min() bfgs: got simple/noder in " << total_count; - - - total_count = 0; - x = p; - val=find_min(lbfgs_search_strategy(8), - objective_delta_stop_strategy(eps), - simple, derivative(simple), x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , simple(x))); - dlog << LINFO << "find_min() lbfgs-8: got simple/noder in " << total_count; - - - total_count = 0; - x = p; - val=find_min(cg_search_strategy(), - objective_delta_stop_strategy(eps), - simple, derivative(simple), x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , simple(x))); - dlog << LINFO << "find_min() cg: got simple/noder in " << total_count; - - - - total_count = 0; - x = p; - val=find_min_using_approximate_derivatives(bfgs_search_strategy(), - objective_delta_stop_strategy(eps), - simple, x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , simple(x))); - dlog << LINFO << "find_min() bfgs: got simple/noder2 in " << total_count; - - - total_count = 0; - x = p; - val=find_min_using_approximate_derivatives(lbfgs_search_strategy(6), - objective_delta_stop_strategy(eps), - simple, x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , simple(x))); - dlog << LINFO << "find_min() lbfgs-6: got simple/noder2 in " << total_count; - - - total_count = 0; - x = p; - val=find_min_using_approximate_derivatives(cg_search_strategy(), - objective_delta_stop_strategy(eps), - simple, x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , simple(x))); - dlog << LINFO << "find_min() cg: got simple/noder2 in " << total_count; - - - total_count = 0; - x = p; - val=find_min_bobyqa(simple, x, 2*x.size()+1, - uniform_matrix(x.size(),1,-1e100), - uniform_matrix(x.size(),1,1e100), - (max(abs(x))+1)/10, - 1e-6, - 10000); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , simple(x))); - dlog << LINFO << "find_min_bobyqa(): got simple in " << total_count; - - } - - - void test_rosen ( - const matrix p - ) - { - const double eps = 1e-15; - const double minf = -10; - matrix x, opt; - opt(0) = 1; - opt(1) = 1; - - double val = 0; - - dlog << LINFO << "testing with rosen and the start point: " << trans(p); - - total_count = 0; - x = p; - val=find_min(bfgs_search_strategy(), - objective_delta_stop_strategy(eps), - rosen, der_rosen, x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x); - DLIB_TEST(approx_equal(val , rosen(x))); - dlog << LINFO << "find_min() bfgs: got rosen in " << total_count; - - - total_count = 0; - x = p; - val=find_min(bfgs_search_strategy(), - gradient_norm_stop_strategy(), - rosen, der_rosen, x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x); - DLIB_TEST(approx_equal(val , rosen(x))); - dlog << LINFO << "find_min() bfgs(gn): got rosen in " << total_count; - - - total_count = 0; - x = p; - val=find_min(lbfgs_search_strategy(20), - objective_delta_stop_strategy(eps), - rosen, der_rosen, x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x); - DLIB_TEST(approx_equal(val , rosen(x))); - dlog << LINFO << "find_min() lbfgs-20: got rosen in " << total_count; - - - total_count = 0; - x = p; - val=find_min(cg_search_strategy(), - objective_delta_stop_strategy(eps), - rosen, der_rosen, x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x); - DLIB_TEST(approx_equal(val , rosen(x))); - dlog << LINFO << "find_min() cg: got rosen in " << total_count; - - - - total_count = 0; - x = p; - val=find_min(bfgs_search_strategy(), - objective_delta_stop_strategy(eps), - rosen, derivative(rosen,1e-5), x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-4),opt-x); - DLIB_TEST(approx_equal(val , rosen(x))); - dlog << LINFO << "find_min() bfgs: got rosen/noder in " << total_count; - - - total_count = 0; - x = p; - val=find_min(lbfgs_search_strategy(5), - objective_delta_stop_strategy(eps), - rosen, derivative(rosen,1e-5), x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-4),opt-x); - DLIB_TEST(approx_equal(val , rosen(x))); - dlog << LINFO << "find_min() lbfgs-5: got rosen/noder in " << total_count; - - - total_count = 0; - x = p; - val=find_min(cg_search_strategy(), - objective_delta_stop_strategy(eps), - rosen, derivative(rosen,1e-5), x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-4),opt-x); - DLIB_TEST(approx_equal(val , rosen(x))); - dlog << LINFO << "find_min() cg: got rosen/noder in " << total_count; - - - total_count = 0; - x = p; - val=find_min_using_approximate_derivatives(cg_search_strategy(), - objective_delta_stop_strategy(eps), - rosen, x, minf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-4),opt-x); - DLIB_TEST(approx_equal(val , rosen(x))); - dlog << LINFO << "find_min() cg: got rosen/noder2 in " << total_count; - - - if (max(abs(p)) < 1000) - { - total_count = 0; - x = p; - val=find_min_bobyqa(rosen, x, 2*x.size()+1, - uniform_matrix(x.size(),1,-1e100), - uniform_matrix(x.size(),1,1e100), - (max(abs(x))+1)/10, - 1e-6, - 10000); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , rosen(x))); - dlog << LINFO << "find_min_bobyqa(): got rosen in " << total_count; - } - } - - - void test_neg_rosen ( - const matrix p - ) - { - const double eps = 1e-15; - const double maxf = 10; - matrix x, opt; - opt(0) = 1; - opt(1) = 1; - - double val = 0; - - dlog << LINFO << "testing with neg_rosen and the start point: " << trans(p); - - total_count = 0; - x = p; - val=find_max( - bfgs_search_strategy(), - objective_delta_stop_strategy(eps), neg_rosen, der_neg_rosen, x, maxf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x); - DLIB_TEST(approx_equal(val , neg_rosen(x))); - dlog << LINFO << "find_max() bfgs: got neg_rosen in " << total_count; - - total_count = 0; - x = p; - val=find_max( - lbfgs_search_strategy(5), - objective_delta_stop_strategy(eps), neg_rosen, der_neg_rosen, x, maxf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x); - DLIB_TEST(approx_equal(val , neg_rosen(x))); - dlog << LINFO << "find_max() lbfgs-5: got neg_rosen in " << total_count; - - total_count = 0; - x = p; - val=find_max( - lbfgs_search_strategy(5), - objective_delta_stop_strategy(eps), neg_rosen, derivative(neg_rosen), x, maxf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x); - DLIB_TEST(approx_equal(val , neg_rosen(x))); - dlog << LINFO << "find_max() lbfgs-5: got neg_rosen/noder in " << total_count; - - - total_count = 0; - x = p; - val=find_max_using_approximate_derivatives( - cg_search_strategy(), - objective_delta_stop_strategy(eps), neg_rosen, x, maxf); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-7),opt-x); - DLIB_TEST(approx_equal(val , neg_rosen(x))); - dlog << LINFO << "find_max() cg: got neg_rosen/noder2 in " << total_count; - - - total_count = 0; - x = p; - val=find_max_bobyqa(neg_rosen, x, 2*x.size()+1, - uniform_matrix(x.size(),1,-1e100), - uniform_matrix(x.size(),1,1e100), - (max(abs(x))+1)/10, - 1e-6, - 10000); - DLIB_TEST_MSG(dlib::equal(x,opt, 1e-5),opt-x); - DLIB_TEST(approx_equal(val , neg_rosen(x))); - dlog << LINFO << "find_max_bobyqa(): got neg_rosen in " << total_count; - } - -// ---------------------------------------------------------------------------------------- - - void test_single_variable_function ( - const double p - ) - { - const double eps = 1e-7; - - - dlog << LINFO << "testing with single_variable_function and the start point: " << p; - double out, x; - - total_count = 0; - x = p; - out = find_min_single_variable(single_variable_function, x, -1e100, 1e100, eps, 1000); - DLIB_TEST_MSG(std::abs(out-5) < 1e-6, out-5); - DLIB_TEST_MSG(std::abs(x) < 1e-6, x); - dlog << LINFO << "find_min_single_variable(): got single_variable_function in " << total_count; - - - total_count = 0; - x = p; - out = -find_max_single_variable(negate_function(single_variable_function), x, -1e100, 1e100, eps, 1000); - DLIB_TEST_MSG(std::abs(out-5) < 1e-6, out-5); - DLIB_TEST_MSG(std::abs(x) < 1e-6, x); - dlog << LINFO << "find_max_single_variable(): got single_variable_function in " << total_count; - - - if (p > 0) - { - total_count = 0; - x = p; - out = find_min_single_variable(single_variable_function, x, -1e-4, 1e100, eps, 1000); - DLIB_TEST_MSG(std::abs(out-5) < 1e-6, out-5); - DLIB_TEST_MSG(std::abs(x) < 1e-6, x); - dlog << LINFO << "find_min_single_variable(): got single_variable_function in " << total_count; - - - if (p > 3) - { - total_count = 0; - x = p; - out = -find_max_single_variable(negate_function(single_variable_function), x, 3, 1e100, eps, 1000); - DLIB_TEST_MSG(std::abs(out - (3*3*3+5)) < 1e-6, out-(3*3*3+5)); - DLIB_TEST_MSG(std::abs(x-3) < 1e-6, x); - dlog << LINFO << "find_max_single_variable(): got single_variable_function in " << total_count; - } - } - - if (p < 0) - { - total_count = 0; - x = p; - out = find_min_single_variable(single_variable_function, x, -1e100, 1e-4, eps, 1000); - DLIB_TEST_MSG(std::abs(out-5) < 1e-6, out-5); - DLIB_TEST_MSG(std::abs(x) < 1e-6, x); - dlog << LINFO << "find_min_single_variable(): got single_variable_function in " << total_count; - - if (p < -3) - { - total_count = 0; - x = p; - out = find_min_single_variable(single_variable_function, x, -1e100, -3, eps, 1000); - DLIB_TEST_MSG(std::abs(out - (3*3*3+5)) < 1e-6, out-(3*3*3+5)); - DLIB_TEST_MSG(std::abs(x+3) < 1e-6, x); - dlog << LINFO << "find_min_single_variable(): got single_variable_function in " << total_count; - } - } - - } - -// ---------------------------------------------------------------------------------------- - - void optimization_test ( - ) - /*! - ensures - - runs tests on the optimization stuff compliance with the specs - !*/ - { - matrix p; - - print_spinner(); - - p.set_size(2); - - // test with single_variable_function - test_single_variable_function(0); - test_single_variable_function(1); - test_single_variable_function(-10); - test_single_variable_function(-100); - test_single_variable_function(900.53); - - // test with the rosen function - p(0) = 9; - p(1) = -4.9; - test_rosen(p); - test_neg_rosen(p); - - p(0) = 0; - p(1) = 0; - test_rosen(p); - - p(0) = 5323; - p(1) = 98248; - test_rosen(p); - - // test with the simple function - p(0) = 1; - p(1) = 1; - test_simple(p); - - p(0) = 0.5; - p(1) = -9; - test_simple(p); - - p(0) = 645; - p(1) = 839485; - test_simple(p); - - print_spinner(); - - // test with the apq function - p.set_size(5); - - p(0) = 1; - p(1) = 1; - p(2) = 1; - p(3) = 1; - p(4) = 1; - test_apq(p); - - p(0) = 1; - p(1) = 2; - p(2) = 3; - p(3) = 4; - p(4) = 5; - test_apq(p); - - p(0) = 1; - p(1) = 2; - p(2) = -3; - p(3) = 4; - p(4) = 5; - test_apq(p); - - print_spinner(); - - p(0) = 1; - p(1) = 2324; - p(2) = -3; - p(3) = 4; - p(4) = 534534; - test_apq(p); - - p.set_size(10); - p(0) = 1; - p(1) = 2; - p(2) = -3; - p(3) = 4; - p(4) = 5; - p(5) = 1; - p(6) = 2; - p(7) = -3; - p(8) = 4; - p(9) = 5; - test_apq(p); - - // test apq with a big vector - p.set_size(500); - dlib::rand rnd; - for (long i = 0; i < p.size(); ++i) - { - p(i) = rnd.get_random_double()*20 - 10; - } - test_apq(p); - - print_spinner(); - - // test with the powell function - p.set_size(4); - - p(0) = 3; - p(1) = -1; - p(2) = 0; - p(3) = 1; - test_powell(p); - - { - matrix m; - m(0) = -0.43; - m(1) = 0.919; - DLIB_TEST(dlib::equal(der_rosen(m) , derivative(rosen)(m),1e-5)); - - DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(0) - - make_line_search_function(derivative(rosen),m,m)(0)) < 1e-5,""); - DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(1) - - make_line_search_function(derivative(rosen),m,m)(1)) < 1e-5,""); - - DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(0) - - make_line_search_function(der_rosen,m,m)(0)) < 1e-5,""); - DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(1) - - make_line_search_function(der_rosen,m,m)(1)) < 1e-5,""); - } - { - matrix m; - m(0) = 1; - m(1) = 2; - DLIB_TEST(dlib::equal(der_rosen(m) , derivative(rosen)(m),1e-5)); - - DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(0) - - make_line_search_function(derivative(rosen),m,m)(0)) < 1e-5,""); - DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(1) - - make_line_search_function(derivative(rosen),m,m)(1)) < 1e-5,""); - - DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(0) - - make_line_search_function(der_rosen,m,m)(0)) < 1e-5,""); - DLIB_TEST_MSG(std::abs(derivative(make_line_search_function(rosen,m,m))(1) - - make_line_search_function(der_rosen,m,m)(1)) < 1e-5,""); - } - - { - matrix m; - m = 1,2; - DLIB_TEST(std::abs(neg_rosen(m) - negate_function(rosen)(m) ) < 1e-16); - } - - } - - template - double unconstrained_gradient_magnitude ( - const der_funct& grad, - const T& x, - const T& lower, - const T& upper - ) - { - T g = grad(x); - - double unorm = 0; - - for (long i = 0; i < g.size(); ++i) - { - if (lower(i) < x(i) && x(i) < upper(i)) - unorm += g(i)*g(i); - else if (x(i) == lower(i) && g(i) < 0) - unorm += g(i)*g(i); - else if (x(i) == upper(i) && g(i) > 0) - unorm += g(i)*g(i); - } - - return unorm; - } - - template - double unconstrained_gradient_magnitude_neg_funct ( - const der_funct& grad, - const T& x, - const T& lower, - const T& upper - ) - { - T g = grad(x); - - double unorm = 0; - - for (long i = 0; i < g.size(); ++i) - { - if (lower(i) < x(i) && x(i) < upper(i)) - unorm += g(i)*g(i); - else if (x(i) == lower(i) && g(i) > 0) - unorm += g(i)*g(i); - else if (x(i) == upper(i) && g(i) < 0) - unorm += g(i)*g(i); - } - - return unorm; - } - - template - double test_bound_solver_neg_rosen (dlib::rand& rnd, search_strategy_type search_strategy) - { - using namespace dlib::test_functions; - print_spinner(); - matrix starting_point, lower, upper, x; - - - // pick random bounds - lower = rnd.get_random_gaussian()+1, rnd.get_random_gaussian()+1; - upper = rnd.get_random_gaussian()+1, rnd.get_random_gaussian()+1; - while (upper(0) < lower(0)) upper(0) = rnd.get_random_gaussian()+1; - while (upper(1) < lower(1)) upper(1) = rnd.get_random_gaussian()+1; - - starting_point = rnd.get_random_double()*(upper(0)-lower(0))+lower(0), - rnd.get_random_double()*(upper(1)-lower(1))+lower(1); - - dlog << LINFO << "lower: "<< trans(lower); - dlog << LINFO << "upper: "<< trans(upper); - dlog << LINFO << "starting: "<< trans(starting_point); - - x = starting_point; - double val = find_max_box_constrained( - search_strategy, - objective_delta_stop_strategy(1e-16, 500), - neg_rosen, der_neg_rosen, x, - lower, - upper - ); - - DLIB_TEST_MSG(std::abs(val - neg_rosen(x)) < 1e-11, std::abs(val - neg_rosen(x))); - dlog << LINFO << "neg_rosen solution:\n" << x; - - dlog << LINFO << "neg_rosen gradient: "<< trans(der_neg_rosen(x)); - const double gradient_residual = unconstrained_gradient_magnitude_neg_funct(der_neg_rosen, x, lower, upper); - dlog << LINFO << "gradient_residual: "<< gradient_residual; - - return gradient_residual; - } - - template - double test_bound_solver_rosen (dlib::rand& rnd, search_strategy_type search_strategy) - { - using namespace dlib::test_functions; - print_spinner(); - matrix starting_point, lower, upper, x; - - - // pick random bounds and sometimes put the upper bound at zero so we can have - // a test where the optimal value has a bound active at 0 so make sure this case - // works properly. - if (rnd.get_random_double() > 0.2) - { - lower = rnd.get_random_gaussian()+1, rnd.get_random_gaussian()+1; - upper = rnd.get_random_gaussian()+1, rnd.get_random_gaussian()+1; - while (upper(0) < lower(0)) upper(0) = rnd.get_random_gaussian()+1; - while (upper(1) < lower(1)) upper(1) = rnd.get_random_gaussian()+1; - } - else - { - upper = 0,0; - if (rnd.get_random_double() > 0.5) - upper(0) = -rnd.get_random_double(); - if (rnd.get_random_double() > 0.5) - upper(1) = -rnd.get_random_double(); - - lower = rnd.get_random_double()+1, rnd.get_random_double()+1; - lower = upper - lower; - } - const bool pick_uniform_bounds = rnd.get_random_double() > 0.9; - if (pick_uniform_bounds) - { - double x = rnd.get_random_gaussian()*2; - double y = rnd.get_random_gaussian()*2; - lower = min(x,y); - upper = max(x,y); - } - - starting_point = rnd.get_random_double()*(upper(0)-lower(0))+lower(0), - rnd.get_random_double()*(upper(1)-lower(1))+lower(1); - - dlog << LINFO << "lower: "<< trans(lower); - dlog << LINFO << "upper: "<< trans(upper); - dlog << LINFO << "starting: "<< trans(starting_point); - - x = starting_point; - double val; - if (!pick_uniform_bounds) - { - val = find_min_box_constrained( - search_strategy, - objective_delta_stop_strategy(1e-16, 500), - rosen, der_rosen, x, - lower, - upper - ); - } - else - { - val = find_min_box_constrained( - search_strategy, - objective_delta_stop_strategy(1e-16, 500), - rosen, der_rosen, x, - lower(0), - upper(0) - ); - } - - - DLIB_TEST_MSG(std::abs(val - rosen(x)) < 1e-11, std::abs(val - rosen(x))); - dlog << LINFO << "rosen solution:\n" << x; - - dlog << LINFO << "rosen gradient: "<< trans(der_rosen(x)); - const double gradient_residual = unconstrained_gradient_magnitude(der_rosen, x, lower, upper); - dlog << LINFO << "gradient_residual: "<< gradient_residual; - - return gradient_residual; - } - - template - double test_bound_solver_brown (dlib::rand& rnd, search_strategy_type search_strategy) - { - using namespace dlib::test_functions; - print_spinner(); - matrix starting_point(4), lower(4), upper(4), x; - - const matrix solution = brown_solution(); - - // pick random bounds - lower = rnd.get_random_gaussian(), rnd.get_random_gaussian(), rnd.get_random_gaussian(), rnd.get_random_gaussian(); - lower = lower*10 + solution; - upper = rnd.get_random_gaussian(), rnd.get_random_gaussian(), rnd.get_random_gaussian(), rnd.get_random_gaussian(); - upper = upper*10 + solution; - for (int i = 0; i < lower.size(); ++i) - { - if (upper(i) < lower(i)) - swap(upper(i),lower(i)); - } - - starting_point = rnd.get_random_double()*(upper(0)-lower(0))+lower(0), - rnd.get_random_double()*(upper(1)-lower(1))+lower(1), - rnd.get_random_double()*(upper(2)-lower(2))+lower(2), - rnd.get_random_double()*(upper(3)-lower(3))+lower(3); - - dlog << LINFO << "lower: "<< trans(lower); - dlog << LINFO << "upper: "<< trans(upper); - dlog << LINFO << "starting: "<< trans(starting_point); - - x = starting_point; - double val = find_min_box_constrained( - search_strategy, - objective_delta_stop_strategy(1e-16, 500), - brown, brown_derivative, x, - lower, - upper - ); - - DLIB_TEST(std::abs(val - brown(x)) < 1e-14); - dlog << LINFO << "brown solution:\n" << x; - return unconstrained_gradient_magnitude(brown_derivative, x, lower, upper); - } - - template - void test_box_constrained_optimizers(search_strategy_type search_strategy) - { - dlib::rand rnd; - running_stats rs; - - dlog << LINFO << "test find_min_box_constrained() on rosen"; - for (int i = 0; i < 10000; ++i) - rs.add(test_bound_solver_rosen(rnd, search_strategy)); - dlog << LINFO << "mean rosen gradient: " << rs.mean(); - dlog << LINFO << "max rosen gradient: " << rs.max(); - DLIB_TEST(rs.mean() < 1e-12); - DLIB_TEST(rs.max() < 1e-9); - - dlog << LINFO << "test find_min_box_constrained() on brown"; - rs.clear(); - for (int i = 0; i < 1000; ++i) - rs.add(test_bound_solver_brown(rnd, search_strategy)); - dlog << LINFO << "mean brown gradient: " << rs.mean(); - dlog << LINFO << "max brown gradient: " << rs.max(); - dlog << LINFO << "min brown gradient: " << rs.min(); - DLIB_TEST(rs.mean() < 1e-5); - DLIB_TEST(rs.max() < 1e-2); - DLIB_TEST(rs.min() < 1e-10); - - dlog << LINFO << "test find_max_box_constrained() on neg_rosen"; - rs.clear(); - for (int i = 0; i < 1000; ++i) - rs.add(test_bound_solver_neg_rosen(rnd, search_strategy)); - dlog << LINFO << "mean neg_rosen gradient: " << rs.mean(); - dlog << LINFO << "max neg_rosen gradient: " << rs.max(); - DLIB_TEST(rs.mean() < 1e-12); - DLIB_TEST(rs.max() < 1e-9); - - } - - void test_poly_min_extract_2nd() - { - double off; - - off = 0.0; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13); - off = 0.1; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13); - off = 0.2; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13); - off = 0.3; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13); - off = 0.4; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13); - off = 0.5; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13); - off = 0.6; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13); - off = 0.8; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13); - off = 0.9; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13); - off = 1.0; DLIB_TEST(std::abs( poly_min_extrap(off*off, -2*off, (1-off)*(1-off)) - off) < 1e-13); - } - - class optimization_tester : public tester - { - public: - optimization_tester ( - ) : - tester ("test_optimization", - "Runs tests on the optimization component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "test_box_constrained_optimizers(bfgs_search_strategy())"; - test_box_constrained_optimizers(bfgs_search_strategy()); - dlog << LINFO << "test_box_constrained_optimizers(lbfgs_search_strategy(5))"; - test_box_constrained_optimizers(lbfgs_search_strategy(5)); - test_poly_min_extract_2nd(); - optimization_test(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/optimization_test_functions.cpp b/lib/3rdParty/dlib/include/dlib/test/optimization_test_functions.cpp deleted file mode 100644 index 5a936169..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/optimization_test_functions.cpp +++ /dev/null @@ -1,425 +0,0 @@ -// Copyright (C) 2010 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#include "optimization_test_functions.h" - -/* - - Most of the code in this file is converted from the set of Fortran 90 routines - created by John Burkardt. - - The original Fortran can be found here: http://orion.math.iastate.edu/burkardt/f_src/testopt/testopt.html - -*/ - - -namespace dlib -{ - namespace test_functions - { - - // ---------------------------------------------------------------------------------------- - - matrix chebyquad_residuals(const matrix& x) - { - matrix fvec(x.size()); - const int n = x.size(); - int i; - int j; - double t; - double t1; - double t2; - double th; - fvec = 0; - - for (j = 1; j <= n; ++j) - { - t1 = 1.0E+00; - t2 = 2.0E+00 * x(j-1) - 1.0E+00; - t = 2.0E+00 * t2; - for (i = 1; i <= n; ++i) - { - fvec(i-1) = fvec(i-1) + t2; - th = t * t2 - t1; - t1 = t2; - t2 = th; - } - } - - for (i = 1; i <= n; ++i) - { - fvec(i-1) = fvec(i-1) / (double) ( n ); - if ( ( i%2 ) == 0 ) - fvec(i-1) = fvec(i-1) + 1.0E+00 / ( (double)i*i - 1.0E+00 ); - } - - return fvec; - } - - // ---------------------------------------------------------------------------------------- - - double chebyquad_residual(int i, const matrix& x) - { - return chebyquad_residuals(x)(i); - } - - // ---------------------------------------------------------------------------------------- - - int& chebyquad_calls() - { - static int count = 0; - return count; - } - - double chebyquad(const matrix& x ) - { - chebyquad_calls()++; - return sum(squared(chebyquad_residuals(x))); - } - - // ---------------------------------------------------------------------------------------- - - matrix chebyquad_derivative (const matrix& x) - { - const int n = x.size(); - matrix fvec = chebyquad_residuals(x); - matrix g(n); - int i; - int j; - double s1; - double s2; - double t; - double t1; - double t2; - double th; - - for (j = 1; j <= n; ++j) - { - g(j-1) = 0.0E+00; - t1 = 1.0E+00; - t2 = 2.0E+00 * x(j-1) - 1.0E+00; - t = 2.0E+00 * t2; - s1 = 0.0E+00; - s2 = 2.0E+00; - for (i = 1; i <= n; ++i) - { - g(j-1) = g(j-1) + fvec(i-1) * s2; - th = 4.0E+00 * t2 + t * s2 - s1; - s1 = s2; - s2 = th; - th = t * t2 - t1; - t1 = t2; - t2 = th; - } - } - - g = 2.0E+00 * g / (double) ( n ); - - return g; - } - - // ---------------------------------------------------------------------------------------- - - matrix chebyquad_start (int n) - { - int i; - matrix x(n); - - for (i = 1; i <= n; ++i) - x(i-1) = double ( i ) / double ( n + 1 ); - - return x; - } - - // ---------------------------------------------------------------------------------------- - - matrix chebyquad_solution (int n) - { - matrix x(n); - - x = 0; - switch (n) - { - case 2: - x = 0.2113249E+00, 0.7886751E+00; - break; - case 4: - x = 0.1026728E+00, 0.4062037E+00, 0.5937963E+00, 0.8973272E+00; - break; - case 6: - x = 0.066877E+00, 0.288741E+00, 0.366682E+00, 0.633318E+00, 0.711259E+00, 0.933123E+00; - break; - case 8: - x = 0.043153E+00, 0.193091E+00, 0.266329E+00, 0.500000E+00, 0.500000E+00, 0.733671E+00, 0.806910E+00, 0.956847E+00; - break; - default: - std::ostringstream sout; - sout << "don't know chebyquad solution for n = " << n; - throw dlib::error(sout.str()); - break; - } - - return x; - } - - // ---------------------------------------------------------------------------------------- - - matrix chebyquad_hessian(const matrix& x) - { - const int lda = x.size(); - const int n = x.size(); - double d1; - double d2; - matrix fvec = chebyquad_residuals(x); - matrix gvec(n); - matrix h(lda,n); - int i; - int j; - int k; - double p1; - double p2; - double s1; - double s2; - double ss1; - double ss2; - double t; - double t1; - double t2; - double th; - double tt; - double tth; - double tt1; - double tt2; - h = 0; - - d1 = 1.0E+00 / double ( n ); - d2 = 2.0E+00 * d1; - - for (j = 1; j <= n; ++j) - { - - h(j-1,j-1) = 4.0E+00 * d1; - t1 = 1.0E+00; - t2 = 2.0E+00 * x(j-1) - 1.0E+00; - t = 2.0E+00 * t2; - s1 = 0.0E+00; - s2 = 2.0E+00; - p1 = 0.0E+00; - p2 = 0.0E+00; - gvec(0) = s2; - - for (i = 2; i <= n; ++i) - { - th = 4.0E+00 * t2 + t * s2 - s1; - s1 = s2; - s2 = th; - th = t * t2 - t1; - t1 = t2; - t2 = th; - th = 8.0E+00 * s1 + t * p2 - p1; - p1 = p2; - p2 = th; - gvec(i-1) = s2; - h(j-1,j-1) = h(j-1,j-1) + fvec(i-1) * th + d1 * s2*s2; - } - - h(j-1,j-1) = d2 * h(j-1,j-1); - - for (k = 1; k <= j-1; ++k) - { - - h(j-1,k-1) = 0.0; - tt1 = 1.0E+00; - tt2 = 2.0E+00 * x(k-1) - 1.0E+00; - tt = 2.0E+00 * tt2; - ss1 = 0.0E+00; - ss2 = 2.0E+00; - - for (i = 1; i <= n; ++i) - { - h(j-1,k-1) = h(j-1,k-1) + ss2 * gvec(i-1); - tth = 4.0E+00 * tt2 + tt * ss2 - ss1; - ss1 = ss2; - ss2 = tth; - tth = tt * tt2 - tt1; - tt1 = tt2; - tt2 = tth; - } - - h(j-1,k-1) = d2 * d1 * h(j-1,k-1); - - } - - } - - h = make_symmetric(h); - return h; - } - - // ---------------------------------------------------------------------------------------- - // ---------------------------------------------------------------------------------------- - // ---------------------------------------------------------------------------------------- - // ---------------------------------------------------------------------------------------- - - double brown_residual (int i, const matrix& x) - /*! - requires - - 1 <= i <= 20 - ensures - - returns the ith brown residual - !*/ - { - double c; - double f; - double f1; - double f2; - - f = 0.0E+00; - - - c = double ( i ) / 5.0E+00; - f1 = x(0) + c * x(1) - std::exp ( c ); - f2 = x(2) + std::sin ( c ) * x(3) - std::cos ( c ); - - f = f1*f1 + f2*f2; - - return f; - } - - // ---------------------------------------------------------------------------------------- - - double brown ( const matrix& x) - { - double f; - int i; - - f = 0; - - for (i = 1; i <= 20; ++i) - { - f += std::pow(brown_residual(i, x), 2); - } - - return f; - } - - // ---------------------------------------------------------------------------------------- - - matrix brown_derivative ( const matrix& x) - { - double c; - double df1dx1; - double df1dx2; - double df2dx3; - double df2dx4; - double f1; - double f2; - matrix g; - int i; - - g = 0; - - for (i = 1; i <= 20; ++i) - { - - c = double ( i ) / 5.0E+00; - - f1 = x(0) + c * x(1) - std::exp ( c ); - f2 = x(2) + std::sin ( c ) * x(3) - std::cos ( c ); - - df1dx1 = 1.0E+00; - df1dx2 = c; - df2dx3 = 1.0E+00; - df2dx4 = std::sin ( c ); - - using std::pow; - g(0) = g(0) + 4.0E+00 * ( pow(f1,3) * df1dx1 + f1 * pow(f2,2) * df1dx1 ); - g(1) = g(1) + 4.0E+00 * ( pow(f1,3) * df1dx2 + f1 * pow(f2,2) * df1dx2 ); - g(2) = g(2) + 4.0E+00 * ( pow(f1,2) * f2 * df2dx3 + pow(f2,3) * df2dx3 ); - g(3) = g(3) + 4.0E+00 * ( pow(f1,2) * f2 * df2dx4 + pow(f2,3) * df2dx4 ); - - } - - return g; - } - - // ---------------------------------------------------------------------------------------- - - matrix brown_hessian ( const matrix& x) - { - double c; - double df1dx1; - double df1dx2; - double df2dx3; - double df2dx4; - double f1; - double f2; - matrix h; - int i; - - h = 0; - - for (i = 1; i <= 20; ++i) - { - - c = double ( i ) / 5.0E+00; - - f1 = x(0) + c * x(1) - std::exp ( c ); - f2 = x(2) + std::sin ( c ) * x(3) - std::cos ( c ); - - df1dx1 = 1.0E+00; - df1dx2 = c; - df2dx3 = 1.0E+00; - df2dx4 = std::sin ( c ); - - using std::pow; - h(0,0) = h(0,0) + 12.0E+00 * pow(f1,2) * df1dx1 * df1dx1 + 4.0E+00 * pow(f2,2) * df1dx1 * df1dx1; - h(0,1) = h(0,1) + 12.0E+00 * pow(f1,2) * df1dx1 * df1dx2 + 4.0E+00 * pow(f2,2) * df1dx1 * df1dx2; - h(0,2) = h(0,2) + 8.0E+00 * f1 * f2 * df1dx1 * df2dx3; - h(0,3) = h(0,3) + 8.0E+00 * f1 * f2 * df1dx1 * df2dx4; - - h(1,0) = h(1,0) + 12.0E+00 * pow(f1,2) * df1dx2 * df1dx1 + 4.0E+00 * pow(f2,2) * df1dx2 * df1dx1; - h(1,1) = h(1,1) + 12.0E+00 * pow(f1,2) * df1dx2 * df1dx2 + 4.0E+00 * pow(f2,2) * df1dx2 * df1dx1; - h(1,2) = h(1,2) + 8.0E+00 * f1 * f2 * df1dx2 * df2dx3; - h(1,3) = h(1,3) + 8.0E+00 * f1 * f2 * df1dx2 * df2dx4; - - h(2,0) = h(2,0) + 8.0E+00 * f1 * f2 * df2dx3 * df1dx1; - h(2,1) = h(2,1) + 8.0E+00 * f1 * f2 * df2dx3 * df1dx2; - h(2,2) = h(2,2) + 4.0E+00 * pow(f1,2) * df2dx3 * df2dx3 + 12.0E+00 * pow(f2,2) * df2dx3 * df2dx3; - h(2,3) = h(2,3) + 4.0E+00 * pow(f1,2) * df2dx4 * df2dx3 + 12.0E+00 * pow(f2,2) * df2dx3 * df2dx4; - - h(3,0) = h(3,0) + 8.0E+00 * f1 * f2 * df2dx4 * df1dx1; - h(3,1) = h(3,1) + 8.0E+00 * f1 * f2 * df2dx4 * df1dx2; - h(3,2) = h(3,2) + 4.0E+00 * pow(f1,2) * df2dx3 * df2dx4 + 12.0E+00 * pow(f2,2) * df2dx4 * df2dx3; - h(3,3) = h(3,3) + 4.0E+00 * pow(f1,2) * df2dx4 * df2dx4 + 12.0E+00 * pow(f2,2) * df2dx4 * df2dx4; - - } - - return make_symmetric(h); - } - - // ---------------------------------------------------------------------------------------- - - matrix brown_start () - { - matrix x; - x = 25.0E+00, 5.0E+00, -5.0E+00, -1.0E+00; - return x; - } - - // ---------------------------------------------------------------------------------------- - - matrix brown_solution () - { - matrix x; - // solution from original documentation. - //x = -11.5844E+00, 13.1999E+00, -0.406200E+00, 0.240998E+00; - x = -11.594439905669450042, 13.203630051593080452, -0.40343948856573402795, 0.23677877338218666914; - return x; - } - - // ---------------------------------------------------------------------------------------- - - } -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/parallel_for.cpp b/lib/3rdParty/dlib/include/dlib/test/parallel_for.cpp deleted file mode 100644 index 5bee4095..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/parallel_for.cpp +++ /dev/null @@ -1,334 +0,0 @@ -// Copyright (C) 2013 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "tester.h" -#include -#include -#include - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - dlib::logger dlog("test.parallel_for"); - - class assign_element - { - public: - - assign_element( - std::vector& vect_ - ) : vect(vect_){} - - std::vector& vect; - - void go (long i ) - { - DLIB_TEST( 0 <= i && i < (long)vect.size()); - vect[i] = i; - } - - void operator() (long i ) const - { - DLIB_TEST( 0 <= i && i < (long)vect.size()); - vect[i] = i; - } - - }; - - void test_parallel_for(long start) - { - std::vector vect(200,0); - - parallel_for(4, start, vect.size(), assign_element(vect)); - - for (long i = 0; i < start; ++i) - { - DLIB_TEST(vect[i] == 0); - } - for (long i = start; i < (long)vect.size(); ++i) - { - DLIB_TEST(vect[i] == i); - } - } - - void test_parallel_for2(long start) - { - std::vector vect(200,0); - - assign_element temp(vect); - parallel_for(4, start, vect.size(), temp, &assign_element::go); - - for (long i = 0; i < start; ++i) - { - DLIB_TEST(vect[i] == 0); - } - for (long i = start; i < (long)vect.size(); ++i) - { - DLIB_TEST(vect[i] == i); - } - } - - struct parfor_test_helper - { - mutable std::vector test; - - parfor_test_helper() : test(400,100000) - { - } - - void go(long begin, long end) - { - for (long i = begin; i < end; ++i) - test[i] = i; - } - - void operator()(long begin, long end) const - { - for (long i = begin; i < end; ++i) - test[i] = i; - } - - void go2(long i) - { - test[i] = i; - } - - }; - - struct parfor_test_helper2 - { - mutable std::vector test; - - parfor_test_helper2() : test(400,100000) - { - } - - void operator()(long i) const - { - test[i] = i; - } - - }; - - void test_parallel_for_additional() - { - { - parfor_test_helper helper; - parallel_for(4, 0, helper.test.size(), helper, &parfor_test_helper::go2); - - for (unsigned long i = 0; i < helper.test.size(); ++i) - { - DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]); - } - } - { - parfor_test_helper helper; - parallel_for(4, 10, helper.test.size(), helper, &parfor_test_helper::go2); - - for (unsigned long i = 0; i < 10; ++i) - { - DLIB_CASSERT(helper.test[i] == 100000, helper.test[i]); - } - for (unsigned long i = 10; i < helper.test.size(); ++i) - { - DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]); - } - } - { - parfor_test_helper helper; - parallel_for_blocked(4, 0, helper.test.size(), helper, &parfor_test_helper::go); - - for (unsigned long i = 0; i < helper.test.size(); ++i) - { - DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]); - } - } - { - parfor_test_helper helper; - parallel_for_blocked(4, 10, helper.test.size(), helper, &parfor_test_helper::go); - - for (unsigned long i = 0; i < 10; ++i) - { - DLIB_CASSERT(helper.test[i] == 100000, helper.test[i]); - } - for (unsigned long i = 10; i < helper.test.size(); ++i) - { - DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]); - } - } - { - parfor_test_helper helper; - parallel_for_blocked(4, 0, helper.test.size(), helper); - - for (unsigned long i = 0; i < helper.test.size(); ++i) - { - DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]); - } - } - { - parfor_test_helper helper; - parallel_for_blocked(4, 10, helper.test.size(), helper); - - for (unsigned long i = 0; i < 10; ++i) - { - DLIB_CASSERT(helper.test[i] == 100000, helper.test[i]); - } - for (unsigned long i = 10; i < helper.test.size(); ++i) - { - DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]); - } - } - { - parfor_test_helper2 helper; - parallel_for(4, 0, helper.test.size(), helper); - - for (unsigned long i = 0; i < helper.test.size(); ++i) - { - DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]); - } - } - { - parfor_test_helper2 helper; - parallel_for(4, 10, helper.test.size(), helper); - - for (unsigned long i = 0; i < 10; ++i) - { - DLIB_CASSERT(helper.test[i] == 100000, helper.test[i]); - } - for (unsigned long i = 10; i < helper.test.size(); ++i) - { - DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]); - } - } - - - - - - - { - parfor_test_helper helper; - parallel_for_verbose(4, 0, helper.test.size(), helper, &parfor_test_helper::go2); - - for (unsigned long i = 0; i < helper.test.size(); ++i) - { - DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]); - } - } - { - parfor_test_helper helper; - parallel_for_verbose(4, 10, helper.test.size(), helper, &parfor_test_helper::go2); - - for (unsigned long i = 0; i < 10; ++i) - { - DLIB_CASSERT(helper.test[i] == 100000, helper.test[i]); - } - for (unsigned long i = 10; i < helper.test.size(); ++i) - { - DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]); - } - } - { - parfor_test_helper helper; - parallel_for_blocked_verbose(4, 0, helper.test.size(), helper, &parfor_test_helper::go); - - for (unsigned long i = 0; i < helper.test.size(); ++i) - { - DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]); - } - } - { - parfor_test_helper helper; - parallel_for_blocked_verbose(4, 10, helper.test.size(), helper, &parfor_test_helper::go); - - for (unsigned long i = 0; i < 10; ++i) - { - DLIB_CASSERT(helper.test[i] == 100000, helper.test[i]); - } - for (unsigned long i = 10; i < helper.test.size(); ++i) - { - DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]); - } - } - { - parfor_test_helper helper; - parallel_for_blocked_verbose(4, 0, helper.test.size(), helper); - - for (unsigned long i = 0; i < helper.test.size(); ++i) - { - DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]); - } - } - { - parfor_test_helper helper; - parallel_for_blocked_verbose(4, 10, helper.test.size(), helper); - - for (unsigned long i = 0; i < 10; ++i) - { - DLIB_CASSERT(helper.test[i] == 100000, helper.test[i]); - } - for (unsigned long i = 10; i < helper.test.size(); ++i) - { - DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]); - } - } - { - parfor_test_helper2 helper; - parallel_for_verbose(4, 0, helper.test.size(), helper); - - for (unsigned long i = 0; i < helper.test.size(); ++i) - { - DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]); - } - } - { - parfor_test_helper2 helper; - parallel_for_verbose(4, 10, helper.test.size(), helper); - - for (unsigned long i = 0; i < 10; ++i) - { - DLIB_CASSERT(helper.test[i] == 100000, helper.test[i]); - } - for (unsigned long i = 10; i < helper.test.size(); ++i) - { - DLIB_CASSERT(helper.test[i] == (long)i, helper.test[i]); - } - } - } - - class test_parallel_for_routines : public tester - { - public: - test_parallel_for_routines ( - ) : - tester ( - "test_parallel_for", // the command line argument name for this test - "Run tests on the parallel_for routines.", // the command line argument description - 0 // the number of command line arguments for this test - ) - { - } - - void perform_test ( - ) - { - test_parallel_for(0); - test_parallel_for(30); - test_parallel_for(50); - test_parallel_for2(0); - test_parallel_for2(30); - test_parallel_for2(50); - - test_parallel_for_additional(); - } - }; - - test_parallel_for_routines a; - -} - - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/parse.cpp b/lib/3rdParty/dlib/include/dlib/test/parse.cpp deleted file mode 100644 index b0ea13b1..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/parse.cpp +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright (C) 2012 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - - logger dlog("test.parse"); - -// ---------------------------------------------------------------------------------------- - - const unsigned long DET = 0; - const unsigned long N = 1; - const unsigned long V = 2; - const unsigned long NP = 3; - const unsigned long VP = 4; - const unsigned long S = 5; - const unsigned long B = 6; - const unsigned long G = 7; - const unsigned long A = 8; - - typedef unsigned long tags; - - template - void user_defined_ruleset ( - const std::vector& words, - const constituent& c, - std::vector >& possible_ids - ) - { - DLIB_TEST(c.begin < c.k && c.k < c.end && c.end <= words.size()); - DLIB_TEST(possible_ids.size() == 0); - - if (c.left_tag == NP && c.right_tag == VP) possible_ids.push_back(make_pair(S,log(0.80))); - else if (c.left_tag == DET && c.right_tag == N) possible_ids.push_back(make_pair(NP,log(0.30))); - else if (c.left_tag == VP && c.right_tag == A) possible_ids.push_back(make_pair(VP,log(0.30))); - else if (c.left_tag == V && c.right_tag == NP) - { - possible_ids.push_back(make_pair(VP,log(0.20))); - possible_ids.push_back(make_pair(B,0.10)); - } - else if (has_glue_term) - { - possible_ids.push_back(make_pair(G, log(0.01))); - } - } - -// ---------------------------------------------------------------------------------------- - - void dotest1() - { - print_spinner(); - dlog << LINFO << "in dotest1()"; - - std::vector words; - std::vector sequence; - for (int i = 0; i < 8; ++i) - { - sequence.push_back(DET); - sequence.push_back(N); - sequence.push_back(V); - sequence.push_back(DET); - sequence.push_back(N); - sequence.push_back(A); - - words.push_back("The"); - words.push_back("flight"); - words.push_back("includes"); - words.push_back("a"); - words.push_back("meal"); - words.push_back("AWORD"); - } - - std::vector > parse_tree; - - find_max_parse_cky(sequence, user_defined_ruleset, parse_tree); - DLIB_TEST(parse_tree.size() != 0); - - - std::vector roots; - find_trees_not_rooted_with_tag(parse_tree, G, roots); - DLIB_TEST(roots.size() == 8); - - for (unsigned long i = 0; i < roots.size(); ++i) - { - dlog << LINFO << parse_tree_to_string(parse_tree, words, roots[i]); - DLIB_TEST(parse_tree_to_string(parse_tree, words, roots[i]) == "[[The flight] [[includes [a meal]] AWORD]]"); - dlog << LINFO << parse_tree_to_string_tagged(parse_tree, words, roots[i]); - DLIB_TEST(parse_tree_to_string_tagged(parse_tree, words, roots[i]) == "[5 [3 The flight] [4 [4 includes [3 a meal]] AWORD]]"); - } - - - words.clear(); - sequence.clear(); - - for (int i = 0; i < 2; ++i) - { - sequence.push_back(DET); - sequence.push_back(N); - sequence.push_back(V); - sequence.push_back(DET); - sequence.push_back(N); - - words.push_back("The"); - words.push_back("flight"); - words.push_back("includes"); - words.push_back("a"); - words.push_back("meal"); - } - - find_max_parse_cky(sequence, user_defined_ruleset, parse_tree); - DLIB_TEST(parse_tree.size() != 0); - - const std::string str1 = "[[[The flight] [includes [a meal]]] [[The flight] [includes [a meal]]]]"; - const std::string str2 = "[7 [5 [3 The flight] [4 includes [3 a meal]]] [5 [3 The flight] [4 includes [3 a meal]]]]"; - dlog << LINFO << parse_tree_to_string(parse_tree, words); - DLIB_TEST(parse_tree_to_string(parse_tree, words) == str1); - dlog << LINFO << parse_tree_to_string_tagged(parse_tree, words); - DLIB_TEST(parse_tree_to_string_tagged(parse_tree, words) == str2); - - const std::string str3 = "[[The flight] [includes [a meal]]] [[The flight] [includes [a meal]]]"; - const std::string str4 = "[5 [3 The flight] [4 includes [3 a meal]]] [5 [3 The flight] [4 includes [3 a meal]]]"; - dlog << LINFO << parse_trees_to_string(parse_tree, words, G); - DLIB_TEST(parse_trees_to_string(parse_tree, words, G) == str3); - dlog << LINFO << parse_trees_to_string_tagged(parse_tree, words, G); - DLIB_TEST(parse_trees_to_string_tagged(parse_tree, words, G) == str4); - - sequence.clear(); - find_max_parse_cky(sequence, user_defined_ruleset, parse_tree); - DLIB_TEST(parse_tree.size() == 0); - } - -// ---------------------------------------------------------------------------------------- - - void dotest2() - { - print_spinner(); - dlog << LINFO << "in dotest2()"; - - std::vector words; - std::vector sequence; - for (int i = 0; i < 8; ++i) - { - sequence.push_back(DET); - sequence.push_back(N); - sequence.push_back(V); - sequence.push_back(DET); - sequence.push_back(N); - - words.push_back("The"); - words.push_back("flight"); - words.push_back("includes"); - words.push_back("a"); - words.push_back("meal"); - } - - std::vector > parse_tree; - - find_max_parse_cky(sequence, user_defined_ruleset, parse_tree); - DLIB_TEST(parse_tree.size() == 0); - - - std::vector roots; - find_trees_not_rooted_with_tag(parse_tree, G, roots); - DLIB_TEST(roots.size() == 0); - - - words.clear(); - sequence.clear(); - - for (int i = 0; i < 2; ++i) - { - sequence.push_back(DET); - sequence.push_back(N); - sequence.push_back(V); - sequence.push_back(DET); - sequence.push_back(N); - - words.push_back("The"); - words.push_back("flight"); - words.push_back("includes"); - words.push_back("a"); - words.push_back("meal"); - } - - find_max_parse_cky(sequence, user_defined_ruleset, parse_tree); - DLIB_TEST(parse_tree.size() == 0); - - sequence.clear(); - find_max_parse_cky(sequence, user_defined_ruleset, parse_tree); - DLIB_TEST(parse_tree.size() == 0); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - class parse_tester : public tester - { - public: - parse_tester ( - ) : - tester ("test_parse", - "Runs tests on the parsing tools.") - {} - - - void perform_test ( - ) - { - dotest1(); - dotest2(); - } - } a; - - -} - - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/pipe.cpp b/lib/3rdParty/dlib/include/dlib/test/pipe.cpp deleted file mode 100644 index 7a670627..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/pipe.cpp +++ /dev/null @@ -1,688 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.pipe"); - - namespace pipe_kernel_test_helpers - { - const unsigned long proc1_count = 10000; - mutex m; - signaler s(m); - unsigned long threads_running = 0; - bool found_error; - - inline void add_running_thread ( - ) - { - auto_mutex M(m); - ++threads_running; - } - - inline void remove_running_thread ( - ) - { - auto_mutex M(m); - --threads_running; - s.broadcast(); - } - - inline void wait_for_threads ( - ) - { - auto_mutex M(m); - while (threads_running > 0) - s.wait(); - } - - template < - typename pipe - > - void threadproc1 ( - void* param - ) - { - add_running_thread(); - pipe& p = *static_cast(param); - try - { - - int last = -1; - for (unsigned long i = 0; i < proc1_count; ++i) - { - int cur=0; - DLIB_TEST(p.dequeue(cur) == true); - DLIB_TEST(last + 1 == cur); - last = cur; - } - DLIB_TEST(p.size() == 0); - } - catch(exception& e) - { - auto_mutex M(m); - found_error = true; - cout << "\n\nERRORS FOUND" << endl; - cout << e.what() << endl; - dlog << LWARN << "ERRORS FOUND"; - dlog << LWARN << e.what(); - p.disable(); - } - - remove_running_thread(); - } - - - template < - typename pipe - > - void threadproc2 ( - void* param - ) - { - add_running_thread(); - pipe& p = *static_cast(param); - try - { - - int last = -1; - int cur; - while (p.dequeue(cur)) - { - DLIB_TEST(last < cur); - last = cur; - } - auto_mutex M(m); - } - catch(exception& e) - { - auto_mutex M(m); - found_error = true; - cout << "\n\nERRORS FOUND" << endl; - cout << e.what() << endl; - dlog << LWARN << "ERRORS FOUND"; - dlog << LWARN << e.what(); - p.disable(); - } - remove_running_thread(); - } - - - - template < - typename pipe - > - void threadproc3 ( - void* param - ) - { - add_running_thread(); - pipe& p = *static_cast(param); - try - { - - int last = -1; - int cur; - while (p.dequeue_or_timeout(cur,100000)) - { - DLIB_TEST(last < cur); - last = cur; - } - auto_mutex M(m); - } - catch(exception& e) - { - auto_mutex M(m); - found_error = true; - cout << "\n\nERRORS FOUND" << endl; - cout << e.what() << endl; - dlog << LWARN << "ERRORS FOUND"; - dlog << LWARN << e.what(); - p.disable(); - } - remove_running_thread(); - } - - - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - template - class PipelineProcessor : private dlib::threaded_object - { - public: - PipelineProcessor( - dlib::pipe & in, - dlib::pipe & out) : - InPipe(in), - OutPipe(out), - InMsg(), - OutMsg() { - start(); - } - - ~PipelineProcessor() { - // signal the thread to stop - stop(); - wait(); - } - - private: - dlib::pipe & InPipe; - dlib::pipe & OutPipe; - - in_type InMsg; - out_type OutMsg; - - void thread() - { - while (!should_stop()) { - if(InPipe.dequeue_or_timeout(InMsg, 100)) - { - // if function signals ready to send OutMsg - while (!OutPipe.enqueue_or_timeout(OutMsg, 100)) - { - // try to send until should stop - if (should_stop()) - { - return; - } - } - } - } - }; - }; - - - void do_zero_size_test_with_timeouts() - { - dlog << LINFO << "in do_zero_size_test_with_timeouts()"; - // make sure we can get though this without deadlocking - for (int k = 0; k < 10; ++k) - { - dlib::pipe in_pipe(10); - dlib::pipe out_pipe(0); - { - PipelineProcessor pp(in_pipe, out_pipe); - - int in = 1; - in_pipe.enqueue(in); - in = 2; - in_pipe.enqueue(in); - in = 3; - in_pipe.enqueue(in); - // sleep to make sure thread enqueued - dlib::sleep(100); - - float out = 1.0f; - out_pipe.dequeue(out); - dlib::sleep(100); - } - print_spinner(); - } - - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - template < - typename pipe - > - void pipe_kernel_test ( - ) - /*! - requires - - pipe is an implementation of pipe/pipe_kernel_abstract.h and - is instantiated with int - ensures - - runs tests on pipe for compliance with the specs - !*/ - { - using namespace pipe_kernel_test_helpers; - found_error = false; - - - print_spinner(); - pipe test(10), test2(100); - pipe test_0(0), test2_0(0); - pipe test_1(1), test2_1(1); - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test2.size() == 0); - DLIB_TEST(test_0.size() == 0); - DLIB_TEST(test2_0.size() == 0); - DLIB_TEST(test_1.size() == 0); - DLIB_TEST(test2_1.size() == 0); - - DLIB_TEST(test.is_enqueue_enabled() == true); - DLIB_TEST(test.is_dequeue_enabled() == true); - DLIB_TEST(test.is_enabled() == true); - - test.empty(); - test2.empty(); - DLIB_TEST(test.size() == 0); - DLIB_TEST(test2.size() == 0); - - test_0.empty(); - test2_0.empty(); - DLIB_TEST(test_0.size() == 0); - DLIB_TEST(test2_0.size() == 0); - - test_1.empty(); - test2_1.empty(); - DLIB_TEST(test_1.size() == 0); - DLIB_TEST(test2_1.size() == 0); - - - - int a; - a = 3; - test.enqueue(a); - DLIB_TEST(test.size() == 1); - a = 5; - test.enqueue(a); - DLIB_TEST(test.size() == 2); - - a = 0; - test.dequeue(a); - DLIB_TEST(a == 3); - DLIB_TEST(test.size() == 1); - - a = 0; - test.dequeue(a); - DLIB_TEST(a == 5); - DLIB_TEST(test.size() == 0); - - - print_spinner(); - { - dlog << LINFO << "starting normal length pipe tests"; - create_new_thread(&threadproc1,&test); - create_new_thread(&threadproc2,&test2); - create_new_thread(&threadproc2,&test2); - create_new_thread(&threadproc2,&test2); - - for (unsigned long i = 0; i < proc1_count; ++i) - { - a = i; - test.enqueue(a); - } - DLIB_TEST(test.is_enqueue_enabled() == true); - test.disable_enqueue(); - DLIB_TEST(test.is_enqueue_enabled() == false); - for (unsigned long i = 0; i < proc1_count; ++i) - { - a = i; - test.enqueue(a); - } - - for (unsigned long i = 0; i < 100000; ++i) - { - a = i; - if (i%2 == 0) - test2.enqueue(a); - else - test2.enqueue_or_timeout(a,100000); - } - - test2.wait_for_num_blocked_dequeues(3); - DLIB_TEST(test2.size() == 0); - test2.disable(); - - wait_for_threads(); - DLIB_TEST(test2.size() == 0); - - test2.enable(); - - print_spinner(); - - create_new_thread(&threadproc3,&test2); - create_new_thread(&threadproc3,&test2); - - - for (unsigned long i = 0; i < 100000; ++i) - { - a = i; - if (i%2 == 0) - test2.enqueue(a); - else - test2.enqueue_or_timeout(a,100000); - } - - test2.wait_for_num_blocked_dequeues(2); - DLIB_TEST(test2.size() == 0); - test2.disable(); - - wait_for_threads(); - DLIB_TEST(test2.size() == 0); - - } - - - print_spinner(); - { - dlog << LINFO << "starting 0 length pipe tests"; - create_new_thread(&threadproc1,&test_0); - create_new_thread(&threadproc2,&test2_0); - create_new_thread(&threadproc2,&test2_0); - create_new_thread(&threadproc2,&test2_0); - dlog << LTRACE << "0: 1"; - - for (unsigned long i = 0; i < proc1_count; ++i) - { - a = i; - test_0.enqueue(a); - } - - dlog << LTRACE << "0: 2"; - DLIB_TEST(test_0.is_enqueue_enabled() == true); - test_0.disable_enqueue(); - DLIB_TEST(test_0.is_enqueue_enabled() == false); - for (unsigned long i = 0; i < proc1_count; ++i) - { - a = i; - test_0.enqueue(a); - } - - dlog << LTRACE << "0: 3"; - for (unsigned long i = 0; i < 100000; ++i) - { - a = i; - if (i%2 == 0) - test2_0.enqueue(a); - else - test2_0.enqueue_or_timeout(a,100000); - } - - print_spinner(); - dlog << LTRACE << "0: 4"; - test2_0.wait_for_num_blocked_dequeues(3); - DLIB_TEST(test2_0.size() == 0); - test2_0.disable(); - - wait_for_threads(); - DLIB_TEST(test2_0.size() == 0); - - dlog << LTRACE << "0: 5"; - test2_0.enable(); - - - create_new_thread(&threadproc3,&test2_0); - create_new_thread(&threadproc3,&test2_0); - - - for (unsigned long i = 0; i < 20000; ++i) - { - if ((i%100) == 0) - print_spinner(); - - a = i; - if (i%2 == 0) - test2_0.enqueue(a); - else - test2_0.enqueue_or_timeout(a,100000); - } - - dlog << LTRACE << "0: 6"; - test2_0.wait_for_num_blocked_dequeues(2); - DLIB_TEST(test2_0.size() == 0); - test2_0.disable(); - - wait_for_threads(); - DLIB_TEST(test2_0.size() == 0); - - dlog << LTRACE << "0: 7"; - } - - print_spinner(); - { - dlog << LINFO << "starting 1 length pipe tests"; - create_new_thread(&threadproc1,&test_1); - create_new_thread(&threadproc2,&test2_1); - create_new_thread(&threadproc2,&test2_1); - create_new_thread(&threadproc2,&test2_1); - - for (unsigned long i = 0; i < proc1_count; ++i) - { - a = i; - test_1.enqueue(a); - } - DLIB_TEST(test_1.is_enqueue_enabled() == true); - test_1.disable_enqueue(); - DLIB_TEST(test_1.is_enqueue_enabled() == false); - for (unsigned long i = 0; i < proc1_count; ++i) - { - a = i; - test_1.enqueue(a); - } - print_spinner(); - - for (unsigned long i = 0; i < 100000; ++i) - { - a = i; - if (i%2 == 0) - test2_1.enqueue(a); - else - test2_1.enqueue_or_timeout(a,100000); - } - - test2_1.wait_for_num_blocked_dequeues(3); - DLIB_TEST(test2_1.size() == 0); - test2_1.disable(); - - wait_for_threads(); - DLIB_TEST(test2_1.size() == 0); - - test2_1.enable(); - - - create_new_thread(&threadproc3,&test2_1); - create_new_thread(&threadproc3,&test2_1); - - - for (unsigned long i = 0; i < 100000; ++i) - { - a = i; - if (i%2 == 0) - test2_1.enqueue(a); - else - test2_1.enqueue_or_timeout(a,100000); - } - - test2_1.wait_for_num_blocked_dequeues(2); - DLIB_TEST(test2_1.size() == 0); - test2_1.disable(); - - wait_for_threads(); - DLIB_TEST(test2_1.size() == 0); - - } - - test.enable_enqueue(); - test_0.enable_enqueue(); - test_1.enable_enqueue(); - - DLIB_TEST(test.is_enabled()); - DLIB_TEST(test.is_enqueue_enabled()); - DLIB_TEST(test_0.is_enabled()); - DLIB_TEST(test_0.is_enqueue_enabled()); - DLIB_TEST(test_1.is_enabled()); - DLIB_TEST(test_1.is_enqueue_enabled()); - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test_0.size() == 0); - DLIB_TEST(test_1.size() == 0); - DLIB_TEST(test.max_size() == 10); - DLIB_TEST(test_0.max_size() == 0); - DLIB_TEST(test_1.max_size() == 1); - - - for (int i = 0; i < 100; ++i) - { - a = 1; - test.enqueue_or_timeout(a,0); - a = 1; - test_0.enqueue_or_timeout(a,0); - a = 1; - test_1.enqueue_or_timeout(a,0); - } - - DLIB_TEST_MSG(test.size() == 10,"size: " << test.size() ); - DLIB_TEST_MSG(test_0.size() == 0,"size: " << test.size() ); - DLIB_TEST_MSG(test_1.size() == 1,"size: " << test.size() ); - - for (int i = 0; i < 10; ++i) - { - a = 0; - DLIB_TEST(test.enqueue_or_timeout(a,10) == false); - a = 0; - DLIB_TEST(test_0.enqueue_or_timeout(a,10) == false); - a = 0; - DLIB_TEST(test_1.enqueue_or_timeout(a,10) == false); - } - - DLIB_TEST_MSG(test.size() == 10,"size: " << test.size() ); - DLIB_TEST_MSG(test_0.size() == 0,"size: " << test.size() ); - DLIB_TEST_MSG(test_1.size() == 1,"size: " << test.size() ); - - for (int i = 0; i < 10; ++i) - { - a = 0; - DLIB_TEST(test.dequeue_or_timeout(a,0) == true); - DLIB_TEST(a == 1); - } - - DLIB_TEST(test.max_size() == 10); - DLIB_TEST(test_0.max_size() == 0); - DLIB_TEST(test_1.max_size() == 1); - - a = 0; - DLIB_TEST(test_1.dequeue_or_timeout(a,0) == true); - - DLIB_TEST(test.max_size() == 10); - DLIB_TEST(test_0.max_size() == 0); - DLIB_TEST(test_1.max_size() == 1); - - - DLIB_TEST_MSG(a == 1,"a: " << a); - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test_0.size() == 0); - DLIB_TEST(test_1.size() == 0); - - DLIB_TEST(test.dequeue_or_timeout(a,0) == false); - DLIB_TEST(test_0.dequeue_or_timeout(a,0) == false); - DLIB_TEST(test_1.dequeue_or_timeout(a,0) == false); - DLIB_TEST(test.dequeue_or_timeout(a,10) == false); - DLIB_TEST(test_0.dequeue_or_timeout(a,10) == false); - DLIB_TEST(test_1.dequeue_or_timeout(a,10) == false); - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test_0.size() == 0); - DLIB_TEST(test_1.size() == 0); - - DLIB_TEST(found_error == false); - - - - - { - test.enable(); - test.enable_enqueue(); - test.empty(); - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.is_enabled() == true); - DLIB_TEST(test.is_enqueue_enabled() == true); - DLIB_TEST(test.is_dequeue_enabled() == true); - test.disable_dequeue(); - dlog << LINFO << "Make sure disable_dequeue() works right..."; - DLIB_TEST(test.is_dequeue_enabled() == false); - DLIB_TEST(test.dequeue(a) == false); - test.wait_until_empty(); - a = 4; - test.enqueue(a); - test.wait_until_empty(); - test.wait_for_num_blocked_dequeues(4); - DLIB_TEST(test.size() == 1); - DLIB_TEST(test.dequeue(a) == false); - DLIB_TEST(test.dequeue_or_timeout(a,10000) == false); - DLIB_TEST(test.size() == 1); - a = 0; - test.enable_dequeue(); - DLIB_TEST(test.is_dequeue_enabled() == true); - DLIB_TEST(test.dequeue(a) == true); - DLIB_TEST(a == 4); - test_1.wait_until_empty(); - } - { - test_1.enable(); - test_1.enable_enqueue(); - test_1.empty(); - DLIB_TEST(test_1.size() == 0); - DLIB_TEST(test_1.is_enabled() == true); - DLIB_TEST(test_1.is_enqueue_enabled() == true); - DLIB_TEST(test_1.is_dequeue_enabled() == true); - test_1.disable_dequeue(); - dlog << LINFO << "Make sure disable_dequeue() works right..."; - DLIB_TEST(test_1.is_dequeue_enabled() == false); - DLIB_TEST(test_1.dequeue(a) == false); - a = 4; - test_1.wait_for_num_blocked_dequeues(4); - test_1.wait_for_num_blocked_dequeues(0); - test_1.enqueue(a); - test_1.wait_until_empty(); - DLIB_TEST(test_1.size() == 1); - DLIB_TEST(test_1.dequeue(a) == false); - DLIB_TEST(test_1.dequeue_or_timeout(a,10000) == false); - DLIB_TEST(test_1.size() == 1); - a = 0; - test_1.enable_dequeue(); - DLIB_TEST(test_1.is_dequeue_enabled() == true); - DLIB_TEST(test_1.dequeue(a) == true); - DLIB_TEST(a == 4); - test_1.wait_until_empty(); - } - - } - - - - - class pipe_tester : public tester - { - public: - pipe_tester ( - ) : - tester ("test_pipe", - "Runs tests on the pipe component.") - {} - - void perform_test ( - ) - { - pipe_kernel_test >(); - - do_zero_size_test_with_timeouts(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/pixel.cpp b/lib/3rdParty/dlib/include/dlib/test/pixel.cpp deleted file mode 100644 index 00a28fa8..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/pixel.cpp +++ /dev/null @@ -1,545 +0,0 @@ -// Copyright (C) 2007 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.pixel"); - - - void pixel_test ( - ) - /*! - ensures - - runs tests on pixel objects and functions for compliance with the specs - !*/ - { - - print_spinner(); - - unsigned char p_gray; - unsigned short p_gray16; - long p_int; - float p_float; - signed char p_schar; - rgb_pixel p_rgb; - hsi_pixel p_hsi, p_hsi2; - rgb_alpha_pixel p_rgba; - - assign_pixel(p_int, 0.0f); - assign_pixel(p_float, 0.0f); - assign_pixel(p_schar, 0); - - assign_pixel(p_gray, -2); - assign_pixel(p_rgb,0); - assign_pixel(p_hsi, -4); - assign_pixel(p_rgba, p_int); - assign_pixel(p_gray16,0); - - DLIB_TEST(p_int == 0); - DLIB_TEST(p_float == 0); - DLIB_TEST(p_schar == 0); - - DLIB_TEST(p_gray == 0); - DLIB_TEST(p_gray16 == 0); - - DLIB_TEST(p_rgb.red == 0); - DLIB_TEST(p_rgb.green == 0); - DLIB_TEST(p_rgb.blue == 0); - - DLIB_TEST(p_rgba.red == 0); - DLIB_TEST(p_rgba.green == 0); - DLIB_TEST(p_rgba.blue == 0); - DLIB_TEST(p_rgba.alpha == 255); - - DLIB_TEST(p_hsi.h == 0); - DLIB_TEST(p_hsi.s == 0); - DLIB_TEST(p_hsi.i == 0); - - assign_pixel(p_gray,10); - assign_pixel(p_gray16,10); - assign_pixel(p_rgb,10); - assign_pixel(p_hsi,10); - assign_pixel(p_rgba,10); - - assign_pixel(p_int, -10); - assign_pixel(p_float, -10); - assign_pixel(p_schar, -10); - - DLIB_TEST(p_int == -10); - DLIB_TEST(p_float == -10); - DLIB_TEST(p_schar == -10); - - DLIB_TEST(p_gray == 10); - DLIB_TEST(p_gray16 == 10); - - DLIB_TEST(p_rgb.red == 10); - DLIB_TEST(p_rgb.green == 10); - DLIB_TEST(p_rgb.blue == 10); - - DLIB_TEST(p_rgba.red == 10); - DLIB_TEST(p_rgba.green == 10); - DLIB_TEST(p_rgba.blue == 10); - DLIB_TEST(p_rgba.alpha == 255); - - DLIB_TEST(p_hsi.h == 0); - DLIB_TEST(p_hsi.s == 0); - DLIB_TEST(p_hsi.i == 10); - - assign_pixel(p_gray16,12345); - DLIB_TEST(p_gray16 == 12345); - - assign_pixel(p_float,3.141); - DLIB_TEST(p_float == 3.141f); - - p_rgb.red = 255; - p_rgb.green = 100; - p_rgb.blue = 50; - - p_rgba.alpha = 4; - assign_pixel(p_gray,p_rgb); - assign_pixel(p_rgb,p_rgb); - assign_pixel(p_rgba,p_rgb); - assign_pixel(p_hsi,p_rgb); - - assign_pixel(p_float,p_rgb); - assign_pixel(p_int,p_rgb); - assign_pixel(p_schar,p_rgb); - - DLIB_TEST(p_schar == std::numeric_limits::max()); - - DLIB_TEST(p_int == (255+100+50)/3); - DLIB_TEST_MSG(p_float == (255+100+50)/3, p_float - (255+100+50)/3); - DLIB_TEST(p_gray == (255+100+50)/3); - - DLIB_TEST(p_rgb.red == 255); - DLIB_TEST(p_rgb.green == 100); - DLIB_TEST(p_rgb.blue == 50); - - DLIB_TEST(p_rgba.red == 255); - DLIB_TEST(p_rgba.green == 100); - DLIB_TEST(p_rgba.blue == 50); - DLIB_TEST(p_rgba.alpha == 255); - - DLIB_TEST(p_hsi.i > 0); - DLIB_TEST(p_hsi.s > 0); - DLIB_TEST(p_hsi.h > 0); - - assign_pixel(p_rgb,0); - DLIB_TEST(p_rgb.red == 0); - DLIB_TEST(p_rgb.green == 0); - DLIB_TEST(p_rgb.blue == 0); - assign_pixel(p_rgb, p_hsi); - - DLIB_TEST_MSG(p_rgb.red > 251 ,(int)p_rgb.green); - DLIB_TEST_MSG(p_rgb.green > 96 && p_rgb.green < 104,(int)p_rgb.green); - DLIB_TEST_MSG(p_rgb.blue > 47 && p_rgb.blue < 53,(int)p_rgb.green); - - assign_pixel(p_hsi2, p_hsi); - DLIB_TEST(p_hsi.h == p_hsi2.h); - DLIB_TEST(p_hsi.s == p_hsi2.s); - DLIB_TEST(p_hsi.i == p_hsi2.i); - assign_pixel(p_hsi,0); - DLIB_TEST(p_hsi.h == 0); - DLIB_TEST(p_hsi.s == 0); - DLIB_TEST(p_hsi.i == 0); - assign_pixel(p_hsi, p_rgba); - - DLIB_TEST(p_hsi.h == p_hsi2.h); - DLIB_TEST(p_hsi.s == p_hsi2.s); - DLIB_TEST(p_hsi.i == p_hsi2.i); - - assign_pixel(p_rgba, 100); - assign_pixel(p_gray, 10); - assign_pixel(p_rgb, 10); - assign_pixel(p_hsi, 10); - - assign_pixel(p_schar, 10); - assign_pixel(p_float, 10); - assign_pixel(p_int, 10); - - p_rgba.alpha = 0; - assign_pixel(p_gray, p_rgba); - DLIB_TEST(p_gray == 10); - assign_pixel(p_schar, p_rgba); - DLIB_TEST(p_schar == 10); - assign_pixel(p_int, p_rgba); - DLIB_TEST(p_int == 10); - assign_pixel(p_float, p_rgba); - DLIB_TEST(p_float == 10); - assign_pixel(p_rgb, p_rgba); - DLIB_TEST(p_rgb.red == 10); - DLIB_TEST(p_rgb.green == 10); - DLIB_TEST(p_rgb.blue == 10); - - assign_pixel(p_hsi, p_rgba); - assign_pixel(p_hsi2, p_rgb); - DLIB_TEST(p_hsi.h == 0); - DLIB_TEST(p_hsi.s == 0); - DLIB_TEST_MSG(p_hsi.i < p_hsi2.i+2 && p_hsi.i > p_hsi2.i -2,(int)p_hsi.i << " " << (int)p_hsi2.i); - - assign_pixel(p_rgba, 100); - assign_pixel(p_gray, 10); - assign_pixel(p_schar, 10); - assign_pixel(p_float, 10); - assign_pixel(p_int, 10); - - assign_pixel(p_rgb, 10); - p_rgba.alpha = 128; - assign_pixel(p_gray, p_rgba); - assign_pixel(p_schar, p_rgba); - assign_pixel(p_float, p_rgba); - assign_pixel(p_int, p_rgba); - assign_pixel(p_rgb, p_rgba); - DLIB_TEST(p_gray == (100 + 10)/2); - DLIB_TEST(p_schar == (100 + 10)/2); - DLIB_TEST(p_int == (100 + 10)/2); - DLIB_TEST(p_float == (100 + 10)/2); - DLIB_TEST(p_rgb.red == (100 + 10)/2); - DLIB_TEST(p_rgb.green == (100 + 10)/2); - DLIB_TEST(p_rgb.blue == (100 + 10)/2); - - assign_pixel(p_rgba, 100); - assign_pixel(p_gray, 10); - assign_pixel(p_schar, 10); - assign_pixel(p_int, 10); - assign_pixel(p_float, 10); - assign_pixel(p_rgb, 10); - DLIB_TEST(p_rgba.alpha == 255); - assign_pixel(p_gray, p_rgba); - assign_pixel(p_schar, p_rgba); - assign_pixel(p_int, p_rgba); - assign_pixel(p_float, p_rgba); - assign_pixel(p_rgb, p_rgba); - DLIB_TEST(p_gray == 100); - DLIB_TEST(p_schar == 100); - DLIB_TEST(p_int == 100); - DLIB_TEST(p_float == 100); - DLIB_TEST(p_rgb.red == 100); - DLIB_TEST(p_rgb.green == 100); - DLIB_TEST(p_rgb.blue == 100); - - - p_rgb.red = 1; - p_rgb.green = 2; - p_rgb.blue = 3; - - p_rgba.red = 4; - p_rgba.green = 5; - p_rgba.blue = 6; - p_rgba.alpha = 7; - - p_gray = 8; - p_schar = 8; - p_int = 8; - p_float = 8; - - p_hsi.h = 9; - p_hsi.s = 10; - p_hsi.i = 11; - - ostringstream sout; - serialize(p_rgb,sout); - serialize(p_rgba,sout); - serialize(p_gray,sout); - serialize(p_schar,sout); - serialize(p_int,sout); - serialize(p_float,sout); - serialize(p_hsi,sout); - - assign_pixel(p_rgb,0); - assign_pixel(p_rgba,0); - assign_pixel(p_gray,0); - assign_pixel(p_schar,0); - assign_pixel(p_int,0); - assign_pixel(p_float,0); - assign_pixel(p_hsi,0); - - istringstream sin(sout.str()); - - deserialize(p_rgb,sin); - deserialize(p_rgba,sin); - deserialize(p_gray,sin); - deserialize(p_schar,sin); - deserialize(p_int,sin); - deserialize(p_float,sin); - deserialize(p_hsi,sin); - - DLIB_TEST(p_rgb.red == 1); - DLIB_TEST(p_rgb.green == 2); - DLIB_TEST(p_rgb.blue == 3); - - DLIB_TEST(p_rgba.red == 4); - DLIB_TEST(p_rgba.green == 5); - DLIB_TEST(p_rgba.blue == 6); - DLIB_TEST(p_rgba.alpha == 7); - - DLIB_TEST(p_gray == 8); - DLIB_TEST(p_schar == 8); - DLIB_TEST(p_int == 8); - DLIB_TEST(p_float == 8); - - DLIB_TEST(p_hsi.h == 9); - DLIB_TEST(p_hsi.s == 10); - DLIB_TEST(p_hsi.i == 11); - - { - matrix m_gray, m_schar, m_int, m_float; - matrix m_rgb, m_hsi; - - m_gray = pixel_to_vector(p_gray); - m_schar = pixel_to_vector(p_schar); - m_int = pixel_to_vector(p_int); - m_float = pixel_to_vector(p_float); - - m_hsi = pixel_to_vector(p_hsi); - m_rgb = pixel_to_vector(p_rgb); - - DLIB_TEST(m_gray(0) == p_gray); - DLIB_TEST(m_float(0) == p_float); - DLIB_TEST(m_int(0) == p_int); - DLIB_TEST(m_schar(0) == p_schar); - - DLIB_TEST(m_rgb(0) == p_rgb.red); - DLIB_TEST(m_rgb(1) == p_rgb.green); - DLIB_TEST(m_rgb(2) == p_rgb.blue); - DLIB_TEST(m_hsi(0) == p_hsi.h); - DLIB_TEST(m_hsi(1) == p_hsi.s); - DLIB_TEST(m_hsi(2) == p_hsi.i); - - DLIB_TEST(p_rgb.red == 1); - DLIB_TEST(p_rgb.green == 2); - DLIB_TEST(p_rgb.blue == 3); - - DLIB_TEST(p_rgba.red == 4); - DLIB_TEST(p_rgba.green == 5); - DLIB_TEST(p_rgba.blue == 6); - DLIB_TEST(p_rgba.alpha == 7); - - DLIB_TEST(p_gray == 8); - DLIB_TEST(p_int == 8); - DLIB_TEST(p_float == 8); - DLIB_TEST(p_schar == 8); - - DLIB_TEST(p_hsi.h == 9); - DLIB_TEST(p_hsi.s == 10); - DLIB_TEST(p_hsi.i == 11); - - assign_pixel(p_gray,0); - assign_pixel(p_hsi,0); - assign_pixel(p_rgb,0); - - vector_to_pixel(p_gray, m_gray); - vector_to_pixel(p_hsi, m_hsi); - vector_to_pixel(p_rgb, m_rgb); - - DLIB_TEST(p_rgb.red == 1); - DLIB_TEST(p_rgb.green == 2); - DLIB_TEST(p_rgb.blue == 3); - - DLIB_TEST(p_rgba.red == 4); - DLIB_TEST(p_rgba.green == 5); - DLIB_TEST(p_rgba.blue == 6); - DLIB_TEST(p_rgba.alpha == 7); - - DLIB_TEST(p_gray == 8); - - DLIB_TEST(p_hsi.h == 9); - DLIB_TEST(p_hsi.s == 10); - DLIB_TEST(p_hsi.i == 11); - } - - - - - { - unsigned char p_gray; - unsigned short p_gray16; - long p_int; - float p_float; - signed char p_schar; - rgb_pixel p_rgb; - hsi_pixel p_hsi, p_hsi2; - rgb_alpha_pixel p_rgba; - - - assign_pixel(p_gray, 0); - assign_pixel(p_gray16, 0); - assign_pixel(p_int, 0); - assign_pixel(p_float, 0); - assign_pixel(p_schar, 0); - assign_pixel(p_rgb, 0); - assign_pixel(p_hsi, 0); - - - assign_pixel(p_gray, 100); - assign_pixel(p_schar, p_gray); - DLIB_TEST(p_schar == 100); - - assign_pixel(p_gray, 200); - assign_pixel(p_schar, p_gray); - DLIB_TEST(p_schar == std::numeric_limits::max()); - - assign_pixel(p_int, p_gray); - DLIB_TEST(p_int == 200); - - assign_pixel(p_float, p_gray); - DLIB_TEST(p_float == 200); - - assign_pixel(p_rgb, p_float); - DLIB_TEST(p_rgb.red == 200); - DLIB_TEST(p_rgb.green == 200); - DLIB_TEST(p_rgb.blue == 200); - - p_schar = 0; - assign_pixel(p_schar, p_rgb); - DLIB_TEST(p_schar == std::numeric_limits::max()); - - - p_schar = -10; - assign_pixel(p_float, p_schar); - DLIB_TEST(p_float == -10); - assign_pixel(p_int, p_schar); - DLIB_TEST(p_int == -10); - assign_pixel(p_schar, p_schar); - DLIB_TEST(p_schar == -10); - assign_pixel(p_gray, p_schar); - DLIB_TEST(p_gray == 0); - - assign_pixel(p_rgb, p_schar); - DLIB_TEST(p_rgb.red == 0); - DLIB_TEST(p_rgb.green == 0); - DLIB_TEST(p_rgb.blue == 0); - - assign_pixel(p_gray16, p_schar); - DLIB_TEST(p_gray16 == 0); - - DLIB_TEST(get_pixel_intensity(p_float) == -10); - DLIB_TEST(get_pixel_intensity(p_int) == -10); - DLIB_TEST(get_pixel_intensity(p_schar) == -10); - DLIB_TEST(get_pixel_intensity(p_rgb) == 0); - DLIB_TEST(get_pixel_intensity(p_gray16) == 0); - - p_rgb.red = 100; - p_rgb.green = 100; - p_rgb.blue = 100; - DLIB_TEST(get_pixel_intensity(p_rgb) == 100); - p_rgb.red = 1; - p_rgb.green = 2; - p_rgb.blue = 3; - DLIB_TEST(get_pixel_intensity(p_rgb) == 2); - p_rgba.alpha = 100; - p_rgba.red = 100; - p_rgba.green = 100; - p_rgba.blue = 100; - DLIB_TEST(get_pixel_intensity(p_rgba) == 100); - p_rgba.red = 1; - p_rgba.green = 2; - p_rgba.blue = 3; - p_rgba.alpha = 0; - DLIB_TEST(get_pixel_intensity(p_rgba) == 2); - p_hsi.h = 123; - p_hsi.s = 100; - p_hsi.i = 84; - DLIB_TEST(get_pixel_intensity(p_hsi) == 84); - - p_float = 54.25; - DLIB_TEST(get_pixel_intensity(p_float) == 54.25); - - assign_pixel(p_gray, p_float); - DLIB_TEST(get_pixel_intensity(p_gray) == 54); - - assign_pixel_intensity(p_float, -1000); - assign_pixel_intensity(p_schar, -100); - assign_pixel_intensity(p_int, -10000); - assign_pixel_intensity(p_gray, -100); - - p_rgba.red = 10; - p_rgba.green = 10; - p_rgba.blue = 10; - p_rgba.alpha = 0; - DLIB_TEST_MSG(get_pixel_intensity(p_rgba) == 10, (int)get_pixel_intensity(p_rgba)); - assign_pixel_intensity(p_rgba, 2); - DLIB_TEST_MSG(p_rgba.red == 2, (int)p_rgba.red); - DLIB_TEST_MSG(p_rgba.green == 2, (int)p_rgba.green); - DLIB_TEST_MSG(p_rgba.blue == 2, (int)p_rgba.blue); - DLIB_TEST_MSG(p_rgba.alpha == 0, (int)p_rgba.alpha); - DLIB_TEST_MSG(get_pixel_intensity(p_rgba) == 2, (int)get_pixel_intensity(p_rgba)); - - DLIB_TEST(p_float == -1000); - DLIB_TEST(get_pixel_intensity(p_float) == -1000); - DLIB_TEST(p_schar == -100); - DLIB_TEST(get_pixel_intensity(p_schar) == -100); - DLIB_TEST(p_int == -10000); - DLIB_TEST(get_pixel_intensity(p_int) == -10000); - DLIB_TEST(p_gray == 0); - assign_pixel_intensity(p_gray, 1000); - DLIB_TEST(p_gray == 255); - DLIB_TEST(get_pixel_intensity(p_gray) == 255); - - assign_pixel_intensity(p_float, p_gray); - DLIB_TEST(p_float == 255); - DLIB_TEST(get_pixel_intensity(p_float) == 255); - - assign_pixel_intensity(p_int, p_gray); - DLIB_TEST(p_int == 255); - DLIB_TEST(get_pixel_intensity(p_int) == 255); - - - p_float = 1e10; - assign_pixel(p_schar, p_float); - DLIB_TEST(p_schar == std::numeric_limits::max()); - - p_float = -1e10; - assign_pixel(p_schar, p_float); - DLIB_TEST(p_schar == std::numeric_limits::min()); - - double p_double = 1e200; - assign_pixel(p_float, p_double); - DLIB_TEST(p_float == std::numeric_limits::max()); - - p_double = -1e200; - assign_pixel(p_float, p_double); - DLIB_TEST(p_float == -std::numeric_limits::max()); - } - - - } - - - - - class pixel_tester : public tester - { - public: - pixel_tester ( - ) : - tester ("test_pixel", - "Runs tests on the pixel objects and functions.") - {} - - void perform_test ( - ) - { - pixel_test(); - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/probabilistic.cpp b/lib/3rdParty/dlib/include/dlib/test/probabilistic.cpp deleted file mode 100644 index e8a24829..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/probabilistic.cpp +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include "../stl_checked.h" -#include "../array.h" -#include "../rand.h" -#include "checkerboard.h" -#include - -#include "tester.h" -#include - - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.probabilistic"); - -// ---------------------------------------------------------------------------------------- - - class test_probabilistic : public tester - { - public: - test_probabilistic ( - ) : - tester ("test_probabilistic", - "Runs tests on the probabilistic trainer adapter.") - {} - - void perform_test ( - ) - { - print_spinner(); - - - typedef double scalar_type; - typedef matrix sample_type; - - std::vector x; - std::vector > x_linearized; - std::vector y; - - get_checkerboard_problem(x,y, 1000, 2); - - random_subset_selector rx; - random_subset_selector ry; - rx.set_max_size(x.size()); - ry.set_max_size(x.size()); - - dlog << LINFO << "pos labels: "<< sum(mat(y) == +1); - dlog << LINFO << "neg labels: "<< sum(mat(y) == -1); - - for (unsigned long i = 0; i < x.size(); ++i) - { - rx.add(x[i]); - ry.add(y[i]); - } - - const scalar_type gamma = 2.0; - - typedef radial_basis_kernel kernel_type; - - krr_trainer krr_trainer; - krr_trainer.use_classification_loss_for_loo_cv(); - krr_trainer.set_kernel(kernel_type(gamma)); - krr_trainer.set_basis(randomly_subsample(x, 100)); - probabilistic_decision_function df; - - dlog << LINFO << "cross validation: " << cross_validate_trainer(krr_trainer, rx,ry, 4); - print_spinner(); - - running_stats rs_pos, rs_neg; - - print_spinner(); - df = probabilistic(krr_trainer,3).train(x, y); - for (unsigned long i = 0; i < x.size(); ++i) - { - if (y[i] > 0) - rs_pos.add(df(x[i])); - else - rs_neg.add(df(x[i])); - } - dlog << LINFO << "rs_pos.mean(): "<< rs_pos.mean(); - dlog << LINFO << "rs_neg.mean(): "<< rs_neg.mean(); - DLIB_TEST_MSG(rs_pos.mean() > 0.95, rs_pos.mean()); - DLIB_TEST_MSG(rs_neg.mean() < 0.05, rs_neg.mean()); - rs_pos.clear(); - rs_neg.clear(); - - - print_spinner(); - df = probabilistic(krr_trainer,3).train(rx, ry); - for (unsigned long i = 0; i < x.size(); ++i) - { - if (y[i] > 0) - rs_pos.add(df(x[i])); - else - rs_neg.add(df(x[i])); - } - dlog << LINFO << "rs_pos.mean(): "<< rs_pos.mean(); - dlog << LINFO << "rs_neg.mean(): "<< rs_neg.mean(); - DLIB_TEST_MSG(rs_pos.mean() > 0.95, rs_pos.mean()); - DLIB_TEST_MSG(rs_neg.mean() < 0.05, rs_neg.mean()); - rs_pos.clear(); - rs_neg.clear(); - - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/pyramid_down.cpp b/lib/3rdParty/dlib/include/dlib/test/pyramid_down.cpp deleted file mode 100644 index 5a3e9405..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/pyramid_down.cpp +++ /dev/null @@ -1,393 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#include -#include -#include -#include -#include -//#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.pyramid_down"); - -// ---------------------------------------------------------------------------------------- - -void test_pyramid_down_grayscale() -{ - array2d img, down; - pyramid_down<2> pyr; - - img.set_size(300,264); - - assign_all_pixels(img, 10); - - pyr(img, down); - - DLIB_TEST(std::abs(down.nr()*2 - img.nr()) < 5); - DLIB_TEST(std::abs(down.nc()*2 - img.nc()) < 5); - - rectangle rect1 = get_rect(img); - rectangle rect2 = pyr.rect_up(get_rect(down)); - double overlap = rect1.intersect(rect2).area() / (double)(rect1 + rect2).area(); - DLIB_TEST(overlap > 0.95); - - rect1 = get_rect(down); - rect2 = pyr.rect_down(get_rect(img)); - overlap = rect1.intersect(rect2).area() / (double)(rect1 + rect2).area(); - DLIB_TEST(overlap > 0.95); - - DLIB_TEST(min(mat(down)) == 10); - DLIB_TEST(max(mat(down)) == 10); -} - -void test_pyramid_down_rgb() -{ - array2d img; - array2d down; - pyramid_down<2> pyr; - - img.set_size(231, 351); - - assign_all_pixels(img, rgb_pixel(1,2,3)); - - pyr(img, down); - - DLIB_TEST(std::abs(down.nr()*2 - img.nr()) < 5); - DLIB_TEST(std::abs(down.nc()*2 - img.nc()) < 5); - - rectangle rect1 = get_rect(img); - rectangle rect2 = pyr.rect_up(get_rect(down)); - double overlap = rect1.intersect(rect2).area() / (double)(rect1 + rect2).area(); - DLIB_TEST(overlap > 0.95); - - rect1 = get_rect(down); - rect2 = pyr.rect_down(get_rect(img)); - overlap = rect1.intersect(rect2).area() / (double)(rect1 + rect2).area(); - DLIB_TEST(overlap > 0.95); - - bool pixels_match = true; - for (long r = 0; r < down.nr(); ++r) - { - for (long c = 0; c < down.nc(); ++c) - { - if (down[r][c].red != 1 || - down[r][c].green != 2 || - down[r][c].blue != 3 ) - { - pixels_match = false; - } - } - } - DLIB_TEST(pixels_match); -} - -// ---------------------------------------------------------------------------- - -template -rgb_pixel mean_pixel ( - const image_type& img, - const rectangle& rect -) -{ - long red = 0; - long green = 0; - long blue = 0; - for (long r = rect.top(); r <= rect.bottom(); ++r) - { - for (long c = rect.left(); c <= rect.right(); ++c) - { - red += img[r][c].red; - green += img[r][c].green; - blue += img[r][c].blue; - } - } - - const long n = rect.area(); - return rgb_pixel(red/n, green/n, blue/n); -} - -// ---------------------------------------------------------------------------- - -template -void test_pyramid_down_rgb2() -{ - array2d img, img3; - array2d img2, img4; - - - img.set_size(300,400); - assign_all_pixels(img, 0); - rectangle rect1 = centered_rect( 10,10, 14, 14); - rectangle rect2 = centered_rect( 100,100, 34, 42); - rectangle rect3 = centered_rect( 310,215, 65, 21); - - fill_rect(img, rect1, rgb_pixel(255,0,0)); - fill_rect(img, rect2, rgb_pixel(0,255,0)); - fill_rect(img, rect3, rgb_pixel(0,0,255)); - - - - pyramid_down_type pyr; - - pyr(img, img2); - pyr(img, img3); - - - DLIB_TEST(((rect1.tl_corner() - pyr.rect_down(pyr.rect_up(rect1,2),2).tl_corner()).length()) < 1); - DLIB_TEST(((rect1.br_corner() - pyr.rect_down(pyr.rect_up(rect1,2),2).br_corner()).length()) < 1); - DLIB_TEST(((rect2.tl_corner() - pyr.rect_down(pyr.rect_up(rect2,2),2).tl_corner()).length()) < 1); - DLIB_TEST(((rect2.br_corner() - pyr.rect_down(pyr.rect_up(rect2,2),2).br_corner()).length()) < 1); - DLIB_TEST(((rect3.tl_corner() - pyr.rect_down(pyr.rect_up(rect3,2),2).tl_corner()).length()) < 1); - DLIB_TEST(((rect3.br_corner() - pyr.rect_down(pyr.rect_up(rect3,2),2).br_corner()).length()) < 1); - - rect1 = shrink_rect(pyr.rect_down(rect1),1); - rect2 = shrink_rect(pyr.rect_down(rect2),1); - rect3 = shrink_rect(pyr.rect_down(rect3),1); - - DLIB_TEST(rect1.area() > 10); - DLIB_TEST(rect2.area() > 10); - DLIB_TEST(rect3.area() > 10); - - /* - image_window my_window(img); - image_window win2(img2); - image_window win3(img3); - win2.add_overlay(image_window::overlay_rect(rect1, rgb_pixel(255,0,0))); - win2.add_overlay(image_window::overlay_rect(rect2, rgb_pixel(255,0,0))); - win2.add_overlay(image_window::overlay_rect(rect3, rgb_pixel(255,0,0))); - win3.add_overlay(image_window::overlay_rect(rect1, rgb_pixel(255,0,0))); - win3.add_overlay(image_window::overlay_rect(rect2, rgb_pixel(255,0,0))); - win3.add_overlay(image_window::overlay_rect(rect3, rgb_pixel(255,0,0))); - */ - - - DLIB_TEST(std::abs((int)mean(subm(matrix_cast(mat(img2)),rect1)) - 255/3) < 3); - DLIB_TEST(std::abs((int)mean(subm(matrix_cast(mat(img2)),rect2)) - 255/3) < 3); - DLIB_TEST(std::abs((int)mean(subm(matrix_cast(mat(img2)),rect3)) - 255/3) < 3); - assign_image(img4, img); - DLIB_TEST(std::abs((int)mean(mat(img4)) - mean(mat(img2))) < 2); - - - rgb_pixel mean1 = mean_pixel(img3, rect1); - rgb_pixel mean2 = mean_pixel(img3, rect2); - rgb_pixel mean3 = mean_pixel(img3, rect3); - rgb_pixel mean_all_true = mean_pixel(img, get_rect(img)); - rgb_pixel mean_all = mean_pixel(img3, get_rect(img3)); - DLIB_TEST(mean1.red > 250); - DLIB_TEST(mean1.green < 3); - DLIB_TEST(mean1.blue < 3); - - DLIB_TEST(mean2.red < 3); - DLIB_TEST(mean2.green > 250); - DLIB_TEST(mean2.blue < 3); - - DLIB_TEST(mean3.red < 3); - DLIB_TEST(mean3.green < 3); - DLIB_TEST(mean3.blue > 250); - - DLIB_TEST(std::abs((int)mean_all_true.red - mean_all.red) < 1); - DLIB_TEST(std::abs((int)mean_all_true.green - mean_all.green) < 1); - DLIB_TEST(std::abs((int)mean_all_true.blue - mean_all.blue) < 1); - - //my_window.wait_until_closed(); -} - - -// ---------------------------------------------------------------------------------------- - -template -void test_pyramid_down_grayscale2() -{ - array2d img, img3; - array2d img2, img4; - - - img.set_size(300,400); - assign_all_pixels(img, 0); - rectangle rect1 = centered_rect( 10,10, 14, 14); - rectangle rect2 = centered_rect( 100,100, 34, 42); - rectangle rect3 = centered_rect( 310,215, 65, 21); - - fill_rect(img, rect1, 255); - fill_rect(img, rect2, 170); - fill_rect(img, rect3, 100); - - - - pyramid_down_type pyr; - - pyr(img, img2); - pyr(img, img3); - - - DLIB_TEST(((rect1.tl_corner() - pyr.rect_down(pyr.rect_up(rect1,2),2).tl_corner()).length()) < 1); - DLIB_TEST(((rect1.br_corner() - pyr.rect_down(pyr.rect_up(rect1,2),2).br_corner()).length()) < 1); - DLIB_TEST(((rect2.tl_corner() - pyr.rect_down(pyr.rect_up(rect2,2),2).tl_corner()).length()) < 1); - DLIB_TEST(((rect2.br_corner() - pyr.rect_down(pyr.rect_up(rect2,2),2).br_corner()).length()) < 1); - DLIB_TEST(((rect3.tl_corner() - pyr.rect_down(pyr.rect_up(rect3,2),2).tl_corner()).length()) < 1); - DLIB_TEST(((rect3.br_corner() - pyr.rect_down(pyr.rect_up(rect3,2),2).br_corner()).length()) < 1); - - rect1 = shrink_rect(pyr.rect_down(rect1),1); - rect2 = shrink_rect(pyr.rect_down(rect2),1); - rect3 = shrink_rect(pyr.rect_down(rect3),1); - - DLIB_TEST(rect1.area() > 10); - DLIB_TEST(rect2.area() > 10); - DLIB_TEST(rect3.area() > 10); - - /* - image_window my_window(img); - image_window win2(img2); - image_window win3(img3); - win2.add_overlay(image_window::overlay_rect(rect1, rgb_pixel(255,0,0))); - win2.add_overlay(image_window::overlay_rect(rect2, rgb_pixel(255,0,0))); - win2.add_overlay(image_window::overlay_rect(rect3, rgb_pixel(255,0,0))); - win3.add_overlay(image_window::overlay_rect(rect1, rgb_pixel(255,0,0))); - win3.add_overlay(image_window::overlay_rect(rect2, rgb_pixel(255,0,0))); - win3.add_overlay(image_window::overlay_rect(rect3, rgb_pixel(255,0,0))); - */ - - - DLIB_TEST(std::abs((int)mean(subm(matrix_cast(mat(img2)),rect1)) - 255) < 3); - DLIB_TEST(std::abs((int)mean(subm(matrix_cast(mat(img2)),rect2)) - 170) < 3); - DLIB_TEST(std::abs((int)mean(subm(matrix_cast(mat(img2)),rect3)) - 100) < 3); - assign_image(img4, img); - DLIB_TEST(std::abs((int)mean(mat(img4)) - mean(mat(img2))) < 2); - - - //my_window.wait_until_closed(); - - - - // make sure the coordinate mapping is invertible when it should be - for (int l = 0; l < 4; ++l) - { - for (long x = -10; x <= 10; ++x) - { - for (long y = -10; y <= 10; ++y) - { - DLIB_TEST_MSG(point(pyr.point_down(pyr.point_up(point(x,y),l),l)) == point(x,y), - point(x,y) << " " << pyr.point_up(point(x,y),l) << " " << pyr.point_down(pyr.point_up(point(x,y),l),l)); - DLIB_TEST_MSG(point(pyr.point_down(point(pyr.point_up(point(x,y),l)),l)) == point(x,y), - point(x,y) << " " << pyr.point_up(point(x,y),l) << " " << pyr.point_down(point(pyr.point_up(point(x,y),l)),l)); - } - } - } -} - - -// ---------------------------------------------------------------------------------------- - -template -void test_pyramid_down_small_sizes() -{ - // just make sure it doesn't get messed up with small images. This test - // is only really useful if asserts are enabled. - pyramid_down_type pyr; - - for (int size = 0; size < 20; ++size) - { - array2d img1(size,size); - array2d img2(size,size); - - array2d out1; - array2d out2; - - assign_all_pixels(img1, 0); - assign_all_pixels(img2, 0); - - pyr(img1, out1); - pyr(img2, out2); - } -} - -// ---------------------------------------------------------------------------------------- - - - class test_pyramid_down : public tester - { - public: - test_pyramid_down ( - ) : - tester ("test_pyramid_down", - "Runs tests on the pyramid_down() function.") - {} - - void perform_test ( - ) - { - print_spinner(); - test_pyramid_down_grayscale(); - print_spinner(); - test_pyramid_down_rgb(); - - print_spinner(); - dlog << LINFO << "call test_pyramid_down_small_sizes >();"; - test_pyramid_down_small_sizes >(); - dlog << LINFO << "call test_pyramid_down_small_sizes >();"; - test_pyramid_down_small_sizes >(); - dlog << LINFO << "call test_pyramid_down_small_sizes >();"; - test_pyramid_down_small_sizes >(); - dlog << LINFO << "call test_pyramid_down_small_sizes >();"; - test_pyramid_down_small_sizes >(); - dlog << LINFO << "call test_pyramid_down_small_sizes();"; - test_pyramid_down_small_sizes(); - dlog << LINFO << "call test_pyramid_down_small_sizes >();"; - test_pyramid_down_small_sizes >(); - - print_spinner(); - dlog << LINFO << "call test_pyramid_down_rgb2 >();"; - test_pyramid_down_rgb2 >(); - - print_spinner(); - dlog << LINFO << "call test_pyramid_down_rgb2 >();"; - test_pyramid_down_rgb2 >(); - - print_spinner(); - dlog << LINFO << "call test_pyramid_down_rgb2 >();"; - test_pyramid_down_rgb2 >(); - - print_spinner(); - dlog << LINFO << "call test_pyramid_down_rgb2 >();"; - test_pyramid_down_rgb2 >(); - - print_spinner(); - dlog << LINFO << "call test_pyramid_down_rgb2 >();"; - test_pyramid_down_rgb2 >(); - - - print_spinner(); - dlog << LINFO << "call test_pyramid_down_grayscale2 >();"; - test_pyramid_down_grayscale2 >(); - - print_spinner(); - dlog << LINFO << "call test_pyramid_down_grayscale2 >();"; - test_pyramid_down_grayscale2 >(); - - print_spinner(); - dlog << LINFO << "call test_pyramid_down_grayscale2 >();"; - test_pyramid_down_grayscale2 >(); - - print_spinner(); - dlog << LINFO << "call test_pyramid_down_grayscale2 >();"; - test_pyramid_down_grayscale2 >(); - - print_spinner(); - dlog << LINFO << "call test_pyramid_down_grayscale2 >();"; - test_pyramid_down_grayscale2 >(); - } - } a; - -} - - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/queue.cpp b/lib/3rdParty/dlib/include/dlib/test/queue.cpp deleted file mode 100644 index efcdf605..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/queue.cpp +++ /dev/null @@ -1,426 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -// This is called an unnamed-namespace and it has the effect of making everything inside this file "private" -// so that everything you declare will have static linkage. Thus we won't have any multiply -// defined symbol errors coming out of the linker when we try to compile the test suite. -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - // Declare the logger we will use in this test. The name of the tester - // should start with "test." - logger dlog("test.queue"); - - template < - typename queue - > - void queue_sort_test ( - ) - /*! - requires - - queue is an implementation of queue/queue_sort_abstract.h - is instantiated with int - ensures - - runs tests on queue for compliance with the specs - !*/ - { - - print_spinner(); - srand(static_cast(time(0))); - - queue q,q2; - - enumerable& e = q; - - // I will use these DLIB_TEST_MSG macros to assert that conditions are true. If they are - // false then it means we have detected an error in the queue object. CASSERT - // will then throw an exception which we will catch at the end of this function and - // report as an error/failed test. - DLIB_TEST(e.at_start() == true); - - int a = 0; - - DLIB_TEST(q.size() == 0); - DLIB_TEST(q.at_start() == true); - DLIB_TEST(q.current_element_valid() == false); - - q.sort(); - - DLIB_TEST(q.size() == 0); - DLIB_TEST(q.at_start() == true); - DLIB_TEST(q.current_element_valid() == false); - - DLIB_TEST (q.move_next() == false); - DLIB_TEST (q.move_next() == false); - DLIB_TEST (q.move_next() == false); - DLIB_TEST (q.move_next() == false); - DLIB_TEST (q.move_next() == false); - DLIB_TEST (q.move_next() == false); - - - DLIB_TEST(q.size() == 0); - DLIB_TEST(q.at_start() == false); - DLIB_TEST(q.current_element_valid() == false); - - - q.reset(); - - DLIB_TEST(q.size() == 0); - DLIB_TEST(q.at_start() == true); - DLIB_TEST(q.current_element_valid() == false); - - - - - - - - - - - - q.clear(); - q2.clear(); - DLIB_TEST(q.size() == 0); - DLIB_TEST(q2.size() == 0); - - for (int i = 0; i < 10000; ++i) - { - int a = i; - q.enqueue(a); - } - - q2.cat(q); - - DLIB_TEST(q.size() == 0); - DLIB_TEST(q2.size() == 10000); - - int g = 0; - while (q2.move_next()) - { - DLIB_TEST_MSG(q2.element() == g,g); - ++g; - } - - for (int i = 0;i < 10000; ++i) - { - int a = 0; - q2.dequeue(a); - DLIB_TEST(a == i); - } - - DLIB_TEST(q.size() == 0); - DLIB_TEST(q2.size() == 0); - q.clear(); - q2.clear(); - - - - - print_spinner(); - - - dlog << LTRACE << "creating big pre-sorted queue"; - q.clear(); - DLIB_TEST(q.size() == 0); - - for (int i = 0; i < 10000; ++i) - { - int a = i; - q.enqueue(a); - } - - dlog << LTRACE << "sorting already sorted queue"; - q.sort(); - - - dlog << LTRACE << "done sorting, checking the results"; - for (int i = 0; i < 10000; ++i) - { - q.dequeue(a); - DLIB_TEST(a == i); - } - - - q.clear(); - dlog << LTRACE << "done with the big pre-sorted queue test"; - - - - - - - - - - - - - - - - q.clear(); - q2.clear(); - DLIB_TEST(q.size() == 0); - DLIB_TEST(q2.size() == 0); - - for (int i = 0; i < 1; ++i) - { - int a = i; - q.enqueue(a); - } - - q2.cat(q); - - DLIB_TEST(q.size() == 0); - DLIB_TEST(q2.size() == 1); - - - - g = 0; - while (q2.move_next()) - { - DLIB_TEST_MSG(q2.element() == g,g); - ++g; - } - - for (int i = 0;i < 1; ++i) - { - int a = 0; - q2.dequeue(a); - DLIB_TEST(a == i); - } - - DLIB_TEST(q.size() == 0); - DLIB_TEST(q2.size() == 0); - q.clear(); - q2.clear(); - - - - - - - - print_spinner(); - - - - - - - - - - - - for (int j = 0; j < 3; ++j) - { - for (int i = 0; i < 10000; ++i) - { - a = ::rand(); - q.enqueue(a); - } - - while (q.move_next()) ; - - DLIB_TEST(q.at_start() == false); - - q.sort(); - - DLIB_TEST(q.at_start() == true); - - // serialize the state of q, then clear q, then - // load the state back into q. - ostringstream sout; - serialize(q,sout); - DLIB_TEST(q.at_start() == true); - istringstream sin(sout.str()); - q.clear(); - deserialize(q,sin); - - - DLIB_TEST(q.at_start() == true); - - a = 0; - int last = 0; - while (q.move_next()) - { - ++a; - DLIB_TEST_MSG(last <= q.element(),"items weren't actually sorted"); - last = q.element(); - DLIB_TEST(q.current_element_valid() == true); - DLIB_TEST(q.at_start() == false); - DLIB_TEST(q.current_element_valid() == true); - - - } - DLIB_TEST_MSG(a == 10000,"some items were lost between the sorting and iterating"); - - - DLIB_TEST(q.size() == 10000); - swap(q,q2); - DLIB_TEST(q2.at_start() == false); - DLIB_TEST(q2.current_element_valid() == false); - - DLIB_TEST (q2.move_next() == false); - DLIB_TEST (q2.move_next() == false); - DLIB_TEST (q2.move_next() == false); - DLIB_TEST (q2.move_next() == false); - DLIB_TEST (q2.move_next() == false); - DLIB_TEST (q2.move_next() == false); - - - DLIB_TEST(q2.size() == 10000); - DLIB_TEST(q2.at_start() == false); - DLIB_TEST(q2.current_element_valid() == false); - - q2.clear(); - - q.swap(q2); - - DLIB_TEST(q.size() == 0); - DLIB_TEST(q.at_start() == true); - DLIB_TEST(q.current_element_valid() == false); - } - - - - print_spinner(); - - - - // try the above code but this time with just one element - // in the queue - for (int j = 0; j < 3; ++j) - { - for (int i = 0; i < 1; ++i) - { - a = ::rand(); - q.enqueue(a); - } - - q.sort(); - - a = 0; - int last = 0; - while (q.move_next()) - { - ++a; - DLIB_TEST_MSG(last <= q.element(),"items weren't actually sorted"); - DLIB_TEST(q.current_element_valid() == true); - - } - DLIB_TEST_MSG(a == 1,"some items were lost between the sorting and iterating"); - - - DLIB_TEST(q.size() == 1); - DLIB_TEST(q.at_start() == false); - DLIB_TEST(q.current_element_valid() == false); - - q.clear(); - - DLIB_TEST(q.size() == 0); - DLIB_TEST(q.at_start() == true); - DLIB_TEST(q.current_element_valid() == false); - } - - - print_spinner(); - - { - q.clear(); - remover& go = q; - for (int i = 0; i < 100; ++i) - { - int a = 3; - q.enqueue(a); - } - DLIB_TEST(go.size() == 100); - for (int i = 0; i < 100; ++i) - { - int a = 9; - q.remove_any(a); - DLIB_TEST(a == 3); - } - DLIB_TEST(go.size() == 0); - } - - } - - - struct factory - { - template - struct return_type { - typedef typename memory_manager::kernel_3c type; - }; - - template - static typename return_type::type* get_instance ( - ) - { - static typename return_type::type a; - return &a; - } - }; - - - - - class queue_tester : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a test for the queue object. When it is constructed - it adds itself into the testing framework. The command line switch is - specified as test_queue by passing that string to the tester constructor. - !*/ - public: - queue_tester ( - ) : - tester ("test_queue", - "Runs tests on the queue component.") - {} - - void perform_test ( - ) - { - // There are multiple implementations of the queue object so use - // the templated function defined above to test them all and report - // a failed test if any of them don't pass. - - typedef dlib::memory_manager_global::kernel_1a mm; - - - dlog << LINFO << "testing sort_1a_c"; - queue_sort_test::sort_1a_c> (); - dlog << LINFO << "testing sort_1a"; - queue_sort_test::sort_1a>(); - dlog << LINFO << "testing sort_1b"; - queue_sort_test::sort_1b> (); - dlog << LINFO << "testing sort_1b_c"; - queue_sort_test::sort_1b_c>(); - dlog << LINFO << "testing sort_1c"; - queue_sort_test::sort_1c> (); - dlog << LINFO << "testing sort_1c_c"; - queue_sort_test::sort_1c_c>(); - } - } a; - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/rand.cpp b/lib/3rdParty/dlib/include/dlib/test/rand.cpp deleted file mode 100644 index 8b94c7c4..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/rand.cpp +++ /dev/null @@ -1,409 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.rand"); - - void check_bpp ( - const std::string str - ) - { - istringstream rdata; - ostringstream sout; - rdata.str(str); - double compressed_size; - compress_stream::kernel_1a cs1; - compress_stream::kernel_2a cs2; - - compress_stream_kernel_1< - entropy_encoder_model_kernel_5<257,entropy_encoder::kernel_1a,4000000,4>, - entropy_decoder_model_kernel_5<257,entropy_decoder::kernel_1a,4000000,4>, - crc32::kernel_1a - > cs3; - - - print_spinner(); - - rdata.clear(); - rdata.seekg(0); - sout.clear(); - sout.str(""); - cs1.compress(rdata,sout); - compressed_size = sout.str().size(); - compressed_size *= 8; - compressed_size /= str.size(); - DLIB_TEST_MSG(compressed_size >= 8, "order 0 bps: " << compressed_size); - dlog << LINFO << "order 0: " << compressed_size; - - print_spinner(); - - rdata.clear(); - rdata.seekg(0); - sout.clear(); - sout.str(""); - cs2.compress(rdata,sout); - compressed_size = sout.str().size(); - compressed_size *= 8; - compressed_size /= str.size(); - DLIB_TEST_MSG(compressed_size >= 8, "order 1 bps: " << compressed_size); - dlog << LINFO << "order 1: " << compressed_size; - - print_spinner(); - - rdata.clear(); - rdata.seekg(0); - sout.clear(); - sout.str(""); - cs3.compress(rdata,sout); - compressed_size = sout.str().size(); - compressed_size *= 8; - compressed_size /= str.size(); - DLIB_TEST_MSG(compressed_size >= 8, "order 4 bps: " << compressed_size); - dlog << LINFO << "order 4: " << compressed_size; - - } - - template < - typename rand - > - void rand_test ( - ) - /*! - requires - - rand is an implementation of rand/rand_kernel_abstract.h - is instantiated with int - ensures - - runs tests on rand for compliance with the specs - !*/ - { - - ostringstream seed; - seed << (unsigned int)time(0); - - ostringstream sout; - - - rand r, r2; - DLIB_TEST(r.get_seed() == ""); - r.set_seed(seed.str()); - - DLIB_TEST(r.get_seed() == seed.str()); - r.clear(); - DLIB_TEST(r.get_seed() == ""); - swap(r,r2); - DLIB_TEST(r.get_seed() == ""); - r.set_seed(seed.str()); - DLIB_TEST(r.get_seed() == seed.str()); - swap(r,r2); - DLIB_TEST(r2.get_seed() == seed.str()); - DLIB_TEST(r.get_seed() == ""); - swap(r,r2); - DLIB_TEST(r.get_seed() == seed.str()); - DLIB_TEST(r2.get_seed() == ""); - - print_spinner(); - unsigned long size = 100000; - for (unsigned long i = 0; i < size; ++i) - { - uint32 ch = r.get_random_32bit_number(); - sout.write((char*)&ch,4); - } - - check_bpp(sout.str()); - sout.clear(); - sout.str(""); - - print_spinner(); - for (unsigned long i = 0; i < size; ++i) - { - uint16 ch = r.get_random_16bit_number(); - sout.write((char*)&ch,2); - } - - check_bpp(sout.str()); - sout.clear(); - sout.str(""); - - print_spinner(); - for (unsigned long i = 0; i < size; ++i) - { - unsigned char ch = r.get_random_8bit_number(); - sout.write((char*)&ch,1); - } - - check_bpp(sout.str()); - sout.clear(); - sout.str(""); - - - // make sure the things can serialize right - { - r.clear(); - r2.clear(); - - - for (int i =0; i < 1000; ++i) - { - r.get_random_32bit_number(); - r.get_random_gaussian(); - } - - ostringstream sout; - serialize(r, sout); - - istringstream sin(sout.str()); - deserialize(r2, sin); - - - for (int i =0; i < 1000; ++i) - { - DLIB_TEST(r.get_random_32bit_number() == r2.get_random_32bit_number()); - DLIB_TEST(std::abs(r.get_random_gaussian() - r2.get_random_gaussian()) < 1e-14); - } - } - - - // make sure calling clear() and set_seed("") do the same thing - { - r.clear(); - r2.set_seed(""); - rand r3; - - - DLIB_TEST(r.get_seed() == r2.get_seed()); - DLIB_TEST(r.get_seed() == r3.get_seed()); - - - for (int i =0; i < 1000; ++i) - { - const uint32 num1 = r.get_random_32bit_number(); - const uint32 num2 = r2.get_random_32bit_number(); - const uint32 num3 = r3.get_random_32bit_number(); - DLIB_TEST( num1 == num2); - DLIB_TEST( num1 == num3); - } - } - - } - - - template - void test_normal_numbers( - rand_type& rnd - ) - { - print_spinner(); - dlog << LINFO << "test normality"; - double cnt1 = 0; // num <= -1.2 - double cnt2 = 0; // num <= -0.5 - double cnt3 = 0; // num <= 0 - double cnt4 = 0; // num <= 0.5 - double cnt5 = 0; // num <= 1.2 - - const unsigned long total = 1000000; - for (unsigned long i = 0; i < total; ++i) - { - const double r = rnd.get_random_gaussian(); - if (r <= -1.2) cnt1 += 1; - if (r <= -0.5) cnt2 += 1; - if (r <= 0) cnt3 += 1; - if (r <= 0.5) cnt4 += 1; - if (r <= 1.2) cnt5 += 1; - } - - cnt1 /= total; - cnt2 /= total; - cnt3 /= total; - cnt4 /= total; - cnt5 /= total; - - dlog << LINFO << "cnt1: "<< cnt1; - dlog << LINFO << "cnt2: "<< cnt2; - dlog << LINFO << "cnt3: "<< cnt3; - dlog << LINFO << "cnt4: "<< cnt4; - dlog << LINFO << "cnt5: "<< cnt5; - - DLIB_TEST(std::abs(cnt1 - 0.11507) < 0.001); - DLIB_TEST(std::abs(cnt2 - 0.30854) < 0.001); - DLIB_TEST(std::abs(cnt3 - 0.5) < 0.001); - DLIB_TEST(std::abs(cnt4 - 0.69146) < 0.001); - DLIB_TEST(std::abs(cnt5 - 0.88493) < 0.001); - - } - - void test_gaussian_random_hash() - { - print_spinner(); - dlog << LINFO << "test_gaussian_random_hash()"; - double cnt1 = 0; // num <= -1.2 - double cnt2 = 0; // num <= -0.5 - double cnt3 = 0; // num <= 0 - double cnt4 = 0; // num <= 0.5 - double cnt5 = 0; // num <= 1.2 - - const unsigned long total = 1000000; - for (unsigned long i = 0; i < total; ++i) - { - const double r = gaussian_random_hash(i,0,0); - if (r <= -1.2) cnt1 += 1; - if (r <= -0.5) cnt2 += 1; - if (r <= 0) cnt3 += 1; - if (r <= 0.5) cnt4 += 1; - if (r <= 1.2) cnt5 += 1; - } - for (unsigned long i = 0; i < total; ++i) - { - const double r = gaussian_random_hash(0,i,0); - if (r <= -1.2) cnt1 += 1; - if (r <= -0.5) cnt2 += 1; - if (r <= 0) cnt3 += 1; - if (r <= 0.5) cnt4 += 1; - if (r <= 1.2) cnt5 += 1; - } - for (unsigned long i = 0; i < total; ++i) - { - const double r = gaussian_random_hash(0,0,i); - if (r <= -1.2) cnt1 += 1; - if (r <= -0.5) cnt2 += 1; - if (r <= 0) cnt3 += 1; - if (r <= 0.5) cnt4 += 1; - if (r <= 1.2) cnt5 += 1; - } - - cnt1 /= total*3; - cnt2 /= total*3; - cnt3 /= total*3; - cnt4 /= total*3; - cnt5 /= total*3; - - dlog << LINFO << "cnt1: "<< cnt1; - dlog << LINFO << "cnt2: "<< cnt2; - dlog << LINFO << "cnt3: "<< cnt3; - dlog << LINFO << "cnt4: "<< cnt4; - dlog << LINFO << "cnt5: "<< cnt5; - - DLIB_TEST(std::abs(cnt1 - 0.11507) < 0.001); - DLIB_TEST(std::abs(cnt2 - 0.30854) < 0.001); - DLIB_TEST(std::abs(cnt3 - 0.5) < 0.001); - DLIB_TEST(std::abs(cnt4 - 0.69146) < 0.001); - DLIB_TEST(std::abs(cnt5 - 0.88493) < 0.001); - } - - void test_uniform_random_hash() - { - print_spinner(); - dlog << LINFO << "test_uniform_random_hash()"; - double cnt1 = 0; // num <= 0.2 - double cnt2 = 0; // num <= 0.4 - double cnt3 = 0; // num <= 0.6 - double cnt4 = 0; // num <= 0.8 - double cnt5 = 0; // num <= 1.0 - - double min_val = 10; - double max_val = 0; - - const unsigned long total = 1000000; - for (unsigned long i = 0; i < total; ++i) - { - const double r = uniform_random_hash(i,0,0); - min_val = min(r,min_val); - max_val = max(r,max_val); - - if (r <= 0.2) cnt1 += 1; - if (r <= 0.4) cnt2 += 1; - if (r <= 0.6) cnt3 += 1; - if (r <= 0.8) cnt4 += 1; - if (r <= 1.0) cnt5 += 1; - } - for (unsigned long i = 0; i < total; ++i) - { - const double r = uniform_random_hash(0,i,0); - min_val = min(r,min_val); - max_val = max(r,max_val); - - if (r <= 0.2) cnt1 += 1; - if (r <= 0.4) cnt2 += 1; - if (r <= 0.6) cnt3 += 1; - if (r <= 0.8) cnt4 += 1; - if (r <= 1.0) cnt5 += 1; - } - for (unsigned long i = 0; i < total; ++i) - { - const double r = uniform_random_hash(0,0,i); - min_val = min(r,min_val); - max_val = max(r,max_val); - - if (r <= 0.2) cnt1 += 1; - if (r <= 0.4) cnt2 += 1; - if (r <= 0.6) cnt3 += 1; - if (r <= 0.8) cnt4 += 1; - if (r <= 1.0) cnt5 += 1; - } - - cnt1 /= total*3; - cnt2 /= total*3; - cnt3 /= total*3; - cnt4 /= total*3; - cnt5 /= total*3; - - dlog << LINFO << "cnt1: "<< cnt1; - dlog << LINFO << "cnt2: "<< cnt2; - dlog << LINFO << "cnt3: "<< cnt3; - dlog << LINFO << "cnt4: "<< cnt4; - dlog << LINFO << "cnt5: "<< cnt5; - dlog << LINFO << "min_val: "<< min_val; - dlog << LINFO << "max_val: "<< max_val; - - DLIB_TEST(std::abs(cnt1 - 0.2) < 0.001); - DLIB_TEST(std::abs(cnt2 - 0.4) < 0.001); - DLIB_TEST(std::abs(cnt3 - 0.6) < 0.001); - DLIB_TEST(std::abs(cnt4 - 0.8) < 0.001); - DLIB_TEST(std::abs(cnt5 - 1.0) < 0.001); - DLIB_TEST(std::abs(min_val - 0.0) < 0.001); - DLIB_TEST(std::abs(max_val - 1.0) < 0.001); - } - - class rand_tester : public tester - { - public: - rand_tester ( - ) : - tester ("test_rand", - "Runs tests on the rand component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a"; - rand_test(); - rand_test(); - - dlib::rand rnd; - test_normal_numbers(rnd); - test_gaussian_random_hash(); - test_uniform_random_hash(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/ranking.cpp b/lib/3rdParty/dlib/include/dlib/test/ranking.cpp deleted file mode 100644 index d1914a87..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/ranking.cpp +++ /dev/null @@ -1,439 +0,0 @@ -// Copyright (C) 2012 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - - logger dlog("test.ranking"); - -// ---------------------------------------------------------------------------------------- - - template - void brute_force_count_ranking_inversions ( - const std::vector& x, - const std::vector& y, - std::vector& x_count, - std::vector& y_count - ) - { - x_count.assign(x.size(),0); - y_count.assign(y.size(),0); - - for (unsigned long i = 0; i < x.size(); ++i) - { - for (unsigned long j = 0; j < y.size(); ++j) - { - if (x[i] <= y[j]) - { - x_count[i]++; - y_count[j]++; - } - } - } - } - -// ---------------------------------------------------------------------------------------- - - void test_count_ranking_inversions() - { - print_spinner(); - dlog << LINFO << "in test_count_ranking_inversions()"; - - dlib::rand rnd; - std::vector x, y; - std::vector x_count, y_count; - std::vector x_count2, y_count2; - for (int iter = 0; iter < 5000; ++iter) - { - x.resize(rnd.get_random_32bit_number()%10); - y.resize(rnd.get_random_32bit_number()%10); - for (unsigned long i = 0; i < x.size(); ++i) - x[i] = ((int)rnd.get_random_32bit_number()%10) - 5; - for (unsigned long i = 0; i < y.size(); ++i) - y[i] = ((int)rnd.get_random_32bit_number()%10) - 5; - - count_ranking_inversions(x, y, x_count, y_count); - brute_force_count_ranking_inversions(x, y, x_count2, y_count2); - - DLIB_TEST(mat(x_count) == mat(x_count2)); - DLIB_TEST(mat(y_count) == mat(y_count2)); - } - } - -// ---------------------------------------------------------------------------------------- - - void run_prior_test() - { - print_spinner(); - typedef matrix sample_type; - typedef linear_kernel kernel_type; - - svm_rank_trainer trainer; - - ranking_pair data; - - sample_type samp; - samp = 0, 0, 1; data.relevant.push_back(samp); - samp = 0, 1, 0; data.nonrelevant.push_back(samp); - - trainer.set_c(10); - decision_function df = trainer.train(data); - - trainer.set_prior(df); - - data.relevant.clear(); - data.nonrelevant.clear(); - samp = 1, 0, 0; data.relevant.push_back(samp); - samp = 0, 1, 0; data.nonrelevant.push_back(samp); - - df = trainer.train(data); - - dlog << LINFO << trans(df.basis_vectors(0)); - DLIB_TEST(df.basis_vectors(0)(0) > 0); - DLIB_TEST(df.basis_vectors(0)(1) < 0); - DLIB_TEST(df.basis_vectors(0)(2) > 0); - } - -// ---------------------------------------------------------------------------------------- - - void run_prior_sparse_test() - { - print_spinner(); - typedef std::map sample_type; - typedef sparse_linear_kernel kernel_type; - - svm_rank_trainer trainer; - - ranking_pair data; - - sample_type samp; - samp[0] = 1; data.relevant.push_back(samp); samp.clear(); - samp[1] = 1; data.nonrelevant.push_back(samp); samp.clear(); - - trainer.set_c(10); - decision_function df = trainer.train(data); - - trainer.set_prior(df); - - data.relevant.clear(); - data.nonrelevant.clear(); - samp[2] = 1; data.relevant.push_back(samp); samp.clear(); - samp[1] = 1; data.nonrelevant.push_back(samp); samp.clear(); - - df = trainer.train(data); - - matrix w = sparse_to_dense(df.basis_vectors(0)); - dlog << LINFO << trans(w); - DLIB_TEST(w(0) > 0.1); - DLIB_TEST(w(1) < -0.1); - DLIB_TEST(w(2) > 0.1); - } - -// ---------------------------------------------------------------------------------------- - - void dotest1() - { - print_spinner(); - dlog << LINFO << "in dotest1()"; - - typedef matrix sample_type; - - typedef linear_kernel kernel_type; - - svm_rank_trainer trainer; - - - std::vector > samples; - - ranking_pair p; - sample_type samp; - - samp = 0, 0, 0, 1; p.relevant.push_back(samp); - samp = 1, 0, 0, 0; p.nonrelevant.push_back(samp); - samples.push_back(p); - - samp = 0, 0, 1, 0; p.relevant.push_back(samp); - samp = 1, 0, 0, 0; p.nonrelevant.push_back(samp); - samp = 0, 1, 0, 0; p.nonrelevant.push_back(samp); - samp = 0, 1, 0, 0; p.nonrelevant.push_back(samp); - samples.push_back(p); - - - trainer.set_c(10); - - decision_function df = trainer.train(samples); - - dlog << LINFO << "accuracy: "<< test_ranking_function(df, samples); - matrix res; - res = 1,1; - DLIB_TEST(equal(test_ranking_function(df, samples), res)); - - DLIB_TEST(equal(test_ranking_function(trainer.train(samples[1]), samples), res)); - - trainer.set_epsilon(1e-13); - df = trainer.train(samples); - - dlog << LINFO << df.basis_vectors(0); - sample_type truew; - truew = -0.5, -0.5, 0.5, 0.5; - DLIB_TEST(length(truew - df.basis_vectors(0)) < 1e-10); - - dlog << LINFO << "accuracy: "<< test_ranking_function(df, samples); - DLIB_TEST(equal(test_ranking_function(df, samples), res)); - - dlog << LINFO << "cv-accuracy: "<< cross_validate_ranking_trainer(trainer, samples,2); - DLIB_TEST(std::abs(cross_validate_ranking_trainer(trainer, samples,2)(0) - 0.7777777778) < 0.0001); - - trainer.set_learns_nonnegative_weights(true); - df = trainer.train(samples); - truew = 0, 0, 1.0, 1.0; - dlog << LINFO << df.basis_vectors(0); - DLIB_TEST(length(truew - df.basis_vectors(0)) < 1e-10); - dlog << LINFO << "accuracy: "<< test_ranking_function(df, samples); - DLIB_TEST(equal(test_ranking_function(df, samples), res)); - - - samples.clear(); - samples.push_back(p); - samples.push_back(p); - samples.push_back(p); - samples.push_back(p); - dlog << LINFO << "cv-accuracy: "<< cross_validate_ranking_trainer(trainer, samples,4); - DLIB_TEST(equal(cross_validate_ranking_trainer(trainer, samples,4) , res)); - - df.basis_vectors(0) = 0; - dlog << LINFO << "BAD RANKING:" << test_ranking_function(df, samples); - DLIB_TEST(test_ranking_function(df, samples)(1) < 0.5); - } - -// ---------------------------------------------------------------------------------------- - - void dotest_sparse_vectors() - { - print_spinner(); - dlog << LINFO << "in dotest_sparse_vectors()"; - - typedef std::map sample_type; - - typedef sparse_linear_kernel kernel_type; - - svm_rank_trainer trainer; - - - std::vector > samples; - - ranking_pair p; - sample_type samp; - - samp[3] = 1; p.relevant.push_back(samp); samp.clear(); - samp[0] = 1; p.nonrelevant.push_back(samp); samp.clear(); - samples.push_back(p); - - samp[2] = 1; p.relevant.push_back(samp); samp.clear(); - samp[0] = 1; p.nonrelevant.push_back(samp); samp.clear(); - samp[1] = 1; p.nonrelevant.push_back(samp); samp.clear(); - samp[1] = 1; p.nonrelevant.push_back(samp); samp.clear(); - samples.push_back(p); - - - trainer.set_c(10); - - decision_function df = trainer.train(samples); - - matrix res; - res = 1,1; - - dlog << LINFO << "accuracy: "<< test_ranking_function(df, samples); - DLIB_TEST(equal(test_ranking_function(df, samples), res)); - - DLIB_TEST(equal(test_ranking_function(trainer.train(samples[1]), samples), res)); - - trainer.set_epsilon(1e-13); - df = trainer.train(samples); - - dlog << LINFO << sparse_to_dense(df.basis_vectors(0)); - sample_type truew; - truew[0] = -0.5; - truew[1] = -0.5; - truew[2] = 0.5; - truew[3] = 0.5; - DLIB_TEST(length(subtract(truew , df.basis_vectors(0))) < 1e-10); - - dlog << LINFO << "accuracy: "<< test_ranking_function(df, samples); - DLIB_TEST(equal(test_ranking_function(df, samples), res)); - - dlog << LINFO << "cv-accuracy: "<< cross_validate_ranking_trainer(trainer, samples,2); - DLIB_TEST(std::abs(cross_validate_ranking_trainer(trainer, samples,2)(0) - 0.7777777778) < 0.0001); - - trainer.set_learns_nonnegative_weights(true); - df = trainer.train(samples); - truew[0] = 0.0; - truew[1] = 0.0; - truew[2] = 1.0; - truew[3] = 1.0; - dlog << LINFO << sparse_to_dense(df.basis_vectors(0)); - DLIB_TEST(length(subtract(truew , df.basis_vectors(0))) < 1e-10); - dlog << LINFO << "accuracy: "<< test_ranking_function(df, samples); - DLIB_TEST(equal(test_ranking_function(df, samples), res)); - - - samples.clear(); - samples.push_back(p); - samples.push_back(p); - samples.push_back(p); - samples.push_back(p); - dlog << LINFO << "cv-accuracy: "<< cross_validate_ranking_trainer(trainer, samples,4); - DLIB_TEST(equal(cross_validate_ranking_trainer(trainer, samples,4) , res) ); - } - -// ---------------------------------------------------------------------------------------- - - template - class simple_rank_trainer - { - public: - template - decision_function train ( - const ranking_pair& pair - ) const - { - typedef matrix sample_type; - - std::vector relevant = pair.relevant; - std::vector nonrelevant = pair.nonrelevant; - - std::vector samples; - std::vector labels; - for (unsigned long i = 0; i < relevant.size(); ++i) - { - for (unsigned long j = 0; j < nonrelevant.size(); ++j) - { - samples.push_back(relevant[i] - nonrelevant[j]); - labels.push_back(+1); - samples.push_back(nonrelevant[i] - relevant[j]); - labels.push_back(-1); - } - } - - if (use_dcd_trainer) - { - svm_c_linear_dcd_trainer trainer; - trainer.set_c(1.0/samples.size()); - trainer.set_epsilon(1e-10); - trainer.force_last_weight_to_1(true); - //trainer.be_verbose(); - return trainer.train(samples, labels); - } - else - { - svm_c_linear_trainer trainer; - trainer.set_c(1.0); - trainer.set_epsilon(1e-13); - trainer.force_last_weight_to_1(true); - //trainer.be_verbose(); - decision_function df = trainer.train(samples, labels); - DLIB_TEST_MSG(df.b == 0, df.b); - return df; - } - } - }; - - template - void test_svmrank_weight_force_dense() - { - print_spinner(); - dlog << LINFO << "use_dcd_trainer: "<< use_dcd_trainer; - - typedef matrix sample_type; - typedef linear_kernel kernel_type; - - ranking_pair pair; - - for (int i = 0; i < 20; ++i) - { - pair.relevant.push_back(abs(gaussian_randm(10,1,i))); - } - - for (int i = 0; i < 20; ++i) - { - pair.nonrelevant.push_back(-abs(gaussian_randm(10,1,i+10000))); - pair.nonrelevant.back()(9) += 1; - } - - - svm_rank_trainer trainer; - trainer.force_last_weight_to_1(true); - trainer.set_epsilon(1e-13); - //trainer.be_verbose(); - decision_function df; - df = trainer.train(pair); - - matrix res; - res = 1,1; - dlog << LINFO << "weights: "<< trans(df.basis_vectors(0)); - const matrix acc1 = test_ranking_function(df, pair); - dlog << LINFO << "ranking accuracy: " << acc1; - DLIB_TEST(equal(acc1,res)); - - simple_rank_trainer strainer; - decision_function df2; - df2 = strainer.train(pair); - dlog << LINFO << "weights: "<< trans(df2.basis_vectors(0)); - const matrix acc2 = test_ranking_function(df2, pair); - dlog << LINFO << "ranking accuracy: " << acc2; - DLIB_TEST(equal(acc2,res)); - - dlog << LINFO << "w error: " << max(abs(df.basis_vectors(0) - df2.basis_vectors(0))); - dlog << LINFO << "b error: " << abs(df.b - df2.b); - DLIB_TEST(std::abs(max(abs(df.basis_vectors(0) - df2.basis_vectors(0)))) < 1e-8); - DLIB_TEST(std::abs(abs(df.b - df2.b)) < 1e-8); - } - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - class test_ranking_tools : public tester - { - public: - test_ranking_tools ( - ) : - tester ("test_ranking", - "Runs tests on the ranking tools.") - {} - - - void perform_test ( - ) - { - test_count_ranking_inversions(); - dotest1(); - dotest_sparse_vectors(); - test_svmrank_weight_force_dense(); - test_svmrank_weight_force_dense(); - run_prior_test(); - run_prior_sparse_test(); - - } - } a; - - -} - - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/read_write_mutex.cpp b/lib/3rdParty/dlib/include/dlib/test/read_write_mutex.cpp deleted file mode 100644 index aae579f5..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/read_write_mutex.cpp +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright (C) 2010 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.read_write_mutex"); - - class read_write_mutex_tester : public tester, multithreaded_object - { - public: - read_write_mutex_tester ( - ) : - tester ("test_read_write_mutex", - "Runs tests on the read_write_mutex component.") - { - register_thread(*this, &read_write_mutex_tester::thread_write); - register_thread(*this, &read_write_mutex_tester::thread_write); - register_thread(*this, &read_write_mutex_tester::thread_write); - - register_thread(*this, &read_write_mutex_tester::thread_readonly); - register_thread(*this, &read_write_mutex_tester::thread_readonly); - register_thread(*this, &read_write_mutex_tester::thread_readonly); - register_thread(*this, &read_write_mutex_tester::thread_readonly2); - register_thread(*this, &read_write_mutex_tester::thread_readonly2); - register_thread(*this, &read_write_mutex_tester::thread_readonly2); - - } - - read_write_mutex m; - - mutex mut; - int num_write; - int num_read; - int max_read; - - bool failure; - - void thread_write () - { - // do this so that the readonly threads can get into their loops first. This way - // we can see if the mutex lets many readers into their area - dlib::sleep(250); - for (int i = 0; i < 6; ++i) - { - auto_mutex lock(m); - - mut.lock(); - ++num_write; - mut.unlock(); - - // only one write thread should ever be active at once - if (num_write != 1) - { - failure = true; - dlog << LERROR << "1"; - } - - dlib::sleep(300); - - // only one write thread should ever be active at once - if (num_write != 1) - { - failure = true; - dlog << LERROR << "2"; - } - - mut.lock(); - --num_write; - mut.unlock(); - - print_spinner(); - } - dlog << LINFO << "exit thread_write()"; - } - - void do_readonly_stuff() - { - mut.lock(); - ++num_read; - max_read = max(num_read, max_read); - mut.unlock(); - - if (num_write != 0) - { - failure = true; - dlog << LERROR << "3"; - } - - dlib::sleep(300); - - if (num_write != 0) - { - failure = true; - dlog << LERROR << "4"; - } - - mut.lock(); - max_read = max(num_read, max_read); - --num_read; - mut.unlock(); - - print_spinner(); - } - - void thread_readonly () - { - for (int i = 0; i < 6; ++i) - { - auto_mutex_readonly lock(m); - DLIB_TEST(lock.has_read_lock()); - DLIB_TEST(!lock.has_write_lock()); - do_readonly_stuff(); - - lock.lock_readonly(); - DLIB_TEST(lock.has_read_lock()); - DLIB_TEST(!lock.has_write_lock()); - lock.unlock(); - DLIB_TEST(!lock.has_read_lock()); - DLIB_TEST(!lock.has_write_lock()); - lock.lock_readonly(); - DLIB_TEST(lock.has_read_lock()); - DLIB_TEST(!lock.has_write_lock()); - lock.lock_write(); - DLIB_TEST(!lock.has_read_lock()); - DLIB_TEST(lock.has_write_lock()); - lock.lock_write(); - DLIB_TEST(!lock.has_read_lock()); - DLIB_TEST(lock.has_write_lock()); - } - - dlog << LINFO << "exit thread_readonly()"; - } - - void thread_readonly2 () - { - for (int i = 0; i < 6; ++i) - { - m.lock_readonly(); - auto_unlock_readonly unlock(m); - - do_readonly_stuff(); - } - dlog << LINFO << "exit thread_readonly2()"; - } - - - void perform_test ( - ) - { - num_write = 0; - num_read = 0; - max_read = 0; - failure = false; - - // doing this big block of weird stuff should have no effect. - { - m.unlock(); - - m.lock_readonly(); - m.lock_readonly(); - m.unlock(); - m.unlock_readonly(); - m.unlock(); - m.unlock_readonly(); - - m.unlock(); - m.unlock_readonly(); - - m.lock(); - m.unlock_readonly(); - m.unlock_readonly(); - m.unlock(); - } - - - // start up our testing threads - start(); - - // wait for the threads to finish - wait(); - - - DLIB_TEST(failure == false); - DLIB_TEST_MSG(max_read == 6, "max_read: "<< max_read); - - } - - } a; - - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/reference_counter.cpp b/lib/3rdParty/dlib/include/dlib/test/reference_counter.cpp deleted file mode 100644 index 330ceed9..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/reference_counter.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include - -#include -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace std; - using namespace dlib; - - logger dlog("test.reference_counter"); - - template < - typename ref_counter - > - void reference_counter_test ( - ) - /*! - requires - - ref_counter is an implementation of reference_counter/reference_counter_kernel_abstract.h - and is instantiated to contain an int - ensures - - runs tests on reference_counter for compliance with the specs - !*/ - { - - ref_counter a, b, c; - - for (long i = 0; i < 10; ++i) - { - print_spinner(); - for (long j = 0; j < 10000; ++j) - { - a.modify() = j; - b.modify() = j+1; - c.modify() = j+2; - DLIB_ASSERT(a.access() == j,""); - DLIB_ASSERT(b.access() == j+1,""); - DLIB_ASSERT(c.access() == j+2,""); - DLIB_ASSERT(a.modify() == j,""); - DLIB_ASSERT(b.modify() == j+1,""); - DLIB_ASSERT(c.modify() == j+2,""); - DLIB_ASSERT(a.access() == j,""); - DLIB_ASSERT(b.access() == j+1,""); - DLIB_ASSERT(c.access() == j+2,""); - DLIB_ASSERT(a.modify() == j,""); - DLIB_ASSERT(b.modify() == j+1,""); - DLIB_ASSERT(c.modify() == j+2,""); - a = c; - DLIB_ASSERT(a.access() == j+2,""); - DLIB_ASSERT(b.access() == j+1,""); - DLIB_ASSERT(c.access() == j+2,""); - DLIB_ASSERT(a.modify() == j+2,""); - DLIB_ASSERT(b.modify() == j+1,""); - DLIB_ASSERT(c.modify() == j+2,""); - DLIB_ASSERT(a.access() == j+2,""); - DLIB_ASSERT(b.access() == j+1,""); - DLIB_ASSERT(c.access() == j+2,""); - DLIB_ASSERT(a.modify() == j+2,""); - DLIB_ASSERT(b.modify() == j+1,""); - DLIB_ASSERT(c.modify() == j+2,""); - - a = b = c; - DLIB_ASSERT(a.access() == b.access(),""); - DLIB_ASSERT(a.access() == c.access(),""); - DLIB_ASSERT(c.access() == b.access(),""); - a.modify() = j; - DLIB_ASSERT(a.access() == j,""); - DLIB_ASSERT(a.access() != b.access(),""); - DLIB_ASSERT(a.access() != c.access(),""); - DLIB_ASSERT(c.access() == b.access(),""); - DLIB_ASSERT(c.access() == j+2,""); - DLIB_ASSERT(b.access() == j+2,""); - - DLIB_ASSERT(a.access() == j,""); - a = a; - DLIB_ASSERT(a.access() == j,""); - c = c; - DLIB_ASSERT(c.access() == j+2,""); - DLIB_ASSERT(b.access() == j+2,""); - swap(a,c); - DLIB_ASSERT(a.access() == j+2,""); - DLIB_ASSERT(c.access() == j,""); - DLIB_ASSERT(b.access() == j+2,""); - } - } - - } - - - - - - class reference_counter_tester : public tester - { - public: - reference_counter_tester ( - ) : - tester ("test_reference_counter", - "Runs tests on the reference_counter component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a"; - reference_counter_test::kernel_1a> (); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/rls.cpp b/lib/3rdParty/dlib/include/dlib/test/rls.cpp deleted file mode 100644 index c4516ad7..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/rls.cpp +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (C) 2012 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.rls"); - - - void test_rls() - { - dlib::rand rnd; - - running_stats rs1, rs2, rs3, rs4, rs5; - - for (int k = 0; k < 2; ++k) - { - for (long num_vars = 1; num_vars < 4; ++num_vars) - { - print_spinner(); - for (long size = 1; size < 300; ++size) - { - { - matrix X = randm(size,num_vars,rnd); - matrix Y = randm(size,1,rnd); - - - const double C = 1000; - const double forget_factor = 1.0; - rls r(forget_factor, C); - for (long i = 0; i < Y.size(); ++i) - { - r.train(trans(rowm(X,i)), Y(i)); - } - - - matrix w = pinv(1.0/C*identity_matrix(X.nc()) + trans(X)*X)*trans(X)*Y; - - rs1.add(length(r.get_w() - w)); - } - - { - matrix X = randm(size,num_vars,rnd); - matrix Y = randm(size,1,rnd); - - matrix G(size,1); - - const double C = 10000; - const double forget_factor = 0.8; - rls r(forget_factor, C); - for (long i = 0; i < Y.size(); ++i) - { - r.train(trans(rowm(X,i)), Y(i)); - - G(i) = std::pow(forget_factor, i/2.0); - } - - G = flipud(G); - - X = diagm(G)*X; - Y = diagm(G)*Y; - - matrix w = pinv(1.0/C*identity_matrix(X.nc()) + trans(X)*X)*trans(X)*Y; - - rs5.add(length(r.get_w() - w)); - } - - { - matrix X = randm(size,num_vars,rnd); - matrix Y = colm(X,0)*10; - - - const double C = 1000000; - const double forget_factor = 1.0; - rls r(forget_factor, C); - for (long i = 0; i < Y.size(); ++i) - { - r.train(trans(rowm(X,i)), Y(i)); - } - - - matrix w = pinv(1.0/C*identity_matrix(X.nc()) + trans(X)*X)*trans(X)*Y; - - rs2.add(length(r.get_w() - w)); - } - - { - matrix X = join_rows(randm(size,num_vars,rnd)-0.5, ones_matrix(size,1)); - matrix Y = uniform_matrix(size,1,10); - - - const double C = 1e7; - const double forget_factor = 1.0; - - matrix w = pinv(1.0/C*identity_matrix(X.nc()) + trans(X)*X)*trans(X)*Y; - - rls r(forget_factor, C); - for (long i = 0; i < Y.size(); ++i) - { - r.train(trans(rowm(X,i)), Y(i)); - rs3.add(std::abs(r(trans(rowm(X,i))) - 10)); - } - - - } - { - matrix X = randm(size,num_vars,rnd)-0.5; - matrix Y = colm(X,0)*10; - - - const double C = 1e6; - const double forget_factor = 0.7; - - - rls r(forget_factor, C); - DLIB_TEST(std::abs(r.get_c() - C) < 1e-10); - DLIB_TEST(std::abs(r.get_forget_factor() - forget_factor) < 1e-15); - DLIB_TEST(r.get_w().size() == 0); - - for (long i = 0; i < Y.size(); ++i) - { - r.train(trans(rowm(X,i)), Y(i)); - rs4.add(std::abs(r(trans(rowm(X,i))) - X(i,0)*10)); - } - - DLIB_TEST(r.get_w().size() == num_vars); - - decision_function > > df = r.get_decision_function(); - DLIB_TEST(std::abs(df(trans(rowm(X,0))) - r(trans(rowm(X,0)))) < 1e-15); - } - } - } - } - - dlog << LINFO << "rs1.mean(): " << rs1.mean(); - dlog << LINFO << "rs2.mean(): " << rs2.mean(); - dlog << LINFO << "rs3.mean(): " << rs3.mean(); - dlog << LINFO << "rs4.mean(): " << rs4.mean(); - dlog << LINFO << "rs5.mean(): " << rs5.mean(); - dlog << LINFO << "rs1.max(): " << rs1.max(); - dlog << LINFO << "rs2.max(): " << rs2.max(); - dlog << LINFO << "rs3.max(): " << rs3.max(); - dlog << LINFO << "rs4.max(): " << rs4.max(); - dlog << LINFO << "rs5.max(): " << rs5.max(); - - DLIB_TEST_MSG(rs1.mean() < 1e-10, rs1.mean()); - DLIB_TEST_MSG(rs2.mean() < 1e-9, rs2.mean()); - DLIB_TEST_MSG(rs3.mean() < 1e-6, rs3.mean()); - DLIB_TEST_MSG(rs4.mean() < 1e-6, rs4.mean()); - DLIB_TEST_MSG(rs5.mean() < 1e-3, rs5.mean()); - - DLIB_TEST_MSG(rs1.max() < 1e-10, rs1.max()); - DLIB_TEST_MSG(rs2.max() < 1e-6, rs2.max()); - DLIB_TEST_MSG(rs3.max() < 0.001, rs3.max()); - DLIB_TEST_MSG(rs4.max() < 0.01, rs4.max()); - DLIB_TEST_MSG(rs5.max() < 0.1, rs5.max()); - - } - - - - - class rls_tester : public tester - { - public: - rls_tester ( - ) : - tester ("test_rls", - "Runs tests on the rls component.") - {} - - void perform_test ( - ) - { - test_rls(); - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/sammon.cpp b/lib/3rdParty/dlib/include/dlib/test/sammon.cpp deleted file mode 100644 index 5328bd1f..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/sammon.cpp +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (C) 2012 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.sammon"); - - - std::vector > make_test_data4( - ) - { - std::vector > data; - - matrix m; - - m = 0,0,0, 0; data.push_back(m); - m = 1,0,0, 0; data.push_back(m); - m = 0,1,0, 0; data.push_back(m); - m = 0,0,1, 0; data.push_back(m); - - return data; - } - - std::vector > make_test_data3( - ) - { - std::vector > data; - - matrix m; - - m = 0,0,0; data.push_back(m); - m = 1,0,0; data.push_back(m); - m = 0,1,0; data.push_back(m); - m = 0,0,1; data.push_back(m); - - return data; - } - - std::vector > make_test_data3d( - ) - { - std::vector > data; - - matrix m; - - m = 0,0,0; data.push_back(m); - m = 1,0,0; data.push_back(m); - m = 0,1,0; data.push_back(m); - m = 0,0,1; data.push_back(m); - - return data; - } - - - void runtest() - { - sammon_projection s; - std::vector > projs = s(make_test_data3(),2); - running_stats rs1, rs2; - - rs1.add(length(projs[0] - projs[1])); - rs1.add(length(projs[0] - projs[2])); - rs1.add(length(projs[0] - projs[3])); - - rs2.add(length(projs[1] - projs[2])); - rs2.add(length(projs[2] - projs[3])); - rs2.add(length(projs[3] - projs[1])); - - DLIB_TEST(rs1.stddev()/rs1.mean() < 1e-4); - DLIB_TEST(rs2.stddev()/rs2.mean() < 1e-4); - - - - projs = s(make_test_data4(),2); - rs1.clear(); - rs2.clear(); - - rs1.add(length(projs[0] - projs[1])); - rs1.add(length(projs[0] - projs[2])); - rs1.add(length(projs[0] - projs[3])); - - rs2.add(length(projs[1] - projs[2])); - rs2.add(length(projs[2] - projs[3])); - rs2.add(length(projs[3] - projs[1])); - - DLIB_TEST(rs1.stddev()/rs1.mean() < 1e-4); - DLIB_TEST(rs2.stddev()/rs2.mean() < 1e-4); - - projs = s(make_test_data3d(),2); - rs1.clear(); - rs2.clear(); - - rs1.add(length(projs[0] - projs[1])); - rs1.add(length(projs[0] - projs[2])); - rs1.add(length(projs[0] - projs[3])); - - rs2.add(length(projs[1] - projs[2])); - rs2.add(length(projs[2] - projs[3])); - rs2.add(length(projs[3] - projs[1])); - - DLIB_TEST(rs1.stddev()/rs1.mean() < 1e-4); - DLIB_TEST(rs2.stddev()/rs2.mean() < 1e-4); - } - - void runtest2() - { - sammon_projection s; - std::vector > projs, temp; - - DLIB_TEST(s(projs,3).size() == 0); - - matrix m; - m = 1,2; - projs.push_back(m); - temp = s(projs,2); - DLIB_TEST(temp.size() == 1); - DLIB_TEST(temp[0].size() == 2); - - projs.push_back(m); - temp = s(projs,1); - DLIB_TEST(temp.size() == 2); - DLIB_TEST(temp[0].size() == 1); - DLIB_TEST(temp[1].size() == 1); - } - - void runtest3(int num_dims) - { - sammon_projection s; - std::vector > projs; - matrix m; - m = 1, 1, 1; - projs.push_back(m); - - m = 1, 2, 1; - projs.push_back(m); - - m = 1, 3, 1; - projs.push_back(m); - - projs = s(projs,num_dims); - - const double d1a = length(projs[0] - projs[1]); - const double d1b = length(projs[1] - projs[2]); - const double d2 = length(projs[0] - projs[2]); - - DLIB_TEST(std::abs(d1a-d1b)/d1a < 1e-8); - DLIB_TEST(std::abs(d2/d1a-2) < 1e-8); - } - - void runtest4(int num_dims) - { - sammon_projection s; - std::vector > projs; - matrix m; - m = 1, 1, 1; - projs.push_back(m); - - m = 1, 2, 1; - projs.push_back(m); - - - projs = s(projs,num_dims); - - DLIB_TEST(length(projs[0] - projs[1]) > 1e-5); - } - - class sammon_tester : public tester - { - public: - sammon_tester ( - ) : - tester ("test_sammon", - "Runs tests on the sammon_projection component.") - {} - - void perform_test ( - ) - { - print_spinner(); - runtest(); - print_spinner(); - runtest2(); - print_spinner(); - runtest3(2); - print_spinner(); - runtest4(2); - runtest3(1); - print_spinner(); - runtest4(1); - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/scan_image.cpp b/lib/3rdParty/dlib/include/dlib/test/scan_image.cpp deleted file mode 100644 index c3a0115e..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/scan_image.cpp +++ /dev/null @@ -1,713 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include "dlib/image_processing.h" - -#include "dlib/test/tester.h" - -#include "dlib/image_transforms.h" -#include "dlib/pixel.h" -#include "dlib/array2d.h" -#include "dlib/array.h" - -// ---------------------------------------------------------------------------------------- - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - using dlib::array; - - // Declare the logger we will use in this test. The name of the tester - // should start with "test." - logger dlog("test.scan_image"); - -// ---------------------------------------------------------------------------------------- - - template - void sum_filter_i ( - const image_type1& img, - image_type2& out, - const rectangle& rect - ) - { - typedef typename image_type1::type pixel_type; - typedef typename promote::type ptype; - integral_image_generic iimg; - iimg.load(img); - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - const rectangle temp = translate_rect(rect, point(c,r)).intersect(get_rect(iimg)); - if (temp.is_empty() == false) - out[r][c] += iimg.get_sum_of_area(temp); - } - } - - } - -// ---------------------------------------------------------------------------------------- - - template < - typename image_array_type - > - void scan_image_i ( - std::vector >& dets, - const image_array_type& images, - const std::vector >& rects, - const double thresh, - const unsigned long max_dets - ) - { - typedef typename image_array_type::type::type pixel_type; - typedef typename promote::type ptype; - array > iimg; - iimg.set_max_size(images.size()); - iimg.set_size(images.size()); - - for (unsigned long i = 0; i < iimg.size(); ++i) - iimg[i].load(images[i]); - - - dets.clear(); - - - for (long r = 0; r < images[0].nr(); ++r) - { - for (long c = 0; c < images[0].nc(); ++c) - { - ptype temp = 0; - for (unsigned long i = 0; i < rects.size(); ++i) - { - rectangle rtemp = translate_rect(rects[i].second,point(c,r)).intersect(get_rect(images[0])); - if (rtemp.is_empty() == false) - temp += iimg[rects[i].first].get_sum_of_area(rtemp); - } - if (temp > thresh) - { - dets.push_back(std::make_pair(temp, point(c,r))); - - if (dets.size() >= max_dets) - return; - - } - } - } - } - -// ---------------------------------------------------------------------------------------- - - template < - typename image_array_type - > - void scan_image_old ( - std::vector >& dets, - const image_array_type& images, - const std::vector >& rects, - const double thresh, - const unsigned long max_dets - ) - { - dets.clear(); - if (max_dets == 0) - return; - - typedef typename image_array_type::type::type pixel_type; - typedef typename promote::type ptype; - - std::vector > column_sums(rects.size()); - for (unsigned long i = 0; i < column_sums.size(); ++i) - { - const typename image_array_type::type& img = images[rects[i].first]; - column_sums[i].resize(img.nc() + rects[i].second.width(),0); - - const long top = -1 + rects[i].second.top(); - const long bottom = -1 + rects[i].second.bottom(); - long left = rects[i].second.left()-1; - - // initialize column_sums[i] at row -1 - for (unsigned long j = 0; j < column_sums[i].size(); ++j) - { - rectangle strip(left,top,left,bottom); - strip = strip.intersect(get_rect(img)); - if (!strip.is_empty()) - { - column_sums[i][j] = sum(matrix_cast(subm(mat(img),strip))); - } - - ++left; - } - } - - - const rectangle area = get_rect(images[0]); - - for (long r = 0; r < images[0].nr(); ++r) - { - // set to sum at point(-1,r). i.e. should be equal to sum_of_rects_in_images(images, rects, point(-1,r)) - // We compute it's value in the next loop. - ptype cur_sum = 0; - - // Update the first part of column_sums since we only work on the c+width part of column_sums - // in the main loop. - for (unsigned long i = 0; i < rects.size(); ++i) - { - const typename image_array_type::type& img = images[rects[i].first]; - const long top = r + rects[i].second.top() - 1; - const long bottom = r + rects[i].second.bottom(); - const long width = rects[i].second.width(); - for (long k = 0; k < width; ++k) - { - const long right = k-width + rects[i].second.right(); - - const ptype br_corner = area.contains(right,bottom) ? img[bottom][right] : 0; - const ptype tr_corner = area.contains(right,top) ? img[top][right] : 0; - // update the sum in this column now that we are on the next row - column_sums[i][k] = column_sums[i][k] + br_corner - tr_corner; - cur_sum += column_sums[i][k]; - } - } - - for (long c = 0; c < images[0].nc(); ++c) - { - for (unsigned long i = 0; i < rects.size(); ++i) - { - const typename image_array_type::type& img = images[rects[i].first]; - const long top = r + rects[i].second.top() - 1; - const long bottom = r + rects[i].second.bottom(); - const long right = c + rects[i].second.right(); - const long width = rects[i].second.width(); - - const ptype br_corner = area.contains(right,bottom) ? img[bottom][right] : 0; - const ptype tr_corner = area.contains(right,top) ? img[top][right] : 0; - // update the sum in this column now that we are on the next row - column_sums[i][c+width] = column_sums[i][c+width] + br_corner - tr_corner; - - - // add in the new right side of the rect and subtract the old right side. - cur_sum = cur_sum + column_sums[i][c+width] - column_sums[i][c]; - - } - - if (cur_sum > thresh) - { - dets.push_back(std::make_pair(cur_sum, point(c,r))); - - if (dets.size() >= max_dets) - return; - } - } - } - } - -// ---------------------------------------------------------------------------------------- - - void run_test1() - { - dlog << LINFO << "run_test1()"; - - print_spinner(); - array2d img, temp_img; - img.set_size(600,600); - assign_all_pixels(img,0); - rectangle rect = centered_rect(10,10,5,5); - dlog << LTRACE << "expected: 10,10"; - fill_rect(img, rect, 255); - - - array > images; - std::vector > rects; - for (int i = 0; i < 10; ++i) - { - assign_image(temp_img, img); - images.push_back(temp_img); - rects.push_back(make_pair(i,centered_rect(0,0,5,5))); - } - - std::vector > dets, dets2, dets3; - - - dlog << LTRACE << "best score: "<< sum_of_rects_in_images(images,rects,point(10,10)); - scan_image(dets,images,rects,30000, 100); - scan_image_i(dets2,images,rects,30000, 100); - scan_image_old(dets3,images,rects,30000, 100); - - - - dlog << LTRACE << "dets.size(): "<< dets.size(); - dlog << LTRACE << "dets2.size(): "<< dets2.size(); - dlog << LTRACE << "dets3.size(): "<< dets3.size(); - - DLIB_TEST(dets.size() == dets2.size()); - DLIB_TEST(dets.size() == dets3.size()); - - for (unsigned long i = 0; i < dets.size(); ++i) - { - //dlog << LTRACE << "dets["< " << dets[i].first; - //dlog << LTRACE << "dets2["< " << dets2[i].first; - //dlog << LTRACE << "dets3["< " << dets3[i].first; - - DLIB_TEST(sum_of_rects_in_images(images, rects, dets[i].second) == dets[i].first); - DLIB_TEST(sum_of_rects_in_images(images, rects, dets2[i].second) == dets2[i].first); - DLIB_TEST(sum_of_rects_in_images(images, rects, dets3[i].second) == dets3[i].first); - } - - - } - -// ---------------------------------------------------------------------------------------- - - void run_test2() - { - print_spinner(); - dlog << LINFO << "run_test2()"; - array2d img, temp_img; - img.set_size(600,600); - assign_all_pixels(img,0); - rectangle rect = centered_rect(10,11,5,6); - dlog << LTRACE << "expected: 10,11"; - fill_rect(img, rect, 255); - - - array > images; - std::vector > rects; - for (int i = 0; i < 10; ++i) - { - assign_image(temp_img, img); - images.push_back(temp_img); - rects.push_back(make_pair(i,centered_rect(0,0,5,5))); - rects.push_back(make_pair(i,centered_rect(3,2,5,6))); - } - - std::vector > dets, dets2, dets3; - - - scan_image(dets,images,rects,30000, 100); - scan_image_i(dets2,images,rects,30000, 100); - scan_image_old(dets3,images,rects,30000, 100); - - - - dlog << LTRACE << "dets.size(): "<< dets.size(); - dlog << LTRACE << "dets2.size(): "<< dets2.size(); - dlog << LTRACE << "dets3.size(): "<< dets3.size(); - - DLIB_TEST(dets.size() == dets2.size()); - DLIB_TEST(dets.size() == dets3.size()); - - for (unsigned long i = 0; i < dets.size(); ++i) - { - //dlog << LTRACE << "dets["< " << dets[i].first; - //dlog << LTRACE << "dets2["< " << dets2[i].first; - //dlog << LTRACE << "dets3["< " << dets3[i].first; - - DLIB_TEST(sum_of_rects_in_images(images, rects, dets[i].second) == dets[i].first); - DLIB_TEST(sum_of_rects_in_images(images, rects, dets2[i].second) == dets2[i].first); - DLIB_TEST(sum_of_rects_in_images(images, rects, dets3[i].second) == dets3[i].first); - } - - - } - -// ---------------------------------------------------------------------------------------- - - template - void run_test3(const double thresh) - { - dlog << LINFO << "running run_test3("< > images; - images.resize(1); - images[0].set_size(200,180); - - for (int iter = 0; iter < 50; ++iter) - { - print_spinner(); - assign_all_pixels(images[0], thresh - 0.0001); - - for (int i = 0; i < 20; ++i) - { - point p1(rnd.get_random_32bit_number()%images[0].nc(), - rnd.get_random_32bit_number()%images[0].nr()); - point p2(rnd.get_random_32bit_number()%images[0].nc(), - rnd.get_random_32bit_number()%images[0].nr()); - - rectangle rect(p1,p2); - fill_rect(images[0], rect, static_cast(rnd.get_random_double()*10 - 5)); - } - - std::vector > rects; - rects.push_back(make_pair(0,centered_rect(0,0,1+rnd.get_random_32bit_number()%40,1+rnd.get_random_32bit_number()%40))); - rects.push_back(make_pair(0,centered_rect(0,0,1+rnd.get_random_32bit_number()%40,1+rnd.get_random_32bit_number()%40))); - - - - - std::vector > dets, dets2, dets3; - scan_image(dets,images,rects,thresh, 100); - scan_image_i(dets2,images,rects,thresh, 100); - scan_image_old(dets3,images,rects,thresh, 100); - - dlog << LTRACE << "dets.size(): "<< dets.size(); - dlog << LTRACE << "dets2.size(): "<< dets2.size(); - dlog << LTRACE << "dets3.size(): "<< dets3.size(); - - DLIB_TEST(dets.size() == dets2.size()); - DLIB_TEST(dets.size() == dets3.size()); - - for (unsigned long i = 0; i < dets.size(); ++i) - { - //dlog << LTRACE << "dets["< " << dets[i].first; - //dlog << LTRACE << "dets2["< " << dets2[i].first; - //dlog << LTRACE << "dets3["< " << dets3[i].first; - - DLIB_TEST_MSG(std::abs(sum_of_rects_in_images(images, rects, dets[i].second) - dets[i].first) < 1e-6, - "error: "<< sum_of_rects_in_images(images, rects, dets[i].second) - dets[i].first - << " dets["< - void test_sum_filter ( - ) - { - dlib::rand rnd; - - for (int k = 0; k < 20; ++k) - { - print_spinner(); - - array2d img(1 + rnd.get_random_32bit_number()%100, - 1 + rnd.get_random_32bit_number()%100); - - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - img[r][c] = static_cast(100*(rnd.get_random_double()-0.5)); - } - } - - array2d test1(img.nr(), img.nc()); - array2d test2(img.nr(), img.nc()); - array2d test1_i(img.nr(), img.nc()); - array2d test2_i(img.nr(), img.nc()); - - assign_all_pixels(test1, 0); - assign_all_pixels(test2, 0); - assign_all_pixels(test1_i, 0); - assign_all_pixels(test2_i, 0); - - for (int i = 0; i < 10; ++i) - { - const long width = rnd.get_random_32bit_number()%10 + 1; - const long height = rnd.get_random_32bit_number()%10 + 1; - const point p(rnd.get_random_32bit_number()%img.nc(), - rnd.get_random_32bit_number()%img.nr()); - - const rectangle rect = centered_rect(p, width, height); - sum_filter(img, test1, rect); - sum_filter(img, test2, rect); - sum_filter(img, test1_i, rect); - sum_filter(img, test2_i, rect); - - DLIB_TEST(mat(test1) == mat(test1_i)); - DLIB_TEST(mat(test2) == mat(test2_i)); - } - } - } - -// ---------------------------------------------------------------------------------------- - - template < - typename image_type1, - typename image_type2 - > - void naive_max_filter ( - const image_type1& img, - image_type2& out, - const long width, - const long height, - typename image_type1::type thresh - ) - { - const rectangle area = get_rect(img); - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - const rectangle win = centered_rect(point(c,r),width,height).intersect(area); - out[r][c] += std::max(dlib::max(subm(mat(img),win)), thresh); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void test_max_filter(long rows, long cols, long width, long height, dlib::rand& rnd) - { - array2d img(rows, cols); - rectangle rect = centered_rect(0,0, width, height); - - array2d out(img.nr(),img.nc()); - assign_all_pixels(out, 0); - array2d out2(img.nr(),img.nc()); - assign_all_pixels(out2, 0); - - for (long r = 0; r < img.nr(); ++r) - { - for (long c = 0; c < img.nc(); ++c) - { - img[r][c] = rnd.get_random_32bit_number(); - } - } - - const int thresh = rnd.get_random_32bit_number(); - - naive_max_filter(img, out2, rect.width(), rect.height(), thresh); - max_filter(img, out, rect.width(), rect.height(), thresh); - - DLIB_TEST_MSG(mat(out) == mat(out2), - "rows: "<< rows - << "\ncols: "<< rows - << "\nwidth: "<< width - << "\nheight: "<< height ); - } - -// ---------------------------------------------------------------------------------------- - - void test_max_filter() - { - dlib::rand rnd; - for (int iter = 0; iter < 300; ++iter) - { - print_spinner(); - test_max_filter(0,0,1,1,rnd); - test_max_filter(0,0,3,1,rnd); - test_max_filter(0,0,3,3,rnd); - test_max_filter(0,0,1,3,rnd); - test_max_filter(1,1,1,1,rnd); - test_max_filter(2,2,1,1,rnd); - test_max_filter(3,3,1,1,rnd); - test_max_filter(3,3,3,3,rnd); - test_max_filter(3,3,2,2,rnd); - test_max_filter(3,3,3,5,rnd); - test_max_filter(3,3,6,8,rnd); - test_max_filter(20,20,901,901,rnd); - test_max_filter(5,5,1,5,rnd); - test_max_filter(50,50,9,9,rnd); - test_max_filter(50,50,9,9,rnd); - test_max_filter(50,50,10,10,rnd); - test_max_filter(50,50,11,10,rnd); - test_max_filter(50,50,10,11,rnd); - test_max_filter(50,50,10,21,rnd); - test_max_filter(50,50,20,10,rnd); - test_max_filter(50,50,20,10,rnd); - test_max_filter(50,50,9,9,rnd); - test_max_filter(20,20,1,901,rnd); - test_max_filter(20,20,3,901,rnd); - test_max_filter(20,20,901,1,rnd); - } - - for (int iter = 0; iter < 200; ++iter) - { - print_spinner(); - test_max_filter((int)rnd.get_random_8bit_number()%100+1, - (int)rnd.get_random_8bit_number()%100+1, - (int)rnd.get_random_8bit_number()%150+1, - (int)rnd.get_random_8bit_number()%150+1, - rnd); - } - } - -// ---------------------------------------------------------------------------------------- - - void make_images ( - dlib::rand& rnd, - array >& images, - long num, - long nr, - long nc - ) - { - images.resize(num); - for (unsigned long i = 0; i < images.size(); ++i) - { - images[i].set_size(nr,nc); - } - - for (unsigned long i = 0; i < images.size(); ++i) - { - for (long r = 0; r < nr; ++r) - { - for (long c = 0; c < nc; ++c) - { - images[i][r][c] = rnd.get_random_8bit_number(); - } - } - } - } - - - template < - typename image_array_type - > - void brute_force_scan_image_movable_parts ( - std::vector >& dets, - const image_array_type& images, - const rectangle& window, - const std::vector >& fixed_rects, - const std::vector >& movable_rects, - const double thresh, - const unsigned long - ) - { - dets.clear(); - if (movable_rects.size() == 0 && fixed_rects.size() == 0) - return; - - for (long r = 0; r < images[0].nr(); ++r) - { - for (long c = 0; c < images[0].nc(); ++c) - { - const point p(c,r); - double score = sum_of_rects_in_images_movable_parts(images, - window, - fixed_rects, - movable_rects, - p); - - if (score >= thresh) - { - dets.push_back(make_pair(score,p)); - } - } - } - } - - void test_scan_images_movable_parts() - { - array > images; - dlib::rand rnd; - for (int iter = 0; iter < 40; ++iter) - { - print_spinner(); - const int num_images = rnd.get_random_32bit_number()%4+1; - - make_images(rnd,images, num_images, - rnd.get_random_32bit_number()%50+1, - rnd.get_random_32bit_number()%50+1 - ); - - std::vector > dets1, dets2; - std::vector > fixed_rects, movable_rects; - - double total_area = 0; - for (unsigned long i = 0; i < images.size(); ++i) - { - fixed_rects.push_back(make_pair(i, centered_rect( - rnd.get_random_32bit_number()%10-5, - rnd.get_random_32bit_number()%10-5, - rnd.get_random_32bit_number()%10, - rnd.get_random_32bit_number()%10 - ))); - - total_area += fixed_rects.back().second.area(); - - movable_rects.push_back(make_pair(i, centered_rect( - 0, - 0, - rnd.get_random_32bit_number()%10+1, - rnd.get_random_32bit_number()%10+1 - ))); - total_area += movable_rects.back().second.area(); - } - - const rectangle window = centered_rect(0,0, - rnd.get_random_32bit_number()%15+1, - rnd.get_random_32bit_number()%15+1); - dlog << LINFO << "window size: "<< window.width() << ", " << window.height(); - const double thresh = total_area*130; - const unsigned long max_dets = get_rect(images[0]).area(); - - scan_image_movable_parts(dets1,images,window,fixed_rects,movable_rects,thresh, max_dets); - brute_force_scan_image_movable_parts(dets2,images,window,fixed_rects,movable_rects,thresh, max_dets); - - dlog << LINFO << "max_possible dets: " << max_dets; - dlog << LINFO << "regular dets: " << dets1.size(); - dlog << LINFO << "brute force: " << dets2.size(); - DLIB_TEST(dets1.size() == dets2.size()); - - array2d check(images[0].nr(), images[0].nc()); - assign_all_pixels(check, 1e-300); - for (unsigned long i = 0; i < dets1.size(); ++i) - { - const point p = dets1[i].second; - check[p.y()][p.x()] = dets1[i].first; - } - for (unsigned long i = 0; i < dets2.size(); ++i) - { - const point p = dets2[i].second; - DLIB_TEST(std::abs(check[p.y()][p.x()] - dets2[i].first) < 1e-10); - } - dlog << LINFO << "=======================\n"; - } - } - -// ---------------------------------------------------------------------------------------- - - class scan_image_tester : public tester - { - public: - scan_image_tester ( - ) : - tester ("test_scan_image", - "Runs tests on the scan_image routine.") - {} - - void perform_test ( - ) - { - test_scan_images_movable_parts(); - test_max_filter(); - - run_test1(); - run_test2(); - run_test3(1); - run_test3(-1); - run_test3(1); - run_test3(-1); - - test_sum_filter(); - test_sum_filter(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/sequence.cpp b/lib/3rdParty/dlib/include/dlib/test/sequence.cpp deleted file mode 100644 index ffa6efdb..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/sequence.cpp +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright (C) 2004 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include - -#include -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace std; - using namespace dlib; - - logger dlog("test.sequence"); - - template < - typename seq - > - void sequence_sort_test ( - ) - /*! - requires - - seq is an implementation of sequence/sequence_sort_aseqract.h is instantiated - with int - ensures - - runs tests on seq for compliance with the specs - !*/ - { - - - srand(static_cast(time(0))); - - - print_spinner(); - - - - - - { - // this test is to make sure that jumping around via - // operator[] doesn't corrupt the object - - seq a; - - for (int i = 0; i < 100; ++i) - { - int x = i; - a.add(a.size(),x); - } - - - int x = 0; - - for (int i = 0; i < (int)a.size(); ++i) - { - DLIB_TEST_MSG(a[i] >= i,"1"); - // cout << a[i] << endl; - } - - for (unsigned long i = 0; i < a.size(); ++i) - { - for (unsigned long j = i+1; j < a.size(); ++j) - { - if ((a[j]+a[i])%3 ==0) - { - a.remove(j,x); - --j; - } - } - } - - //cout << endl; - - for (int i = 0; i < (int)a.size(); ++i) - { - // cout << a[i] << endl; - DLIB_TEST_MSG(a[i] >= i,"2"); - } - - } - - - - - - - - seq test, test2; - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - - enumerable& e = test; - - DLIB_TEST(e.at_start() == true); - DLIB_TEST(e.current_element_valid() == false); - - - for (int g = 0; g < 5; ++g) - { - test.clear(); - test2.clear(); - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(e.at_start() == true); - DLIB_TEST(e.current_element_valid() == false); - - DLIB_TEST(e.move_next() == false); - DLIB_TEST(e.current_element_valid() == false); - DLIB_TEST(e.at_start() == false); - DLIB_TEST(test.at_start() == false); - swap(test,test2); - DLIB_TEST(test.at_start() == true); - test.clear(); - test2.clear(); - - int a; - - - for (int i = 0; i < 100; ++i) - { - a = i; - test.add(i,a); - } - - DLIB_TEST(test.size() == 100); - - for (int i = 0; i < static_cast(test.size()); ++i) - { - DLIB_TEST(test[i] == i); - } - - swap(test,test2); - - a = 0; - DLIB_TEST(test2.at_start() == true); - while(test2.move_next()) - { - DLIB_TEST(test2.at_start() == false); - DLIB_TEST(test2.current_element_valid() == true); - DLIB_TEST(test2.element() == a); - ++a; - } - - DLIB_TEST(test2.at_start() == false); - DLIB_TEST(test2.current_element_valid() == false); - - test2.reset(); - - DLIB_TEST(test2.at_start() == true); - DLIB_TEST(test2.current_element_valid() == false); - - a = 0; - while(test2.move_next()) - { - DLIB_TEST(test2.at_start() == false); - DLIB_TEST(test2.current_element_valid() == true); - DLIB_TEST(test2.element() == a); - ++a; - } - - - - - - for (int i = 0; i < 1000; ++i) - { - a = ::rand(); - test.add(0,a); - } - DLIB_TEST(test.size() == 1000); - - test.sort(); - - - for (unsigned long i = 0; i < test.size()-1; ++i) - { - DLIB_TEST(test[i] <= test[i+1]); - } - - a = 0; - while(test.move_next()) - { - DLIB_TEST(a <= test.element()); - a = test.element(); - } - - - test.clear(); - test2.clear(); - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test2.size() == 0); - - for (int i = 0; i < 100; ++i) - { - a = i; - test.add(i,a); - } - - for (int i = 100; i < 200; ++i) - { - a = i; - test.add(i,a); - } - - test.cat(test2); - DLIB_TEST(test.size() == 200); - DLIB_TEST(test2.size() == 0); - - - // serialize the state of test, then clear test, then - // load the state back into test. - ostringstream sout; - serialize(test,sout); - DLIB_TEST(test.at_start() == true); - istringstream sin(sout.str()); - test.clear(); - deserialize(test,sin); - - - for (int i = 0; i < 200; ++i) - { - DLIB_TEST(test[i] == i); - } - - a = 0; - while (test.move_next()) - { - DLIB_TEST(test.element() == a); - DLIB_TEST(test[0]==0); - ++a; - } - - DLIB_TEST(a == 200); - - DLIB_TEST(test[9] == 9); - test.remove(9,a); - DLIB_TEST(a == 9); - DLIB_TEST(test[9] == 10); - DLIB_TEST(test.size() == 199); - - test.remove(0,a); - DLIB_TEST(test[0] == 1); - DLIB_TEST(test.size() == 198); - DLIB_TEST(a == 0); - DLIB_TEST(test[9] == 11); - DLIB_TEST(test[20] == 22); - - - - - } - - { - test.clear(); - for (int i = 0; i < 100; ++i) - { - int a = 3; - test.add(0,a); - } - DLIB_TEST(test.size() == 100); - remover& go = test; - for (int i = 0; i < 100; ++i) - { - int a = 9; - go.remove_any(a); - DLIB_TEST(a == 3); - } - DLIB_TEST(go.size() == 0); - } - - - } - - - - - class sequence_tester : public tester - { - public: - sequence_tester ( - ) : - tester ("test_sequence", - "Runs tests on the sequence component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing sort_1a"; - sequence_sort_test::sort_1a> (); - dlog << LINFO << "testing sort_1a_c"; - sequence_sort_test::sort_1a_c>(); - dlog << LINFO << "testing sort_2a"; - sequence_sort_test::sort_2a> (); - dlog << LINFO << "testing sort_2a_c"; - sequence_sort_test::sort_2a_c>(); - } - } a; - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/sequence_labeler.cpp b/lib/3rdParty/dlib/include/dlib/test/sequence_labeler.cpp deleted file mode 100644 index 4002d682..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/sequence_labeler.cpp +++ /dev/null @@ -1,461 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include "tester.h" -#include -#include - - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.sequence_labeler"); - -// ---------------------------------------------------------------------------------------- - - const unsigned long num_label_states = 3; // the "hidden" states - const unsigned long num_sample_states = 3; - -// ---------------------------------------------------------------------------------------- - - struct funny_sequence - { - std::vector item; - unsigned long size() const { return item.size(); } - }; - funny_sequence make_funny_sequence(const std::vector& item) - { - funny_sequence temp; - temp.item = item; - return temp; - } - -// ---------------------------------------------------------------------------------------- - - class feature_extractor - { - public: - typedef funny_sequence sequence_type; - - unsigned long num_features() const - { - return num_label_states*num_label_states + num_label_states*num_sample_states; - } - - unsigned long order() const - { - return 1; - } - - unsigned long num_labels() const - { - return num_label_states; - } - - template - void get_features ( - feature_setter& set_feature, - const sequence_type& x, - const matrix_exp& y, - unsigned long position - ) const - { - if (y.size() > 1) - set_feature(y(1)*num_label_states + y(0)); - - set_feature(num_label_states*num_label_states + - y(0)*num_sample_states + x.item[position]); - } - }; - - class feature_extractor_partial - { - public: - typedef funny_sequence sequence_type; - - unsigned long num_features() const - { - return num_label_states*num_label_states + num_label_states*num_sample_states; - } - - unsigned long order() const - { - return 1; - } - - unsigned long num_labels() const - { - return num_label_states; - } - - template - void get_features ( - feature_setter& set_feature, - const sequence_type& x, - const matrix_exp& y, - unsigned long position - ) const - { - if (y.size() > 1) - { - set_feature(y(1)*num_label_states + y(0), 0.5); - set_feature(y(1)*num_label_states + y(0), 0.5); - } - - set_feature(num_label_states*num_label_states + - y(0)*num_sample_states + x.item[position],0.25); - set_feature(num_label_states*num_label_states + - y(0)*num_sample_states + x.item[position],0.75); - } - }; - - bool called_rejct_labeling = false; - class feature_extractor2 - { - public: - typedef funny_sequence sequence_type; - - unsigned long num_features() const - { - return num_label_states*num_label_states + num_label_states*num_sample_states; - } - - unsigned long order() const - { - return 1; - } - - unsigned long num_labels() const - { - return num_label_states; - } - - template - bool reject_labeling ( - const sequence_type& , - const matrix_exp& , - unsigned long - ) const - { - called_rejct_labeling = true; - return false; - } - - template - void get_features ( - feature_setter& set_feature, - const sequence_type& x, - const matrix_exp& y, - unsigned long position - ) const - { - if (y.size() > 1) - set_feature(y(1)*num_label_states + y(0)); - - set_feature(num_label_states*num_label_states + - y(0)*num_sample_states + x.item[position]); - } - }; - - void serialize(const feature_extractor&, std::ostream&) {} - void deserialize(feature_extractor&, std::istream&) {} - void serialize(const feature_extractor2&, std::ostream&) {} - void deserialize(feature_extractor2&, std::istream&) {} - -// ---------------------------------------------------------------------------------------- - - void sample_hmm ( - dlib::rand& rnd, - const matrix& transition_probabilities, - const matrix& emission_probabilities, - unsigned long previous_label, - unsigned long& next_label, - unsigned long& next_sample - ) - /*! - requires - - previous_label < transition_probabilities.nr() - - transition_probabilities.nr() == transition_probabilities.nc() - - transition_probabilities.nr() == emission_probabilities.nr() - - The rows of transition_probabilities and emission_probabilities must sum to 1. - (i.e. sum_cols(transition_probabilities) and sum_cols(emission_probabilities) - must evaluate to vectors of all 1s.) - ensures - - This function randomly samples the HMM defined by transition_probabilities - and emission_probabilities assuming that the previous hidden state - was previous_label. - - The HMM is defined by: - - P(next_label |previous_label) == transition_probabilities(previous_label, next_label) - - P(next_sample|next_label) == emission_probabilities (next_label, next_sample) - - #next_label == the sampled value of the hidden state - - #next_sample == the sampled value of the observed state - !*/ - { - // sample next_label - double p = rnd.get_random_double(); - for (long c = 0; p >= 0 && c < transition_probabilities.nc(); ++c) - { - next_label = c; - p -= transition_probabilities(previous_label, c); - } - - // now sample next_sample - p = rnd.get_random_double(); - for (long c = 0; p >= 0 && c < emission_probabilities.nc(); ++c) - { - next_sample = c; - p -= emission_probabilities(next_label, c); - } - } - -// ---------------------------------------------------------------------------------------- - - void make_dataset ( - const matrix& transition_probabilities, - const matrix& emission_probabilities, - std::vector& samples, - std::vector >& labels, - unsigned long dataset_size - ) - /*! - requires - - transition_probabilities.nr() == transition_probabilities.nc() - - transition_probabilities.nr() == emission_probabilities.nr() - - The rows of transition_probabilities and emission_probabilities must sum to 1. - (i.e. sum_cols(transition_probabilities) and sum_cols(emission_probabilities) - must evaluate to vectors of all 1s.) - ensures - - This function randomly samples a bunch of sequences from the HMM defined by - transition_probabilities and emission_probabilities. - - The HMM is defined by: - - The probability of transitioning from hidden state H1 to H2 - is given by transition_probabilities(H1,H2). - - The probability of a hidden state H producing an observed state - O is given by emission_probabilities(H,O). - - #samples.size() == labels.size() == dataset_size - - for all valid i: - - #labels[i] is a randomly sampled sequence of hidden states from the - given HMM. #samples[i] is its corresponding randomly sampled sequence - of observed states. - !*/ - { - samples.clear(); - labels.clear(); - - dlib::rand rnd; - - // now randomly sample some labeled sequences from our Hidden Markov Model - for (unsigned long iter = 0; iter < dataset_size; ++iter) - { - const unsigned long sequence_size = rnd.get_random_32bit_number()%20+3; - std::vector sample(sequence_size); - std::vector label(sequence_size); - - unsigned long previous_label = rnd.get_random_32bit_number()%num_label_states; - for (unsigned long i = 0; i < sample.size(); ++i) - { - unsigned long next_label=0, next_sample=0; - sample_hmm(rnd, transition_probabilities, emission_probabilities, - previous_label, next_label, next_sample); - - label[i] = next_label; - sample[i] = next_sample; - - previous_label = next_label; - } - - samples.push_back(make_funny_sequence(sample)); - labels.push_back(label); - } - } - -// ---------------------------------------------------------------------------------------- - - template - void do_test() - { - called_rejct_labeling = false; - - matrix transition_probabilities(num_label_states, num_label_states); - transition_probabilities = 0.05, 0.90, 0.05, - 0.05, 0.05, 0.90, - 0.90, 0.05, 0.05; - - matrix emission_probabilities(num_label_states,num_sample_states); - emission_probabilities = 0.5, 0.5, 0.0, - 0.0, 0.5, 0.5, - 0.5, 0.0, 0.5; - - print_spinner(); - - - std::vector samples; - std::vector > labels; - make_dataset(transition_probabilities,emission_probabilities, - samples, labels, 1000); - - dlog << LINFO << "samples.size(): "<< samples.size(); - - // print out some of the randomly sampled sequences - for (int i = 0; i < 10; ++i) - { - dlog << LINFO << "hidden states: " << trans(mat(labels[i])); - dlog << LINFO << "observed states: " << trans(mat(samples[i].item)); - dlog << LINFO << "******************************"; - } - - print_spinner(); - structural_sequence_labeling_trainer trainer; - trainer.set_c(4); - DLIB_TEST(trainer.get_c() == 4); - trainer.set_num_threads(4); - DLIB_TEST(trainer.get_num_threads() == 4); - - - - // Learn to do sequence labeling from the dataset - sequence_labeler labeler = trainer.train(samples, labels); - - std::vector predicted_labels = labeler(samples[0]); - dlog << LINFO << "true hidden states: "<< trans(mat(labels[0])); - dlog << LINFO << "predicted hidden states: "<< trans(mat(predicted_labels)); - - DLIB_TEST(mat(labels[0]) == mat(predicted_labels)); - - - print_spinner(); - - - // We can also do cross-validation - matrix confusion_matrix; - confusion_matrix = cross_validate_sequence_labeler(trainer, samples, labels, 4); - dlog << LINFO << "cross-validation: "; - dlog << LINFO << confusion_matrix; - double accuracy = sum(diag(confusion_matrix))/sum(confusion_matrix); - dlog << LINFO << "label accuracy: "<< accuracy; - DLIB_TEST(std::abs(accuracy - 0.882) < 0.01); - - print_spinner(); - - - matrix true_hmm_model_weights = log(join_cols(reshape_to_column_vector(transition_probabilities), - reshape_to_column_vector(emission_probabilities))); - - sequence_labeler labeler_true(true_hmm_model_weights); - - confusion_matrix = test_sequence_labeler(labeler_true, samples, labels); - dlog << LINFO << "True HMM model: "; - dlog << LINFO << confusion_matrix; - accuracy = sum(diag(confusion_matrix))/sum(confusion_matrix); - dlog << LINFO << "label accuracy: "<< accuracy; - DLIB_TEST(std::abs(accuracy - 0.882) < 0.01); - - - - print_spinner(); - - - - - // Finally, the labeler can be serialized to disk just like most dlib objects. - ostringstream sout; - serialize(labeler, sout); - - sequence_labeler labeler2; - // recall from disk - istringstream sin(sout.str()); - deserialize(labeler2, sin); - confusion_matrix = test_sequence_labeler(labeler2, samples, labels); - dlog << LINFO << "deserialized labeler: "; - dlog << LINFO << confusion_matrix; - accuracy = sum(diag(confusion_matrix))/sum(confusion_matrix); - dlog << LINFO << "label accuracy: "<< accuracy; - DLIB_TEST(std::abs(accuracy - 0.882) < 0.01); - } - -// ---------------------------------------------------------------------------------------- - - void test2() - { - /* - The point of this test is to make sure calling set_feature() multiple - times works the way it is supposed to. - */ - - print_spinner(); - std::vector samples; - std::vector > labels; - - matrix transition_probabilities(num_label_states, num_label_states); - transition_probabilities = 0.05, 0.90, 0.05, - 0.05, 0.05, 0.90, - 0.90, 0.05, 0.05; - - matrix emission_probabilities(num_label_states,num_sample_states); - emission_probabilities = 0.5, 0.5, 0.0, - 0.0, 0.5, 0.5, - 0.5, 0.0, 0.5; - - - make_dataset(transition_probabilities,emission_probabilities, - samples, labels, 1000); - - dlog << LINFO << "samples.size(): "<< samples.size(); - - structural_sequence_labeling_trainer trainer; - structural_sequence_labeling_trainer trainer_part; - trainer.set_c(4); - trainer_part.set_c(4); - trainer.set_num_threads(4); - trainer_part.set_num_threads(4); - trainer.set_epsilon(1e-8); - trainer_part.set_epsilon(1e-8); - - - - // Learn to do sequence labeling from the dataset - sequence_labeler labeler = trainer.train(samples, labels); - sequence_labeler labeler_part = trainer_part.train(samples, labels); - - dlog << LINFO << "weight disagreement: "<< max(abs(labeler.get_weights() - labeler_part.get_weights())); - dlog << LINFO << "max weight magnitude: "<< max(abs(labeler.get_weights())); - - // Both feature extractors should be equivalent. - DLIB_TEST(max(abs(labeler.get_weights() - labeler_part.get_weights())) < 1e-6); - - } - -// ---------------------------------------------------------------------------------------- - - class sequence_labeler_tester : public tester - { - public: - sequence_labeler_tester ( - ) : - tester ("test_sequence_labeler", - "Runs tests on the sequence labeling code.") - {} - - void perform_test ( - ) - { - do_test(); - DLIB_TEST(called_rejct_labeling == false); - do_test(); - DLIB_TEST(called_rejct_labeling == true); - - test2(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/sequence_segmenter.cpp b/lib/3rdParty/dlib/include/dlib/test/sequence_segmenter.cpp deleted file mode 100644 index acdcd69b..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/sequence_segmenter.cpp +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright (C) 2013 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include "tester.h" -#include -#include - - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.sequence_segmenter"); - -// ---------------------------------------------------------------------------------------- - - dlib::rand rnd; - - template - class unigram_extractor - { - public: - - const static bool use_BIO_model = use_BIO_model_; - const static bool use_high_order_features = use_high_order_features_; - const static bool allow_negative_weights = allow_negative_weights_; - - typedef std::vector sequence_type; - - std::map > feats; - - unigram_extractor() - { - matrix v1, v2, v3; - v1 = randm(num_features(), 1, rnd); - v2 = randm(num_features(), 1, rnd); - v3 = randm(num_features(), 1, rnd); - v1(0) = 1; - v2(1) = 1; - v3(2) = 1; - v1(3) = -1; - v2(4) = -1; - v3(5) = -1; - for (unsigned long i = 0; i < num_features(); ++i) - { - if ( i < 3) - feats[i] = v1; - else if (i < 6) - feats[i] = v2; - else - feats[i] = v3; - } - } - - unsigned long num_features() const { return 10; } - unsigned long window_size() const { return 3; } - - template - void get_features ( - feature_setter& set_feature, - const sequence_type& x, - unsigned long position - ) const - { - const matrix& m = feats.find(x[position])->second; - for (unsigned long i = 0; i < num_features(); ++i) - { - set_feature(i, m(i)); - } - } - - }; - - template - void serialize(const unigram_extractor& item , std::ostream& out ) - { - serialize(item.feats, out); - } - - template - void deserialize(unigram_extractor& item, std::istream& in) - { - deserialize(item.feats, in); - } - -// ---------------------------------------------------------------------------------------- - - void make_dataset ( - std::vector >& samples, - std::vector >& labels, - unsigned long dataset_size - ) - { - samples.clear(); - labels.clear(); - - samples.resize(dataset_size); - labels.resize(dataset_size); - - - unigram_extractor fe; - dlib::rand rnd; - - for (unsigned long iter = 0; iter < dataset_size; ++iter) - { - - samples[iter].resize(10); - labels[iter].resize(10); - - for (unsigned long i = 0; i < samples[iter].size(); ++i) - { - samples[iter][i] = rnd.get_random_32bit_number()%fe.num_features(); - if (samples[iter][i] < 3) - { - labels[iter][i] = impl_ss::BEGIN; - } - else if (samples[iter][i] < 6) - { - labels[iter][i] = impl_ss::INSIDE; - } - else - { - labels[iter][i] = impl_ss::OUTSIDE; - } - - if (i != 0) - { - // do rejection sampling to avoid impossible labels - if (labels[iter][i] == impl_ss::INSIDE && - labels[iter][i-1] == impl_ss::OUTSIDE) - { - --i; - } - } - } - } - } - -// ---------------------------------------------------------------------------------------- - - void make_dataset2 ( - std::vector >& samples, - std::vector > >& segments, - unsigned long dataset_size - ) - { - segments.clear(); - std::vector > labels; - make_dataset(samples, labels, dataset_size); - segments.resize(samples.size()); - - // Convert from BIO tagging to the explicit segments representation. - for (unsigned long k = 0; k < labels.size(); ++k) - { - for (unsigned long i = 0; i < labels[k].size(); ++i) - { - if (labels[k][i] == impl_ss::BEGIN) - { - const unsigned long begin = i; - ++i; - while (i < labels[k].size() && labels[k][i] == impl_ss::INSIDE) - ++i; - - segments[k].push_back(std::make_pair(begin, i)); - --i; - } - } - } - } - -// ---------------------------------------------------------------------------------------- - - template - void do_test() - { - dlog << LINFO << "use_BIO_model: "<< use_BIO_model; - dlog << LINFO << "use_high_order_features: "<< use_high_order_features; - dlog << LINFO << "allow_negative_weights: "<< allow_negative_weights; - - std::vector > samples; - std::vector > > segments; - make_dataset2( samples, segments, 100); - - print_spinner(); - typedef unigram_extractor fe_type; - - fe_type fe_temp; - fe_type fe_temp2; - structural_sequence_segmentation_trainer trainer(fe_temp2); - trainer.set_c(5); - trainer.set_num_threads(1); - - - sequence_segmenter labeler = trainer.train(samples, segments); - - print_spinner(); - - const std::vector > predicted_labels = labeler(samples[1]); - const std::vector > true_labels = segments[1]; - /* - for (unsigned long i = 0; i < predicted_labels.size(); ++i) - cout << "["< 0); - DLIB_TEST(predicted_labels.size() == true_labels.size()); - for (unsigned long i = 0; i < predicted_labels.size(); ++i) - { - DLIB_TEST(predicted_labels[i].first == true_labels[i].first); - DLIB_TEST(predicted_labels[i].second == true_labels[i].second); - } - - - matrix res; - - res = cross_validate_sequence_segmenter(trainer, samples, segments, 3); - dlog << LINFO << "cv res: "<< res; - DLIB_TEST(min(res) > 0.98); - make_dataset2( samples, segments, 100); - res = test_sequence_segmenter(labeler, samples, segments); - dlog << LINFO << "test res: "<< res; - DLIB_TEST(min(res) > 0.98); - - print_spinner(); - - ostringstream sout; - serialize(labeler, sout); - istringstream sin(sout.str()); - sequence_segmenter labeler2; - deserialize(labeler2, sin); - - res = test_sequence_segmenter(labeler2, samples, segments); - dlog << LINFO << "test res2: "<< res; - DLIB_TEST(min(res) > 0.98); - - long N; - if (use_BIO_model) - N = 3*3+3; - else - N = 5*5+5; - const double min_normal_weight = min(colm(labeler2.get_weights(), 0, labeler2.get_weights().size()-N)); - const double min_trans_weight = min(labeler2.get_weights()); - dlog << LINFO << "min_normal_weight: " << min_normal_weight; - dlog << LINFO << "min_trans_weight: " << min_trans_weight; - if (allow_negative_weights) - { - DLIB_TEST(min_normal_weight < 0); - DLIB_TEST(min_trans_weight < 0); - } - else - { - DLIB_TEST(min_normal_weight == 0); - DLIB_TEST(min_trans_weight < 0); - } - } - -// ---------------------------------------------------------------------------------------- - - - class unit_test_sequence_segmenter : public tester - { - public: - unit_test_sequence_segmenter ( - ) : - tester ("test_sequence_segmenter", - "Runs tests on the sequence segmenting code.") - {} - - void perform_test ( - ) - { - do_test(); - do_test(); - do_test(); - do_test(); - do_test(); - do_test(); - do_test(); - do_test(); - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/serialize.cpp b/lib/3rdParty/dlib/include/dlib/test/serialize.cpp deleted file mode 100644 index 78e6a66f..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/serialize.cpp +++ /dev/null @@ -1,1029 +0,0 @@ -// Copyright (C) 2008 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace dlib -{ - static bool operator!=(const rgb_pixel& a, const rgb_pixel& b) - { - return !(a.red==b.red && a.green==b.green && a.blue==b.blue); - } - static bool operator!=(const bgr_pixel& a, const bgr_pixel& b) - { - return !(a.red==b.red && a.green==b.green && a.blue==b.blue); - } - - static bool operator!=(const hsi_pixel& a, const hsi_pixel& b) - { - return !(a.h==b.h && a.s==b.s && a.i==b.i); - } - static bool operator!=(const rgb_alpha_pixel& a, const rgb_alpha_pixel& b) - { - return !(a.red==b.red && a.green==b.green && a.blue==b.blue && a.alpha==b.alpha); - } - -} - -namespace -{ - -// ---------------------------------------------------------------------------------------- - - using namespace test; - using namespace dlib; - using namespace std; - - struct test_object - { - signed char i1; - signed short i2; - signed long i3; - unsigned char i4; - unsigned short i5; - unsigned long i6; - uint64 i7; - int64 i8; - - signed char i1_0; - signed short i2_0; - signed long i3_0; - unsigned char i4_0; - unsigned short i5_0; - unsigned long i6_0; - uint64 i7_0; - int64 i8_0; - - signed char i1_n; - signed short i2_n; - signed long i3_n; - - - float f1; - double f2; - long double f3; - float f1_inf; - double f2_inf; - long double f3_inf; - float f1_ninf; - double f2_ninf; - long double f3_ninf; - float f1_qnan; - double f2_qnan; - long double f3_qnan; - float f1_snan; - double f2_snan; - long double f3_snan; - - std::string s1; - std::wstring s2; - - int array[10]; - - bool b_true; - bool b_false; - - - void set_state_1( - ) - { - i1 = 1; - i2 = 2; - i3 = 3; - i4 = 4; - i5 = 5; - i6 = 6; - i7 = 7; - i8 = 8; - - i1_0 = 0; - i2_0 = 0; - i3_0 = 0; - i4_0 = 0; - i5_0 = 0; - i6_0 = 0; - i7_0 = 0; - i8_0 = 0; - - i1_n = -1; - i2_n = -2; - i3_n = -3; - - f1 = 123.456f; - f2 = 543.341; - f3 = 5234234.23; - - f1_inf = numeric_limits::infinity(); - f2_inf = numeric_limits::infinity(); - f3_inf = numeric_limits::infinity(); - f1_ninf = -numeric_limits::infinity(); - f2_ninf = -numeric_limits::infinity(); - f3_ninf = -numeric_limits::infinity(); - f1_qnan = numeric_limits::quiet_NaN(); - f2_qnan = numeric_limits::quiet_NaN(); - f3_qnan = numeric_limits::quiet_NaN(); - f1_snan = numeric_limits::signaling_NaN(); - f2_snan = numeric_limits::signaling_NaN(); - f3_snan = numeric_limits::signaling_NaN(); - - s1 = "davis"; - s2 = L"yo yo yo"; - - for (int i = 0; i < 10; ++i) - array[i] = i; - - b_true = true; - b_false = false; - } - - void set_state_2( - ) - { - i1 = 10; - i2 = 20; - i3 = 30; - i4 = 40; - i5 = 50; - i6 = 60; - i7 = 70; - i8 = 80; - - i1_0 = 5; - i2_0 = 6; - i3_0 = 7; - i4_0 = 8; - i5_0 = 9; - i6_0 = 10; - i7_0 = 11; - i8_0 = 12; - - i1_n = -13; - i2_n = -25; - i3_n = -12; - - f1 = 45.3f; - f2 = 0.001; - f3 = 2.332; - - f1_inf = f1; - f2_inf = f2; - f3_inf = f3; - f1_ninf = f1; - f2_ninf = f2; - f3_ninf = f3; - f1_qnan = f1; - f2_qnan = f2; - f3_qnan = f3; - f1_snan = f1; - f2_snan = f2; - f3_snan = f3; - - s1 = ""; - s2 = L""; - - for (int i = 0; i < 10; ++i) - array[i] = 10-i; - - b_true = false; - b_false = true; - } - - void assert_in_state_1 ( - ) - { - DLIB_TEST (i1 == 1); - DLIB_TEST (i2 == 2); - DLIB_TEST (i3 == 3); - DLIB_TEST (i4 == 4); - DLIB_TEST (i5 == 5); - DLIB_TEST (i6 == 6); - DLIB_TEST (i7 == 7); - DLIB_TEST (i8 == 8); - - DLIB_TEST (i1_0 == 0); - DLIB_TEST (i2_0 == 0); - DLIB_TEST (i3_0 == 0); - DLIB_TEST (i4_0 == 0); - DLIB_TEST (i5_0 == 0); - DLIB_TEST (i6_0 == 0); - DLIB_TEST (i7_0 == 0); - DLIB_TEST (i8_0 == 0); - - DLIB_TEST (i1_n == -1); - DLIB_TEST (i2_n == -2); - DLIB_TEST (i3_n == -3); - - DLIB_TEST (abs(f1 -123.456) < 1e-5); - DLIB_TEST (abs(f2 - 543.341) < 1e-10); - DLIB_TEST (abs(f3 - 5234234.23) < 1e-10); - - DLIB_TEST (f1_inf == numeric_limits::infinity()); - DLIB_TEST (f2_inf == numeric_limits::infinity()); - DLIB_TEST (f3_inf == numeric_limits::infinity()); - DLIB_TEST (f1_ninf == -numeric_limits::infinity()); - DLIB_TEST (f2_ninf == -numeric_limits::infinity()); - DLIB_TEST (f3_ninf == -numeric_limits::infinity()); - DLIB_TEST (!(f1_qnan <= numeric_limits::infinity() && f1_qnan >= -numeric_limits::infinity() )); - DLIB_TEST (!(f2_qnan <= numeric_limits::infinity() && f1_qnan >= -numeric_limits::infinity() )); - DLIB_TEST (!(f3_qnan <= numeric_limits::infinity() && f1_qnan >= -numeric_limits::infinity() )); - DLIB_TEST (!(f1_snan <= numeric_limits::infinity() && f1_qnan >= -numeric_limits::infinity() )); - DLIB_TEST (!(f2_snan <= numeric_limits::infinity() && f1_qnan >= -numeric_limits::infinity() )); - DLIB_TEST (!(f3_snan <= numeric_limits::infinity() && f1_qnan >= -numeric_limits::infinity() )); - - DLIB_TEST (s1 == "davis"); - DLIB_TEST (s2 == L"yo yo yo"); - - for (int i = 0; i < 10; ++i) - { - DLIB_TEST (array[i] == i); - } - - DLIB_TEST (b_true == true); - DLIB_TEST (b_false == false); - - } - - void assert_in_state_2 ( - ) - { - DLIB_TEST (i1 == 10); - DLIB_TEST (i2 == 20); - DLIB_TEST (i3 == 30); - DLIB_TEST (i4 == 40); - DLIB_TEST (i5 == 50); - DLIB_TEST (i6 == 60); - DLIB_TEST (i7 == 70); - DLIB_TEST (i8 == 80); - - DLIB_TEST (i1_0 == 5); - DLIB_TEST (i2_0 == 6); - DLIB_TEST (i3_0 == 7); - DLIB_TEST (i4_0 == 8); - DLIB_TEST (i5_0 == 9); - DLIB_TEST (i6_0 == 10); - DLIB_TEST (i7_0 == 11); - DLIB_TEST (i8_0 == 12); - - DLIB_TEST (i1_n == -13); - DLIB_TEST (i2_n == -25); - DLIB_TEST (i3_n == -12); - - DLIB_TEST (abs(f1 - 45.3) < 1e-5); - DLIB_TEST (abs(f2 - 0.001) < 1e-10); - DLIB_TEST (abs(f3 - 2.332) < 1e-10); - DLIB_TEST (abs(f1_inf - 45.3) < 1e-5); - DLIB_TEST (abs(f2_inf - 0.001) < 1e-10); - DLIB_TEST (abs(f3_inf - 2.332) < 1e-10); - DLIB_TEST (abs(f1_ninf - 45.3) < 1e-5); - DLIB_TEST (abs(f2_ninf - 0.001) < 1e-10); - DLIB_TEST (abs(f3_ninf - 2.332) < 1e-10); - DLIB_TEST (abs(f1_qnan - 45.3) < 1e-5); - DLIB_TEST (abs(f2_qnan - 0.001) < 1e-10); - DLIB_TEST (abs(f3_qnan - 2.332) < 1e-10); - DLIB_TEST (abs(f1_snan - 45.3) < 1e-5); - DLIB_TEST (abs(f2_snan - 0.001) < 1e-10); - DLIB_TEST (abs(f3_snan - 2.332) < 1e-10); - - DLIB_TEST (s1 == ""); - DLIB_TEST (s2 == L""); - - for (int i = 0; i < 10; ++i) - { - DLIB_TEST (array[i] == 10-i); - } - - DLIB_TEST (b_true == false); - DLIB_TEST (b_false == true); - - } - - }; - -// ---------------------------------------------------------------------------------------- - - void serialize ( - const test_object& item, - std::ostream& out - ) - { - dlib::serialize(item.i1,out); - dlib::serialize(item.i2,out); - dlib::serialize(item.i3,out); - dlib::serialize(item.i4,out); - dlib::serialize(item.i5,out); - dlib::serialize(item.i6,out); - dlib::serialize(item.i7,out); - dlib::serialize(item.i8,out); - - dlib::serialize(item.i1_0,out); - dlib::serialize(item.i2_0,out); - dlib::serialize(item.i3_0,out); - dlib::serialize(item.i4_0,out); - dlib::serialize(item.i5_0,out); - dlib::serialize(item.i6_0,out); - dlib::serialize(item.i7_0,out); - dlib::serialize(item.i8_0,out); - - dlib::serialize(item.i1_n,out); - dlib::serialize(item.i2_n,out); - dlib::serialize(item.i3_n,out); - - - dlib::serialize(item.f1,out); - dlib::serialize(item.f2,out); - dlib::serialize(item.f3,out); - - dlib::serialize(item.f1_inf,out); - dlib::serialize(item.f2_inf,out); - dlib::serialize(item.f3_inf,out); - dlib::serialize(item.f1_ninf,out); - dlib::serialize(item.f2_ninf,out); - dlib::serialize(item.f3_ninf,out); - dlib::serialize(item.f1_qnan,out); - dlib::serialize(item.f2_qnan,out); - dlib::serialize(item.f3_qnan,out); - dlib::serialize(item.f1_snan,out); - dlib::serialize(item.f2_snan,out); - dlib::serialize(item.f3_snan,out); - - dlib::serialize(item.s1,out); - dlib::serialize(item.s2,out); - - dlib::serialize(item.array,out); - - dlib::serialize(item.b_true,out); - dlib::serialize(item.b_false,out); - } - -// ---------------------------------------------------------------------------------------- - - void deserialize ( - test_object& item, - std::istream& in - ) - { - dlib::deserialize(item.i1,in); - dlib::deserialize(item.i2,in); - dlib::deserialize(item.i3,in); - dlib::deserialize(item.i4,in); - dlib::deserialize(item.i5,in); - dlib::deserialize(item.i6,in); - dlib::deserialize(item.i7,in); - dlib::deserialize(item.i8,in); - - dlib::deserialize(item.i1_0,in); - dlib::deserialize(item.i2_0,in); - dlib::deserialize(item.i3_0,in); - dlib::deserialize(item.i4_0,in); - dlib::deserialize(item.i5_0,in); - dlib::deserialize(item.i6_0,in); - dlib::deserialize(item.i7_0,in); - dlib::deserialize(item.i8_0,in); - - dlib::deserialize(item.i1_n,in); - dlib::deserialize(item.i2_n,in); - dlib::deserialize(item.i3_n,in); - - - dlib::deserialize(item.f1,in); - dlib::deserialize(item.f2,in); - dlib::deserialize(item.f3,in); - - dlib::deserialize(item.f1_inf,in); - dlib::deserialize(item.f2_inf,in); - dlib::deserialize(item.f3_inf,in); - dlib::deserialize(item.f1_ninf,in); - dlib::deserialize(item.f2_ninf,in); - dlib::deserialize(item.f3_ninf,in); - dlib::deserialize(item.f1_qnan,in); - dlib::deserialize(item.f2_qnan,in); - dlib::deserialize(item.f3_qnan,in); - dlib::deserialize(item.f1_snan,in); - dlib::deserialize(item.f2_snan,in); - dlib::deserialize(item.f3_snan,in); - - dlib::deserialize(item.s1,in); - dlib::deserialize(item.s2,in); - - dlib::deserialize(item.array,in); - - dlib::deserialize(item.b_true,in); - dlib::deserialize(item.b_false,in); - } - -// ---------------------------------------------------------------------------------------- - - // This function returns the contents of the file 'stuff.bin' but using the old - // floating point serialization format. - const std::string get_decoded_string() - { - dlib::base64::kernel_1a base64_coder; - dlib::compress_stream::kernel_1ea compressor; - std::ostringstream sout; - std::istringstream sin; - - - // The base64 encoded data from the file 'stuff.bin' we want to decode and return. - sout << "AVaifX9zEbXa9aocsrcRuvnNrR3WLuuU5eLWiy0UeXmnKXGLKZz8V44gzT4CM6wnCmAHFQug8G3C"; - sout << "4cuLdNgp2ApkeLcvwFNJRENE0ShrRaxEBFEA8nah7vm8B2VmgImNblCejuP5IcDt60EaCKlqiit8"; - sout << "+JGrzYxqBm3xFS4P+qlOROdbxc7pXBmUdh0rqNSEvn0FBPdoqY/5SpHgA2yAcH8XFrM1cdu0xS3P"; - sout << "8PBcmLMJ7bFdzplwhrjuxtm4NfEOi6Rl9sU44AXycYgJd0+uH+dyoI9X3co5b3YWJtjvdVeztNAr"; - sout << "BfSPfR6oAVNfiMBG7QA="; - - - // Put the data into the istream sin - sin.str(sout.str()); - sout.str(""); - - // Decode the base64 text into its compressed binary form - base64_coder.decode(sin,sout); - sin.clear(); - sin.str(sout.str()); - sout.str(""); - - // Decompress the data into its original form - compressor.decompress(sin,sout); - - // Return the decoded and decompressed data - return sout.str(); - } - - - // This function returns the contents of the file 'stuff.bin' but using the new - // floating point serialization format. - const std::string get_decoded_string2() - { - dlib::base64 base64_coder; - dlib::compress_stream::kernel_1ea compressor; - std::ostringstream sout; - std::istringstream sin; - - // The base64 encoded data from the file 'stuff.bin' we want to decode and return. - sout << "AVaifX9zEbXa9aocsrcRuvnNqzZLptZ5mRd46xScCIfX6sq/46hG9JwIInElG50EtJKJY/+jAWit"; - sout << "TpDBWrxBz124JRLsBz62h0D3Tqgnd8zygRx7t33Ybw40o07MrhzNEHgYavUukaPje5by78JIWHgk"; - sout << "l7nb/TK+9ndVLrAThJ4v+GiPT3kh9H1tAAAAAQhbLa06pQjhrnjTXcRox1ZBEAV9/q1zAA=="; - - // Put the data into the istream sin - sin.str(sout.str()); - sout.str(""); - - // Decode the base64 text into its compressed binary form - base64_coder.decode(sin,sout); - sin.clear(); - sin.str(sout.str()); - sout.str(""); - - // Decompress the data into its original form - compressor.decompress(sin,sout); - - // Return the decoded and decompressed data - return sout.str(); - } - -// ---------------------------------------------------------------------------------------- - - // Declare the logger we will use in this test. The name of the tester - // should start with "test." - logger dlog("test.serialize"); - - void serialize_test ( - ) - /*! - ensures - - runs tests on the serialization code for compliance with the specs - !*/ - { - - - print_spinner(); - - ostringstream sout; - test_object obj; - - obj.set_state_1(); - obj.assert_in_state_1(); - serialize(obj, sout); - obj.assert_in_state_1(); - - obj.set_state_2(); - obj.assert_in_state_2(); - serialize(obj, sout); - obj.assert_in_state_2(); - - - istringstream sin(sout.str()); - - deserialize(obj,sin); - obj.assert_in_state_1(); - deserialize(obj,sin); - obj.assert_in_state_2(); - - - // now do the same thing as above but deserialize from some stored binary - // data to make sure the serialized values are portable between different - // machines - - sin.clear(); - sin.str(get_decoded_string()); - deserialize(obj,sin); - obj.assert_in_state_1(); - deserialize(obj,sin); - obj.assert_in_state_2(); - - - sin.clear(); - sin.str(get_decoded_string2()); - deserialize(obj,sin); - obj.assert_in_state_1(); - deserialize(obj,sin); - obj.assert_in_state_2(); - - - /* - // This is the code that produced the encoded data stored in the get_decoded_string() function - ofstream fout("stuff.bin",ios::binary); - obj.set_state_1(); - obj.assert_in_state_1(); - serialize(obj, fout); - obj.assert_in_state_1(); - - obj.set_state_2(); - obj.assert_in_state_2(); - serialize(obj, fout); - obj.assert_in_state_2(); - */ - - - test_object obj2; - obj.set_state_1(); - obj2.set_state_2(); - dlib::serialize("serialization_test.dat") << obj << obj2; - obj.assert_in_state_1(); - obj2.assert_in_state_2(); - obj.set_state_2(); - obj2.set_state_1(); - obj.assert_in_state_2(); - obj2.assert_in_state_1(); - dlib::deserialize("serialization_test.dat") >> obj >> obj2; - obj.assert_in_state_1(); - obj2.assert_in_state_2(); - } - - - template - void test_vector ( - ) - { - std::vector a, b; - - for (int i = -10; i < 30; ++i) - { - a.push_back(i); - } - - ostringstream sout; - dlib::serialize(a, sout); - istringstream sin(sout.str()); - - dlib::deserialize(b, sin); - - - DLIB_TEST(a.size() == b.size()); - DLIB_TEST(a.size() == 40); - for (unsigned long i = 0; i < a.size(); ++i) - { - DLIB_TEST(a[i] == b[i]); - } - - std::vector c; - sout.str(""); - dlib::serialize(c, sout); - sin.str(sout.str()); - dlib::deserialize(a, sin); - DLIB_TEST(a.size() == 0); - DLIB_TEST(c.size() == 0); - } - - void test_vector_bool ( - ) - { - std::vector a, b; - - a.push_back(true); - a.push_back(true); - a.push_back(false); - a.push_back(true); - a.push_back(false); - a.push_back(true); - - ostringstream sout; - dlib::serialize(a, sout); - istringstream sin(sout.str()); - - dlib::deserialize(b, sin); - - - DLIB_TEST(a.size() == b.size()); - DLIB_TEST(a.size() == 6); - for (unsigned long i = 0; i < a.size(); ++i) - { - DLIB_TEST(a[i] == b[i]); - } - } - -// ---------------------------------------------------------------------------------------- - - // This function returns the contents of the file 'matarray.dat' - const std::string get_decoded_string_matarray_old() - { - dlib::base64 base64_coder; - dlib::compress_stream::kernel_1ea compressor; - std::ostringstream sout; - std::istringstream sin; - - // The base64 encoded data from the file 'matarray.dat' we want to decode and return. - sout << "AW852sEbTIeV+m/wLUcKJKPW+6IclviUWZcFh1daDZ0blDjPNTgPx0Lv56sIEwlG4I6C5OJzJBkZ"; - sout << "PvczLjS7IEKh6eg7amNOyEexsQSgojL1oMe2gDEfkyInUGPJV90sNS0cvp/hIB134V8JCTYUP6vH"; - sout << "9qpegLSIIQG+/NjLWyK2472vC88BJfKgkL3CPLMjQwB3tB928FNLbESDLIvpnb6q9ve68iuoyZZt"; - sout << "z3TTJxHW3MIdgzuhNomvPxfo/Q+7lC/Orj0FewUX90al6DckwzOtLVRidh/ZKpsQsxzJYQGkjdX5"; - sout << "mDzzXKqQb3Y3DnzEmwtRD9CUON3iRv1r26gHWLYorrYA"; - - - // Put the data into the istream sin - sin.str(sout.str()); - sout.str(""); - - // Decode the base64 text into its compressed binary form - base64_coder.decode(sin,sout); - sin.clear(); - sin.str(sout.str()); - sout.str(""); - - // Decompress the data into its original form - compressor.decompress(sin,sout); - - // Return the decoded and decompressed data - return sout.str(); - } - - // This function returns the contents of the file 'matarray.dat' - const std::string get_decoded_string_matarray() - { - dlib::base64 base64_coder; - dlib::compress_stream::kernel_1ea compressor; - std::ostringstream sout; - std::istringstream sin; - - // The base64 encoded data from the file 'matarray.dat' we want to decode and return. - sout << "gO6XH2WGbm8Xaw3a5FJbh3V823W6P2Qk/vHaAAAAARccIppHWdmViaKby7JA5PQvXjYMWUYvXRHv"; - sout << "xPdURZl1un3CT/rjT11Yry0y3+1W7GBmfBJ0gVFKGdiGuqoNAMtmzL/ll3YfEQ7ED7aB33aDTktw"; - sout << "AWVkHT+gqTbKwjP+8YvB3s3ziK640ITOAWazAghKDVl7AHGn+fjq29paBZMczuJofl8FinZUhwa9"; - sout << "Ol5gdAEQa6VZDmJUeo2soTJcEDpkW9LkRmXvjQkyEHfEHQNFDfQq4p2U+dHz4lOKlcj3VzQIeG/s"; - sout << "oxa9KhJND4aQ5xeNUUHUzFBU3XhQHlyDIn/RNdX/ZwA="; - - - // Put the data into the istream sin - sin.str(sout.str()); - sout.str(""); - - // Decode the base64 text into its compressed binary form - base64_coder.decode(sin,sout); - sin.clear(); - sin.str(sout.str()); - sout.str(""); - - // Decompress the data into its original form - compressor.decompress(sin,sout); - - // Return the decoded and decompressed data - return sout.str(); - } - - void setup_mats_and_arrays ( - array2d& a, - matrix& m, - array2d& img1, - array2d& img2, - array2d& img3, - array2d& img4, - array2d& img5 - ) - { - a.set_size(3,5); - int cnt = 0; - for (long r = 0; r < a.nr(); ++r) - { - for (long c = 0; c < a.nc(); ++c) - { - a[r][c] = cnt++; - } - } - m = mat(a); - - img1.set_size(3,5); - img2.set_size(3,5); - img3.set_size(3,5); - img4.set_size(3,5); - img5.set_size(3,5); - - assign_all_pixels(img1, 0); - assign_all_pixels(img2, 0); - assign_all_pixels(img3, 0); - assign_all_pixels(img4, 0); - assign_all_pixels(img5, 0); - - unsigned char pcnt = 0; - for (long r = 0; r < img1.nr(); ++r) - { - for (long c = 0; c < img1.nc(); ++c) - { - rgb_alpha_pixel temp; - temp.red = pcnt++; - temp.green = pcnt++; - temp.blue = pcnt++; - temp.alpha = 150+pcnt++; - assign_pixel(img1[r][c], temp); - assign_pixel(img2[r][c], temp); - assign_pixel(img3[r][c], temp); - assign_pixel(img4[r][c], temp); - } - } - - for (long r = 0; r < img5.nr(); ++r) - { - for (long c = 0; c < img5.nc(); ++c) - { - img5[r][c].h = pcnt++; - img5[r][c].s = pcnt++; - img5[r][c].i = pcnt++; - } - } - } - - - void test_deserialize( - std::istream& fin - ) - { - array2d a; - matrix m; - array2d img1; - array2d img2; - array2d img3; - array2d img4; - array2d img5; - setup_mats_and_arrays(a,m,img1,img2,img3,img4,img5); - - - array2d img1_; - array2d img2_; - array2d img3_; - array2d img4_; - array2d img5_; - - matrix m_; - array2d a_; - - deserialize(a_, fin); DLIB_TEST(mat(a_) == mat(a)); - deserialize(m_, fin); DLIB_TEST(mat(m_) == mat(m)); - deserialize(a_, fin); DLIB_TEST(mat(a_) == mat(a)); - deserialize(m_, fin); DLIB_TEST(mat(m_) == mat(m)); - - deserialize(img1_, fin); DLIB_TEST(mat(img1_) == mat(img1)); - deserialize(img2_, fin); DLIB_TEST(mat(img2_) == mat(img2)); - deserialize(img3_, fin); DLIB_TEST(mat(img3_) == mat(img3)); - deserialize(img4_, fin); DLIB_TEST(mat(img4_) == mat(img4)); - deserialize(img5_, fin); DLIB_TEST(mat(img5_) == mat(img5)); - } - - void test_deserialize_all_array2d( - std::istream& fin - ) - { - array2d a; - matrix m; - array2d img1; - array2d img2; - array2d img3; - array2d img4; - array2d img5; - setup_mats_and_arrays(a,m,img1,img2,img3,img4,img5); - - - array2d img1_; - array2d img2_; - array2d img3_; - array2d img4_; - array2d img5_; - - array2d m_; - array2d a_; - - deserialize(a_, fin); DLIB_TEST(mat(a_) == mat(a)); - deserialize(m_, fin); DLIB_TEST(mat(m_) == mat(m)); - deserialize(a_, fin); DLIB_TEST(mat(a_) == mat(a)); - deserialize(m_, fin); DLIB_TEST(mat(m_) == mat(m)); - - deserialize(img1_, fin); DLIB_TEST(mat(img1_) == mat(img1)); - deserialize(img2_, fin); DLIB_TEST(mat(img2_) == mat(img2)); - deserialize(img3_, fin); DLIB_TEST(mat(img3_) == mat(img3)); - deserialize(img4_, fin); DLIB_TEST(mat(img4_) == mat(img4)); - deserialize(img5_, fin); DLIB_TEST(mat(img5_) == mat(img5)); - } - - void test_deserialize_all_matrix( - std::istream& fin - ) - { - array2d a; - matrix m; - array2d img1; - array2d img2; - array2d img3; - array2d img4; - array2d img5; - setup_mats_and_arrays(a,m,img1,img2,img3,img4,img5); - - - matrix img1_; - matrix img2_; - matrix img3_; - matrix img4_; - matrix img5_; - - matrix m_; - matrix a_; - - deserialize(a_, fin); DLIB_TEST(mat(a_) == mat(a)); - deserialize(m_, fin); DLIB_TEST(mat(m_) == mat(m)); - deserialize(a_, fin); DLIB_TEST(mat(a_) == mat(a)); - deserialize(m_, fin); DLIB_TEST(mat(m_) == mat(m)); - - deserialize(img1_, fin); DLIB_TEST(mat(img1_) == mat(img1)); - deserialize(img2_, fin); DLIB_TEST(mat(img2_) == mat(img2)); - deserialize(img3_, fin); DLIB_TEST(mat(img3_) == mat(img3)); - deserialize(img4_, fin); DLIB_TEST(mat(img4_) == mat(img4)); - deserialize(img5_, fin); DLIB_TEST(mat(img5_) == mat(img5)); - } - - void test_array2d_and_matrix_serialization() - { - ostringstream sout; - array2d a; - matrix m; - array2d img1; - array2d img2; - array2d img3; - array2d img4; - array2d img5; - setup_mats_and_arrays(a,m,img1,img2,img3,img4,img5); - - serialize(a, sout); - serialize(m, sout); - serialize(a, sout); - serialize(m, sout); - - serialize(img1, sout); - serialize(img2, sout); - serialize(img3, sout); - serialize(img4, sout); - serialize(img5, sout); - - // -------------------- - - { - istringstream sin(sout.str()); - test_deserialize(sin); - } - { - istringstream sin(sout.str()); - test_deserialize_all_array2d(sin); - } - { - istringstream sin(sout.str()); - test_deserialize_all_matrix(sin); - } - - - { - istringstream sin(get_decoded_string_matarray()); - test_deserialize(sin); - } - { - istringstream sin(get_decoded_string_matarray()); - test_deserialize_all_array2d(sin); - } - { - istringstream sin(get_decoded_string_matarray()); - test_deserialize_all_matrix(sin); - } - - - { - // Make sure we can still deserialize the serialization - // format for array2d and matrix objects used by older versions - // of dlib. - istringstream sin(get_decoded_string_matarray_old()); - test_deserialize(sin); - } - } - -// ---------------------------------------------------------------------------------------- - - void test_strings() - { - string str1 = "stuff"; - char buf[6]; - buf[0] = 0; - buf[1] = 1; - buf[2] = 2; - buf[3] = 0; - buf[4] = 3; - buf[5] = 3; - - dlib::serialize("ser_test_string.dat") << str1 << buf << "morestuff" << ""; - - string str2, str3, str4; - char buf2[6]; - memset(buf2,0,sizeof(buf2)); - dlib::deserialize("ser_test_string.dat") >> str2 >> buf2 >> str3 >> str4; - DLIB_TEST(str2 == "stuff"); - DLIB_TEST(str3 == "morestuff"); - DLIB_TEST(str4 == ""); - DLIB_TEST(buf2[0] == 0); - DLIB_TEST(buf2[1] == 1); - DLIB_TEST(buf2[2] == 2); - DLIB_TEST(buf2[3] == 0); - DLIB_TEST(buf2[4] == 3); - DLIB_TEST(buf2[5] == 3); - - - ofstream fout("ser_test_string.dat", ios::binary); - dlib::serialize(str1, fout); - dlib::serialize(buf, fout); - dlib::serialize("morestuff", fout); - fout.close(); - ifstream fin("ser_test_string.dat", ios::binary); - memset(buf2,0,sizeof(buf2)); - str2.clear(); - str3.clear(); - dlib::deserialize(str2, fin); - dlib::deserialize(buf2, fin); - dlib::deserialize(str3, fin); - - DLIB_TEST(str2 == "stuff"); - DLIB_TEST(str3 == "morestuff"); - DLIB_TEST(buf2[0] == 0); - DLIB_TEST(buf2[1] == 1); - DLIB_TEST(buf2[2] == 2); - DLIB_TEST(buf2[3] == 0); - DLIB_TEST(buf2[4] == 3); - DLIB_TEST(buf2[5] == 3); - } - -// ---------------------------------------------------------------------------------------- - - class serialize_tester : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a test for the serialization . When it is constructed - it adds itself into the testing framework. The command line switch is - specified as test_serialize by passing that string to the tester constructor. - !*/ - public: - serialize_tester ( - ) : - tester ("test_serialize", - "Runs tests on the serialization code.") - {} - - void perform_test ( - ) - { - serialize_test(); - test_vector(); - test_vector(); - test_vector(); - test_vector_bool(); - test_array2d_and_matrix_serialization(); - test_strings(); - } - } a; - - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/set.cpp b/lib/3rdParty/dlib/include/dlib/test/set.cpp deleted file mode 100644 index f8d3bd37..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/set.cpp +++ /dev/null @@ -1,464 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace std; - using namespace dlib; - - logger dlog("test.set"); - - template < - typename set - > - void set_compare_test ( - ) - /*! - requires - - set is an implementation of set/set_compare_abstract.h and - is instantiated with int - ensures - - runs tests on set for compliance with the specs - !*/ - { - - - srand(static_cast(time(0))); - - - - set test, test2; - - enumerable& e = test; - DLIB_TEST(e.at_start() == true); - - for (int j = 0; j < 4; ++j) - { - - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == false); - - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.is_member(5) == false); - DLIB_TEST(test.is_member(0) == false); - DLIB_TEST(test.is_member(-999) == false); - DLIB_TEST(test.is_member(4999) == false); - - - int a,b = 0; - a = 8; - test.add(a); - DLIB_TEST(test.size() == 1); - DLIB_TEST(test.is_member(8) == true); - DLIB_TEST(test.is_member(5) == false); - DLIB_TEST(test.is_member(0) == false); - DLIB_TEST(test.is_member(-999) == false); - DLIB_TEST(test.is_member(4999) == false); - a = 53; - test.add(a); - DLIB_TEST(test.size() == 2); - DLIB_TEST(test.is_member(53) == true); - DLIB_TEST(test.is_member(5) == false); - DLIB_TEST(test.is_member(0) == false); - DLIB_TEST(test.is_member(-999) == false); - DLIB_TEST(test.is_member(4999) == false); - - - swap(test,test2); - - - - DLIB_TEST(test2.is_member(8) == true); - DLIB_TEST(test2.is_member(5) == false); - DLIB_TEST(test2.is_member(0) == false); - DLIB_TEST(test2.is_member(-999) == false); - DLIB_TEST(test2.is_member(4999) == false); - DLIB_TEST(test2.size() == 2); - DLIB_TEST(test2.is_member(53) == true); - DLIB_TEST(test2.is_member(5) == false); - DLIB_TEST(test2.is_member(0) == false); - DLIB_TEST(test2.is_member(-999) == false); - DLIB_TEST(test2.is_member(4999) == false); - - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.is_member(8) == false); - DLIB_TEST(test.is_member(5) == false); - DLIB_TEST(test.is_member(0) == false); - DLIB_TEST(test.is_member(-999) == false); - DLIB_TEST(test.is_member(4999) == false); - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.is_member(53) == false); - DLIB_TEST(test.is_member(5) == false); - DLIB_TEST(test.is_member(0) == false); - DLIB_TEST(test.is_member(-999) == false); - DLIB_TEST(test.is_member(4999) == false); - - - test.clear(); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.at_start() == false); - - - DLIB_TEST(test.size() == 0); - - while (test.size() < 10000) - { - a = ::rand(); - if (!test.is_member(a)) - test.add(a); - } - - DLIB_TEST(test.size() == 10000); - test.clear(); - DLIB_TEST(test.size() == 0); - - while (test.size() < 10000) - { - a = ::rand(); - if (!test.is_member(a)) - test.add(a); - } - - DLIB_TEST(test.size() == 10000); - - int count = 0; - a = 0; - while (test.move_next()) - { - enumerable& gogo = test; - gogo.element(); - - DLIB_TEST(test.element() == test.element()); - DLIB_TEST(test.element() == test.element()); - DLIB_TEST(test.element() == test.element()); - - DLIB_TEST(a <= test.element()); - a = test.element(); - ++count; - } - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.move_next() == false); - - DLIB_TEST(count == 10000); - - test.swap(test2); - - DLIB_TEST(test.size() == 2); - DLIB_TEST(test2.size() == 10000); - count = 0; - a = -1; - test2.reset(); - while (test2.move_next()) - { - DLIB_TEST(test2.element() == test2.element()); - DLIB_TEST(test2.element() == test2.element()); - DLIB_TEST(test2.element() == test2.element()); - DLIB_TEST(a < test2.element()); - a = test2.element(); - ++count; - } - DLIB_TEST(test2.size() == 10000); - DLIB_TEST(count == 10000); - DLIB_TEST(test2.current_element_valid() == false); - DLIB_TEST(test2.at_start() == false); - DLIB_TEST(test2.move_next() == false); - DLIB_TEST(test2.current_element_valid() == false); - DLIB_TEST(test2.at_start() == false); - DLIB_TEST(test2.move_next() == false); - - - - test2.clear(); - DLIB_TEST(test2.size() == 0); - DLIB_TEST(test2.at_start() == true); - - while (test.size() < 20000) - { - a = ::rand(); - if (!test.is_member(a)) - test.add(a); - } - - DLIB_TEST(test.at_start() == true); - - { - int* array = new int[test.size()]; - int* tmp = array; - - count = 0; - while (test.move_next()) - { - DLIB_TEST(test.element() == test.element()); - DLIB_TEST(test.element() == test.element()); - DLIB_TEST(test.element() == test.element()); - *tmp = test.element(); - ++tmp; - ++count; - } - DLIB_TEST(count == 20000); - - // serialize the state of test, then clear test, then - // load the state back into test. - ostringstream sout; - serialize(test,sout); - DLIB_TEST(test.at_start() == true); - istringstream sin(sout.str()); - test.clear(); - deserialize(test,sin); - - - - tmp = array; - for (int i = 0; i < 20000; ++i) - { - DLIB_TEST(test.is_member(*tmp) == true); - ++tmp; - } - - DLIB_TEST(test.size() == 20000); - - tmp = array; - count = 0; - while (test.size() > 10000) - { - test.remove(*tmp,a); - DLIB_TEST(*tmp == a); - ++tmp; - ++count; - } - DLIB_TEST(count == 10000); - DLIB_TEST(test.size() == 10000); - - while (test.move_next()) - { - DLIB_TEST(test.element() == *tmp); - DLIB_TEST(test.element() == *tmp); - DLIB_TEST(test.element() == *tmp); - ++tmp; - ++count; - } - DLIB_TEST(count == 20000); - DLIB_TEST(test.size() == 10000); - - while (test.size() < 20000) - { - a = ::rand(); - if (!test.is_member(a)) - test.add(a); - } - - test2.swap(test); - - count = 0; - a = 0; - while (test2.move_next()) - { - DLIB_TEST(test2.element() == test2.element()); - DLIB_TEST(test2.element() == test2.element()); - DLIB_TEST(test2.element() == test2.element()); - DLIB_TEST(a <= test2.element()); - a = test2.element(); - ++count; - } - - DLIB_TEST(count == 20000); - DLIB_TEST(test2.size() == 20000); - - a = -1; - while (test2.size()>0) - { - test2.remove_any(b); - DLIB_TEST( a < b); - a = b; - } - - DLIB_TEST(test2.size() == 0); - delete [] array; - } - - test.clear(); - test2.clear(); - while (test.size() < 10000) - { - a = ::rand(); - if (!test.is_member(a)) - test.add(a); - } - - count = 0; - a = -1; - while (test.move_next()) - { - DLIB_TEST(a < test.element()); - a = test.element(); - ++count; - if (count == 5000) - break; - DLIB_TEST(test.current_element_valid() == true); - } - - test.reset(); - - count = 0; - a = -1; - while (test.move_next()) - { - DLIB_TEST(a < test.element()); - a = test.element(); - ++count; - DLIB_TEST(test.current_element_valid() == true); - } - - DLIB_TEST(count == 10000); - - - test.clear(); - test2.clear(); - } - - - - { - DLIB_TEST(test == test2); - DLIB_TEST((test < test2) == false); - DLIB_TEST((test2 < test) == false); - - int a = 3, b = 3; - test.add(a); - test2.add(b); - test.move_next(); - DLIB_TEST(test == test2); - DLIB_TEST(test.at_start() && test2.at_start()); - test.move_next(); - DLIB_TEST((test < test2) == false); - DLIB_TEST(test.at_start() && test2.at_start()); - test.move_next(); - DLIB_TEST((test2 < test) == false); - DLIB_TEST(test.at_start() && test2.at_start()); - - a = 2; b = 5; - test.add(a); - test2.add(b); - DLIB_TEST(test.at_start() && test2.at_start()); - test2.move_next(); - DLIB_TEST((test == test2) == false); - DLIB_TEST(test.at_start() && test2.at_start()); - test2.move_next(); - DLIB_TEST((test < test2) == true); - DLIB_TEST(test.at_start() && test2.at_start()); - test2.move_next(); - DLIB_TEST((test2 < test) == false); - DLIB_TEST(test.at_start() && test2.at_start()); - - - a = 8; - test.add(a); - DLIB_TEST(test.at_start() && test2.at_start()); - test2.move_next(); - DLIB_TEST((test == test2) == false); - DLIB_TEST(test.at_start() && test2.at_start()); - test2.move_next(); - DLIB_TEST((test < test2) == false); - DLIB_TEST(test.at_start() && test2.at_start()); - test2.move_next(); - DLIB_TEST((test2 < test) == true); - DLIB_TEST(test.at_start() && test2.at_start()); - - test.clear(); - - DLIB_TEST(test.at_start() && test2.at_start()); - test2.move_next(); - DLIB_TEST((test == test2) == false); - DLIB_TEST(test.at_start() && test2.at_start()); - test2.move_next(); - DLIB_TEST((test < test2) == true); - DLIB_TEST(test.at_start() && test2.at_start()); - test2.move_next(); - DLIB_TEST((test2 < test) == false); - DLIB_TEST(test.at_start() && test2.at_start()); - - - } - - - { - test.clear(); - DLIB_TEST(test.size() == 0); - int a = 5; - test.add(a); - a = 7; - test.add(a); - DLIB_TEST(test.size() == 2); - DLIB_TEST(test.is_member(7)); - DLIB_TEST(test.is_member(5)); - test.destroy(7); - DLIB_TEST(test.size() == 1); - DLIB_TEST(!test.is_member(7)); - DLIB_TEST(test.is_member(5)); - test.destroy(5); - DLIB_TEST(test.size() == 0); - DLIB_TEST(!test.is_member(7)); - DLIB_TEST(!test.is_member(5)); - } - - - } - - - - - class set_tester : public tester - { - public: - set_tester ( - ) : - tester ("test_set", - "Runs tests on the set component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing compare_1a"; - set_compare_test::compare_1a> (); - dlog << LINFO << "testing compare_1a_c"; - set_compare_test::compare_1a_c>(); - dlog << LINFO << "testing compare_1b"; - set_compare_test::compare_1b> (); - dlog << LINFO << "testing compare_1b_c"; - set_compare_test::compare_1b_c>(); - } - } a; - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/sldf.cpp b/lib/3rdParty/dlib/include/dlib/test/sldf.cpp deleted file mode 100644 index 4ca9a3dd..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/sldf.cpp +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright (C) 2010 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "tester.h" -#include -#include -#include -#include -#include -#include -#include - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - dlib::logger dlog("test.sldf"); - - - class sldf_tester : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a unit test. When it is constructed - it adds itself into the testing framework. - !*/ - public: - sldf_tester ( - ) : - tester ( - "test_sldf", // the command line argument name for this test - "Run tests on the simplify_linear_decision_function routines.", // the command line argument description - 0 // the number of command line arguments for this test - ) - { - } - - dlib::rand rnd; - - - void perform_test ( - ) - { - print_spinner(); - typedef std::map sample_type; - - typedef matrix dense_sample_type; - - typedef sparse_linear_kernel kernel_type; - typedef linear_kernel dense_kernel_type; - - - svm_nu_trainer linear_trainer; - linear_trainer.set_nu(0.2); - svm_nu_trainer dense_linear_trainer; - dense_linear_trainer.set_nu(0.2); - - std::vector samples; - std::vector labels; - - // make an instance of a sample vector so we can use it below - sample_type sample; - - // Now lets go into a loop and randomly generate 300 samples. - double label = +1; - for (int i = 0; i < 300; ++i) - { - // flip this flag - label *= -1; - - sample.clear(); - - // now make a random sparse sample with at most 10 non-zero elements - for (int j = 0; j < 10; ++j) - { - int idx = rnd.get_random_32bit_number()%100; - double value = rnd.get_random_double(); - - sample[idx] = label*value; - } - - // Also save the samples we are generating so we can let the svm_c_linear_trainer - // learn from them below. - samples.push_back(sample); - labels.push_back(label); - } - - - { - print_spinner(); - dlog << LINFO << " test with sparse samples "; - decision_function df = linear_trainer.train(samples, labels); - - dlog << LINFO << "df.basis_vectors.size(): "<< df.basis_vectors.size(); - DLIB_TEST(df.basis_vectors.size() > 4); - - dlog << LINFO << "test scores: "<< test_binary_decision_function(df, samples, labels); - - // save the outputs of the decision function before we mess with it - std::vector prev_vals; - for (unsigned long i = 0; i < samples.size(); ++i) - prev_vals.push_back(df(samples[i])); - - df = simplify_linear_decision_function(df); - - dlog << LINFO << "df.basis_vectors.size(): "<< df.basis_vectors.size(); - DLIB_TEST(df.basis_vectors.size() == 1); - - dlog << LINFO << "test scores: "<< test_binary_decision_function(df, samples, labels); - - // now check that the simplified decision function still produces the same results - std::vector cur_vals; - for (unsigned long i = 0; i < samples.size(); ++i) - cur_vals.push_back(df(samples[i])); - - const double err = max(abs(mat(cur_vals) - mat(prev_vals))); - dlog << LINFO << "simplify error: "<< err; - DLIB_TEST(err < 1e-13); - - } - - - // same as above but call simplify_linear_decision_function() two times - { - print_spinner(); - dlog << LINFO << " test with sparse samples "; - decision_function df = linear_trainer.train(samples, labels); - - dlog << LINFO << "df.basis_vectors.size(): "<< df.basis_vectors.size(); - DLIB_TEST(df.basis_vectors.size() > 4); - - dlog << LINFO << "test scores: "<< test_binary_decision_function(df, samples, labels); - - // save the outputs of the decision function before we mess with it - std::vector prev_vals; - for (unsigned long i = 0; i < samples.size(); ++i) - prev_vals.push_back(df(samples[i])); - - df = simplify_linear_decision_function(df); - df = simplify_linear_decision_function(df); - - dlog << LINFO << "df.basis_vectors.size(): "<< df.basis_vectors.size(); - DLIB_TEST(df.basis_vectors.size() == 1); - - dlog << LINFO << "test scores: "<< test_binary_decision_function(df, samples, labels); - - // now check that the simplified decision function still produces the same results - std::vector cur_vals; - for (unsigned long i = 0; i < samples.size(); ++i) - cur_vals.push_back(df(samples[i])); - - const double err = max(abs(mat(cur_vals) - mat(prev_vals))); - dlog << LINFO << "simplify error: "<< err; - DLIB_TEST(err < 1e-13); - - } - - - { - print_spinner(); - dlog << LINFO << " test with dense samples "; - std::vector dense_samples(sparse_to_dense(samples)); - - // In addition to the rule we learned with the pegasos trainer lets also use our linear_trainer - // to learn a decision rule. - decision_function dense_df = dense_linear_trainer.train(dense_samples, labels); - - dlog << LINFO << "dense_df.basis_vectors.size(): "<< dense_df.basis_vectors.size(); - DLIB_TEST(dense_df.basis_vectors.size() > 4); - - dlog << LINFO << "test scores: "<< test_binary_decision_function(dense_df, dense_samples, labels); - - // save the outputs of the decision function before we mess with it - std::vector prev_vals; - for (unsigned long i = 0; i < dense_samples.size(); ++i) - prev_vals.push_back(dense_df(dense_samples[i])); - - dense_df = simplify_linear_decision_function(dense_df); - - dlog << LINFO << "dense_df.basis_vectors.size(): "<< dense_df.basis_vectors.size(); - DLIB_TEST(dense_df.basis_vectors.size() == 1); - - dlog << LINFO << "test scores: "<< test_binary_decision_function(dense_df, dense_samples, labels); - - - // now check that the simplified decision function still produces the same results - std::vector cur_vals; - for (unsigned long i = 0; i < dense_samples.size(); ++i) - cur_vals.push_back(dense_df(dense_samples[i])); - - const double err = max(abs(mat(cur_vals) - mat(prev_vals))); - dlog << LINFO << "simplify error: "<< err; - DLIB_TEST(err < 1e-13); - } - - // same as above but call simplify_linear_decision_function() two times - { - print_spinner(); - dlog << LINFO << " test with dense samples "; - std::vector dense_samples(sparse_to_dense(samples)); - - // In addition to the rule we learned with the pegasos trainer lets also use our linear_trainer - // to learn a decision rule. - decision_function dense_df = dense_linear_trainer.train(dense_samples, labels); - - dlog << LINFO << "dense_df.basis_vectors.size(): "<< dense_df.basis_vectors.size(); - DLIB_TEST(dense_df.basis_vectors.size() > 4); - - dlog << LINFO << "test scores: "<< test_binary_decision_function(dense_df, dense_samples, labels); - - // save the outputs of the decision function before we mess with it - std::vector prev_vals; - for (unsigned long i = 0; i < dense_samples.size(); ++i) - prev_vals.push_back(dense_df(dense_samples[i])); - - dense_df = simplify_linear_decision_function(dense_df); - dense_df = simplify_linear_decision_function(dense_df); - - dlog << LINFO << "dense_df.basis_vectors.size(): "<< dense_df.basis_vectors.size(); - DLIB_TEST(dense_df.basis_vectors.size() == 1); - - dlog << LINFO << "test scores: "<< test_binary_decision_function(dense_df, dense_samples, labels); - - - // now check that the simplified decision function still produces the same results - std::vector cur_vals; - for (unsigned long i = 0; i < dense_samples.size(); ++i) - cur_vals.push_back(dense_df(dense_samples[i])); - - const double err = max(abs(mat(cur_vals) - mat(prev_vals))); - dlog << LINFO << "simplify error: "<< err; - DLIB_TEST(err < 1e-13); - } - - { - print_spinner(); - - dlog << LINFO << " test with sparse samples and a vector normalizer"; - std::vector dense_samples(sparse_to_dense(samples)); - std::vector norm_samples; - - // make a normalizer and normalize everything - vector_normalizer normalizer; - normalizer.train(dense_samples); - for (unsigned long i = 0; i < dense_samples.size(); ++i) - norm_samples.push_back(normalizer(dense_samples[i])); - - normalized_function > dense_df; - - dense_df.normalizer = normalizer; - dense_df.function = dense_linear_trainer.train(norm_samples, labels); - - dlog << LINFO << "dense_df.function.basis_vectors.size(): "<< dense_df.function.basis_vectors.size(); - DLIB_TEST(dense_df.function.basis_vectors.size() > 4); - - dlog << LINFO << "test scores: "<< test_binary_decision_function(dense_df, dense_samples, labels); - - // save the outputs of the decision function before we mess with it - std::vector prev_vals; - for (unsigned long i = 0; i < dense_samples.size(); ++i) - prev_vals.push_back(dense_df(dense_samples[i])); - - - decision_function simple_df = simplify_linear_decision_function(dense_df); - - dlog << LINFO << "simple_df.basis_vectors.size(): "<< simple_df.basis_vectors.size(); - DLIB_TEST(simple_df.basis_vectors.size() == 1); - - dlog << LINFO << "test scores: "<< test_binary_decision_function(simple_df, dense_samples, labels); - - - // now check that the simplified decision function still produces the same results - std::vector cur_vals; - for (unsigned long i = 0; i < dense_samples.size(); ++i) - cur_vals.push_back(simple_df(dense_samples[i])); - - const double err = max(abs(mat(cur_vals) - mat(prev_vals))); - dlog << LINFO << "simplify error: "<< err; - DLIB_TEST(err < 1e-13); - - } - - } - }; - - // Create an instance of this object. Doing this causes this test - // to be automatically inserted into the testing framework whenever this cpp file - // is linked into the project. Note that since we are inside an unnamed-namespace - // we won't get any linker errors about the symbol a being defined multiple times. - sldf_tester a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/sliding_buffer.cpp b/lib/3rdParty/dlib/include/dlib/test/sliding_buffer.cpp deleted file mode 100644 index 449ea858..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/sliding_buffer.cpp +++ /dev/null @@ -1,439 +0,0 @@ -// Copyright (C) 2004 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include - -#include -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace std; - using namespace dlib; - - logger dlog("test.sliding_buffer"); - - template < - typename buf - > - void sliding_buffer_kernel_test ( - ) - /*! - requires - - buf is an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h - - buf is instantiated with T=unsigned char - ensures - - runs tests on buf for compliance with the specs - !*/ - { - - print_spinner(); - - buf test; - - DLIB_TEST(test.size() == 0); - - test.set_size(3); - buf test2; - - DLIB_TEST(test.size() == 8); - - for (int g = 0; g < 2; ++g) - { - - test.clear(); - - DLIB_TEST(test.size() == 0); - test.set_size(2); - - DLIB_TEST(test.size() == 4); - - - - test[0] = 'a'; - test[1] = 's'; - test[2] = 'd'; - test[3] = 'f'; - - unsigned long id = test.get_element_id(2); - DLIB_TEST(test[test.get_element_index(id)] == 'd'); - - - DLIB_TEST(test[0] == 'a'); - DLIB_TEST(test[1] == 's'); - DLIB_TEST(test[2] == 'd'); - DLIB_TEST(test[3] == 'f'); - - DLIB_TEST(test2.size() == 0); - swap(test,test2); - DLIB_TEST(test2.size() == 4); - - DLIB_TEST(test2[0] == 'a'); - DLIB_TEST(test2[1] == 's'); - DLIB_TEST(test2[2] == 'd'); - DLIB_TEST(test2[3] == 'f'); - - swap(test,test2); - - test.rotate_left(4); - - - DLIB_TEST(test[test.get_element_index(id)] == 'd'); - - DLIB_TEST(test[0] == 'a'); - DLIB_TEST(test[1] == 's'); - DLIB_TEST(test[2] == 'd'); - DLIB_TEST(test[3] == 'f'); - - test.rotate_right(1); - - DLIB_TEST(test[test.get_element_index(id)] == 'd'); - - DLIB_TEST(test[0] == 's'); - DLIB_TEST(test[1] == 'd'); - DLIB_TEST(test[2] == 'f'); - DLIB_TEST(test[3] == 'a'); - - - test.rotate_left(1); - - DLIB_TEST(test[test.get_element_index(id)] == 'd'); - DLIB_TEST(test[0] == 'a'); - DLIB_TEST(test[1] == 's'); - DLIB_TEST(test[2] == 'd'); - DLIB_TEST(test[3] == 'f'); - - - test.rotate_left(16); - - DLIB_TEST(test[test.get_element_index(id)] == 'd'); - DLIB_TEST(test[0] == 'a'); - DLIB_TEST(test[1] == 's'); - DLIB_TEST(test[2] == 'd'); - DLIB_TEST(test[3] == 'f'); - - - test.rotate_left(2); - - DLIB_TEST(test[test.get_element_index(id)] == 'd'); - - DLIB_TEST(test[0] == 'd'); - DLIB_TEST(test[1] == 'f'); - DLIB_TEST(test[2] == 'a'); - DLIB_TEST(test[3] == 's'); - - test.rotate_left(1); - - DLIB_TEST(test[test.get_element_index(id)] == 'd'); - DLIB_TEST(test[0] == 's'); - DLIB_TEST(test[1] == 'd'); - DLIB_TEST(test[2] == 'f'); - DLIB_TEST(test[3] == 'a'); - - test.rotate_left(1); - - DLIB_TEST(test[test.get_element_index(id)] == 'd'); - DLIB_TEST(test[0] == 'a'); - DLIB_TEST(test[1] == 's'); - DLIB_TEST(test[2] == 'd'); - DLIB_TEST(test[3] == 'f'); - - DLIB_TEST(test.size() == 4); - - test[0] = 'x'; - - DLIB_TEST(test[0] == 'x'); - DLIB_TEST(test[1] == 's'); - DLIB_TEST(test[2] == 'd'); - DLIB_TEST(test[3] == 'f'); - - test.rotate_left(1); - - DLIB_TEST_MSG(test[0] == 'f',test[0]); - DLIB_TEST(test[1] == 'x'); - DLIB_TEST(test[2] == 's'); - DLIB_TEST(test[3] == 'd'); - - - test[0] = 'x'; - - DLIB_TEST(test[0] == 'x'); - DLIB_TEST(test[1] == 'x'); - DLIB_TEST(test[2] == 's'); - DLIB_TEST(test[3] == 'd'); - - - test.rotate_left(1); - - - DLIB_TEST(test[0] == 'd'); - DLIB_TEST(test[1] == 'x'); - DLIB_TEST(test[2] == 'x'); - DLIB_TEST(test[3] == 's'); - - - - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == true); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == true); - - test.clear(); - test2.clear(); - - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == false); - - swap(test,test2); - - DLIB_TEST(test2.at_start() == false); - DLIB_TEST(test2.current_element_valid() == false); - DLIB_TEST(test2.move_next() == false); - DLIB_TEST(test2.at_start() == false); - DLIB_TEST(test2.current_element_valid() == false); - - - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.at_start() == false); - - test.set_size(3); - DLIB_TEST(test.size() == 8); - - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == true); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == true); - test.reset(); - DLIB_TEST(test.size() == 8); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == true); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == true); - - - test.rotate_right(1); - DLIB_TEST(test.size() == 8); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == true); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == true); - - test.rotate_left(1); - DLIB_TEST(test.size() == 8); - DLIB_TEST(test.at_start() == true); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == true); - DLIB_TEST(test.at_start() == false); - DLIB_TEST(test.current_element_valid() == true); - test.reset(); - - - for (unsigned long i = 0; i < test.size(); ++i) - { - test[i] = static_cast(i); - } - - unsigned long count = 0; - while (test.move_next()) - { - DLIB_TEST(test.element() == count); - ++count; - } - - DLIB_TEST(count == test.size()); - - - test2.clear(); - ostringstream sout; - istringstream sin; - - serialize(test,sout); - sin.str(sout.str()); - deserialize(test2,sin); - - char ch; - sin >> ch; - DLIB_TEST( !sin); - - DLIB_TEST(test2.size() == test.size()); - - - for (unsigned long i = 0; i < test.size(); ++i) - { - DLIB_TEST_MSG(test[i] == test2[i], - "\ni: " << i << - "\ntest[i]: " << test[i] << - "\ntest2[i]: " << test2[i]); - } - - count = 0; - while (test.move_next() && test2.move_next()) - { - DLIB_TEST(test.element() == count); - DLIB_TEST(test2.element() == count); - ++count; - } - - DLIB_TEST(test2.size() == count); - DLIB_TEST(test.size() == count); - - test2.clear(); - - - } // for (int g = 0; g < 2; ++g) - - - } - - - - void test_circular_buffer() - { - circular_buffer buf; - - DLIB_TEST(buf.size() == 0); - - buf.assign(4, 0); - DLIB_TEST(buf.size() == 4); - - DLIB_TEST(buf[0] == 0); - DLIB_TEST(buf[1] == 0); - DLIB_TEST(buf[2] == 0); - DLIB_TEST(buf[3] == 0); - buf.push_back(1); - DLIB_TEST(buf[0] == 0); - DLIB_TEST(buf[1] == 0); - DLIB_TEST(buf[2] == 0); - DLIB_TEST(buf[3] == 1); - buf.push_back(2); - DLIB_TEST(buf[0] == 0); - DLIB_TEST(buf[1] == 0); - DLIB_TEST(buf[2] == 1); - DLIB_TEST(buf[3] == 2); - buf.push_front(3); - DLIB_TEST(buf[0] == 3); - DLIB_TEST(buf[1] == 0); - DLIB_TEST(buf[2] == 0); - DLIB_TEST(buf[3] == 1); - buf.push_front(4); - DLIB_TEST(buf.front() == 4); - DLIB_TEST(buf[0] == 4); - DLIB_TEST(buf[1] == 3); - DLIB_TEST(buf[2] == 0); - DLIB_TEST(buf[3] == 0); - - buf.assign(4, 5); - DLIB_TEST(buf[0] == 5); - DLIB_TEST(buf[1] == 5); - DLIB_TEST(buf[2] == 5); - DLIB_TEST(buf[3] == 5); - - buf.push_back(3); - DLIB_TEST(buf[0] == 5); - DLIB_TEST(buf[1] == 5); - DLIB_TEST(buf[2] == 5); - DLIB_TEST(buf[3] == 3); - buf.push_back(2); - DLIB_TEST(buf[0] == 5); - DLIB_TEST(buf[1] == 5); - DLIB_TEST(buf[2] == 3); - DLIB_TEST(buf[3] == 2); - buf.push_back(1); - DLIB_TEST(buf[0] == 5); - DLIB_TEST(buf[1] == 3); - DLIB_TEST(buf[2] == 2); - DLIB_TEST(buf[3] == 1); - buf.push_back(0); - DLIB_TEST(buf[0] == 3); - DLIB_TEST(buf[1] == 2); - DLIB_TEST(buf[2] == 1); - DLIB_TEST(buf[3] == 0); - buf.push_back(-1); - DLIB_TEST(buf.back() == -1); - DLIB_TEST(buf[0] == 2); - DLIB_TEST(buf[1] == 1); - DLIB_TEST(buf[2] == 0); - DLIB_TEST(buf[3] == -1); - - buf.resize(1); - buf[0] = 9; - DLIB_TEST(buf.size() == 1); - DLIB_TEST(buf[0] == 9); - buf.push_back(1); - DLIB_TEST(buf[0] == 1); - buf.push_back(4); - DLIB_TEST(buf[0] == 4); - buf.push_front(3); - DLIB_TEST(buf[0] == 3); - - buf.clear(); - DLIB_TEST(buf.size() == 0); - - buf.assign(3, 0); - - circular_buffer buf2, buf3; - - buf.push_back(1); - buf.push_back(2); - - ostringstream sout; - serialize(buf, sout); - istringstream sin(sout.str()); - deserialize(buf2, sin); - - DLIB_TEST(buf.size() == buf2.size()); - for (unsigned long i = 0; i < buf.size(); ++i) - DLIB_TEST(buf[i] == buf2[i]); - - buf.swap(buf3); - DLIB_TEST(buf.size() == 0); - DLIB_TEST(buf3.size() == buf2.size()); - for (unsigned long i = 0; i < buf3.size(); ++i) - DLIB_TEST(buf3[i] == buf2[i]); - - - - } - - - - class sliding_buffer_tester : public tester - { - public: - sliding_buffer_tester ( - ) : - tester ("test_sliding_buffer", - "Runs tests on the sliding_buffer component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a"; - sliding_buffer_kernel_test::kernel_1a> (); - dlog << LINFO << "testing kernel_1a_c"; - sliding_buffer_kernel_test::kernel_1a_c>(); - - test_circular_buffer(); - } - } a; - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/smart_pointers.cpp b/lib/3rdParty/dlib/include/dlib/test/smart_pointers.cpp deleted file mode 100644 index b9907731..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/smart_pointers.cpp +++ /dev/null @@ -1,440 +0,0 @@ -// Copyright (C) 2007 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - bool used_array_delete; - template - struct test_deleter - { - void operator() (T* item) const - { - used_array_delete = false; - delete item; - } - }; - - template - struct test_deleter - { - void operator() (T* item) const - { - used_array_delete = true; - delete [] item; - } - }; - - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.smart_pointers"); - - int counter = 0; - struct base - { - int num; - virtual ~base() {} - }; - - struct derived : public base - { - derived() { ++counter; } - ~derived() { --counter; } - }; - - int deleter_called = 0; - void deleter ( derived* p) { ++deleter_called; delete p; } - void deleter_base ( base* p) { ++deleter_called; delete p; } - typedef void (*D)(derived*); - typedef void (*Db)(base*); - - void smart_pointers_test ( - ) - /*! - ensures - - runs tests on the smart pointers for compliance with the specs - !*/ - { - counter = 0; - deleter_called = 0; - - { - DLIB_TEST_MSG(counter == 0,counter); - scoped_ptr p1(new derived); - scoped_ptr p2(new derived); - scoped_ptr p3; - DLIB_TEST_MSG(counter == 2,counter); - DLIB_TEST(!p3); - - p1->num = 1; - p2->num = 2; - DLIB_TEST(p1->num == 1); - DLIB_TEST(p2->num == 2); - - (*p1).num = 3; - (*p2).num = 4; - DLIB_TEST(p1->num == 3); - DLIB_TEST(p2->num == 4); - - DLIB_TEST_MSG(counter == 2,counter); - - DLIB_TEST(p1); - DLIB_TEST(p2); - - DLIB_TEST_MSG(counter == 2,counter); - p1.reset(); - DLIB_TEST_MSG(counter == 1,counter); - DLIB_TEST(!p1); - DLIB_TEST(p2); - p1.reset(new derived); - DLIB_TEST_MSG(counter == 2,counter); - DLIB_TEST(p1); - - - DLIB_TEST_MSG(counter == 2,counter); - p2.reset(); - DLIB_TEST_MSG(counter == 1,counter); - DLIB_TEST(!p2); - derived* d = new derived; - p2.reset(d); - DLIB_TEST(p2.get() == d); - DLIB_TEST_MSG(counter == 2,counter); - DLIB_TEST(p2); - DLIB_TEST(!p3); - p2->num = 9; - swap(p2,p3); - DLIB_TEST(!p2); - DLIB_TEST(p3); - DLIB_TEST(p3->num == 9); - p2.swap(p3); - DLIB_TEST(p2); - DLIB_TEST(!p3); - DLIB_TEST(p2->num == 9); - - - DLIB_TEST_MSG(counter == 2,counter); - - } - DLIB_TEST_MSG(counter == 0,counter); - - { - base* realp1 = new derived; - derived* realp2 = new derived; - dlib::shared_ptr p1(realp1); - dlib::shared_ptr p2(realp2,&deleter); - dlib::shared_ptr p3; - dlib::shared_ptr p4; - DLIB_TEST(p4.get() == 0); - DLIB_TEST(p1); - DLIB_TEST(p2); - DLIB_TEST(!p3); - DLIB_TEST(!p4); - DLIB_TEST(p1.get() == realp1); - DLIB_TEST(p2.get() == realp2); - p1->num = 1; - p2->num = 2; - DLIB_TEST((*p1).num == 1); - DLIB_TEST((*p2).num == 2); - - p1.swap(p3); - DLIB_TEST(!p1); - DLIB_TEST(p3); - DLIB_TEST((*p3).num == 1); - DLIB_TEST(p3->num == 1); - swap(p1,p3); - DLIB_TEST(p1); - DLIB_TEST(!p3); - DLIB_TEST((*p1).num == 1); - DLIB_TEST(p1->num == 1); - DLIB_TEST_MSG(counter == 2,counter); - - DLIB_TEST(p1.unique()); - DLIB_TEST(p2.unique()); - DLIB_TEST(!p3.unique()); - DLIB_TEST(!p4.unique()); - - DLIB_TEST(p1.use_count() == 1); - DLIB_TEST(p2.use_count() == 1); - DLIB_TEST(p3.use_count() == 0); - DLIB_TEST(p4.use_count() == 0); - - dlib::shared_ptr p11(p1); - - DLIB_TEST(!p1.unique()); - DLIB_TEST(p2.unique()); - DLIB_TEST(!p3.unique()); - DLIB_TEST(!p4.unique()); - - DLIB_TEST(p1.use_count() == 2); - DLIB_TEST(p2.use_count() == 1); - DLIB_TEST(p3.use_count() == 0); - DLIB_TEST(p4.use_count() == 0); - - dlib::shared_ptr p22(p2); - - DLIB_TEST(!p1.unique()); - DLIB_TEST(!p2.unique()); - DLIB_TEST(!p3.unique()); - DLIB_TEST(!p4.unique()); - - DLIB_TEST(p1.use_count() == 2); - DLIB_TEST(p2.use_count() == 2); - DLIB_TEST(p3.use_count() == 0); - DLIB_TEST(p4.use_count() == 0); - - DLIB_TEST(p11.get() == realp1); - DLIB_TEST(p11 == p1); - DLIB_TEST(p22 == p2); - DLIB_TEST(p3 == p4); - DLIB_TEST(p11 != p22); - DLIB_TEST(p1 != p2); - DLIB_TEST(p3 != p1); - DLIB_TEST(p3 != p11); - DLIB_TEST(p3 != p2); - - - p1 = p1 = p1; - DLIB_TEST(p1.use_count() == 2); - DLIB_TEST(p1->num == 1); - DLIB_TEST(p11.use_count() == 2); - p1.reset(); - DLIB_TEST(p1.get() == 0); - DLIB_TEST(p1.use_count() == 0); - DLIB_TEST(p1.unique() == false); - DLIB_TEST(p11.use_count() == 1); - p11 = p2; - DLIB_TEST(p1.use_count() == 0); - DLIB_TEST(p1.unique() == false); - DLIB_TEST(p11.use_count() == 3); - DLIB_TEST(p11.unique() == false); - - // now p11, p2, and p22 all reference the same thing and the rest are null - DLIB_TEST_MSG((p11 < p2) == false,"") - DLIB_TEST_MSG((p2 < p11) == false,"") - - DLIB_TEST(get_deleter(p4) == 0); - p4 = p2; - DLIB_TEST(get_deleter(p4) != 0); - DLIB_TEST(get_deleter(p4) == get_deleter(p2)); - DLIB_TEST(get_deleter(p4) == get_deleter(p11)); - DLIB_TEST(get_deleter(p4) == 0); - - realp1 = new derived; - p1.reset(realp1, &deleter_base); - DLIB_TEST(p1.get() == realp1); - DLIB_TEST(p1.unique()); - DLIB_TEST(p1.use_count() == 1); - DLIB_TEST(*get_deleter(p1) == &deleter_base); - DLIB_TEST(p1 != p4); - p4 = dynamic_pointer_cast(p1); - DLIB_TEST(!p1.unique()); - DLIB_TEST(p1.use_count() == 2); - DLIB_TEST(p1 == p4); - - realp1 = new derived; - p1.reset(realp1); - DLIB_TEST(p1.get() == realp1); - DLIB_TEST(p1.unique()); - DLIB_TEST(p1.use_count() == 1); - DLIB_TEST(get_deleter(p1) == 0); - - - auto_ptr ap1(new derived); - auto_ptr ap2(new derived); - ap1->num = 35; - ap2->num = 36; - - DLIB_TEST(ap1.get() != 0); - DLIB_TEST(ap2.get() != 0); - p1 = ap2; - p2 = ap1; - - DLIB_TEST(ap1.get() == 0); - DLIB_TEST(p1.unique()); - DLIB_TEST(p1.use_count() == 1); - DLIB_TEST(ap2.get() == 0); - DLIB_TEST(p2.unique()); - DLIB_TEST(p2.use_count() == 1); - DLIB_TEST(p1->num == 36); - DLIB_TEST(p2->num == 35); - - } - - DLIB_TEST_MSG(counter == 0,counter); - DLIB_TEST_MSG(deleter_called == 2,counter); - - dlib::weak_ptr wp4; - { - dlib::shared_ptr p1(new derived, &deleter_base); - dlib::shared_ptr p2; - dlib::shared_ptr p3; - - dlib::weak_ptr wp1; - dlib::weak_ptr wp2; - dlib::weak_ptr wp3; - - dlib::weak_ptr wp1c(p1); - dlib::weak_ptr wp2c(p1); - dlib::weak_ptr wp3c(p2); - - DLIB_TEST(wp1c.use_count() == 1); - DLIB_TEST(wp1c.lock() == p1); - DLIB_TEST(wp1c.expired() == false); - - DLIB_TEST(wp2c.use_count() == 1); - DLIB_TEST(wp2c.lock() == p1); - DLIB_TEST(wp2c.expired() == false); - - DLIB_TEST(wp3c.use_count() == 0); - DLIB_TEST(wp3c.lock() == dlib::shared_ptr()); - DLIB_TEST(wp3c.expired() == true); - - DLIB_TEST(wp2.use_count() == 0); - DLIB_TEST(wp2.expired() == true); - DLIB_TEST(wp2.lock().use_count() == 0); - DLIB_TEST(wp2.lock().unique() == false); - - wp1 = p1; - wp2 = wp1; - wp3 = p1; - - DLIB_TEST(p1.use_count() == 1); - DLIB_TEST(p1.unique()); - DLIB_TEST(wp1.use_count() == 1); - DLIB_TEST(wp2.use_count() == 1); - DLIB_TEST(wp3.use_count() == 1); - DLIB_TEST(wp1.expired() == false); - DLIB_TEST(wp2.expired() == false); - DLIB_TEST(wp3.expired() == false); - DLIB_TEST(wp1.lock() == p1); - DLIB_TEST(wp2.lock() == p1); - DLIB_TEST(wp3.lock() == p1); - - wp3.reset(); - - DLIB_TEST(p1.use_count() == 1); - DLIB_TEST(p1.unique()); - DLIB_TEST(wp1.use_count() == 1); - DLIB_TEST(wp2.use_count() == 1); - DLIB_TEST(wp3.use_count() == 0); - DLIB_TEST(wp1.expired() == false); - DLIB_TEST(wp2.expired() == false); - DLIB_TEST(wp3.expired() == true); - DLIB_TEST(wp1.lock() == p1); - DLIB_TEST(wp2.lock() == p1); - DLIB_TEST(wp3.lock() == dlib::shared_ptr()); - - - p1.reset(); - - DLIB_TEST(p1.use_count() == 0); - DLIB_TEST(p1.unique() == false); - DLIB_TEST(wp1.use_count() == 0); - DLIB_TEST(wp2.use_count() == 0); - DLIB_TEST(wp3.use_count() == 0); - DLIB_TEST(wp1.expired() == true); - DLIB_TEST(wp2.expired() == true); - DLIB_TEST(wp3.expired() == true); - DLIB_TEST(wp1.lock() == dlib::shared_ptr()); - DLIB_TEST(wp2.lock() == dlib::shared_ptr()); - DLIB_TEST(wp3.lock() == dlib::shared_ptr()); - - p1.reset(new derived); - - DLIB_TEST(p1.use_count() == 1); - DLIB_TEST(p1.unique() == true); - DLIB_TEST(wp1.use_count() == 0); - DLIB_TEST(wp2.use_count() == 0); - DLIB_TEST(wp3.use_count() == 0); - DLIB_TEST(wp1.expired() == true); - DLIB_TEST(wp2.expired() == true); - DLIB_TEST(wp3.expired() == true); - DLIB_TEST(wp1.lock() == dlib::shared_ptr()); - DLIB_TEST(wp2.lock() == dlib::shared_ptr()); - DLIB_TEST(wp3.lock() == dlib::shared_ptr()); - - DLIB_TEST(wp4.expired() == true); - DLIB_TEST(wp4.lock() == dlib::shared_ptr()); - wp4 = p1; - p3 = p1; - DLIB_TEST(wp4.expired() == false); - DLIB_TEST(wp4.lock() == p3); - - - bool ok = false; - try { - dlib::shared_ptr bad_ptr(wp1); - } catch (dlib::bad_weak_ptr&) - { - ok = true; - } - DLIB_TEST(ok); - } - DLIB_TEST(wp4.expired() == true); - DLIB_TEST(wp4.lock() == dlib::shared_ptr()); - - - DLIB_TEST_MSG(counter == 0,counter); - DLIB_TEST_MSG(deleter_called == 3,counter); - - { - scoped_ptr a(new int[10]); - - { - used_array_delete = false; - scoped_ptr > b(new int[10]); - - for (int i = 0; i < 10; ++i) - { - a[i] = i; - b[i] = i; - } - } - DLIB_TEST(used_array_delete == true); - - - { - used_array_delete = true; - scoped_ptr > c(new int); - } - DLIB_TEST(used_array_delete == false); - - scoped_ptr const_a(new int[10]); - - } - - } - - - - class smart_pointers_tester : public tester - { - public: - smart_pointers_tester ( - ) : - tester ("test_smart_pointers", - "Runs tests on the smart pointers.") - {} - - void perform_test ( - ) - { - smart_pointers_test(); - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/sockets.cpp b/lib/3rdParty/dlib/include/dlib/test/sockets.cpp deleted file mode 100644 index ab036144..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/sockets.cpp +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace { - - using namespace test; - using namespace dlib; - using namespace std; - - dlib::mutex gm; - dlib::signaler gs(gm); - const char magic_num = 42; - const int min_bytes_sent = 10000; - int assigned_port; - - logger dlog("test.sockets"); - -// ---------------------------------------------------------------------------------------- - - class serv : public server::kernel_1a_c - { - public: - serv ( - ) : - error_occurred (false), - got_connections(false) - {} - - void on_listening_port_assigned ( - ) - { - auto_mutex M(gm); - assigned_port = get_listening_port(); - gs.broadcast(); - } - - - void on_connect ( - connection& con - ) - { - dlog << LINFO << "in serv::on_connect(): got new connection"; - int status; - int count = 0; - char buf[100]; - while ((status = con.read(buf,sizeof(buf))) > 0) - { - for (int i = 0; i < status; ++i) - { - if (buf[i] != magic_num) - { - tag = 4.0; - error_occurred = true; - } - } - count += status; - } - if (count != min_bytes_sent) - { - tag = 5.0; - error_occurred = true; - } - got_connections = true; - dlog << LINFO << "in serv::on_connect(): on_connect ending"; - } - - bool error_occurred; - bool got_connections; - double tag; - }; - -// ---------------------------------------------------------------------------------------- - - class thread_container : public multithreaded_object - { - public: - - serv& srv; - - thread_container ( - serv& srv_ - ) : srv(srv_) - { - for (int i = 0; i < 10; ++i) - register_thread(*this, &thread_container::thread_proc); - - // start up the threads - start(); - } - - ~thread_container () - { - // wait for all threads to terminate - wait(); - } - - void thread_proc ( - ) - { - try - { - dlog << LTRACE << "enter thread"; - { - auto_mutex M(gm); - while (assigned_port == 0) - gs.wait(); - } - - int status; - scoped_ptr con; - string hostname; - string ip; - status = get_local_hostname(hostname); - if (status) - { - srv.tag = 1.0; - srv.error_occurred = true; - srv.clear(); - dlog << LERROR << "leaving thread, line: " << __LINE__; - dlog << LERROR << "get_local_hostname() failed"; - return; - } - - status = hostname_to_ip(hostname,ip); - if (status) - { - srv.tag = 2.0; - srv.error_occurred = true; - srv.clear(); - dlog << LERROR << "leaving thread, line: " << __LINE__; - dlog << LERROR << "hostname_to_ip() failed"; - return; - } - - dlog << LTRACE << "try to connect to the server at port " << srv.get_listening_port(); - status = create_connection(con,srv.get_listening_port(),ip); - if (status) - { - srv.tag = 3.0; - srv.error_occurred = true; - srv.clear(); - dlog << LERROR << "leaving thread, line: " << __LINE__; - dlog << LERROR << "create_connection() failed"; - return; - } - - dlog << LTRACE << "sending magic_num to server"; - int i; - for (i = 0; i < min_bytes_sent; ++i) - { - con->write(&magic_num,1); - } - - dlog << LTRACE << "shutting down connection to server"; - close_gracefully(con); - dlog << LTRACE << "finished calling close_gracefully() on the connection"; - } - catch (exception& e) - { - srv.error_occurred = true; - dlog << LERROR << "exception thrown in thread_proc(): " << e.what(); - cout << "exception thrown in thread_proc(): " << e.what(); - } - dlog << LTRACE << "exit thread"; - } - }; - - void run_server(serv* srv) - { - dlog << LTRACE << "calling srv.start()"; - srv->start(); - dlog << LTRACE << "srv.start() just ended."; - } - - void sockets_test ( - ) - /*! - requires - - sockets is an implementation of sockets/sockets_kernel_abstract.h - is instantiated with int - ensures - - runs tests on sockets for compliance with the specs - !*/ - { - - dlog << LTRACE << "starting test"; - serv srv; - - assigned_port = 0; - - - dlog << LTRACE << "spawning threads"; - thread_container stuff(srv); - - - - thread_function thread2(run_server, &srv); - - // wait until all the sending threads have ended - stuff.wait(); - - if (srv.error_occurred) - { - dlog << LDEBUG << "tag: " << srv.tag; - } - - srv.clear(); - - dlog << LTRACE << "ending successful test"; - DLIB_TEST( !srv.error_occurred); - DLIB_TEST( srv.got_connections); - } - -// ---------------------------------------------------------------------------------------- - - - class sockets_tester : public tester - { - public: - sockets_tester ( - ) : - tester ("test_sockets", - "Runs tests on the sockets component.") - {} - - void perform_test ( - ) - { - sockets_test(); - } - } a; - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/sockets2.cpp b/lib/3rdParty/dlib/include/dlib/test/sockets2.cpp deleted file mode 100644 index c6fbbf50..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/sockets2.cpp +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright (C) 2008 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "tester.h" -#include -#include -#include -#include - -// This is called an unnamed-namespace and it has the effect of making everything -// inside this file "private" so that everything you declare will have static linkage. -// Thus we won't have any multiply defined symbol errors coming out of the linker when -// we try to compile the test suite. -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - // Declare the logger we will use in this test. The name of the logger - // should start with "test." - dlib::logger dlog("test.sockets2"); - - - class sockets2_tester : public tester, private multithreaded_object - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a unit test. When it is constructed - it adds itself into the testing framework. - !*/ - - short port_num; - string data_to_send; - - bool test_failed; - - void write_thread ( - ) - { - try - { - scoped_ptr con(connect("127.0.0.1", port_num)); - - // Send a copy of the data down the connection so we can test our the read() function - // that uses timeouts in the main thread. - if (con->write(data_to_send.data(), data_to_send.size()) != (int)data_to_send.size()) - { - test_failed = true; - dlog << LERROR << "failed to send all the data down the connection"; - } - - close_gracefully(con,300000); - } - catch (exception& e) - { - test_failed = true; - dlog << LERROR << e.what(); - } - } - - void no_write_thread ( - ) - { - try - { - scoped_ptr con(connect("127.0.0.1", port_num)); - - // just do nothing until the connection closes - char ch; - con->read(&ch, 1); - dlog << LDEBUG << "silent connection finally closing"; - } - catch (exception& e) - { - test_failed = true; - dlog << LERROR << e.what(); - } - } - - public: - sockets2_tester ( - ) : - tester ( - "test_sockets2", // the command line argument name for this test - "Run sockets2 tests.", // the command line argument description - 0 // the number of command line arguments for this test - ) - { - register_thread(*this, &sockets2_tester::write_thread); - register_thread(*this, &sockets2_tester::write_thread); - register_thread(*this, &sockets2_tester::write_thread); - register_thread(*this, &sockets2_tester::write_thread); - register_thread(*this, &sockets2_tester::write_thread); - register_thread(*this, &sockets2_tester::no_write_thread); - } - - void perform_test ( - ) - { - run_tests(0); - run_tests(40); - } - - void run_tests ( - unsigned long timeout_to_use - ) - { - // make sure there aren't any threads running - wait(); - - port_num = 5000; - test_failed = false; - - print_spinner(); - data_to_send = "oi 2m3ormao2m fo2im3fo23mi o2mi3 foa2m3fao23ifm2o3fmia23oima23iom3giugbiua"; - // make the block of data much larger - for (int i = 0; i < 11; ++i) - data_to_send = data_to_send + data_to_send; - - dlog << LINFO << "data block size: " << data_to_send.size(); - - - scoped_ptr list; - DLIB_TEST(create_listener(list, port_num, "127.0.0.1") == 0); - DLIB_TEST(list); - - // kick off the sending threads - start(); - - - dlib::array > cons; - std::vector bytes_received(6,0); - scoped_ptr con_temp; - - // accept the 6 connections we should get - for (int i = 0; i < 6; ++i) - { - DLIB_TEST(list->accept(con_temp) == 0); - cons.push_back(con_temp); - print_spinner(); - } - - int finished_cons = 0; - - // now receive all the bytes from the sending threads - while (finished_cons < 5) - { - for (unsigned long i = 0; i < cons.size(); ++i) - { - if (cons[i]) - { - const int buf_size = 3000; - char buf[buf_size]; - - int status = cons[i]->read(buf, buf_size, timeout_to_use); - - if (status > 0) - { - DLIB_TEST(equal(buf, buf+status, data_to_send.begin()+bytes_received[i])); - bytes_received[i] += status; - } - else if (status == 0) - { - // the connection is closed to kill it - cons[i].reset(); - ++finished_cons; - } - } - } - print_spinner(); - } - - for (unsigned long i = 0; i < bytes_received.size(); ++i) - { - DLIB_TEST(bytes_received[i] == (long)data_to_send.size() || cons[i]); - } - - - dlog << LINFO << "All data received correctly"; - - cons.clear(); - - - print_spinner(); - - DLIB_TEST(test_failed == false); - - - // wait for all the sending threads to terminate - wait(); - } - }; - - // Create an instance of this object. Doing this causes this test - // to be automatically inserted into the testing framework whenever this cpp file - // is linked into the project. Note that since we are inside an unnamed-namespace - // we won't get any linker errors about the symbol a being defined multiple times. - sockets2_tester a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/sockstreambuf.cpp b/lib/3rdParty/dlib/include/dlib/test/sockstreambuf.cpp deleted file mode 100644 index bc5b95a6..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/sockstreambuf.cpp +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - dlib::mutex m; - dlib::signaler s(m); - bool thread_running; - - logger dlog("test.sockstreambuf"); - -// ---------------------------------------------------------------------------------------- - - template - struct thread_proc_struct - { - static void thread_proc ( - void* param - ) - { - - listener& list = *static_cast(param); - connection* con; - list.accept(con); - - ssb buf(con); - ostream out(&buf); - - - char ch; - char* bigbuf = new char[1000000]; - - - for (int i = 'a'; i < 'z'; ++i) - { - ch = i; - out << ch << " "; - } - - out.put('A'); - - for (int i = 0; i < 256; ++i) - { - ch = i; - out.write(&ch,1); - } - - for (int i = -100; i < 25600; ++i) - { - out << i << " "; - } - - out.put('A'); - - for (int i = -100; i < 25600; ++i) - { - out.write((char*)&i,sizeof(i)); - } - - for (int i = 0; i < 1000000; ++i) - { - bigbuf[i] = (i&0xFF); - } - out.write(bigbuf,1000000); - - out.put('d'); - out.put('a'); - out.put('v'); - out.put('i'); - out.put('s'); - - - string tstring = "this is a test"; - int tint = -853; - unsigned int tuint = 89; - serialize(tstring,out); - serialize(tint,out); - serialize(tuint,out); - - - out.flush(); - - - auto_mutex M(m); - thread_running = false; - s.signal(); - - dlib::sleep(300); - delete con; - delete &list; - - delete [] bigbuf; - } - }; - - template - void sockstreambuf_test ( - ) - /*! - requires - - ssb is an implementation of sockstreambuf/sockstreambuf_kernel_abstract.h - ensures - - runs tests on ssb for compliance with the specs - !*/ - { - char ch; - vector vbuf; - vbuf.resize(1000000); - char* bigbuf = &vbuf[0]; - connection* con; - - print_spinner(); - thread_running = true; - listener* list; - if (create_listener(list,0)) - { - DLIB_TEST_MSG(false, "Unable to create a listener"); - } - - create_new_thread(&thread_proc_struct::thread_proc,list); - - if (create_connection(con,list->get_listening_port(),"127.0.0.1")) - { - DLIB_TEST_MSG(false, "Unable to create a connection"); - } - - // make sure con gets deleted - scoped_ptr del_con(con); - - ssb buf(con); - istream in(&buf); - - - - for (int i = 'a'; i < 'z'; ++i) - { - in >> ch; - char c = i; - DLIB_TEST_MSG(ch == c,"ch: " << (int)ch << " c: " << (int)c); - } - - in.get(); - DLIB_TEST_MSG(in.peek() == 'A', "*" << in.peek() << "*"); - in.get(); - - for (int i = 0; i < 256; ++i) - { - in.read(&ch,1); - char c = i; - DLIB_TEST_MSG(ch == c,"ch: " << (int)ch << " c: " << (int)c ); - } - - for (int i = -100; i < 25600; ++i) - { - int n = 0; - in >> n; - DLIB_TEST_MSG(n == i,"n: " << n << " i:" << i); - } - - in.get(); - DLIB_TEST_MSG(in.peek() == 'A', "*" << in.peek() << "*"); - in.get(); - - for (int i = -100; i < 25600; ++i) - { - int n; - in.read((char*)&n,sizeof(n)); - DLIB_TEST_MSG(n == i,"n: " << n << " i:" << i); - } - - in.read(bigbuf,1000000); - for (int i = 0; i < 1000000; ++i) - { - DLIB_TEST(bigbuf[i] == (char)(i&0xFF)); - } - - DLIB_TEST(in.get() == 'd'); - DLIB_TEST(in.get() == 'a'); - DLIB_TEST(in.get() == 'v'); - DLIB_TEST(in.get() == 'i'); - - DLIB_TEST(in.peek() == 's'); - - DLIB_TEST(in.get() == 's'); - - in.putback('s'); - DLIB_TEST(in.peek() == 's'); - - DLIB_TEST(in.get() == 's'); - - - string tstring; - int tint; - unsigned int tuint; - deserialize(tstring,in); - deserialize(tint,in); - deserialize(tuint,in); - - DLIB_TEST(tstring == "this is a test"); - DLIB_TEST(tint == -853); - DLIB_TEST(tuint == 89); - - - - auto_mutex M(m); - while (thread_running) - s.wait(); - - } - -// ---------------------------------------------------------------------------------------- - - - class sockstreambuf_tester : public tester - { - public: - sockstreambuf_tester ( - ) : - tester ("test_sockstreambuf", - "Runs tests on the sockstreambuf component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing sockstreambuf"; - sockstreambuf_test(); - dlog << LINFO << "testing sockstreambuf_unbuffered"; - sockstreambuf_test(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/sparse_vector.cpp b/lib/3rdParty/dlib/include/dlib/test/sparse_vector.cpp deleted file mode 100644 index 97b60b7b..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/sparse_vector.cpp +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright (C) 2012 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include -#include "tester.h" -#include -#include -#include -#include -#include - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - dlib::logger dlog("test.sparse_vector"); - - void test_sparse_matrix_vector_multiplies() - { - dlib::rand rnd; - - const long size = 30; - - for (int iter = 0; iter < 10; ++iter) - { - print_spinner(); - - std::vector edges; - std::vector oedges; - matrix M(size,size); - M = 0; - for (long i = 0; i < M.size()/3; ++i) - { - const long r = rnd.get_random_32bit_number()%M.nr(); - const long c = rnd.get_random_32bit_number()%M.nc(); - const double d = rnd.get_random_gaussian()*10; - M(r,c) += d; - oedges.push_back(ordered_sample_pair(r,c,d)); - } - - matrix SM(size,size); - SM = 0; - for (long i = 0; i < SM.size()/3; ++i) - { - const long r = rnd.get_random_32bit_number()%SM.nr(); - const long c = rnd.get_random_32bit_number()%SM.nc(); - const double d = rnd.get_random_gaussian()*10; - SM(r,c) += d; - if (r != c) - SM(c,r) += d; - edges.push_back(sample_pair(r,c,d)); - } - - const matrix v = randm(size,1); - - matrix result; - - sparse_matrix_vector_multiply(oedges, v, result); - DLIB_TEST_MSG(length(M*v - result) < 1e-12, length(M*v - result)); - - sparse_matrix_vector_multiply(edges, v, result); - DLIB_TEST_MSG(length(SM*v - result) < 1e-12, length(SM*v - result)); - - } - } - -// ---------------------------------------------------------------------------------------- - - void test_sparse_matrix_vector_multiply1() - { - print_spinner(); - std::map sv; - sv[2] = 8; - sv[6] = 2.3; - - matrix v; - v = 0; - v(2) = 8; - v(6) = 2.3; - - - matrix r1, r2; - - r1 = gaussian_randm(4,10)*v; - r2 = sparse_matrix_vector_multiply(gaussian_randm(4,std::numeric_limits::max()),sv); - - DLIB_TEST(max(abs(r1-r2)) < 1e-15); - } - -// ---------------------------------------------------------------------------------------- - - void test_sparse_matrix_vector_multiply2() - { - std::vector > sv; - sv.push_back(make_pair(6, 1.42)); - sv.push_back(make_pair(3, 5)); - - matrix v; - v = 0; - v(3) = 5; - v(6) = 1.42; - - - matrix r1, r2; - - r1 = gaussian_randm(3,9)*v; - r2 = sparse_matrix_vector_multiply(gaussian_randm(3,std::numeric_limits::max()),sv); - - DLIB_TEST(max(abs(r1-r2)) < 1e-15); - } - -// ---------------------------------------------------------------------------------------- - - void test_make_sparse_vector_inplace() - { - std::vector > vect; - vect.push_back(make_pair(4,1)); - vect.push_back(make_pair(0,1)); - vect.push_back(make_pair(4,1)); - vect.push_back(make_pair(3,1)); - vect.push_back(make_pair(8,1)); - vect.push_back(make_pair(8,1)); - vect.push_back(make_pair(8,1)); - vect.push_back(make_pair(8,1)); - - make_sparse_vector_inplace(vect); - - DLIB_TEST(vect.size() == 4); - DLIB_TEST(vect[0].first == 0); - DLIB_TEST(vect[1].first == 3); - DLIB_TEST(vect[2].first == 4); - DLIB_TEST(vect[3].first == 8); - - DLIB_TEST(vect[0].second == 1); - DLIB_TEST(vect[1].second == 1); - DLIB_TEST(vect[2].second == 2); - DLIB_TEST(vect[3].second == 4); - } - -// ---------------------------------------------------------------------------------------- - - class sparse_vector_tester : public tester - { - public: - sparse_vector_tester ( - ) : - tester ( - "test_sparse_vector", // the command line argument name for this test - "Run tests on the sparse_vector routines.", // the command line argument description - 0 // the number of command line arguments for this test - ) - { - } - - - void perform_test ( - ) - { - test_make_sparse_vector_inplace(); - - std::map v; - v[4] = 8; - v[2] = -4; - v[9] = 10; - - DLIB_TEST(max(v) == 10); - DLIB_TEST(min(v) == -4); - - v.clear(); - v[4] = 8; - v[9] = 10; - DLIB_TEST(max(v) == 10); - DLIB_TEST(min(v) == 0); - - - v.clear(); - v[4] = -9; - v[9] = -4; - DLIB_TEST(max(v) == 0); - DLIB_TEST(min(v) == -9); - - - { - matrix a(2,2), b(2,2); - a = randm(2,2); - b = randm(2,2); - - DLIB_TEST(equal(a-b, subtract(a,b))); - DLIB_TEST(equal(a+b, add(a,b))); - DLIB_TEST(equal(a-(b+b), subtract(a,b+b))); - DLIB_TEST(equal(a+b+b, add(a,b+b))); - } - - { - std::map a, b, c; - a[1] = 2; - a[3] = 5; - - b[0] = 3; - b[1] = 1; - - c = add(a,b); - DLIB_TEST(c.size() == 3); - DLIB_TEST(c[0] == 3); - DLIB_TEST(c[1] == 3); - DLIB_TEST(c[3] == 5); - - c = subtract(a,b); - DLIB_TEST(c.size() == 3); - DLIB_TEST(c[0] == -3); - DLIB_TEST(c[1] == 1); - DLIB_TEST(c[3] == 5); - - c = add(b,a); - DLIB_TEST(c.size() == 3); - DLIB_TEST(c[0] == 3); - DLIB_TEST(c[1] == 3); - DLIB_TEST(c[3] == 5); - - c = subtract(b,a); - DLIB_TEST(c.size() == 3); - DLIB_TEST(c[0] == 3); - DLIB_TEST(c[1] == -1); - DLIB_TEST(c[3] == -5); - - std::vector > aa, bb, cc; - - aa.assign(a.begin(), a.end()); - bb.assign(b.begin(), b.end()); - - cc = add(aa,bb); - DLIB_TEST(cc.size() == 3); - DLIB_TEST(cc[0].first == 0); - DLIB_TEST(cc[1].first == 1); - DLIB_TEST(cc[2].first == 3); - DLIB_TEST(cc[0].second == 3); - DLIB_TEST(cc[1].second == 3); - DLIB_TEST(cc[2].second == 5); - - cc = subtract(aa,bb); - DLIB_TEST(cc.size() == 3); - DLIB_TEST(cc[0].first == 0); - DLIB_TEST(cc[1].first == 1); - DLIB_TEST(cc[2].first == 3); - DLIB_TEST(cc[0].second == -3); - DLIB_TEST(cc[1].second == 1); - DLIB_TEST(cc[2].second == 5); - - cc = add(bb,aa); - DLIB_TEST(cc.size() == 3); - DLIB_TEST(cc[0].first == 0); - DLIB_TEST(cc[1].first == 1); - DLIB_TEST(cc[2].first == 3); - DLIB_TEST(cc[0].second == 3); - DLIB_TEST(cc[1].second == 3); - DLIB_TEST(cc[2].second == 5); - - cc = subtract(bb,aa); - DLIB_TEST(cc.size() == 3); - DLIB_TEST(cc[0].first == 0); - DLIB_TEST(cc[1].first == 1); - DLIB_TEST(cc[2].first == 3); - DLIB_TEST(cc[0].second == 3); - DLIB_TEST(cc[1].second == -1); - DLIB_TEST(cc[2].second == -5); - - } - - test_sparse_matrix_vector_multiplies(); - test_sparse_matrix_vector_multiply1(); - test_sparse_matrix_vector_multiply2(); - - { - matrix a, b; - a = gaussian_randm(6,1, 0); - b = gaussian_randm(6,1, 1); - - std::vector > aa, bb; - - assign(aa, a); - assign(bb, b); - - // dot() does something special when the sparse vectors have entries for - // each dimension, which is what happens when they are copied from dense - // vectors. So the point of the tests in this block is to make sure dot() - // works right in this case. - DLIB_TEST(std::abs(dot(a,b) - dot(aa,bb)) < 1e-14); - a(3) = 0; - assign(aa, a); - DLIB_TEST(std::abs(dot(a,b) - dot(aa,bb)) < 1e-14); - } - } - }; - - sparse_vector_tester a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/stack.cpp b/lib/3rdParty/dlib/include/dlib/test/stack.cpp deleted file mode 100644 index 0b92eaeb..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/stack.cpp +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright (C) 2005 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.stack"); - - template < - typename stack - > - void stack_kernel_test ( - ) - /*! - requires - - stack is an implementation of stack/stack_sort_abstract.h - stack is instantiated with int - ensures - - runs tests on stack for compliance with the specs - !*/ - { - - - srand(static_cast(time(0))); - - print_spinner(); - - stack a1, a2; - - - - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start()); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.size() == 0); - - swap(a1,a2); - DLIB_TEST(a2.size() == 0); - DLIB_TEST(a2.current_element_valid() == false); - DLIB_TEST(a2.at_start() == false); - DLIB_TEST(a2.move_next() == false); - DLIB_TEST(a2.current_element_valid() == false); - DLIB_TEST(a2.size() == 0); - DLIB_TEST(a2.at_start() == false); - DLIB_TEST(a2.size() == 0); - - - - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start()); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.size() == 0); - - a1.reset(); - a2.reset(); - - for (unsigned long k = 0; k < 4; ++k) - { - - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start()); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.size() == 0); - - swap(a1,a2); - DLIB_TEST(a2.size() == 0); - DLIB_TEST(a2.current_element_valid() == false); - DLIB_TEST(a2.at_start() == false); - DLIB_TEST(a2.move_next() == false); - DLIB_TEST(a2.current_element_valid() == false); - DLIB_TEST(a2.size() == 0); - DLIB_TEST(a2.at_start() == false); - DLIB_TEST(a2.size() == 0); - - - - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start()); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.size() == 0); - - a1.clear(); - a2.clear(); - - - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start()); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.size() == 0); - - swap(a1,a2); - DLIB_TEST(a2.size() == 0); - DLIB_TEST(a2.current_element_valid() == false); - DLIB_TEST(a2.at_start() == false); - DLIB_TEST(a2.move_next() == false); - DLIB_TEST(a2.current_element_valid() == false); - DLIB_TEST(a2.size() == 0); - DLIB_TEST(a2.at_start() == false); - DLIB_TEST(a2.size() == 0); - - - - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start()); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.move_next() == false); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a1.at_start() == false); - DLIB_TEST(a1.size() == 0); - - a1.clear(); - a2.clear(); - - - for (unsigned long i = 0; i < 100; ++i) - { - int a = (int)i; - a1.push(a); - } - - DLIB_TEST(a1.size() == 100); - - int count = 99; - while (a1.move_next()) - { - DLIB_TEST_MSG(a1.element() == count,a1.element() << " : " << count); - --count; - } - - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.at_start() == false); - - a1.swap(a2); - - count = 99; - DLIB_TEST(a2.current_element_valid() == false); - DLIB_TEST(a2.at_start() == false); - DLIB_TEST(a1.current_element_valid() == false); - DLIB_TEST(a1.at_start() == true); - - DLIB_TEST(a1.size() == 0); - DLIB_TEST(a2.size() == 100); - DLIB_TEST(a2.current() == 99); - - a2.reset(); - while (a2.move_next()) - { - DLIB_TEST(a2.element() == count--); - } - - DLIB_TEST(a2.current_element_valid() == false); - DLIB_TEST(a2.at_start() == false); - int b = 4; - a2.push(b); - DLIB_TEST(a2.current_element_valid() == false); - DLIB_TEST(a2.at_start() == true); - - DLIB_TEST(a2.current() == 4); - int c = 0; - a2.pop(c); - DLIB_TEST(c == 4); - - // serialize the state of a2, then clear a2, then - // load the state back into a2. - ostringstream sout; - serialize(a2,sout); - DLIB_TEST(a2.at_start() == true); - istringstream sin(sout.str()); - a2.clear(); - deserialize(a2,sin); - - - count = 99; - while (a2.size()) - { - int a = 0; - DLIB_TEST(a2.current() == count); - DLIB_TEST(const_cast(a2).current() == count); - a2.pop(a); - DLIB_TEST(a == count--); - } - - - - - - - a1.clear(); - a2.clear(); - } - - - { - a1.clear(); - remover& go = a1; - for (int i = 0; i < 100; ++i) - { - int a = 3; - a1.push(a); - } - DLIB_TEST(go.size() == 100); - for (int i = 0; i < 100; ++i) - { - int a = 9; - a1.remove_any(a); - DLIB_TEST(a == 3); - } - DLIB_TEST(go.size() == 0); - } - - } - - - - - class stack_tester : public tester - { - public: - stack_tester ( - ) : - tester ("test_stack", - "Runs tests on the stack component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a"; - stack_kernel_test::kernel_1a> (); - dlog << LINFO << "testing kernel_1a_c"; - stack_kernel_test::kernel_1a_c>(); - } - } a; - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/static_map.cpp b/lib/3rdParty/dlib/include/dlib/test/static_map.cpp deleted file mode 100644 index 931ae1fa..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/static_map.cpp +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright (C) 2005 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include - -#include -#include - -#include -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace std; - using namespace dlib; - - logger dlog("test.static_map"); - - template < - typename map - > - void static_map_kernel_test ( - ) - /*! - requires - - map is an implementation of static_map/static_map_kernel_abstract.h and - is instantiated to map int to int - ensures - - runs tests on map for compliance with the specs - !*/ - { - - print_spinner(); - srand(static_cast(time(0))); - - typedef binary_search_tree::kernel_2a_c bst; - typedef hash_table::kernel_1a_c ht; - - const unsigned long table_4_max_size = 100; - const unsigned long tree_max_size = 50000; - ht table_4(4); - ht table_8(8); - bst tree; - - ht table_4b(4); - ht table_8b(8); - bst treeb; - - - // just do the following to make sure operator[] doesn't hang - // under some instances - { - int g = 1, h = 1; - treeb.add(g,h); - map test; - map test2; - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test.at_start()); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.move_next() == false); - DLIB_TEST(test.current_element_valid() == false); - DLIB_TEST(test.at_start() == false); - - swap(test,test2); - DLIB_TEST(test2.at_start() == false); - DLIB_TEST(test.at_start() == true); - - swap(test,test2); - DLIB_TEST(test.at_start() == false); - - - DLIB_TEST(test.size() == 0); - DLIB_TEST(test[1] == 0); - DLIB_TEST(test[2] == 0); - DLIB_TEST(test[3] == 0); - DLIB_TEST(test[0] == 0); - - test.load(treeb); - DLIB_TEST(test.at_start()); - DLIB_TEST(test[1] != 0); - DLIB_TEST(test[2] == 0); - DLIB_TEST(test[3] == 0); - DLIB_TEST(test[0] == 0); - - test2.clear(); - swap(test2,test); - DLIB_TEST(test2[1] != 0); - DLIB_TEST(test2[2] == 0); - DLIB_TEST(test2[3] == 0); - DLIB_TEST(test2[0] == 0); - DLIB_TEST(test[1] == 0); - DLIB_TEST(test[2] == 0); - DLIB_TEST(test[3] == 0); - DLIB_TEST(test[0] == 0); - - - DLIB_TEST(treeb.size() == 0); - treeb.clear(); - } - - - for (unsigned long i = 0; i < table_4_max_size; ++i) - { - int a = ::rand()&0xFF; - int b = a + 1; - int ab = a; - int bb = b; - table_4.add(a,b); - table_4b.add(ab,bb); - } - - for (unsigned long i = 0; i < table_4_max_size; ++i) - { - int a = ::rand()&0xF; - int b = a + 1; - int ab = a; - int bb = b; - table_8.add(a,b); - table_8b.add(ab,bb); - } - - for (unsigned long i = 0; i < tree_max_size; ++i) - { - int a = ::rand()&0xFFF; - int b = a + 1; - int ab = a; - int bb = b; - tree.add(a,b); - treeb.add(ab,bb); - } - - map m_4; - m_4.load(table_4); - map m_8; - m_8.load(table_8); - map m_t; - m_t.load(tree); - map e; - e.load(table_4); - - DLIB_TEST(e.size() == 0); - DLIB_TEST(e.at_start() == true); - DLIB_TEST(e.current_element_valid() == false); - DLIB_TEST(e.move_next() == false); - DLIB_TEST(e.at_start() == false); - DLIB_TEST(e.current_element_valid() == false); - - DLIB_TEST(m_4.size() == table_4b.size()); - DLIB_TEST(m_8.size() == table_8b.size()); - DLIB_TEST(m_t.size() == treeb.size()); - - DLIB_TEST(m_4.at_start() == true); - DLIB_TEST(m_8.at_start() == true); - DLIB_TEST(m_t.at_start() == true); - DLIB_TEST(m_4.current_element_valid() == false); - DLIB_TEST(m_8.current_element_valid() == false); - DLIB_TEST(m_t.current_element_valid() == false); - - - DLIB_TEST(m_4.move_next() == true); - DLIB_TEST(m_4.at_start() == false); - DLIB_TEST(m_4.current_element_valid() == true); - DLIB_TEST(m_8.move_next() == true); - DLIB_TEST(m_8.at_start() == false); - DLIB_TEST(m_8.current_element_valid() == true); - DLIB_TEST(m_t.move_next() == true); - DLIB_TEST(m_t.at_start() == false); - DLIB_TEST(m_t.current_element_valid() == true); - - m_4.reset(); - m_8.reset(); - m_t.reset(); - - while (m_4.move_next()) - { - DLIB_TEST( table_4b[m_4.element().key()] != 0); - DLIB_TEST( *table_4b[m_4.element().key()] == m_4.element().value()); - } - - // serialize the state of m_4, then clear m_4, then - // load the state back into m_4. - ostringstream sout; - serialize(m_4,sout); - DLIB_TEST(m_4.at_start() == true); - istringstream sin(sout.str()); - m_4.clear(); - deserialize(m_4,sin); - DLIB_TEST(m_4.at_start() == true); - - - - while (table_4b.move_next()) - { - DLIB_TEST( m_4[table_4b.element().key()] != 0); - DLIB_TEST( *m_4[table_4b.element().key()] == table_4b.element().value()); - } - - // serialize the state of m_8, then clear m_8, then - // load the state back into m_8. - sout.str(""); - serialize(m_8,sout); - DLIB_TEST(m_8.at_start() == true); - sin.str(sout.str()); - m_8.clear(); - deserialize(m_8,sin); - DLIB_TEST(m_8.at_start() == true); - - while (m_8.move_next()) - { - DLIB_TEST( table_8b[m_8.element().key()] != 0); - DLIB_TEST( *table_8b[m_8.element().key()] == m_8.element().value()); - } - - while (table_8b.move_next()) - { - DLIB_TEST( m_8[table_8b.element().key()] != 0); - DLIB_TEST( *m_8[table_8b.element().key()] == table_8b.element().value()); - } - - - while (m_t.move_next()) - { - DLIB_TEST( treeb[m_t.element().key()] != 0); - DLIB_TEST( *treeb[m_t.element().key()] == m_t.element().value()); - } - - // make sure operator[] doesn't hang - for (int l = 1; l < 10000; ++l) - { - DLIB_TEST(m_t[l+0xFFF] == 0); - } - - while (treeb.move_next()) - { - DLIB_TEST( m_t[treeb.element().key()] != 0); - DLIB_TEST( *m_t[treeb.element().key()] == treeb.element().value()); - } - - - - m_4.reset(); - m_8.reset(); - m_t.reset(); - - int last = 0; - while (m_4.move_next()) - { - DLIB_TEST(last <= m_4.element().key()); - DLIB_TEST(m_4.element().key() + 1 == m_4.element().value()); - last = m_4.element().key(); - } - - last = 0; - while (m_8.move_next()) - { - DLIB_TEST(last <= m_8.element().key()); - DLIB_TEST(m_8.element().key() + 1 == m_8.element().value()); - last = m_8.element().key(); - } - - last = 0; - while (m_t.move_next()) - { - DLIB_TEST(last <= m_t.element().key()); - DLIB_TEST(m_t.element().key() + 1 == m_t.element().value()); - last = m_t.element().key(); - } - - - - - - - // this is just to test swap - m_4.swap(m_8); - m_4.reset(); - table_4b.reset(); - while (m_8.move_next()) - { - DLIB_TEST( table_4b[m_8.element().key()] != 0); - DLIB_TEST( *table_4b[m_8.element().key()] == m_8.element().value()); - } - - while (table_4b.move_next()) - { - DLIB_TEST( m_8[table_4b.element().key()] != 0); - DLIB_TEST( *m_8[table_4b.element().key()] == table_4b.element().value()); - } - - } - - - - - - class static_map_tester : public tester - { - public: - static_map_tester ( - ) : - tester ("test_static_map", - "Runs tests on the static_map component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a"; - static_map_kernel_test::kernel_1a> (); - dlog << LINFO << "testing kernel_1a_c"; - static_map_kernel_test::kernel_1a_c>(); - } - } a; - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/static_set.cpp b/lib/3rdParty/dlib/include/dlib/test/static_set.cpp deleted file mode 100644 index 0ad864e4..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/static_set.cpp +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright (C) 2005 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include - -#include -#include -#include -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace std; - using namespace dlib; - - logger dlog("test.static_set"); - - template < - typename set - > - void static_set_kernel_test ( - ) - /*! - requires - - set is an implementation of static_set/static_set_kernel_abstract.h and - is instantiated to hold ints - ensures - - runs tests on set for compliance with the specs - !*/ - { - - print_spinner(); - - srand(static_cast(time(0))); - - typedef queue::kernel_2a_c queue_of_int; - typedef dlib::set::kernel_1a_c set_of_int; - - queue_of_int q, qb, qc; - set_of_int ds; - - set S; - S.load(ds); - - for (int k = 1; k < 1000; ++k) - { - q.clear(); - qb.clear(); - qc.clear(); - unsigned long num = k; - for (unsigned long i = 0; i < num; ++i) - { - int a = ::rand()&0xFF; - int b = a; - int c = a; - q.enqueue(a); - qb.enqueue(b); - qc.enqueue(c); - } - - - - set s; - - DLIB_TEST(s.size() == 0); - DLIB_TEST(s.at_start()); - DLIB_TEST(s.current_element_valid() == false); - DLIB_TEST(s.move_next() == false); - DLIB_TEST(s.current_element_valid() == false); - DLIB_TEST(s.at_start() == false); - - s.load(q); - DLIB_TEST(s.at_start()); - set se; - se.load(q); - - DLIB_TEST(se.size() == 0); - DLIB_TEST(se.at_start() == true); - DLIB_TEST(se.current_element_valid() == false); - DLIB_TEST(se.move_next() == false); - DLIB_TEST(se.at_start() == false); - DLIB_TEST(se.current_element_valid() == false); - - - DLIB_TEST(s.size() == qb.size()); - DLIB_TEST(s.at_start() == true); - DLIB_TEST(s.current_element_valid() == false); - DLIB_TEST(s.move_next() == true); - DLIB_TEST(s.at_start() == false); - DLIB_TEST(s.current_element_valid() == true); - s.reset(); - se.reset(); - - swap(se,s); - - DLIB_TEST(s.size() == 0); - DLIB_TEST(s.at_start() == true); - DLIB_TEST(s.current_element_valid() == false); - DLIB_TEST(s.move_next() == false); - DLIB_TEST(s.at_start() == false); - DLIB_TEST(s.current_element_valid() == false); - - DLIB_TEST(se.size() == qb.size()); - DLIB_TEST(se.at_start() == true); - DLIB_TEST(se.current_element_valid() == false); - DLIB_TEST(se.move_next() == true); - DLIB_TEST(se.at_start() == false); - DLIB_TEST(se.current_element_valid() == true); - s.reset(); - se.reset(); - - swap(se,s); - - - - int last = 0; - while (s.move_next()) - { - DLIB_TEST(last <= s.element()); - last = s.element(); - } - - - - while (qb.move_next()) - { - int a; - qb.dequeue(a); - DLIB_TEST(s.is_member(a)); - DLIB_TEST(!se.is_member(a)); - - // make sure is_member() doesn't hang - for (int l = 0; l < 100; ++l) - { - int a = ::rand(); - s.is_member(a); - } - } - - swap(s,se); - - // serialize the state of se, then clear se, then - // load the state back into se. - ostringstream sout; - serialize(se,sout); - DLIB_TEST(se.at_start() == true); - istringstream sin(sout.str()); - se.clear(); - deserialize(se,sin); - DLIB_TEST(se.at_start() == true); - - - last = 0; - while (se.move_next()) - { - DLIB_TEST(last <= se.element()); - last = se.element(); - } - - - DLIB_TEST(s.size() == 0); - DLIB_TEST(se.size() == qc.size()); - - while (qc.move_next()) - { - int a; - qc.dequeue(a); - DLIB_TEST(se.is_member(a)); - DLIB_TEST(!s.is_member(a)); - } - - - } - } - - - - - - class static_set_tester : public tester - { - public: - static_set_tester ( - ) : - tester ("test_static_set", - "Runs tests on the static_set component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a"; - static_set_kernel_test::kernel_1a> (); - dlog << LINFO << "testing kernel_1a_c"; - static_set_kernel_test::kernel_1a_c>(); - } - } a; - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/statistics.cpp b/lib/3rdParty/dlib/include/dlib/test/statistics.cpp deleted file mode 100644 index ae9c36a7..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/statistics.cpp +++ /dev/null @@ -1,720 +0,0 @@ -// Copyright (C) 2010 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.statistics"); - - - - class statistics_tester : public tester - { - public: - statistics_tester ( - ) : - tester ("test_statistics", - "Runs tests on the statistics component.") - {} - - void test_random_subset_selector () - { - random_subset_selector rand_set; - - for (int j = 0; j < 30; ++j) - { - print_spinner(); - - running_stats rs, rs2; - - rand_set.set_max_size(1000); - - for (double i = 0; i < 100000; ++i) - { - rs.add(i); - rand_set.add(i); - } - - - for (unsigned long i = 0; i < rand_set.size(); ++i) - rs2.add(rand_set[i]); - - - dlog << LDEBUG << "true mean: " << rs.mean(); - dlog << LDEBUG << "true sampled: " << rs2.mean(); - double ratio = rs.mean()/rs2.mean(); - DLIB_TEST_MSG(0.96 < ratio && ratio < 1.04, " ratio: " << ratio); - } - - - { - random_subset_selector r1, r2; - r1.set_max_size(300); - for (int i = 0; i < 4000; ++i) - r1.add(i); - - ostringstream sout; - serialize(r1, sout); - istringstream sin(sout.str()); - deserialize(r2, sin); - - DLIB_TEST(r1.size() == r2.size()); - DLIB_TEST(r1.max_size() == r2.max_size()); - DLIB_TEST(r1.next_add_accepts() == r2.next_add_accepts()); - DLIB_TEST(std::equal(r1.begin(), r1.end(), r2.begin())); - - for (int i = 0; i < 4000; ++i) - { - r1.add(i); - r2.add(i); - } - - DLIB_TEST(r1.size() == r2.size()); - DLIB_TEST(r1.max_size() == r2.max_size()); - DLIB_TEST(r1.next_add_accepts() == r2.next_add_accepts()); - DLIB_TEST(std::equal(r1.begin(), r1.end(), r2.begin())); - } - } - - void test_random_subset_selector2 () - { - random_subset_selector rand_set; - DLIB_TEST(rand_set.next_add_accepts() == false); - DLIB_TEST(rand_set.size() == 0); - DLIB_TEST(rand_set.max_size() == 0); - - for (int j = 0; j < 30; ++j) - { - print_spinner(); - - running_stats rs, rs2; - - rand_set.set_max_size(1000); - DLIB_TEST(rand_set.next_add_accepts() == true); - - for (double i = 0; i < 100000; ++i) - { - rs.add(i); - if (rand_set.next_add_accepts()) - rand_set.add(i); - else - rand_set.add(); - } - - DLIB_TEST(rand_set.size() == 1000); - DLIB_TEST(rand_set.max_size() == 1000); - - for (unsigned long i = 0; i < rand_set.size(); ++i) - rs2.add(rand_set[i]); - - - dlog << LDEBUG << "true mean: " << rs.mean(); - dlog << LDEBUG << "true sampled: " << rs2.mean(); - double ratio = rs.mean()/rs2.mean(); - DLIB_TEST_MSG(0.96 < ratio && ratio < 1.04, " ratio: " << ratio); - } - } - - void test_running_cross_covariance () - { - running_cross_covariance > rcc1, rcc2; - - matrix xm, ym; - const int num = 40; - - dlib::rand rnd; - for (int i = 0; i < num; ++i) - { - matrix x = randm(4,1,rnd); - matrix y = randm(4,1,rnd); - - xm += x/num; - ym += y/num; - - if (i < 15) - rcc1.add(x,y); - else - rcc2.add(x,y); - } - - rnd.clear(); - matrix cov; - for (int i = 0; i < num; ++i) - { - matrix x = randm(4,1,rnd); - matrix y = randm(4,1,rnd); - cov += (x-xm)*trans(y-ym); - } - cov /= num-1; - - running_cross_covariance > rcc = rcc1 + rcc2; - DLIB_TEST(max(abs(rcc.covariance_xy()-cov)) < 1e-14); - DLIB_TEST(max(abs(rcc.mean_x()-xm)) < 1e-14); - DLIB_TEST(max(abs(rcc.mean_y()-ym)) < 1e-14); - } - - std::map dense_to_sparse ( - const matrix& x - ) - { - std::map temp; - for (long i = 0; i < x.size(); ++i) - temp[i] = x(i); - return temp; - } - - void test_running_cross_covariance_sparse() - { - running_cross_covariance > rcc1, rcc2; - - running_covariance > rc1, rc2; - - matrix xm, ym; - const int num = 40; - - rc1.set_dimension(4); - rc2.set_dimension(4); - - rcc1.set_dimensions(4,5); - rcc2.set_dimensions(4,5); - - dlib::rand rnd; - for (int i = 0; i < num; ++i) - { - matrix x = randm(4,1,rnd); - matrix y = randm(5,1,rnd); - - xm += x/num; - ym += y/num; - - if (i < 15) - { - rcc1.add(x,dense_to_sparse(y)); - rc1.add(x); - } - else if (i < 30) - { - rcc2.add(dense_to_sparse(x),y); - rc2.add(dense_to_sparse(x)); - } - else - { - rcc2.add(dense_to_sparse(x),dense_to_sparse(y)); - rc2.add(x); - } - } - - rnd.clear(); - matrix cov, cov2; - for (int i = 0; i < num; ++i) - { - matrix x = randm(4,1,rnd); - matrix y = randm(5,1,rnd); - cov += (x-xm)*trans(y-ym); - cov2 += (x-xm)*trans(x-xm); - } - cov /= num-1; - cov2 /= num-1; - - running_cross_covariance > rcc = rcc1 + rcc2; - DLIB_TEST_MSG(max(abs(rcc.covariance_xy()-cov)) < 1e-14, max(abs(rcc.covariance_xy()-cov))); - DLIB_TEST(max(abs(rcc.mean_x()-xm)) < 1e-14); - DLIB_TEST(max(abs(rcc.mean_y()-ym)) < 1e-14); - - running_covariance > rc = rc1 + rc2; - DLIB_TEST(max(abs(rc.covariance()-cov2)) < 1e-14); - DLIB_TEST(max(abs(rc.mean()-xm)) < 1e-14); - } - - void test_running_covariance ( - ) - { - dlib::rand rnd; - std::vector > vects; - - running_covariance > cov, cov2; - DLIB_TEST(cov.in_vector_size() == 0); - - for (unsigned long dims = 1; dims < 5; ++dims) - { - for (unsigned long samps = 2; samps < 10; ++samps) - { - vects.clear(); - cov.clear(); - DLIB_TEST(cov.in_vector_size() == 0); - for (unsigned long i = 0; i < samps; ++i) - { - vects.push_back(randm(dims,1,rnd)); - cov.add(vects.back()); - - } - DLIB_TEST(cov.in_vector_size() == (long)dims); - - DLIB_TEST(equal(mean(mat(vects)), cov.mean())); - DLIB_TEST_MSG(equal(covariance(mat(vects)), cov.covariance()), - max(abs(covariance(mat(vects)) - cov.covariance())) - << " dims = " << dims << " samps = " << samps - ); - } - } - - for (unsigned long dims = 1; dims < 5; ++dims) - { - for (unsigned long samps = 2; samps < 10; ++samps) - { - vects.clear(); - cov.clear(); - cov2.clear(); - DLIB_TEST(cov.in_vector_size() == 0); - for (unsigned long i = 0; i < samps; ++i) - { - vects.push_back(randm(dims,1,rnd)); - if ((i%2) == 0) - cov.add(vects.back()); - else - cov2.add(vects.back()); - - } - DLIB_TEST((cov+cov2).in_vector_size() == (long)dims); - - DLIB_TEST(equal(mean(mat(vects)), (cov+cov2).mean())); - DLIB_TEST_MSG(equal(covariance(mat(vects)), (cov+cov2).covariance()), - max(abs(covariance(mat(vects)) - (cov+cov2).covariance())) - << " dims = " << dims << " samps = " << samps - ); - } - } - - } - - void test_running_stats() - { - print_spinner(); - - running_stats rs, rs2; - - running_scalar_covariance rsc1, rsc2; - - for (double i = 0; i < 100; ++i) - { - rs.add(i); - - rsc1.add(i,i); - rsc2.add(i,i); - rsc2.add(i,-i); - } - - // make sure the running_stats and running_scalar_covariance agree - DLIB_TEST_MSG(std::abs(rs.mean() - rsc1.mean_x()) < 1e-10, std::abs(rs.mean() - rsc1.mean_x())); - DLIB_TEST(std::abs(rs.mean() - rsc1.mean_y()) < 1e-10); - DLIB_TEST(std::abs(rs.stddev() - rsc1.stddev_x()) < 1e-10); - DLIB_TEST(std::abs(rs.stddev() - rsc1.stddev_y()) < 1e-10); - DLIB_TEST(std::abs(rs.variance() - rsc1.variance_x()) < 1e-10); - DLIB_TEST(std::abs(rs.variance() - rsc1.variance_y()) < 1e-10); - DLIB_TEST(rs.current_n() == rsc1.current_n()); - - DLIB_TEST(std::abs(rsc1.correlation() - 1) < 1e-10); - DLIB_TEST(std::abs(rsc2.correlation() - 0) < 1e-10); - - - - // test serialization of running_stats - ostringstream sout; - serialize(rs, sout); - istringstream sin(sout.str()); - deserialize(rs2, sin); - // make sure the running_stats and running_scalar_covariance agree - DLIB_TEST_MSG(std::abs(rs2.mean() - rsc1.mean_x()) < 1e-10, std::abs(rs2.mean() - rsc1.mean_x())); - DLIB_TEST(std::abs(rs2.mean() - rsc1.mean_y()) < 1e-10); - DLIB_TEST(std::abs(rs2.stddev() - rsc1.stddev_x()) < 1e-10); - DLIB_TEST(std::abs(rs2.stddev() - rsc1.stddev_y()) < 1e-10); - DLIB_TEST(std::abs(rs2.variance() - rsc1.variance_x()) < 1e-10); - DLIB_TEST(std::abs(rs2.variance() - rsc1.variance_y()) < 1e-10); - DLIB_TEST(rs2.current_n() == rsc1.current_n()); - - rsc1.clear(); - rsc1.add(1, -1); - rsc1.add(0, 0); - rsc1.add(1, -1); - rsc1.add(0, 0); - rsc1.add(1, -1); - rsc1.add(0, 0); - - DLIB_TEST(std::abs(rsc1.covariance() - -0.3) < 1e-10); - } - - void test_skewness_and_kurtosis_1() - { - - dlib::rand rnum; - running_stats rs1; - - double tp = 0; - - rnum.set_seed("DlibRocks"); - - for(int i = 0; i< 1000000; i++) - { - tp = rnum.get_random_gaussian(); - rs1.add(tp); - } - - // check the unbiased skewness and excess kurtosis of one million Gaussian - // draws are both near_vects zero. - DLIB_TEST(abs(rs1.skewness()) < 0.1); - DLIB_TEST(abs(rs1.ex_kurtosis()) < 0.1); - } - - void test_skewness_and_kurtosis_2() - { - - string str = "DlibRocks"; - - for(int j = 0; j<5 ; j++) - { - matrix dat; - dlib::rand rnum; - running_stats rs1; - - double tp = 0; - double n = 100000; - double xb = 0; - - double sknum = 0; - double skdenom = 0; - double unbi_skew = 0; - - double exkurnum = 0; - double exkurdenom = 0; - double unbi_exkur = 0; - - random_shuffle(str.begin(), str.end()); - rnum.set_seed(str); - - for(int i = 0; i t(15),u(15),v(15); - - for (unsigned long i = 0; i < t.size(); ++i) - { - t[i] = i; - u[i] = i+1; - v[i] = i+2; - } - randomize_samples(t,u,v); - - DLIB_TEST(t.size() == 15); - DLIB_TEST(u.size() == 15); - DLIB_TEST(v.size() == 15); - - for (unsigned long i = 0; i < t.size(); ++i) - { - const unsigned long val = t[i]; - DLIB_TEST(u[i] == val+1); - DLIB_TEST(v[i] == val+2); - } - } - void test_randomize_samples2() - { - dlib::matrix t(15),u(15),v(15); - - for (long i = 0; i < t.size(); ++i) - { - t(i) = i; - u(i) = i+1; - v(i) = i+2; - } - randomize_samples(t,u,v); - - DLIB_TEST(t.size() == 15); - DLIB_TEST(u.size() == 15); - DLIB_TEST(v.size() == 15); - - for (long i = 0; i < t.size(); ++i) - { - const long val = t(i); - DLIB_TEST(u(i) == val+1); - DLIB_TEST(v(i) == val+2); - } - } - - void another_test() - { - std::vector a; - - running_stats rs1, rs2; - - for (int i = 0; i < 10; ++i) - { - rs1.add(i); - a.push_back(i); - } - - DLIB_TEST(std::abs(variance(mat(a)) - rs1.variance()) < 1e-13); - DLIB_TEST(std::abs(stddev(mat(a)) - rs1.stddev()) < 1e-13); - DLIB_TEST(std::abs(mean(mat(a)) - rs1.mean()) < 1e-13); - - for (int i = 10; i < 20; ++i) - { - rs2.add(i); - a.push_back(i); - } - - DLIB_TEST(std::abs(variance(mat(a)) - (rs1+rs2).variance()) < 1e-13); - DLIB_TEST(std::abs(mean(mat(a)) - (rs1+rs2).mean()) < 1e-13); - DLIB_TEST((rs1+rs2).current_n() == 20); - - running_scalar_covariance rc1, rc2, rc3; - dlib::rand rnd; - for (double i = 0; i < 10; ++i) - { - const double a = i + rnd.get_random_gaussian(); - const double b = i + rnd.get_random_gaussian(); - rc1.add(a,b); - rc3.add(a,b); - } - for (double i = 11; i < 20; ++i) - { - const double a = i + rnd.get_random_gaussian(); - const double b = i + rnd.get_random_gaussian(); - rc2.add(a,b); - rc3.add(a,b); - } - - DLIB_TEST(std::abs((rc1+rc2).mean_x() - rc3.mean_x()) < 1e-13); - DLIB_TEST(std::abs((rc1+rc2).mean_y() - rc3.mean_y()) < 1e-13); - DLIB_TEST_MSG(std::abs((rc1+rc2).variance_x() - rc3.variance_x()) < 1e-13, std::abs((rc1+rc2).variance_x() - rc3.variance_x())); - DLIB_TEST(std::abs((rc1+rc2).variance_y() - rc3.variance_y()) < 1e-13); - DLIB_TEST(std::abs((rc1+rc2).covariance() - rc3.covariance()) < 1e-13); - DLIB_TEST((rc1+rc2).current_n() == rc3.current_n()); - - } - - void test_average_precision() - { - std::vector items; - DLIB_TEST(average_precision(items) == 1); - DLIB_TEST(average_precision(items,1) == 0); - - items.push_back(true); - DLIB_TEST(average_precision(items) == 1); - DLIB_TEST(std::abs(average_precision(items,1) - 0.5) < 1e-14); - - items.push_back(true); - DLIB_TEST(average_precision(items) == 1); - DLIB_TEST(std::abs(average_precision(items,1) - 2.0/3.0) < 1e-14); - - items.push_back(false); - - DLIB_TEST(average_precision(items) == 1); - DLIB_TEST(std::abs(average_precision(items,1) - 2.0/3.0) < 1e-14); - - items.push_back(true); - - DLIB_TEST(std::abs(average_precision(items) - (2.0+3.0/4.0)/3.0) < 1e-14); - - items.push_back(true); - - DLIB_TEST(std::abs(average_precision(items) - (2.0 + 4.0/5.0 + 4.0/5.0)/4.0) < 1e-14); - DLIB_TEST(std::abs(average_precision(items,1) - (2.0 + 4.0/5.0 + 4.0/5.0)/5.0) < 1e-14); - } - - - template - void check_distance_metrics ( - const std::vector >& samples - ) - { - running_stats rs; - for (unsigned long i = 0; i < samples.size(); ++i) - { - for (unsigned long j = 0; j < samples[i].near_vects.size(); ++j) - { - const double d1 = length_squared(samples[i].anchor_vect - samples[i].near_vects[j]); - for (unsigned long k = 0; k < samples[i].far_vects.size(); ++k) - { - const double d2 = length_squared(samples[i].anchor_vect - samples[i].far_vects[k]); - rs.add(d2-d1); - } - } - } - - dlog << LINFO << "dist gap max: "<< rs.max(); - dlog << LINFO << "dist gap min: "<< rs.min(); - dlog << LINFO << "dist gap mean: "<< rs.mean(); - dlog << LINFO << "dist gap stddev: "<< rs.stddev(); - DLIB_TEST(rs.min() >= 0.99); - DLIB_TEST(rs.mean() >= 0.9999); - } - - void test_vector_normalizer_frobmetric(dlib::rand& rnd) - { - print_spinner(); - typedef matrix sample_type; - vector_normalizer_frobmetric normalizer; - - std::vector > samples; - frobmetric_training_sample samp; - - const long key = 1; - const long dims = 5; - // Lets make some two class training data. Each sample will have dims dimensions but - // only the one with index equal to key will be meaningful. In particular, if the key - // dimension is > 0 then the sample is class +1 and -1 otherwise. - - long k = 0; - for (int i = 0; i < 50; ++i) - { - samp.clear(); - samp.anchor_vect = gaussian_randm(dims,1,k++); - if (samp.anchor_vect(key) > 0) - samp.anchor_vect(key) = rnd.get_random_double() + 5; - else - samp.anchor_vect(key) = -(rnd.get_random_double() + 5); - - matrix temp; - - for (int j = 0; j < 5; ++j) - { - // Don't always put an equal number of near_vects and far_vects vectors into the - // training samples. - const int numa = rnd.get_random_32bit_number()%2 + 1; - const int numb = rnd.get_random_32bit_number()%2 + 1; - - for (int num = 0; num < numa; ++num) - { - temp = gaussian_randm(dims,1,k++); temp(key) = 0.1; - //temp = gaussian_randm(dims,1,k++); temp(key) = std::abs(temp(key)); - if (samp.anchor_vect(key) > 0) samp.near_vects.push_back(temp); - else samp.far_vects.push_back(temp); - } - - for (int num = 0; num < numb; ++num) - { - temp = gaussian_randm(dims,1,k++); temp(key) = -0.1; - //temp = gaussian_randm(dims,1,k++); temp(key) = -std::abs(temp(key)); - if (samp.anchor_vect(key) < 0) samp.near_vects.push_back(temp); - else samp.far_vects.push_back(temp); - } - } - samples.push_back(samp); - } - - normalizer.set_epsilon(0.0001); - normalizer.set_c(100); - normalizer.set_max_iterations(6000); - normalizer.train(samples); - - dlog << LINFO << "learned transform: \n" << normalizer.transform(); - - matrix total; - - for (unsigned long i = 0; i < samples.size(); ++i) - { - samples[i].anchor_vect = normalizer(samples[i].anchor_vect); - total += samples[i].anchor_vect; - for (unsigned long j = 0; j < samples[i].near_vects.size(); ++j) - samples[i].near_vects[j] = normalizer(samples[i].near_vects[j]); - for (unsigned long j = 0; j < samples[i].far_vects.size(); ++j) - samples[i].far_vects[j] = normalizer(samples[i].far_vects[j]); - } - total /= samples.size(); - dlog << LINFO << "sample transformed means: "<< trans(total); - DLIB_TEST(length(total) < 1e-9); - check_distance_metrics(samples); - - // make sure serialization works - stringstream os; - serialize(normalizer, os); - vector_normalizer_frobmetric normalizer2; - deserialize(normalizer2, os); - DLIB_TEST(equal(normalizer.transform(), normalizer2.transform())); - DLIB_TEST(equal(normalizer.transformed_means(), normalizer2.transformed_means())); - DLIB_TEST(normalizer.in_vector_size() == normalizer2.in_vector_size()); - DLIB_TEST(normalizer.out_vector_size() == normalizer2.out_vector_size()); - DLIB_TEST(normalizer.get_max_iterations() == normalizer2.get_max_iterations()); - DLIB_TEST(std::abs(normalizer.get_c() - normalizer2.get_c()) < 1e-14); - DLIB_TEST(std::abs(normalizer.get_epsilon() - normalizer2.get_epsilon()) < 1e-14); - - } - - - void perform_test ( - ) - { - dlib::rand rnd; - for (int i = 0; i < 5; ++i) - test_vector_normalizer_frobmetric(rnd); - - test_random_subset_selector(); - test_random_subset_selector2(); - test_running_covariance(); - test_running_cross_covariance(); - test_running_cross_covariance_sparse(); - test_running_stats(); - test_skewness_and_kurtosis_1(); - test_skewness_and_kurtosis_2(); - test_randomize_samples(); - test_randomize_samples2(); - another_test(); - test_average_precision(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/std_vector_c.cpp b/lib/3rdParty/dlib/include/dlib/test/std_vector_c.cpp deleted file mode 100644 index fe7f8251..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/std_vector_c.cpp +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (C) 2010 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include - -#include "tester.h" - -// This is called an unnamed-namespace and it has the effect of making everything inside this file "private" -// so that everything you declare will have static linkage. Thus we won't have any multiply -// defined symbol errors coming out of the linker when we try to compile the test suite. -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - // Declare the logger we will use in this test. The name of the tester - // should start with "test." - logger dlog("test.std_vector_c"); - - - class std_vector_c_tester : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a test for the std_vector_c object. When it is constructed - it adds itself into the testing framework. The command line switch is - specified as test_std_vector_c by passing that string to the tester constructor. - !*/ - public: - std_vector_c_tester ( - ) : - tester ("test_std_vector_c", - "Runs tests on the std_vector_c component.") - {} - - void perform_test ( - ) - { - std::vector c; - std_vector_c a, b; - a.push_back(3); - a.push_back(2); - a.push_back(1); - - DLIB_TEST(a[0] == 3); - DLIB_TEST(a[1] == 2); - DLIB_TEST(a[2] == 1); - c = a; - DLIB_TEST(c[0] == 3); - DLIB_TEST(c[1] == 2); - DLIB_TEST(c[2] == 1); - DLIB_TEST(c.size() == 3); - DLIB_TEST(a.size() == 3); - DLIB_TEST(b.size() == 0); - - DLIB_TEST(a == c); - DLIB_TEST(!(a != c)); - DLIB_TEST(a <= c); - DLIB_TEST(a >= c); - DLIB_TEST(!(a < c)); - DLIB_TEST(!(a > c)); - - swap(b,c); - DLIB_TEST(b[0] == 3); - DLIB_TEST(b[1] == 2); - DLIB_TEST(b[2] == 1); - DLIB_TEST(c.size() == 0); - DLIB_TEST(b.size() == 3); - swap(c,b); - DLIB_TEST(c[0] == 3); - DLIB_TEST(c[1] == 2); - DLIB_TEST(c[2] == 1); - DLIB_TEST(c.size() == 3); - DLIB_TEST(b.size() == 0); - swap(a,b); - DLIB_TEST(b[0] == 3); - DLIB_TEST(b[1] == 2); - DLIB_TEST(b[2] == 1); - DLIB_TEST(b.size() == 3); - DLIB_TEST(a.size() == 0); - - - swap(b,c); - swap(c,c); - - - std_vector_c h(a); - std_vector_c i(c); - std::vector j(b); - } - } a; - -} - diff --git a/lib/3rdParty/dlib/include/dlib/test/string.cpp b/lib/3rdParty/dlib/include/dlib/test/string.cpp deleted file mode 100644 index c554c64a..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/string.cpp +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright (C) 2007 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.string"); - - - void string_test ( - ) - /*! - ensures - - runs tests on string functions for compliance with the specs - !*/ - { - - print_spinner(); - - string a = " davis "; - string A = " DAVIS "; - string empty = " "; - - dlog << LTRACE << 1; - - double dval; - int ival; - bool bval; - - DLIB_TEST_MSG(string_cast("5") == 5,string_cast("5")); - DLIB_TEST_MSG(string_cast("0x5") == 5,string_cast("0x5")); - DLIB_TEST_MSG(string_cast("0xA") == 10,string_cast("0xA")); - DLIB_TEST(string_cast("0.5") == 0.5); - DLIB_TEST((dval = sa ="0.5") == 0.5); - DLIB_TEST(string_cast("0.5 !") == "0.5 !"); - DLIB_TEST(string_cast("true") == true); - DLIB_TEST((bval = sa = "true") == true); - DLIB_TEST(string_cast("false") == false); - DLIB_TEST(string_cast("TRUE") == true); - DLIB_TEST(string_cast("FALSE") == false); - DLIB_TEST((bval = sa = "FALSE") == false); - - dlog << LTRACE << 2; - - DLIB_TEST_MSG(string_cast(L"5") == 5,string_cast("5")); - DLIB_TEST_MSG((ival = sa = L"5") == 5,string_cast("5")); - dlog << LTRACE << 2.1; - DLIB_TEST_MSG(string_cast(L"0x5") == 5,string_cast("0x5")); - DLIB_TEST_MSG(string_cast(L"0xA") == 10,string_cast("0xA")); - DLIB_TEST(string_cast(L"0.5") == 0.5); - DLIB_TEST(string_cast(L"0.5 !") == "0.5 !"); - DLIB_TEST(string_cast(L"true") == true); - DLIB_TEST(string_cast(L"false") == false); - DLIB_TEST(string_cast(L"TRUE") == true); - DLIB_TEST((bval = sa = L"TRUE") == true); - DLIB_TEST(string_cast(L"FALSE") == false); - - dlog << LTRACE << 3; - - DLIB_TEST(cast_to_string(5) == "5"); - DLIB_TEST(cast_to_string(5.5) == "5.5"); - - dlog << LTRACE << 4; - DLIB_TEST(cast_to_wstring(5) == L"5"); - DLIB_TEST(cast_to_wstring(5.5) == L"5.5"); - dlog << LTRACE << 5; - DLIB_TEST(toupper(a) == A); - DLIB_TEST(toupper(A) == A); - DLIB_TEST(tolower(a) == a); - DLIB_TEST(tolower(A) == a); - DLIB_TEST(trim(a) == "davis"); - DLIB_TEST(ltrim(a) == "davis "); - DLIB_TEST(rtrim(a) == " davis"); - DLIB_TEST(trim(string_cast(a)) == L"davis"); - DLIB_TEST(ltrim(string_cast(a)) == L"davis "); - DLIB_TEST(rtrim(string_cast(a)) == L" davis"); - DLIB_TEST(trim(a, " ") == "davis"); - DLIB_TEST(ltrim(a, " ") == "davis "); - DLIB_TEST(rtrim(a, " ") == " davis"); - DLIB_TEST(trim(empty) == ""); - DLIB_TEST(ltrim(empty) == ""); - DLIB_TEST(rtrim(empty) == ""); - DLIB_TEST(trim(string_cast(empty)) == L""); - DLIB_TEST(ltrim(string_cast(empty)) == L""); - DLIB_TEST(rtrim(string_cast(empty)) == L""); - DLIB_TEST(trim(empty, " ") == ""); - DLIB_TEST(ltrim(empty, " ") == ""); - DLIB_TEST(rtrim(empty, " ") == ""); - - - dlog << LTRACE << 6; - DLIB_TEST( (lpad(wstring(L"davis"), 10) == L" davis")); - DLIB_TEST( (rpad(wstring(L"davis"), 10) == L"davis ")); - DLIB_TEST( (pad(wstring(L"davis"), 10) == L" davis ")); - - DLIB_TEST( (lpad(string("davis"), -10) == "davis")); - DLIB_TEST( (rpad(string("davis"), -10) == "davis")); - DLIB_TEST( (pad(string("davis"), -10) == "davis")); - DLIB_TEST( (lpad(string("davis"), 10) == " davis")); - DLIB_TEST( (rpad(string("davis"), 10) == "davis ")); - DLIB_TEST( (pad(string("davis"), 10) == " davis ")); - DLIB_TEST( (lpad(string("davis"), 10, string("*")) == "*****davis")); - DLIB_TEST( (rpad(string("davis"), 10, string("*")) == "davis*****")); - DLIB_TEST( (pad(string("davis"), 10, string("*")) == "**davis***")); - DLIB_TEST( (lpad(string("davis"), 10, string("_-")) == "_-_-_davis")); - DLIB_TEST( (rpad(string("davis"), 10, string("_-")) == "davis_-_-_")); - DLIB_TEST( (pad(string("davis"), 10, string("_-")) == "_-davis_-_")); - DLIB_TEST( (lpad(string("davis"), 10, string("willy wanka")) == "willydavis")); - DLIB_TEST( (rpad(string("davis"), 10, string("willy wanka")) == "daviswilly")); - DLIB_TEST( (pad(string("davis"), 10, string("willy wanka")) == "widaviswil")); - DLIB_TEST( (lpad(string("davis"), 10, "*")) == "*****davis"); - DLIB_TEST( (rpad(string("davis"), 10, "*") == "davis*****")); - DLIB_TEST( (pad(string("davis"), 10, "*") == "**davis***")); - DLIB_TEST( (lpad(string("davis"), 10, "_-") == "_-_-_davis")); - DLIB_TEST( (rpad(string("davis"), 10, "_-") == "davis_-_-_")); - DLIB_TEST( (pad(string("davis"), 10, "_-") == "_-davis_-_")); - DLIB_TEST( (lpad(string("davis"), 10, "willy wanka") == "willydavis")); - DLIB_TEST( (rpad(string("davis"), 10, "willy wanka") == "daviswilly")); - DLIB_TEST( (pad(string("davis"), 10, "willy wanka") == "widaviswil")); - dlog << LTRACE << 7; - - a = "file.txt"; - DLIB_TEST( (left_substr(a,string(".")) == "file")); - DLIB_TEST( (left_substr(a,".") == "file")); - DLIB_TEST( (right_substr(a,string(".")) == "txt")); - DLIB_TEST( (right_substr(a,".") == "txt")); - - DLIB_TEST( (left_substr(a," ") == "file.txt")); - DLIB_TEST( (right_substr(a," ") == "")); - - DLIB_TEST( (left_substr(a,"") == "file.txt")); - DLIB_TEST( (right_substr(a,"") == "")); - - wstring ws = L"file.txt"; - DLIB_TEST( (left_substr(ws,wstring(L".")) == L"file")); - DLIB_TEST_MSG( (left_substr(ws,L".") == L"file"), L""); - DLIB_TEST( (right_substr(ws,wstring(L".")) == L"txt")); - DLIB_TEST_MSG( (right_substr(ws,L".") == L"txt"), L""); - - - dlog << LTRACE << 8; - { - ostringstream sout; - wchar_t w = 85; - char c = 4; - serialize(w,sout); - serialize(c,sout); - w = static_cast(-1); - serialize(w,sout); - c = static_cast(-1); - serialize(c,sout); - - istringstream sin(sout.str()); - w = 0; - c = 0; - deserialize(w,sin); - deserialize(c,sin); - DLIB_TEST(w == 85); - DLIB_TEST(c == 4); - deserialize(w,sin); - deserialize(c,sin); - DLIB_TEST(w == static_cast(-1)); - DLIB_TEST(c == static_cast(-1)); - - wstring str = L"test string"; - - sout.str(""); - serialize(str, sout); - sin.clear(); - sin.str(sout.str()); - str = L"something else"; - deserialize(str,sin); - DLIB_TEST(str == L"test string"); - } - } - - - void test_split() - { - std::vector v; - - string str; - string delim = " , "; - - v = split(string("one, two,three four")," ,"); - DLIB_TEST(v.size() == 4); - DLIB_TEST(v[0] == "one"); - DLIB_TEST(v[1] == "two"); - DLIB_TEST(v[2] == "three"); - DLIB_TEST(v[3] == "four"); - - v = split(string("one, two,three four"),delim); - DLIB_TEST(v.size() == 4); - DLIB_TEST(v[0] == "one"); - DLIB_TEST(v[1] == "two"); - DLIB_TEST(v[2] == "three"); - DLIB_TEST(v[3] == "four"); - - v = split(string("")); - DLIB_TEST(v.size() == 0); - - v = split(string(" ")); - DLIB_TEST(v.size() == 0); - - v = split(string(" one two ")); - DLIB_TEST(v.size() == 2); - DLIB_TEST(v[0] == "one"); - DLIB_TEST(v[1] == "two"); - - v = split(string(" one ")); - DLIB_TEST(v.size() == 1); - DLIB_TEST(v[0] == "one"); - - v = split(string("one")); - DLIB_TEST(v.size() == 1); - DLIB_TEST(v[0] == "one"); - - v = split(string("o")); - DLIB_TEST(v.size() == 1); - DLIB_TEST(v[0] == "o"); - - - std::vector wv; - wstring wstr = L"test string"; - wv = split(wstr); - DLIB_TEST(wv.size() == 2); - DLIB_TEST(wv[0] == L"test"); - DLIB_TEST(wv[1] == L"string"); - wv = split(wstr,L" "); - DLIB_TEST(wv.size() == 2); - DLIB_TEST(wv[0] == L"test"); - DLIB_TEST(wv[1] == L"string"); - - - wstr = L"test string hah"; - DLIB_TEST(split_on_first(wstr).first == L"test"); - DLIB_TEST(split_on_first(wstr).second == L"string hah"); - DLIB_TEST(split_on_first(wstr,L"#").first == L"test string hah"); - DLIB_TEST(split_on_first(wstr,L"#").second == L""); - DLIB_TEST(split_on_last(wstr).first == L"test string"); - DLIB_TEST(split_on_last(wstr).second == L"hah"); - DLIB_TEST(split_on_last(wstr,L"#").first == L"test string hah"); - DLIB_TEST(split_on_last(wstr,L"#").second == L""); - wstr = L""; - DLIB_TEST(split_on_first(wstr).first == L""); - DLIB_TEST(split_on_first(wstr).second == L""); - - str = "test string hah"; - DLIB_TEST(split_on_first(str).first == "test"); - DLIB_TEST(split_on_first(str).second == "string hah"); - DLIB_TEST(split_on_first(str,"#").first == "test string hah"); - DLIB_TEST(split_on_first(str,"#").second == ""); - DLIB_TEST(split_on_last(str).first == "test string"); - DLIB_TEST(split_on_last(str).second == "hah"); - DLIB_TEST(split_on_last(str,"#").first == "test string hah"); - DLIB_TEST(split_on_last(str,"#").second == ""); - str = ""; - DLIB_TEST(split_on_first(str).first == ""); - DLIB_TEST(split_on_first(str).second == ""); - - wstr = L"test.string.hah"; - DLIB_TEST(split_on_first(wstr,L".").first == L"test"); - DLIB_TEST(split_on_first(wstr,L".").second == L"string.hah"); - DLIB_TEST(split_on_first(wstr).first == L"test.string.hah"); - DLIB_TEST(split_on_first(wstr).second == L""); - DLIB_TEST(split_on_last(wstr,L".").first == L"test.string"); - DLIB_TEST(split_on_last(wstr,L".").second == L"hah"); - DLIB_TEST(split_on_last(wstr).first == L"test.string.hah"); - DLIB_TEST(split_on_last(wstr).second == L""); - wstr = L""; - DLIB_TEST(split_on_first(wstr).first == L""); - DLIB_TEST(split_on_first(wstr).second == L""); - - str = "test.string.hah"; - DLIB_TEST(split_on_first(str,".").first == "test"); - DLIB_TEST(split_on_first(str,".").second == "string.hah"); - DLIB_TEST(split_on_first(str).first == "test.string.hah"); - DLIB_TEST(split_on_first(str).second == ""); - DLIB_TEST(split_on_last(str,".").first == "test.string"); - DLIB_TEST(split_on_last(str,".").second == "hah"); - DLIB_TEST(split_on_last(str).first == "test.string.hah"); - DLIB_TEST(split_on_last(str).second == ""); - str = ""; - DLIB_TEST(split_on_first(str).first == ""); - DLIB_TEST(split_on_first(str).second == ""); - } - - - - class string_tester : public tester - { - public: - string_tester ( - ) : - tester ("test_string", - "Runs tests on the string objects and functions.") - {} - - void perform_test ( - ) - { - string_test(); - test_split(); - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/svm.cpp b/lib/3rdParty/dlib/include/dlib/test/svm.cpp deleted file mode 100644 index e2af3eb5..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/svm.cpp +++ /dev/null @@ -1,661 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include "../stl_checked.h" -#include "../array.h" -#include "../rand.h" -#include "checkerboard.h" -#include - -#include "tester.h" -#include - - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.svm"); - -// ---------------------------------------------------------------------------------------- - - void test_clutering ( - ) - { - dlog << LINFO << " being test_clutering()"; - // Here we declare that our samples will be 2 dimensional column vectors. - typedef matrix sample_type; - - // Now we are making a typedef for the kind of kernel we want to use. I picked the - // radial basis kernel because it only has one parameter and generally gives good - // results without much fiddling. - typedef radial_basis_kernel kernel_type; - - // Here we declare an instance of the kcentroid object. The first argument to the constructor - // is the kernel we wish to use. The second is a parameter that determines the numerical - // accuracy with which the object will perform part of the learning algorithm. Generally - // smaller values give better results but cause the algorithm to run slower. You just have - // to play with it to decide what balance of speed and accuracy is right for your problem. - // Here we have set it to 0.01. - kcentroid kc(kernel_type(0.1),0.01); - - // Now we make an instance of the kkmeans object and tell it to use kcentroid objects - // that are configured with the parameters from the kc object we defined above. - kkmeans test(kc); - - std::vector samples; - std::vector initial_centers; - - sample_type m; - - dlib::rand rnd; - - print_spinner(); - // we will make 50 points from each class - const long num = 50; - - // make some samples near the origin - double radius = 0.5; - for (long i = 0; i < num; ++i) - { - double sign = 1; - if (rnd.get_random_double() < 0.5) - sign = -1; - m(0) = 2*radius*rnd.get_random_double()-radius; - m(1) = sign*sqrt(radius*radius - m(0)*m(0)); - - // add this sample to our set of samples we will run k-means - samples.push_back(m); - } - - // make some samples in a circle around the origin but far away - radius = 10.0; - for (long i = 0; i < num; ++i) - { - double sign = 1; - if (rnd.get_random_double() < 0.5) - sign = -1; - m(0) = 2*radius*rnd.get_random_double()-radius; - m(1) = sign*sqrt(radius*radius - m(0)*m(0)); - - // add this sample to our set of samples we will run k-means - samples.push_back(m); - } - - // make some samples in a circle around the point (25,25) - radius = 4.0; - for (long i = 0; i < num; ++i) - { - double sign = 1; - if (rnd.get_random_double() < 0.5) - sign = -1; - m(0) = 2*radius*rnd.get_random_double()-radius; - m(1) = sign*sqrt(radius*radius - m(0)*m(0)); - - // translate this point away from the origin - m(0) += 25; - m(1) += 25; - - // add this sample to our set of samples we will run k-means - samples.push_back(m); - } - print_spinner(); - - // tell the kkmeans object we made that we want to run k-means with k set to 3. - // (i.e. we want 3 clusters) - test.set_number_of_centers(3); - - // You need to pick some initial centers for the k-means algorithm. So here - // we will use the dlib::pick_initial_centers() function which tries to find - // n points that are far apart (basically). - pick_initial_centers(3, initial_centers, samples, test.get_kernel()); - - print_spinner(); - // now run the k-means algorithm on our set of samples. - test.train(samples,initial_centers); - print_spinner(); - - const unsigned long class1 = test(samples[0]); - const unsigned long class2 = test(samples[num]); - const unsigned long class3 = test(samples[2*num]); - // now loop over all our samples and print out their predicted class. In this example - // all points are correctly identified. - for (unsigned long i = 0; i < samples.size()/3; ++i) - { - DLIB_TEST(test(samples[i]) == class1); - DLIB_TEST(test(samples[i+num]) == class2); - DLIB_TEST(test(samples[i+2*num]) == class3); - } - - dlog << LINFO << " end test_clutering()"; - } - -// ---------------------------------------------------------------------------------------- - - // Here is the sinc function we will be trying to learn with the krls - // object. - double sinc(double x) - { - if (x == 0) - return 1; - return sin(x)/x; - } - - - void test_regression ( - ) - { - dlog << LINFO << " being test_regression()"; - // Here we declare that our samples will be 1 dimensional column vectors. The reason for - // using a matrix here is that in general you can use N dimensional vectors as inputs to the - // krls object. But here we only have 1 dimension to make the example simple. - typedef matrix sample_type; - - // Now we are making a typedef for the kind of kernel we want to use. I picked the - // radial basis kernel because it only has one parameter and generally gives good - // results without much fiddling. - typedef radial_basis_kernel kernel_type; - - // Here we declare an instance of the krls object. The first argument to the constructor - // is the kernel we wish to use. The second is a parameter that determines the numerical - // accuracy with which the object will perform part of the regression algorithm. Generally - // smaller values give better results but cause the algorithm to run slower. You just have - // to play with it to decide what balance of speed and accuracy is right for your problem. - // Here we have set it to 0.001. - krls test(kernel_type(0.1),0.001); - rvm_regression_trainer rvm_test; - rvm_test.set_kernel(test.get_kernel()); - - krr_trainer krr_test; - krr_test.set_kernel(test.get_kernel()); - - svr_trainer svr_test; - svr_test.set_kernel(test.get_kernel()); - svr_test.set_epsilon_insensitivity(0.0001); - svr_test.set_c(10); - - rbf_network_trainer rbf_test; - rbf_test.set_kernel(test.get_kernel()); - rbf_test.set_num_centers(13); - - print_spinner(); - std::vector samples; - std::vector samples2; - std::vector labels; - std::vector labels2; - // now we train our object on a few samples of the sinc function. - sample_type m; - for (double x = -10; x <= 5; x += 0.6) - { - m(0) = x; - test.train(m, sinc(x)); - - samples.push_back(m); - samples2.push_back(m); - labels.push_back(sinc(x)); - labels2.push_back(2); - } - - print_spinner(); - decision_function test2 = rvm_test.train(samples, labels); - print_spinner(); - decision_function test3 = rbf_test.train(samples, labels); - print_spinner(); - decision_function test4 = krr_test.train(samples, labels); - print_spinner(); - decision_function test5 = svr_test.train(samples, labels); - print_spinner(); - - // now we output the value of the sinc function for a few test points as well as the - // value predicted by krls object. - m(0) = 2.5; dlog << LDEBUG << "krls: " << sinc(m(0)) << " " << test(m); DLIB_TEST(abs(sinc(m(0)) - test(m)) < 0.01); - m(0) = 0.1; dlog << LDEBUG << "krls: " << sinc(m(0)) << " " << test(m); DLIB_TEST(abs(sinc(m(0)) - test(m)) < 0.01); - m(0) = -4; dlog << LDEBUG << "krls: " << sinc(m(0)) << " " << test(m); DLIB_TEST(abs(sinc(m(0)) - test(m)) < 0.01); - m(0) = 5.0; dlog << LDEBUG << "krls: " << sinc(m(0)) << " " << test(m); DLIB_TEST(abs(sinc(m(0)) - test(m)) < 0.01); - - m(0) = 2.5; dlog << LDEBUG << "rvm: " << sinc(m(0)) << " " << test2(m); DLIB_TEST(abs(sinc(m(0)) - test2(m)) < 0.01); - m(0) = 0.1; dlog << LDEBUG << "rvm: " << sinc(m(0)) << " " << test2(m); DLIB_TEST(abs(sinc(m(0)) - test2(m)) < 0.01); - m(0) = -4; dlog << LDEBUG << "rvm: " << sinc(m(0)) << " " << test2(m); DLIB_TEST(abs(sinc(m(0)) - test2(m)) < 0.01); - m(0) = 5.0; dlog << LDEBUG << "rvm: " << sinc(m(0)) << " " << test2(m); DLIB_TEST(abs(sinc(m(0)) - test2(m)) < 0.01); - - m(0) = 2.5; dlog << LDEBUG << "rbf: " << sinc(m(0)) << " " << test3(m); DLIB_TEST(abs(sinc(m(0)) - test3(m)) < 0.01); - m(0) = 0.1; dlog << LDEBUG << "rbf: " << sinc(m(0)) << " " << test3(m); DLIB_TEST(abs(sinc(m(0)) - test3(m)) < 0.01); - m(0) = -4; dlog << LDEBUG << "rbf: " << sinc(m(0)) << " " << test3(m); DLIB_TEST(abs(sinc(m(0)) - test3(m)) < 0.01); - m(0) = 5.0; dlog << LDEBUG << "rbf: " << sinc(m(0)) << " " << test3(m); DLIB_TEST(abs(sinc(m(0)) - test3(m)) < 0.01); - - m(0) = 2.5; dlog << LDEBUG << "krr: " << sinc(m(0)) << " " << test4(m); DLIB_TEST(abs(sinc(m(0)) - test4(m)) < 0.01); - m(0) = 0.1; dlog << LDEBUG << "krr: " << sinc(m(0)) << " " << test4(m); DLIB_TEST(abs(sinc(m(0)) - test4(m)) < 0.01); - m(0) = -4; dlog << LDEBUG << "krr: " << sinc(m(0)) << " " << test4(m); DLIB_TEST(abs(sinc(m(0)) - test4(m)) < 0.01); - m(0) = 5.0; dlog << LDEBUG << "krr: " << sinc(m(0)) << " " << test4(m); DLIB_TEST(abs(sinc(m(0)) - test4(m)) < 0.01); - - m(0) = 2.5; dlog << LDEBUG << "svr: " << sinc(m(0)) << " " << test5(m); DLIB_TEST(abs(sinc(m(0)) - test5(m)) < 0.01); - m(0) = 0.1; dlog << LDEBUG << "svr: " << sinc(m(0)) << " " << test5(m); DLIB_TEST(abs(sinc(m(0)) - test5(m)) < 0.01); - m(0) = -4; dlog << LDEBUG << "svr: " << sinc(m(0)) << " " << test5(m); DLIB_TEST(abs(sinc(m(0)) - test5(m)) < 0.01); - m(0) = 5.0; dlog << LDEBUG << "svr: " << sinc(m(0)) << " " << test5(m); DLIB_TEST(abs(sinc(m(0)) - test5(m)) < 0.01); - - - randomize_samples(samples, labels); - dlog << LINFO << "KRR MSE and R-squared: "<< cross_validate_regression_trainer(krr_test, samples, labels, 6); - dlog << LINFO << "SVR MSE and R-squared: "<< cross_validate_regression_trainer(svr_test, samples, labels, 6); - matrix cv = cross_validate_regression_trainer(krr_test, samples, labels, 6); - DLIB_TEST(cv(0) < 1e-4); - DLIB_TEST(cv(1) > 0.99); - cv = cross_validate_regression_trainer(svr_test, samples, labels, 6); - DLIB_TEST(cv(0) < 1e-4); - DLIB_TEST(cv(1) > 0.99); - - - - - randomize_samples(samples2, labels2); - dlog << LINFO << "KRR MSE and R-squared: "<< cross_validate_regression_trainer(krr_test, samples2, labels2, 6); - dlog << LINFO << "SVR MSE and R-squared: "<< cross_validate_regression_trainer(svr_test, samples2, labels2, 6); - cv = cross_validate_regression_trainer(krr_test, samples2, labels2, 6); - DLIB_TEST(cv(0) < 1e-4); - cv = cross_validate_regression_trainer(svr_test, samples2, labels2, 6); - DLIB_TEST(cv(0) < 1e-4); - - dlog << LINFO << " end test_regression()"; - } - -// ---------------------------------------------------------------------------------------- - - void test_anomaly_detection ( - ) - { - dlog << LINFO << " begin test_anomaly_detection()"; - // Here we declare that our samples will be 2 dimensional column vectors. - typedef matrix sample_type; - - // Now we are making a typedef for the kind of kernel we want to use. I picked the - // radial basis kernel because it only has one parameter and generally gives good - // results without much fiddling. - typedef radial_basis_kernel kernel_type; - - // Here we declare an instance of the kcentroid object. The first argument to the constructor - // is the kernel we wish to use. The second is a parameter that determines the numerical - // accuracy with which the object will perform part of the learning algorithm. Generally - // smaller values give better results but cause the algorithm to run slower. You just have - // to play with it to decide what balance of speed and accuracy is right for your problem. - // Here we have set it to 0.01. - kcentroid test(kernel_type(0.1),0.01); - - - svm_one_class_trainer one_class_trainer; - one_class_trainer.set_nu(0.4); - one_class_trainer.set_kernel(kernel_type(0.2)); - - std::vector samples; - - // now we train our object on a few samples of the sinc function. - sample_type m; - for (double x = -15; x <= 8; x += 1) - { - m(0) = x; - m(1) = sinc(x); - test.train(m); - samples.push_back(m); - } - - decision_function df = one_class_trainer.train(samples); - - running_stats rs; - - // Now lets output the distance from the centroid to some points that are from the sinc function. - // These numbers should all be similar. We will also calculate the statistics of these numbers - // by accumulating them into the running_stats object called rs. This will let us easily - // find the mean and standard deviation of the distances for use below. - dlog << LDEBUG << "Points that are on the sinc function:\n"; - m(0) = -1.5; m(1) = sinc(m(0)); dlog << LDEBUG << " " << test(m); rs.add(test(m)); - m(0) = -1.5; m(1) = sinc(m(0)); dlog << LDEBUG << " " << test(m); rs.add(test(m)); - m(0) = -0; m(1) = sinc(m(0)); dlog << LDEBUG << " " << test(m); rs.add(test(m)); - m(0) = -0.5; m(1) = sinc(m(0)); dlog << LDEBUG << " " << test(m); rs.add(test(m)); - m(0) = -4.1; m(1) = sinc(m(0)); dlog << LDEBUG << " " << test(m); rs.add(test(m)); - m(0) = -1.5; m(1) = sinc(m(0)); dlog << LDEBUG << " " << test(m); rs.add(test(m)); - m(0) = -0.5; m(1) = sinc(m(0)); dlog << LDEBUG << " " << test(m); rs.add(test(m)); - - m(0) = -1.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(rs.scale(test(m)) < 2, rs.scale(test(m))); - m(0) = -1.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(rs.scale(test(m)) < 2, rs.scale(test(m))); - m(0) = -0; m(1) = sinc(m(0)); DLIB_TEST_MSG(rs.scale(test(m)) < 2, rs.scale(test(m))); - m(0) = -0.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(rs.scale(test(m)) < 2, rs.scale(test(m))); - m(0) = -4.1; m(1) = sinc(m(0)); DLIB_TEST_MSG(rs.scale(test(m)) < 2, rs.scale(test(m))); - m(0) = -1.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(rs.scale(test(m)) < 2, rs.scale(test(m))); - m(0) = -0.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(rs.scale(test(m)) < 2, rs.scale(test(m))); - - const double thresh = 0.01; - m(0) = -1.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(df(m)+thresh > 0, df(m)); - m(0) = -1.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(df(m)+thresh > 0, df(m)); - m(0) = -0; m(1) = sinc(m(0)); DLIB_TEST_MSG(df(m)+thresh > 0, df(m)); - m(0) = -0.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(df(m)+thresh > 0, df(m)); - m(0) = -4.1; m(1) = sinc(m(0)); DLIB_TEST_MSG(df(m)+thresh > 0, df(m)); - m(0) = -1.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(df(m)+thresh > 0, df(m)); - m(0) = -0.5; m(1) = sinc(m(0)); DLIB_TEST_MSG(df(m)+thresh > 0, df(m)); - - dlog << LDEBUG; - // Lets output the distance from the centroid to some points that are NOT from the sinc function. - // These numbers should all be significantly bigger than previous set of numbers. We will also - // use the rs.scale() function to find out how many standard deviations they are away from the - // mean of the test points from the sinc function. So in this case our criterion for "significantly bigger" - // is > 3 or 4 standard deviations away from the above points that actually are on the sinc function. - dlog << LDEBUG << "Points that are NOT on the sinc function:\n"; - m(0) = -1.5; m(1) = sinc(m(0))+4; - dlog << LDEBUG << " " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc."; - DLIB_TEST_MSG(rs.scale(test(m)) > 6, rs.scale(test(m))); - DLIB_TEST_MSG(df(m) + thresh < 0, df(m)); - - m(0) = -1.5; m(1) = sinc(m(0))+3; - dlog << LDEBUG << " " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc."; - DLIB_TEST_MSG(rs.scale(test(m)) > 6, rs.scale(test(m))); - DLIB_TEST_MSG(df(m) + thresh < 0, df(m)); - - m(0) = -0; m(1) = -sinc(m(0)); - dlog << LDEBUG << " " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc."; - DLIB_TEST_MSG(rs.scale(test(m)) > 6, rs.scale(test(m))); - DLIB_TEST_MSG(df(m) + thresh < 0, df(m)); - - m(0) = -0.5; m(1) = -sinc(m(0)); - dlog << LDEBUG << " " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc."; - DLIB_TEST_MSG(rs.scale(test(m)) > 6, rs.scale(test(m))); - DLIB_TEST_MSG(df(m) + thresh < 0, df(m)); - - m(0) = -4.1; m(1) = sinc(m(0))+2; - dlog << LDEBUG << " " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc."; - DLIB_TEST_MSG(rs.scale(test(m)) > 6, rs.scale(test(m))); - DLIB_TEST_MSG(df(m) + thresh < 0, df(m)); - - m(0) = -1.5; m(1) = sinc(m(0))+0.9; - dlog << LDEBUG << " " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc."; - DLIB_TEST_MSG(rs.scale(test(m)) > 6, rs.scale(test(m))); - DLIB_TEST_MSG(df(m) + thresh < 0, df(m)); - - m(0) = -0.5; m(1) = sinc(m(0))+1; - dlog << LDEBUG << " " << test(m) << " is " << rs.scale(test(m)) << " standard deviations from sinc."; - DLIB_TEST_MSG(rs.scale(test(m)) > 6, rs.scale(test(m))); - DLIB_TEST_MSG(df(m) + thresh < 0, df(m)); - - dlog << LINFO << " end test_anomaly_detection()"; - } - -// ---------------------------------------------------------------------------------------- - - void unittest_binary_classification ( - ) - /*! - ensures - - runs tests on the svm stuff compliance with the specs - !*/ - { - dlog << LINFO << " begin unittest_binary_classification()"; - print_spinner(); - - - typedef double scalar_type; - typedef matrix sample_type; - - std::vector x; - std::vector > x_linearized; - std::vector y; - - get_checkerboard_problem(x,y, 300, 2); - const scalar_type gamma = 1; - - typedef radial_basis_kernel kernel_type; - - rbf_network_trainer rbf_trainer; - rbf_trainer.set_kernel(kernel_type(gamma)); - rbf_trainer.set_num_centers(100); - - rvm_trainer rvm_trainer; - rvm_trainer.set_kernel(kernel_type(gamma)); - - krr_trainer krr_trainer; - krr_trainer.use_classification_loss_for_loo_cv(); - krr_trainer.set_kernel(kernel_type(gamma)); - - svm_pegasos pegasos_trainer; - pegasos_trainer.set_kernel(kernel_type(gamma)); - pegasos_trainer.set_lambda(0.00001); - - - svm_c_ekm_trainer ocas_ekm_trainer; - ocas_ekm_trainer.set_kernel(kernel_type(gamma)); - ocas_ekm_trainer.set_c(100000); - - svm_nu_trainer trainer; - trainer.set_kernel(kernel_type(gamma)); - trainer.set_nu(0.05); - - svm_c_trainer c_trainer; - c_trainer.set_kernel(kernel_type(gamma)); - c_trainer.set_c(100); - - svm_c_linear_trainer > > lin_trainer; - lin_trainer.set_c(100000); - // use an ekm to linearize this dataset so we can use it with the lin_trainer - empirical_kernel_map ekm; - ekm.load(kernel_type(gamma), x); - for (unsigned long i = 0; i < x.size(); ++i) - x_linearized.push_back(ekm.project(x[i])); - - - print_spinner(); - matrix rvm_cv = cross_validate_trainer_threaded(rvm_trainer, x,y, 4, 2); - print_spinner(); - matrix krr_cv = cross_validate_trainer_threaded(krr_trainer, x,y, 4, 2); - print_spinner(); - matrix svm_cv = cross_validate_trainer(trainer, x,y, 4); - print_spinner(); - matrix svm_c_cv = cross_validate_trainer(c_trainer, x,y, 4); - print_spinner(); - matrix rbf_cv = cross_validate_trainer_threaded(rbf_trainer, x,y, 10, 2); - print_spinner(); - matrix lin_cv = cross_validate_trainer_threaded(lin_trainer, x_linearized, y, 4, 2); - print_spinner(); - matrix ocas_ekm_cv = cross_validate_trainer_threaded(ocas_ekm_trainer, x, y, 4, 2); - print_spinner(); - ocas_ekm_trainer.set_basis(randomly_subsample(x, 300)); - matrix ocas_ekm_cv2 = cross_validate_trainer_threaded(ocas_ekm_trainer, x, y, 4, 2); - print_spinner(); - matrix peg_cv = cross_validate_trainer_threaded(batch(pegasos_trainer,1.0), x,y, 4, 2); - print_spinner(); - matrix peg_c_cv = cross_validate_trainer_threaded(batch_cached(pegasos_trainer,1.0), x,y, 4, 2); - print_spinner(); - - dlog << LDEBUG << "rvm cv: " << rvm_cv; - dlog << LDEBUG << "krr cv: " << krr_cv; - dlog << LDEBUG << "nu-svm cv: " << svm_cv; - dlog << LDEBUG << "C-svm cv: " << svm_c_cv; - dlog << LDEBUG << "rbf cv: " << rbf_cv; - dlog << LDEBUG << "lin cv: " << lin_cv; - dlog << LDEBUG << "ocas_ekm cv: " << ocas_ekm_cv; - dlog << LDEBUG << "ocas_ekm cv2: " << ocas_ekm_cv2; - dlog << LDEBUG << "peg cv: " << peg_cv; - dlog << LDEBUG << "peg cached cv: " << peg_c_cv; - - // make sure the cached version of pegasos computes the same result - DLIB_TEST_MSG(sum(abs(peg_cv - peg_c_cv)) < std::sqrt(std::numeric_limits::epsilon()), - sum(abs(peg_cv - peg_c_cv)) << " \n" << peg_cv << peg_c_cv ); - - DLIB_TEST_MSG(mean(rvm_cv) > 0.9, rvm_cv); - DLIB_TEST_MSG(mean(krr_cv) > 0.9, krr_cv); - DLIB_TEST_MSG(mean(svm_cv) > 0.9, svm_cv); - DLIB_TEST_MSG(mean(svm_c_cv) > 0.9, svm_c_cv); - DLIB_TEST_MSG(mean(rbf_cv) > 0.9, rbf_cv); - DLIB_TEST_MSG(mean(lin_cv) > 0.9, lin_cv); - DLIB_TEST_MSG(mean(peg_cv) > 0.9, peg_cv); - DLIB_TEST_MSG(mean(peg_c_cv) > 0.9, peg_c_cv); - DLIB_TEST_MSG(mean(ocas_ekm_cv) > 0.9, ocas_ekm_cv); - DLIB_TEST_MSG(mean(ocas_ekm_cv2) > 0.9, ocas_ekm_cv2); - - const long num_sv = trainer.train(x,y).basis_vectors.size(); - print_spinner(); - const long num_rv = rvm_trainer.train(x,y).basis_vectors.size(); - print_spinner(); - dlog << LDEBUG << "num sv: " << num_sv; - dlog << LDEBUG << "num rv: " << num_rv; - print_spinner(); - ocas_ekm_trainer.clear_basis(); - const long num_bv = ocas_ekm_trainer.train(x,y).basis_vectors.size(); - dlog << LDEBUG << "num ekm bv: " << num_bv; - - DLIB_TEST(num_rv <= 17); - DLIB_TEST_MSG(num_sv <= 45, num_sv); - DLIB_TEST_MSG(num_bv <= 45, num_bv); - - decision_function df = reduced2(trainer, 19).train(x,y); - print_spinner(); - - matrix svm_reduced_error = test_binary_decision_function(df, x, y); - print_spinner(); - dlog << LDEBUG << "svm reduced test error: " << svm_reduced_error; - dlog << LDEBUG << "svm reduced num sv: " << df.basis_vectors.size(); - DLIB_TEST(mean(svm_reduced_error) > 0.9); - - svm_cv = cross_validate_trainer(reduced(trainer,30), x,y, 4); - dlog << LDEBUG << "svm reduced cv: " << svm_cv; - DLIB_TEST_MSG(mean(svm_cv) > 0.9, svm_cv); - - DLIB_TEST(df.basis_vectors.size() <= 19); - dlog << LINFO << " end unittest_binary_classification()"; - } - -// ---------------------------------------------------------------------------------------- - - template - struct kernel_der_obj - { - typename kernel_type::sample_type x; - kernel_type k; - - double operator()(const typename kernel_type::sample_type& y) const { return k(x,y); } - }; - - - template - void test_kernel_derivative ( - const kernel_type& k, - const typename kernel_type::sample_type& x, - const typename kernel_type::sample_type& y - ) - { - kernel_der_obj obj; - obj.x = x; - obj.k = k; - kernel_derivative der(obj.k); - DLIB_TEST(dlib::equal(derivative(obj)(y) , der(obj.x,y), 1e-5)); - } - - void test_kernel_derivative ( - ) - { - typedef matrix sample_type; - - sigmoid_kernel k1; - radial_basis_kernel k2; - linear_kernel k3; - polynomial_kernel k4(2,3,4); - - offset_kernel > k5; - offset_kernel > k6; - - dlib::rand rnd; - - sample_type x, y; - for (int i = 0; i < 10; ++i) - { - x = randm(2,1,rnd); - y = randm(2,1,rnd); - test_kernel_derivative(k1, x, y); - test_kernel_derivative(k2, x, y); - test_kernel_derivative(k3, x, y); - test_kernel_derivative(k4, x, y); - test_kernel_derivative(k5, x, y); - test_kernel_derivative(k6, x, y); - } - } - -// ---------------------------------------------------------------------------------------- - - void test_svm_trainer2() - { - typedef matrix sample_type; - typedef linear_kernel kernel_type; - - - std::vector samples; - std::vector labels; - - sample_type samp; - samp(0) = 1; - samp(1) = 1; - samples.push_back(samp); - labels.push_back(+1); - - samp(0) = 1; - samp(1) = 2; - samples.push_back(samp); - labels.push_back(-1); - - svm_c_trainer trainer; - - decision_function df = trainer.train(samples, labels); - - samp(0) = 1; - samp(1) = 1; - dlog << LINFO << "test +1 : "<< df(samp); - DLIB_TEST(df(samp) > 0); - samp(0) = 1; - samp(1) = 2; - dlog << LINFO << "test -1 : "<< df(samp); - DLIB_TEST(df(samp) < 0); - - svm_nu_trainer trainer2; - df = trainer2.train(samples, labels); - - samp(0) = 1; - samp(1) = 1; - dlog << LINFO << "test +1 : "<< df(samp); - DLIB_TEST(df(samp) > 0); - samp(0) = 1; - samp(1) = 2; - dlog << LINFO << "test -1 : "<< df(samp); - DLIB_TEST(df(samp) < 0); - - } - -// ---------------------------------------------------------------------------------------- - - class svm_tester : public tester - { - public: - svm_tester ( - ) : - tester ("test_svm", - "Runs tests on the svm/kernel algorithm components.") - {} - - void perform_test ( - ) - { - test_kernel_derivative(); - unittest_binary_classification(); - test_clutering(); - test_regression(); - test_anomaly_detection(); - test_svm_trainer2(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/svm_c_linear.cpp b/lib/3rdParty/dlib/include/dlib/test/svm_c_linear.cpp deleted file mode 100644 index 9e30d81f..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/svm_c_linear.cpp +++ /dev/null @@ -1,392 +0,0 @@ -// Copyright (C) 2010 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include "../stl_checked.h" -#include "../array.h" -#include "../rand.h" -#include "checkerboard.h" -#include - -#include "tester.h" -#include - - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.svm_c_linear"); - - typedef matrix sample_type; - typedef std::vector > sparse_sample_type; - -// ---------------------------------------------------------------------------------------- - - void run_prior_test() - { - typedef matrix sample_type; - typedef linear_kernel kernel_type; - - svm_c_linear_trainer trainer; - - std::vector samples; - std::vector labels; - - sample_type samp; - samp = 0, 0, 1; samples.push_back(samp); labels.push_back(+1); - samp = 0, 1, 0; samples.push_back(samp); labels.push_back(-1); - - trainer.set_c(10); - decision_function df = trainer.train(samples, labels); - - trainer.set_prior(df); - - samples.clear(); - labels.clear(); - samp = 1, 0, 0; samples.push_back(samp); labels.push_back(+1); - samp = 0, 1, 0; samples.push_back(samp); labels.push_back(-1); - - df = trainer.train(samples, labels); - - samp = 0, 0, 1; samples.push_back(samp); labels.push_back(+1); - matrix rs = test_binary_decision_function(df, samples, labels); - dlog << LINFO << rs; - DLIB_TEST(rs(0) == 1); - DLIB_TEST(rs(1) == 1); - - dlog << LINFO << trans(df.basis_vectors(0)); - DLIB_TEST(df.basis_vectors(0)(0) > 0); - DLIB_TEST(df.basis_vectors(0)(1) < 0); - DLIB_TEST(df.basis_vectors(0)(2) > 0); - } - - void run_prior_sparse_test() - { - typedef std::map sample_type; - typedef sparse_linear_kernel kernel_type; - - svm_c_linear_trainer trainer; - - std::vector samples; - std::vector labels; - - sample_type samp; - samp[0] = 1; samples.push_back(samp); labels.push_back(+1); samp.clear(); - samp[1] = 1; samples.push_back(samp); labels.push_back(-1); samp.clear(); - - trainer.set_c(10); - decision_function df = trainer.train(samples, labels); - - trainer.set_prior(df); - - samples.clear(); - labels.clear(); - samp[2] = 1; samples.push_back(samp); labels.push_back(+1); samp.clear(); - samp[1] = 1; samples.push_back(samp); labels.push_back(-1); samp.clear(); - - df = trainer.train(samples, labels); - - matrix rs = test_binary_decision_function(df, samples, labels); - dlog << LINFO << rs; - DLIB_TEST(rs(0) == 1); - DLIB_TEST(rs(1) == 1); - - matrix w = sparse_to_dense(df.basis_vectors(0)); - dlog << LINFO << trans(w); - DLIB_TEST(w(0) > 0.1); - DLIB_TEST(w(1) < -0.1); - DLIB_TEST(w(2) > 0.1); - } - - void get_simple_points ( - std::vector& samples, - std::vector& labels - ) - { - samples.clear(); - labels.clear(); - sample_type samp(2); - - samp = 0,0; - samples.push_back(samp); - labels.push_back(-1); - - samp = 0,1; - samples.push_back(samp); - labels.push_back(-1); - - samp = 3,0; - samples.push_back(samp); - labels.push_back(+1); - - samp = 3,1; - samples.push_back(samp); - labels.push_back(+1); - } - -// ---------------------------------------------------------------------------------------- - - void get_simple_points_sparse ( - std::vector& samples, - std::vector& labels - ) - { - samples.clear(); - labels.clear(); - sparse_sample_type samp; - - samp.push_back(make_pair(0, 0.0)); - samp.push_back(make_pair(1, 0.0)); - samples.push_back(samp); - labels.push_back(-1); - - samp.clear(); - samp.push_back(make_pair(0, 0.0)); - samp.push_back(make_pair(1, 1.0)); - samples.push_back(samp); - labels.push_back(-1); - - samp.clear(); - samp.push_back(make_pair(0, 3.0)); - samp.push_back(make_pair(1, 0.0)); - samples.push_back(samp); - labels.push_back(+1); - - samp.clear(); - samp.push_back(make_pair(0, 3.0)); - samp.push_back(make_pair(1, 1.0)); - samples.push_back(samp); - labels.push_back(+1); - } - -// ---------------------------------------------------------------------------------------- - - void test_sparse ( - ) - { - print_spinner(); - dlog << LINFO << "test with sparse vectors"; - std::vector samples; - std::vector labels; - - sample_type samp; - - get_simple_points_sparse(samples,labels); - - svm_c_linear_trainer > trainer; - trainer.set_c(1e4); - //trainer.be_verbose(); - trainer.set_epsilon(1e-11); - - - double obj; - decision_function > df = trainer.train(samples, labels, obj); - dlog << LDEBUG << "obj: "<< obj; - DLIB_TEST_MSG(abs(obj - 0.72222222222) < 1e-7, obj); - - DLIB_TEST(abs(df(samples[0]) - (-1)) < 1e-6); - DLIB_TEST(abs(df(samples[1]) - (-1)) < 1e-6); - DLIB_TEST(abs(df(samples[2]) - (1)) < 1e-6); - DLIB_TEST(abs(df(samples[3]) - (1)) < 1e-6); - - - // While we are at it, make sure the krr_trainer works with sparse samples - krr_trainer > krr; - - df = krr.train(samples, labels); - DLIB_TEST(abs(df(samples[0]) - (-1)) < 1e-6); - DLIB_TEST(abs(df(samples[1]) - (-1)) < 1e-6); - DLIB_TEST(abs(df(samples[2]) - (1)) < 1e-6); - DLIB_TEST(abs(df(samples[3]) - (1)) < 1e-6); - - - // Now test some of the sparse helper functions - DLIB_TEST(max_index_plus_one(samples) == 2); - DLIB_TEST(max_index_plus_one(samples[0]) == 2); - - matrix m; - m = 1; - add_to(m, samples[3]); - DLIB_TEST(m(0) == 1 + samples[3][0].second); - DLIB_TEST(m(1) == 1 + samples[3][1].second); - DLIB_TEST(m(2) == 1); - - m = 1; - subtract_from(m, samples[3]); - DLIB_TEST(m(0) == 1 - samples[3][0].second); - DLIB_TEST(m(1) == 1 - samples[3][1].second); - DLIB_TEST(m(2) == 1); - - m = 1; - add_to(m, samples[3], 2); - DLIB_TEST(m(0) == 1 + 2*samples[3][0].second); - DLIB_TEST(m(1) == 1 + 2*samples[3][1].second); - DLIB_TEST(m(2) == 1); - - m = 1; - subtract_from(m, samples[3], 2); - DLIB_TEST(m(0) == 1 - 2*samples[3][0].second); - DLIB_TEST(m(1) == 1 - 2*samples[3][1].second); - DLIB_TEST(m(2) == 1); - - } - -// ---------------------------------------------------------------------------------------- - - void test_dense ( - ) - { - print_spinner(); - dlog << LINFO << "test with dense vectors"; - std::vector samples; - std::vector labels; - - sample_type samp; - - get_simple_points(samples,labels); - - svm_c_linear_trainer > trainer; - trainer.set_c(1e4); - //trainer.be_verbose(); - trainer.set_epsilon(1e-11); - - - double obj; - decision_function > df = trainer.train(samples, labels, obj); - dlog << LDEBUG << "obj: "<< obj; - DLIB_TEST_MSG(abs(obj - 0.72222222222) < 1e-7, abs(obj - 0.72222222222)); - // There shouldn't be any margin violations since this dataset is so trivial. So that means the objective - // should be exactly the squared norm of the decision plane (times 0.5). - DLIB_TEST_MSG(abs(length_squared(df.basis_vectors(0))*0.5 + df.b*df.b*0.5 - 0.72222222222) < 1e-7, - length_squared(df.basis_vectors(0))*0.5 + df.b*df.b*0.5); - - DLIB_TEST(abs(df(samples[0]) - (-1)) < 1e-6); - DLIB_TEST(abs(df(samples[1]) - (-1)) < 1e-6); - DLIB_TEST(abs(df(samples[2]) - (1)) < 1e-6); - DLIB_TEST(abs(df(samples[3]) - (1)) < 1e-6); - } - -// ---------------------------------------------------------------------------------------- - - class tester_svm_c_linear : public tester - { - public: - tester_svm_c_linear ( - ) : - tester ("test_svm_c_linear", - "Runs tests on the svm_c_linear_trainer.") - {} - - void perform_test ( - ) - { - test_dense(); - test_sparse(); - run_prior_test(); - run_prior_sparse_test(); - - // test mixed sparse and dense dot products - { - std::map sv; - matrix dv(4); - - dv = 1,2,3,4; - - sv[0] = 1; - sv[3] = 1; - - - DLIB_TEST(dot(sv,dv) == 5); - DLIB_TEST(dot(dv,sv) == 5); - DLIB_TEST(dot(dv,dv) == 30); - DLIB_TEST(dot(sv,sv) == 2); - - sv[10] = 9; - DLIB_TEST(dot(sv,dv) == 5); - } - - // test mixed sparse dense assignments - { - std::map sv, sv2; - std::vector > sv3; - matrix dv(4), dv2; - - dv = 1,2,3,4; - - sv[0] = 1; - sv[3] = 1; - - - assign(dv2, dv); - - DLIB_TEST(dv2.size() == 4); - DLIB_TEST(dv2(0) == 1); - DLIB_TEST(dv2(1) == 2); - DLIB_TEST(dv2(2) == 3); - DLIB_TEST(dv2(3) == 4); - - assign(sv2, dv); - DLIB_TEST(sv2.size() == 4); - DLIB_TEST(sv2[0] == 1); - DLIB_TEST(sv2[1] == 2); - DLIB_TEST(sv2[2] == 3); - DLIB_TEST(sv2[3] == 4); - - assign(sv2, sv); - DLIB_TEST(sv2.size() == 2); - DLIB_TEST(sv2[0] == 1); - DLIB_TEST(sv2[1] == 0); - DLIB_TEST(sv2[2] == 0); - DLIB_TEST(sv2[3] == 1); - - assign(sv3, sv); - DLIB_TEST(sv3.size() == 2); - DLIB_TEST(sv3[0].second == 1); - DLIB_TEST(sv3[1].second == 1); - DLIB_TEST(sv3[0].first == 0); - DLIB_TEST(sv3[1].first == 3); - - assign(sv3, dv); - DLIB_TEST(sv3.size() == 4); - DLIB_TEST(sv3[0].second == 1); - DLIB_TEST(sv3[1].second == 2); - DLIB_TEST(sv3[2].second == 3); - DLIB_TEST(sv3[3].second == 4); - DLIB_TEST(sv3[0].first == 0); - DLIB_TEST(sv3[1].first == 1); - DLIB_TEST(sv3[2].first == 2); - DLIB_TEST(sv3[3].first == 3); - - assign(sv3, sv); - DLIB_TEST(sv3.size() == 2); - DLIB_TEST(sv3[0].second == 1); - DLIB_TEST(sv3[1].second == 1); - DLIB_TEST(sv3[0].first == 0); - DLIB_TEST(sv3[1].first == 3); - - sv.clear(); - assign(sv, sv3); - DLIB_TEST(sv.size() == 2); - DLIB_TEST(sv[0] == 1); - DLIB_TEST(sv[1] == 0); - DLIB_TEST(sv[2] == 0); - DLIB_TEST(sv[3] == 1); - - } - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/svm_c_linear_dcd.cpp b/lib/3rdParty/dlib/include/dlib/test/svm_c_linear_dcd.cpp deleted file mode 100644 index 32f6b9c8..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/svm_c_linear_dcd.cpp +++ /dev/null @@ -1,484 +0,0 @@ -// Copyright (C) 2012 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include - -#include "tester.h" - - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.svm_c_linear_dcd"); - -// ---------------------------------------------------------------------------------------- - - void test_sparse() - { - typedef std::map sample_type; - - - typedef sparse_linear_kernel kernel_type; - - - - svm_c_linear_trainer linear_trainer_cpa; - svm_c_linear_dcd_trainer linear_trainer; - - svm_c_linear_dcd_trainer::optimizer_state state; - - const double C = 0.2; - linear_trainer.set_epsilon(1e-10); - linear_trainer_cpa.set_epsilon(1e-10); - - - std::vector samples; - std::vector labels; - - // make an instance of a sample vector so we can use it below - sample_type sample; - - decision_function df, df2, df3; - - dlib::rand rnd; - // Now lets go into a loop and randomly generate 10000 samples. - double label = +1; - for (int i = 0; i < 100; ++i) - { - // flip this flag - label *= -1; - - sample.clear(); - - // now make a random sparse sample with at most 10 non-zero elements - for (int j = 0; j < 5; ++j) - { - int idx = rnd.get_random_32bit_number()%10; - double value = rnd.get_random_double(); - - sample[idx] = label*value; - } - - // Also save the samples we are generating so we can let the svm_c_linear_trainer - // learn from them below. - samples.push_back(sample); - labels.push_back(label); - - if (samples.size() > 1) - { - linear_trainer_cpa.set_c_class1(C); - linear_trainer_cpa.set_c_class2(1.5*C); - linear_trainer.set_c_class1(C/samples.size()); - linear_trainer.set_c_class2(1.5*C/samples.size()); - - df = linear_trainer.train(samples, labels, state); - df2 = linear_trainer_cpa.train(samples, labels); - df3 = linear_trainer.train(samples, labels); - - DLIB_TEST_MSG( dlib::distance(df.basis_vectors(0), df2.basis_vectors(0)) < 1e-8, dlib::distance(df.basis_vectors(0), df2.basis_vectors(0))); - DLIB_TEST( std::abs(df.b - df2.b) < 1e-8); - DLIB_TEST( dlib::distance(df.basis_vectors(0), df3.basis_vectors(0)) < 1e-8); - DLIB_TEST( std::abs(df.b - df3.b) < 1e-8); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void test_normal_no_bias() - { - typedef matrix sample_type; - - - typedef linear_kernel kernel_type; - - - - svm_c_linear_trainer linear_trainer_cpa; - svm_c_linear_dcd_trainer linear_trainer; - - svm_c_linear_dcd_trainer::optimizer_state state; - - const double C = 1.0; - linear_trainer.set_epsilon(1e-10); - linear_trainer_cpa.set_epsilon(1e-10); - - linear_trainer.include_bias(false); - - - std::vector samples, samples_explict_bias; - std::vector labels; - - // make an instance of a sample vector so we can use it below - sample_type sample; - - decision_function df, df2, df3; - - dlib::rand rnd; - // Now lets go into a loop and randomly generate 10000 samples. - double label = +1; - for (int i = 0; i < 100; ++i) - { - // flip this flag - label *= -1; - - sample = 0; - - // now make a random sparse sample with at most 10 non-zero elements - for (int j = 0; j < 5; ++j) - { - int idx = rnd.get_random_32bit_number()%9; - double value = rnd.get_random_double(); - - sample(idx) = label*value; - } - - // Also save the samples we are generating so we can let the svm_c_linear_trainer - // learn from them below. - samples.push_back(sample); - labels.push_back(label); - - sample(9) = -1; - samples_explict_bias.push_back(sample); - - if (samples.size() > 1) - { - linear_trainer_cpa.set_c_class1(C); - linear_trainer_cpa.set_c_class2(1.5*C); - linear_trainer.set_c_class1(C/samples.size()); - linear_trainer.set_c_class2(1.5*C/samples.size()); - - df = linear_trainer.train(samples_explict_bias, labels, state); - df2 = linear_trainer_cpa.train(samples, labels); - df3 = linear_trainer.train(samples_explict_bias, labels); - - DLIB_TEST( std::abs(df2.basis_vectors(0)(9)) < 1e-7); - DLIB_TEST_MSG( max(abs(colm(df.basis_vectors(0),0,9) - colm(df2.basis_vectors(0),0,9))) < 1e-6, max(abs(colm(df.basis_vectors(0),0,9) - colm(df2.basis_vectors(0),0,9)))); - DLIB_TEST( std::abs(df.basis_vectors(0)(9) - df2.b) < 1e-6); - DLIB_TEST( max(abs(df.basis_vectors(0) - df3.basis_vectors(0))) < 1e-6); - DLIB_TEST( std::abs(df.b - df3.b) < 1e-7); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void test_normal() - { - typedef matrix sample_type; - - - typedef linear_kernel kernel_type; - - - - svm_c_linear_trainer linear_trainer_cpa; - svm_c_linear_dcd_trainer linear_trainer; - - svm_c_linear_dcd_trainer::optimizer_state state; - - const double C = 1; - linear_trainer.set_epsilon(1e-10); - linear_trainer_cpa.set_epsilon(1e-10); - - std::vector samples; - std::vector labels; - - // make an instance of a sample vector so we can use it below - sample_type sample; - - decision_function df, df2, df3; - - dlib::rand rnd; - // Now lets go into a loop and randomly generate 10000 samples. - double label = +1; - for (int i = 0; i < 100; ++i) - { - // flip this flag - label *= -1; - - sample = 0; - - // now make a random sparse sample with at most 10 non-zero elements - for (int j = 0; j < 5; ++j) - { - int idx = rnd.get_random_32bit_number()%10; - double value = rnd.get_random_double(); - - sample(idx) = label*value; - } - - // Also save the samples we are generating so we can let the svm_c_linear_trainer - // learn from them below. - samples.push_back(sample); - labels.push_back(label); - - if (samples.size() > 1) - { - linear_trainer_cpa.set_c_class1(C); - linear_trainer_cpa.set_c_class2(1.5*C); - linear_trainer.set_c_class1(C/samples.size()); - linear_trainer.set_c_class2(1.5*C/samples.size()); - - df = linear_trainer.train(samples, labels, state); - df2 = linear_trainer_cpa.train(samples, labels); - df3 = linear_trainer.train(samples, labels); - - DLIB_TEST_MSG( max(abs(df.basis_vectors(0) - df2.basis_vectors(0))) < 1e-7, max(abs(df.basis_vectors(0) - df2.basis_vectors(0)))); - DLIB_TEST( std::abs(df.b - df2.b) < 1e-7); - DLIB_TEST( max(abs(df.basis_vectors(0) - df3.basis_vectors(0))) < 1e-7); - DLIB_TEST( std::abs(df.b - df3.b) < 1e-7); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void test_normal_force_last_weight(bool have_bias, bool force_weight) - { - typedef matrix sample_type; - dlog << LINFO << "have_bias: "<< have_bias << " force_weight: "<< force_weight; - - - typedef linear_kernel kernel_type; - - - svm_c_linear_trainer linear_trainer_cpa; - - svm_c_linear_dcd_trainer linear_trainer; - - svm_c_linear_dcd_trainer::optimizer_state state; - - const double C = 1; - linear_trainer.set_epsilon(1e-10); - linear_trainer_cpa.set_epsilon(1e-11); - - linear_trainer_cpa.force_last_weight_to_1(force_weight); - - linear_trainer.force_last_weight_to_1(force_weight); - linear_trainer.include_bias(have_bias); - - std::vector samples; - std::vector labels; - - // make an instance of a sample vector so we can use it below - sample_type sample; - - decision_function df, df2; - - running_stats rs; - - dlib::rand rnd; - // Now lets go into a loop and randomly generate 10000 samples. - double label = +1; - for (int i = 0; i < 40; ++i) - { - // flip this flag - label *= -1; - - sample = 0; - - // now make a random sparse sample with at most 10 non-zero elements - for (int j = 0; j < 5; ++j) - { - int idx = rnd.get_random_32bit_number()%9; - double value = rnd.get_random_double(); - - sample(idx) = label*value + label; - } - - sample(9) = 4; - - // Also save the samples we are generating so we can let the svm_c_linear_trainer - // learn from them below. - samples.push_back(sample); - labels.push_back(label); - - linear_trainer.set_c(C); - linear_trainer_cpa.set_c(C*samples.size()); - - df = linear_trainer.train(samples, labels, state); - - if (force_weight) - { - DLIB_TEST(std::abs(df.basis_vectors(0)(9) - 1) < 1e-8); - DLIB_TEST(std::abs(df.b) < 1e-8); - - if (samples.size() > 1) - { - df2 = linear_trainer_cpa.train(samples, labels); - DLIB_TEST_MSG( max(abs(df.basis_vectors(0) - df2.basis_vectors(0))) < 1e-7, max(abs(df.basis_vectors(0) - df2.basis_vectors(0)))); - DLIB_TEST( std::abs(df.b - df2.b) < 1e-7); - } - } - - if (!have_bias) - DLIB_TEST(std::abs(df.b) < 1e-8); - - - for (unsigned long k = 0; k < samples.size(); ++k) - { - //cout << "pred: "<< labels[k]*df(samples[k]) << endl; - rs.add(labels[k]*df(samples[k])); - } - } - DLIB_TEST_MSG(std::abs(rs.min()-1) < 1e-7, std::abs(rs.min()-1)); - } - -// ---------------------------------------------------------------------------------------- - - void test_normal_1_sample(double label) - { - typedef matrix sample_type; - - - typedef linear_kernel kernel_type; - - - - svm_c_linear_dcd_trainer linear_trainer; - - svm_c_linear_dcd_trainer::optimizer_state state; - - const double C = 10; - linear_trainer.set_epsilon(1e-10); - linear_trainer.set_c(C); - - - linear_trainer.force_last_weight_to_1(true); - linear_trainer.include_bias(false); - - std::vector samples; - std::vector labels; - - // make an instance of a sample vector so we can use it below - sample_type sample; - - sample = 0; - sample(0) = -1; - sample(1) = -1; - sample(9) = 4; - - samples.push_back(sample); - labels.push_back(label); - - for (int i = 0; i < 4; ++i) - { - decision_function df; - df = linear_trainer.train(samples, labels); - - if (label > 0) - { - DLIB_TEST(std::abs(df(samples[0])-4) < 1e-8); - } - else - { - DLIB_TEST(std::abs(df(samples[0])+1) < 1e-8); - } - } - } - -// ---------------------------------------------------------------------------------------- - - void test_sparse_1_sample(double label) - { - typedef std::vector > sample_type; - - - typedef sparse_linear_kernel kernel_type; - - - - svm_c_linear_dcd_trainer linear_trainer; - - svm_c_linear_dcd_trainer::optimizer_state state; - - const double C = 10; - linear_trainer.set_epsilon(1e-10); - linear_trainer.set_c(C); - - - linear_trainer.force_last_weight_to_1(true); - linear_trainer.include_bias(false); - - std::vector samples; - std::vector labels; - - // make an instance of a sample vector so we can use it below - sample_type sample; - - sample.push_back(make_pair(0,-1)); - sample.push_back(make_pair(1,1)); - sample.push_back(make_pair(9,4)); - - for (int i = 0; i < 4; ++i) - { - samples.push_back(sample); - labels.push_back(label); - - decision_function df; - df = linear_trainer.train(samples, labels); - - - if (label > 0) - { - DLIB_TEST(std::abs(df(samples[0])-4) < 1e-8); - } - else - { - DLIB_TEST(std::abs(df(samples[0])+1) < 1e-8); - } - } - } - -// ---------------------------------------------------------------------------------------- - - class tester_svm_c_linear_dcd : public tester - { - public: - tester_svm_c_linear_dcd ( - ) : - tester ("test_svm_c_linear_dcd", - "Runs tests on the svm_c_linear_dcd_trainer.") - {} - - void perform_test ( - ) - { - test_normal(); - print_spinner(); - test_normal_no_bias(); - print_spinner(); - test_sparse(); - print_spinner(); - test_normal_force_last_weight(false,false); - print_spinner(); - test_normal_force_last_weight(false,true); - print_spinner(); - test_normal_force_last_weight(true,false); - print_spinner(); - test_normal_force_last_weight(true,true); - print_spinner(); - test_normal_1_sample(+1); - print_spinner(); - test_normal_1_sample(-1); - print_spinner(); - test_sparse_1_sample(+1); - print_spinner(); - test_sparse_1_sample(-1); - print_spinner(); - } - } a; - -} - - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/svm_multiclass_linear.cpp b/lib/3rdParty/dlib/include/dlib/test/svm_multiclass_linear.cpp deleted file mode 100644 index e01d4889..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/svm_multiclass_linear.cpp +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "tester.h" -#include -#include -#include "create_iris_datafile.h" -#include -#include -#include - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - dlib::logger dlog("test.svm_multiclass_trainer"); - - - class test_svm_multiclass_trainer : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a unit test. When it is constructed - it adds itself into the testing framework. - !*/ - public: - test_svm_multiclass_trainer ( - ) : - tester ( - "test_svm_multiclass_trainer", // the command line argument name for this test - "Run tests on the svm_multiclass_linear_trainer stuff.", // the command line argument description - 0 // the number of command line arguments for this test - ) - { - } - - - void test_prior () - { - print_spinner(); - typedef matrix sample_type; - typedef linear_kernel kernel_type; - - std::vector samples; - std::vector labels; - - for (int i = 0; i < 4; ++i) - { - if (i==2) - ++i; - for (int iter = 0; iter < 5; ++iter) - { - sample_type samp; - samp = 0; - samp(i) = 1; - samples.push_back(samp); - labels.push_back(i); - } - } - - - svm_multiclass_linear_trainer trainer; - - multiclass_linear_decision_function df = trainer.train(samples, labels); - - //cout << "test: \n" << test_multiclass_decision_function(df, samples, labels) << endl; - //cout << df.weights << endl; - //cout << df.b << endl; - - std::vector samples2; - std::vector labels2; - int i = 2; - for (int iter = 0; iter < 5; ++iter) - { - sample_type samp; - samp = 0; - samp(i) = 1; - samples2.push_back(samp); - labels2.push_back(i); - samples.push_back(samp); - labels.push_back(i); - } - - trainer.set_prior(df); - trainer.set_c(0.1); - df = trainer.train(samples2, labels2); - - matrix res = test_multiclass_decision_function(df, samples, labels); - dlog << LINFO << "test: \n" << res; - dlog << LINFO << df.weights; - dlog << LINFO << df.b; - DLIB_TEST((unsigned int)sum(diag(res))==samples.size()); - } - - void test_prior_sparse () - { - print_spinner(); - typedef std::map sample_type; - typedef sparse_linear_kernel kernel_type; - - std::vector samples; - std::vector labels; - - for (int i = 0; i < 4; ++i) - { - if (i==2) - ++i; - for (int iter = 0; iter < 5; ++iter) - { - sample_type samp; - samp[i] = 1; - samples.push_back(samp); - labels.push_back(i); - } - } - - - svm_multiclass_linear_trainer trainer; - - multiclass_linear_decision_function df = trainer.train(samples, labels); - - //cout << "test: \n" << test_multiclass_decision_function(df, samples, labels) << endl; - //cout << df.weights << endl; - //cout << df.b << endl; - - std::vector samples2; - std::vector labels2; - int i = 2; - for (int iter = 0; iter < 5; ++iter) - { - sample_type samp; - samp[i] = 1; - samp[i+10] = 1; - samples2.push_back(samp); - labels2.push_back(i); - samples.push_back(samp); - labels.push_back(i); - } - - trainer.set_prior(df); - trainer.set_c(0.1); - df = trainer.train(samples2, labels2); - - matrix res = test_multiclass_decision_function(df, samples, labels); - dlog << LINFO << "test: \n" << res; - dlog << LINFO << df.weights; - dlog << LINFO << df.b; - DLIB_TEST((unsigned int)sum(diag(res))==samples.size()); - } - - template - void run_test() - { - print_spinner(); - - typedef typename sample_type::value_type::second_type scalar_type; - - std::vector samples; - std::vector labels; - - load_libsvm_formatted_data("iris.scale",samples, labels); - - DLIB_TEST(samples.size() == 150); - DLIB_TEST(labels.size() == 150); - - typedef sparse_linear_kernel kernel_type; - svm_multiclass_linear_trainer trainer; - trainer.set_c(100); - trainer.set_epsilon(0.000001); - - randomize_samples(samples, labels); - matrix cv = cross_validate_multiclass_trainer(trainer, samples, labels, 4); - - dlog << LINFO << "confusion matrix: \n" << cv; - const scalar_type cv_accuracy = sum(diag(cv))/sum(cv); - dlog << LINFO << "cv accuracy: " << cv_accuracy; - DLIB_TEST(cv_accuracy > 0.97); - - - - - { - print_spinner(); - typedef matrix dsample_type; - std::vector dsamples = sparse_to_dense(samples); - DLIB_TEST(dsamples.size() == 150); - - typedef linear_kernel kernel_type; - svm_multiclass_linear_trainer trainer; - trainer.set_c(100); - - cv = cross_validate_multiclass_trainer(trainer, dsamples, labels, 4); - - dlog << LINFO << "dense confusion matrix: \n" << cv; - const scalar_type cv_accuracy = sum(diag(cv))/sum(cv); - dlog << LINFO << "dense cv accuracy: " << cv_accuracy; - DLIB_TEST(cv_accuracy > 0.97); - } - - } - - - - - void perform_test ( - ) - { - print_spinner(); - create_iris_datafile(); - - run_test >(); - run_test >(); - run_test > >(); - run_test > >(); - - test_prior(); - test_prior_sparse(); - } - }; - - test_svm_multiclass_trainer a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/svm_struct.cpp b/lib/3rdParty/dlib/include/dlib/test/svm_struct.cpp deleted file mode 100644 index 00208c48..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/svm_struct.cpp +++ /dev/null @@ -1,641 +0,0 @@ -// Copyright (C) 2011 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.svm_struct"); - - - template < - typename matrix_type, - typename sample_type, - typename label_type - > - class test_multiclass_svm_problem : public structural_svm_problem_threaded > > - { - - public: - typedef typename matrix_type::type scalar_type; - typedef std::vector > feature_vector_type; - - test_multiclass_svm_problem ( - const std::vector& samples_, - const std::vector& labels_ - ) : - structural_svm_problem_threaded > >(2), - samples(samples_), - labels(labels_), - dims(10+1) // +1 for the bias - { - for (int i = 0; i < 10; ++i) - { - distinct_labels.push_back(i); - } - } - - virtual long get_num_dimensions ( - ) const - { - return dims*10; - } - - virtual long get_num_samples ( - ) const - { - return static_cast(samples.size()); - } - - virtual void get_truth_joint_feature_vector ( - long idx, - feature_vector_type& psi - ) const - { - assign(psi, samples[idx]); - // Add a constant -1 to account for the bias term. - psi.push_back(std::make_pair(dims-1,static_cast(-1))); - - // Find which distinct label goes with this psi. - const long label_idx = index_of_max(mat(distinct_labels) == labels[idx]); - - offset_feature_vector(psi, dims*label_idx); - } - - virtual void separation_oracle ( - const long idx, - const matrix_type& current_solution, - scalar_type& loss, - feature_vector_type& psi - ) const - { - scalar_type best_val = -std::numeric_limits::infinity(); - unsigned long best_idx = 0; - - // Figure out which label is the best. That is, what label maximizes - // LOSS(idx,y) + F(x,y). Note that y in this case is given by distinct_labels[i]. - for (unsigned long i = 0; i < distinct_labels.size(); ++i) - { - // Compute the F(x,y) part: - // perform: temp == dot(relevant part of current solution, samples[idx]) - current_bias - scalar_type temp = dot(rowm(current_solution, range(i*dims, (i+1)*dims-2)), samples[idx]) - current_solution((i+1)*dims-1); - - // Add the LOSS(idx,y) part: - if (labels[idx] != distinct_labels[i]) - temp += 1; - - // Now temp == LOSS(idx,y) + F(x,y). Check if it is the biggest we have seen. - if (temp > best_val) - { - best_val = temp; - best_idx = i; - } - } - - assign(psi, samples[idx]); - // add a constant -1 to account for the bias term - psi.push_back(std::make_pair(dims-1,static_cast(-1))); - - offset_feature_vector(psi, dims*best_idx); - - if (distinct_labels[best_idx] == labels[idx]) - loss = 0; - else - loss = 1; - } - - private: - - void offset_feature_vector ( - feature_vector_type& sample, - const unsigned long val - ) const - { - if (val != 0) - { - for (typename feature_vector_type::iterator i = sample.begin(); i != sample.end(); ++i) - { - i->first += val; - } - } - } - - - const std::vector& samples; - const std::vector& labels; - std::vector distinct_labels; - const long dims; - }; - -// ---------------------------------------------------------------------------------------- - - template < - typename K, - typename label_type_ = typename K::scalar_type - > - class test_svm_multiclass_linear_trainer2 - { - public: - typedef label_type_ label_type; - typedef K kernel_type; - typedef typename kernel_type::scalar_type scalar_type; - typedef typename kernel_type::sample_type sample_type; - typedef typename kernel_type::mem_manager_type mem_manager_type; - - typedef multiclass_linear_decision_function trained_function_type; - - - test_svm_multiclass_linear_trainer2 ( - ) : - C(10), - eps(1e-4), - verbose(false) - { - } - - trained_function_type train ( - const std::vector& all_samples, - const std::vector& all_labels - ) const - { - scalar_type svm_objective = 0; - return train(all_samples, all_labels, svm_objective); - } - - trained_function_type train ( - const std::vector& all_samples, - const std::vector& all_labels, - scalar_type& svm_objective - ) const - { - // make sure requires clause is not broken - DLIB_ASSERT(is_learning_problem(all_samples,all_labels), - "\t trained_function_type test_svm_multiclass_linear_trainer2::train(all_samples,all_labels)" - << "\n\t invalid inputs were given to this function" - << "\n\t all_samples.size(): " << all_samples.size() - << "\n\t all_labels.size(): " << all_labels.size() - ); - - typedef matrix w_type; - w_type weights; - std::vector samples1(all_samples.begin(), all_samples.begin()+all_samples.size()/2); - std::vector samples2(all_samples.begin()+all_samples.size()/2, all_samples.end()); - - std::vector labels1(all_labels.begin(), all_labels.begin()+all_labels.size()/2); - std::vector labels2(all_labels.begin()+all_labels.size()/2, all_labels.end()); - test_multiclass_svm_problem problem1(samples1, labels1); - test_multiclass_svm_problem problem2(samples2, labels2); - problem1.set_max_cache_size(3); - problem2.set_max_cache_size(0); - - svm_struct_processing_node node1(problem1, 12345, 3); - svm_struct_processing_node node2(problem2, 12346, 0); - - solver.set_inactive_plane_threshold(50); - solver.set_subproblem_epsilon(1e-4); - - svm_struct_controller_node controller; - controller.set_c(C); - controller.set_epsilon(eps); - if (verbose) - controller.be_verbose(); - controller.add_processing_node("127.0.0.1", 12345); - controller.add_processing_node("localhost:12346"); - svm_objective = controller(solver, weights); - - - - trained_function_type df; - - const long dims = max_index_plus_one(all_samples); - df.labels = select_all_distinct_labels(all_labels); - df.weights = colm(reshape(weights, df.labels.size(), dims+1), range(0,dims-1)); - df.b = colm(reshape(weights, df.labels.size(), dims+1), dims); - return df; - } - - private: - scalar_type C; - scalar_type eps; - bool verbose; - mutable oca solver; - }; - -// ---------------------------------------------------------------------------------------- - - template < - typename K, - typename label_type_ = typename K::scalar_type - > - class test_svm_multiclass_linear_trainer3 - { - public: - typedef label_type_ label_type; - typedef K kernel_type; - typedef typename kernel_type::scalar_type scalar_type; - typedef typename kernel_type::sample_type sample_type; - typedef typename kernel_type::mem_manager_type mem_manager_type; - - typedef multiclass_linear_decision_function trained_function_type; - - - test_svm_multiclass_linear_trainer3 ( - ) : - C(10), - eps(1e-4), - verbose(false) - { - } - - trained_function_type train ( - const std::vector& all_samples, - const std::vector& all_labels - ) const - { - scalar_type svm_objective = 0; - return train(all_samples, all_labels, svm_objective); - } - - trained_function_type train ( - const std::vector& all_samples, - const std::vector& all_labels, - scalar_type& svm_objective - ) const - { - // make sure requires clause is not broken - DLIB_ASSERT(is_learning_problem(all_samples,all_labels), - "\t trained_function_type test_svm_multiclass_linear_trainer3::train(all_samples,all_labels)" - << "\n\t invalid inputs were given to this function" - << "\n\t all_samples.size(): " << all_samples.size() - << "\n\t all_labels.size(): " << all_labels.size() - ); - - typedef matrix w_type; - w_type weights; - test_multiclass_svm_problem problem(all_samples, all_labels); - problem.set_max_cache_size(0); - - problem.set_c(C); - problem.set_epsilon(eps); - - if (verbose) - problem.be_verbose(); - - solver.set_inactive_plane_threshold(50); - solver.set_subproblem_epsilon(1e-4); - svm_objective = solver(problem, weights); - - - trained_function_type df; - - const long dims = max_index_plus_one(all_samples); - df.labels = select_all_distinct_labels(all_labels); - df.weights = colm(reshape(weights, df.labels.size(), dims+1), range(0,dims-1)); - df.b = colm(reshape(weights, df.labels.size(), dims+1), dims); - return df; - } - - private: - scalar_type C; - scalar_type eps; - bool verbose; - mutable oca solver; - }; - -// ---------------------------------------------------------------------------------------- - - template < - typename K, - typename label_type_ = typename K::scalar_type - > - class test_svm_multiclass_linear_trainer4 - { - public: - typedef label_type_ label_type; - typedef K kernel_type; - typedef typename kernel_type::scalar_type scalar_type; - typedef typename kernel_type::sample_type sample_type; - typedef typename kernel_type::mem_manager_type mem_manager_type; - - typedef multiclass_linear_decision_function trained_function_type; - - - test_svm_multiclass_linear_trainer4 ( - ) : - C(10), - eps(1e-4), - verbose(false) - { - } - - trained_function_type train ( - const std::vector& all_samples, - const std::vector& all_labels - ) const - { - scalar_type svm_objective = 0; - return train(all_samples, all_labels, svm_objective); - } - - trained_function_type train ( - const std::vector& all_samples, - const std::vector& all_labels, - scalar_type& svm_objective - ) const - { - // make sure requires clause is not broken - DLIB_ASSERT(is_learning_problem(all_samples,all_labels), - "\t trained_function_type test_svm_multiclass_linear_trainer4::train(all_samples,all_labels)" - << "\n\t invalid inputs were given to this function" - << "\n\t all_samples.size(): " << all_samples.size() - << "\n\t all_labels.size(): " << all_labels.size() - ); - - typedef matrix w_type; - w_type weights; - test_multiclass_svm_problem problem(all_samples, all_labels); - problem.set_max_cache_size(3); - - problem.set_c(C); - problem.set_epsilon(eps); - - if (verbose) - problem.be_verbose(); - - solver.set_inactive_plane_threshold(50); - solver.set_subproblem_epsilon(1e-4); - svm_objective = solver(problem, weights); - - - trained_function_type df; - - const long dims = max_index_plus_one(all_samples); - df.labels = select_all_distinct_labels(all_labels); - df.weights = colm(reshape(weights, df.labels.size(), dims+1), range(0,dims-1)); - df.b = colm(reshape(weights, df.labels.size(), dims+1), dims); - return df; - } - - private: - scalar_type C; - scalar_type eps; - bool verbose; - mutable oca solver; - }; - -// ---------------------------------------------------------------------------------------- - - template < - typename K, - typename label_type_ = typename K::scalar_type - > - class test_svm_multiclass_linear_trainer5 - { - public: - typedef label_type_ label_type; - typedef K kernel_type; - typedef typename kernel_type::scalar_type scalar_type; - typedef typename kernel_type::sample_type sample_type; - typedef typename kernel_type::mem_manager_type mem_manager_type; - - typedef multiclass_linear_decision_function trained_function_type; - - - test_svm_multiclass_linear_trainer5 ( - ) : - C(10), - eps(1e-4), - verbose(false) - { - } - - trained_function_type train ( - const std::vector& all_samples, - const std::vector& all_labels - ) const - { - scalar_type svm_objective = 0; - return train(all_samples, all_labels, svm_objective); - } - - trained_function_type train ( - const std::vector& all_samples, - const std::vector& all_labels, - scalar_type& svm_objective - ) const - { - // make sure requires clause is not broken - DLIB_ASSERT(is_learning_problem(all_samples,all_labels), - "\t trained_function_type test_svm_multiclass_linear_trainer5::train(all_samples,all_labels)" - << "\n\t invalid inputs were given to this function" - << "\n\t all_samples.size(): " << all_samples.size() - << "\n\t all_labels.size(): " << all_labels.size() - ); - - typedef matrix w_type; - w_type weights; - const long dims = max_index_plus_one(all_samples); - trained_function_type df; - df.labels = select_all_distinct_labels(all_labels); - multiclass_svm_problem problem(all_samples, all_labels, df.labels, dims, 4); - problem.set_max_cache_size(3); - - problem.set_c(C); - problem.set_epsilon(eps); - - if (verbose) - problem.be_verbose(); - - solver.set_inactive_plane_threshold(50); - solver.set_subproblem_epsilon(1e-4); - svm_objective = solver(problem, weights); - - - - df.weights = colm(reshape(weights, df.labels.size(), dims+1), range(0,dims-1)); - df.b = colm(reshape(weights, df.labels.size(), dims+1), dims); - return df; - } - - private: - scalar_type C; - scalar_type eps; - bool verbose; - mutable oca solver; - }; - - -// ---------------------------------------------------------------------------------------- - - typedef matrix sample_type; - typedef double scalar_type; - - void make_dataset ( - std::vector& samples, - std::vector& labels, - int num, - dlib::rand& rnd - ) - { - samples.clear(); - labels.clear(); - for (int i = 0; i < 10; ++i) - { - for (int j = 0; j < num; ++j) - { - sample_type samp; - samp = 0; - samp(i) = 10*rnd.get_random_double()+1; - - samples.push_back(samp); - labels.push_back(i); - } - } - } - -// ---------------------------------------------------------------------------------------- - - class test_svm_struct : public tester - { - public: - test_svm_struct ( - ) : - tester ("test_svm_struct", - "Runs tests on the structural svm components.") - {} - - void run_test ( - const std::vector& samples, - const std::vector& labels, - const double true_obj - ) - { - typedef linear_kernel kernel_type; - svm_multiclass_linear_trainer trainer1; - test_svm_multiclass_linear_trainer2 trainer2; - test_svm_multiclass_linear_trainer3 trainer3; - test_svm_multiclass_linear_trainer4 trainer4; - test_svm_multiclass_linear_trainer5 trainer5; - - trainer1.set_epsilon(1e-4); - trainer1.set_c(10); - - - multiclass_linear_decision_function df1, df2, df3, df4, df5; - double obj1, obj2, obj3, obj4, obj5; - - // Solve a multiclass SVM a whole bunch of different ways and make sure - // they all give the same answer. - print_spinner(); - df1 = trainer1.train(samples, labels, obj1); - print_spinner(); - df2 = trainer2.train(samples, labels, obj2); - print_spinner(); - df3 = trainer3.train(samples, labels, obj3); - print_spinner(); - df4 = trainer4.train(samples, labels, obj4); - print_spinner(); - df5 = trainer5.train(samples, labels, obj5); - print_spinner(); - - dlog << LINFO << "obj1: "<< obj1; - dlog << LINFO << "obj2: "<< obj2; - dlog << LINFO << "obj3: "<< obj3; - dlog << LINFO << "obj4: "<< obj4; - dlog << LINFO << "obj5: "<< obj5; - DLIB_TEST(std::abs(obj1 - obj2) < 1e-2); - DLIB_TEST(std::abs(obj1 - obj3) < 1e-2); - DLIB_TEST(std::abs(obj1 - obj4) < 1e-2); - DLIB_TEST(std::abs(obj1 - obj5) < 1e-2); - DLIB_TEST(std::abs(obj1 - true_obj) < 1e-2); - DLIB_TEST(std::abs(obj2 - true_obj) < 1e-2); - DLIB_TEST(std::abs(obj3 - true_obj) < 1e-2); - DLIB_TEST(std::abs(obj4 - true_obj) < 1e-2); - DLIB_TEST(std::abs(obj5 - true_obj) < 1e-2); - - dlog << LINFO << "weight error: "<< max(abs(df1.weights - df2.weights)); - dlog << LINFO << "weight error: "<< max(abs(df1.weights - df3.weights)); - dlog << LINFO << "weight error: "<< max(abs(df1.weights - df4.weights)); - dlog << LINFO << "weight error: "<< max(abs(df1.weights - df5.weights)); - - DLIB_TEST(max(abs(df1.weights - df2.weights)) < 1e-2); - DLIB_TEST(max(abs(df1.weights - df3.weights)) < 1e-2); - DLIB_TEST(max(abs(df1.weights - df4.weights)) < 1e-2); - DLIB_TEST(max(abs(df1.weights - df5.weights)) < 1e-2); - - dlog << LINFO << "b error: "<< max(abs(df1.b - df2.b)); - dlog << LINFO << "b error: "<< max(abs(df1.b - df3.b)); - dlog << LINFO << "b error: "<< max(abs(df1.b - df4.b)); - dlog << LINFO << "b error: "<< max(abs(df1.b - df5.b)); - DLIB_TEST(max(abs(df1.b - df2.b)) < 1e-2); - DLIB_TEST(max(abs(df1.b - df3.b)) < 1e-2); - DLIB_TEST(max(abs(df1.b - df4.b)) < 1e-2); - DLIB_TEST(max(abs(df1.b - df5.b)) < 1e-2); - - matrix res = test_multiclass_decision_function(df1, samples, labels); - dlog << LINFO << res; - dlog << LINFO << "accuracy: " << sum(diag(res))/sum(res); - DLIB_TEST(sum(diag(res)) == samples.size()); - - res = test_multiclass_decision_function(df2, samples, labels); - dlog << LINFO << res; - dlog << LINFO << "accuracy: " << sum(diag(res))/sum(res); - DLIB_TEST(sum(diag(res)) == samples.size()); - - res = test_multiclass_decision_function(df3, samples, labels); - dlog << LINFO << res; - dlog << LINFO << "accuracy: " << sum(diag(res))/sum(res); - DLIB_TEST(sum(diag(res)) == samples.size()); - - res = test_multiclass_decision_function(df4, samples, labels); - dlog << LINFO << res; - dlog << LINFO << "accuracy: " << sum(diag(res))/sum(res); - DLIB_TEST(sum(diag(res)) == samples.size()); - - res = test_multiclass_decision_function(df5, samples, labels); - dlog << LINFO << res; - dlog << LINFO << "accuracy: " << sum(diag(res))/sum(res); - DLIB_TEST(sum(diag(res)) == samples.size()); - } - - void perform_test ( - ) - { - std::vector samples; - std::vector labels; - - dlib::rand rnd; - - dlog << LINFO << "test with 100 samples per class"; - make_dataset(samples, labels, 100, rnd); - run_test(samples, labels, 1.155); - - dlog << LINFO << "test with 1 sample per class"; - make_dataset(samples, labels, 1, rnd); - run_test(samples, labels, 0.251); - - dlog << LINFO << "test with 2 sample per class"; - make_dataset(samples, labels, 2, rnd); - run_test(samples, labels, 0.444); - } - } a; - - - -} - - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/svr_linear_trainer.cpp b/lib/3rdParty/dlib/include/dlib/test/svr_linear_trainer.cpp deleted file mode 100644 index ca1a5442..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/svr_linear_trainer.cpp +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (C) 2013 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include - -#include "tester.h" -#include - - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.svr_linear_trainer"); - - typedef matrix sample_type; - typedef std::vector > sparse_sample_type; - -// ---------------------------------------------------------------------------------------- - - double sinc(double x) - { - if (x == 0) - return 1; - return sin(x)/x; - } - - template - void test1() - { - typedef matrix sample_type; - - typedef radial_basis_kernel kernel_type; - - print_spinner(); - - std::vector samples; - std::vector targets; - - // The first thing we do is pick a few training points from the sinc() function. - sample_type m(1); - for (scalar_type x = -10; x <= 4; x += 1) - { - m(0) = x; - - samples.push_back(m); - targets.push_back(sinc(x)+1.1); - } - - randomize_samples(samples, targets); - - empirical_kernel_map ekm; - ekm.load(kernel_type(0.1), samples); - - for (unsigned long i = 0; i < samples.size(); ++i) - samples[i] = ekm.project(samples[i]); - - svr_linear_trainer > linear_trainer; - linear_trainer.set_epsilon(0.0001); - linear_trainer.set_c(30); - linear_trainer.set_epsilon_insensitivity(0.001); - - matrix res = cross_validate_regression_trainer(linear_trainer, samples, targets, 5); - dlog << LINFO << "MSE and R-Squared: "<< res; - DLIB_TEST(res(0) < 1e-4); - DLIB_TEST(res(1) > 0.99); - - dlib::rand rnd; - - samples.clear(); - targets.clear(); - std::vector noisefree_targets; - for (scalar_type x = 0; x <= 5; x += 0.1) - { - m(0) = x; - samples.push_back(matrix_cast(linpiece(m, linspace(0,5,20)))); - targets.push_back(x*x + rnd.get_random_gaussian()); - noisefree_targets.push_back(x*x); - } - linear_trainer.set_learns_nonnegative_weights(true); - linear_trainer.set_epsilon_insensitivity(1.0); - decision_function > df2 = linear_trainer.train(samples, targets); - - print_spinner(); - res = test_regression_function(df2, samples, noisefree_targets); - dlog << LINFO << "MSE and R-Squared: "<< res; - DLIB_TEST(res(0) < 0.15); - DLIB_TEST(res(1) > 0.98); - DLIB_TEST(df2.basis_vectors.size()==1); - DLIB_TEST(max(df2.basis_vectors(0)) >= 0); - - linear_trainer.force_last_weight_to_1(true); - df2 = linear_trainer.train(samples, targets); - DLIB_TEST(std::abs(df2.basis_vectors(0)(samples[0].size()-1) - 1.0) < 1e-14); - - res = test_regression_function(df2, samples, noisefree_targets); - dlog << LINFO << "MSE and R-Squared: "<< res; - DLIB_TEST(res(0) < 0.20); - DLIB_TEST(res(1) > 0.98); - - - // convert into sparse vectors and try it out - typedef std::vector > sparse_samp; - std::vector ssamples; - for (unsigned long i = 0; i < samples.size(); ++i) - { - sparse_samp s; - for (long j = 0; j < samples[i].size(); ++j) - s.push_back(make_pair(j,samples[i](j))); - ssamples.push_back(s); - } - - svr_linear_trainer > strainer; - strainer.set_learns_nonnegative_weights(true); - strainer.set_epsilon_insensitivity(1.0); - strainer.set_c(30); - decision_function > df; - df = strainer.train(ssamples, targets); - res = test_regression_function(df, ssamples, noisefree_targets); - dlog << LINFO << "MSE and R-Squared: "<< res; - DLIB_TEST(res(0) < 0.15); - DLIB_TEST(res(1) > 0.98); - DLIB_TEST(df2.basis_vectors.size()==1); - DLIB_TEST(max(sparse_to_dense(df2.basis_vectors(0))) >= 0); - } - - -// ---------------------------------------------------------------------------------------- - - class tester_svr_linear_trainer : public tester - { - public: - tester_svr_linear_trainer ( - ) : - tester ("test_svr_linear_trainer", - "Runs tests on the svr_linear_trainer.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "TEST double"; - test1(); - dlog << LINFO << "TEST float"; - test1(); - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/symmetric_matrix_cache.cpp b/lib/3rdParty/dlib/include/dlib/test/symmetric_matrix_cache.cpp deleted file mode 100644 index 6d93a4da..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/symmetric_matrix_cache.cpp +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright (C) 2010 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include "tester.h" -#include -#include -#include -#include - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - dlib::logger dlog("test.symmetric_matrix_cache"); - - - class test_symmetric_matrix_cache : public tester - { - /*! - WHAT THIS OBJECT REPRESENTS - This object represents a unit test. When it is constructed - it adds itself into the testing framework. - !*/ - public: - test_symmetric_matrix_cache ( - ) : - tester ( - "test_symmetric_matrix_cache", // the command line argument name for this test - "Run tests on the symmetric_matrix_cache function.", // the command line argument description - 0 // the number of command line arguments for this test - ) - { - } - - dlib::rand rnd; - - // ----------------------------------- - - template - void test_colm_exp ( - const matrix_exp& m1, - const matrix_exp& m2 - ) - { - for (long i = 0; i < m1.nc(); ++i) - { - - typename colm_exp::type c1 = colm(m1,i); - typename colm_exp::type c2 = colm(m2,i); - - DLIB_TEST(equal(c1 , c2)); - DLIB_TEST(equal(colm(m1,i) , c2)); - DLIB_TEST(equal(c1 , colm(m2,i))); - DLIB_TEST(equal(colm(m1,i) , colm(m2,i))); - } - - - // Get a bunch of columns at once to test out the reference - // counting and automatic cache expansion built into the symmetric_matrix_cache. - // This test verifies that, for example, getting column 3 doesn't stomp on - // any of the previous columns. - typename colm_exp::type c1_0 = colm(m1,0); - typename colm_exp::type c1_1 = colm(m1,1); - typename colm_exp::type c1_2 = colm(m1,2); - typename colm_exp::type c1_3 = colm(m1,3); - typename colm_exp::type c1_4 = colm(m1,4); - typename colm_exp::type c1_5 = colm(m1,5); - - typename colm_exp::type c2_0 = colm(m2,0); - typename colm_exp::type c2_1 = colm(m2,1); - typename colm_exp::type c2_2 = colm(m2,2); - typename colm_exp::type c2_3 = colm(m2,3); - typename colm_exp::type c2_4 = colm(m2,4); - typename colm_exp::type c2_5 = colm(m2,5); - - DLIB_TEST(equal(c1_0, c2_0)); - DLIB_TEST(equal(c1_1, c2_1)); - DLIB_TEST(equal(c1_2, c2_2)); - DLIB_TEST(equal(c1_3, c2_3)); - DLIB_TEST(equal(c1_4, c2_4)); - DLIB_TEST(equal(c1_5, c2_5)); - } - - // ----------------------------------- - - template - void test_rowm_exp ( - const matrix_exp& m1, - const matrix_exp& m2 - ) - { - for (long i = 0; i < m1.nc(); ++i) - { - - typename rowm_exp::type r1 = rowm(m1,i); - typename rowm_exp::type r2 = rowm(m2,i); - - DLIB_TEST(equal(r1 , r2)); - DLIB_TEST(equal(rowm(m1,i) , r2)); - DLIB_TEST(equal(r1 , rowm(m2,i))); - DLIB_TEST(equal(rowm(m1,i) , rowm(m2,i))); - } - - - // Get a bunch of rows at once to test out the reference - // counting and automatic cache expansion built into the symmetric_matrix_cache. - // This test verifies that, for example, getting row 3 doesn't stomp on - // any of the previous rows. - typename rowm_exp::type r1_0 = rowm(m1,0); - typename rowm_exp::type r1_1 = rowm(m1,1); - typename rowm_exp::type r1_2 = rowm(m1,2); - typename rowm_exp::type r1_3 = rowm(m1,3); - typename rowm_exp::type r1_4 = rowm(m1,4); - typename rowm_exp::type r1_5 = rowm(m1,5); - - typename rowm_exp::type r2_0 = rowm(m2,0); - typename rowm_exp::type r2_1 = rowm(m2,1); - typename rowm_exp::type r2_2 = rowm(m2,2); - typename rowm_exp::type r2_3 = rowm(m2,3); - typename rowm_exp::type r2_4 = rowm(m2,4); - typename rowm_exp::type r2_5 = rowm(m2,5); - - DLIB_TEST(equal(r1_0, r2_0)); - DLIB_TEST(equal(r1_1, r2_1)); - DLIB_TEST(equal(r1_2, r2_2)); - DLIB_TEST(equal(r1_3, r2_3)); - DLIB_TEST(equal(r1_4, r2_4)); - DLIB_TEST(equal(r1_5, r2_5)); - } - - // ----------------------------------- - - template - void test_diag_exp ( - const matrix_exp& m1, - const matrix_exp& m2 - ) - { - - typename diag_exp::type c1 = diag(m1); - typename diag_exp::type c2 = diag(m2); - - DLIB_TEST(equal(c1 , c2)); - DLIB_TEST(equal(diag(m1) , c2)); - DLIB_TEST(equal(c1 , diag(m2))); - DLIB_TEST(equal(diag(m1) , diag(m2))); - } - - // ----------------------------------- - - void test_stuff ( - long csize - ) - { - print_spinner(); - dlog << LINFO << "csize: "<< csize; - matrix m = randm(10,10,rnd); - - m = make_symmetric(m); - - DLIB_TEST(equal(symmetric_matrix_cache(m, csize), matrix_cast(m))); - DLIB_TEST(equal(symmetric_matrix_cache(m, csize), matrix_cast(m))); - - dlog << LINFO << "test colm/rowm"; - - - for (long i = 0; i < m.nr(); ++i) - { - DLIB_TEST(equal(colm(symmetric_matrix_cache(m, csize),i), colm(matrix_cast(m),i))); - DLIB_TEST(equal(rowm(symmetric_matrix_cache(m, csize),i), rowm(matrix_cast(m),i))); - // things are supposed to be symmetric - DLIB_TEST(equal(colm(symmetric_matrix_cache(m, csize),i), trans(rowm(matrix_cast(m),i)))); - DLIB_TEST(equal(rowm(symmetric_matrix_cache(m, csize),i), trans(colm(matrix_cast(m),i)))); - } - - dlog << LINFO << "test diag"; - DLIB_TEST(equal(diag(symmetric_matrix_cache(m,csize)), diag(matrix_cast(m)))); - - test_colm_exp(symmetric_matrix_cache(m,csize), matrix_cast(m)); - test_rowm_exp(symmetric_matrix_cache(m,csize), matrix_cast(m)); - test_diag_exp(symmetric_matrix_cache(m,csize), matrix_cast(m)); - - test_colm_exp(tmp(symmetric_matrix_cache(m,csize)), tmp(matrix_cast(m))); - test_rowm_exp(symmetric_matrix_cache(m,csize), tmp(matrix_cast(m))); - test_diag_exp(tmp(symmetric_matrix_cache(m,csize)), tmp(matrix_cast(m))); - } - - - void perform_test ( - ) - { - - for (int itr = 0; itr < 5; ++itr) - { - test_stuff(0); - test_stuff(1); - test_stuff(2); - } - - } - }; - - // Create an instance of this object. Doing this causes this test - // to be automatically inserted into the testing framework whenever this cpp file - // is linked into the project. Note that since we are inside an unnamed-namespace - // we won't get any linker errors about the symbol a being defined multiple times. - test_symmetric_matrix_cache a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/tester.cpp b/lib/3rdParty/dlib/include/dlib/test/tester.cpp deleted file mode 100644 index 2fb4d41a..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/tester.cpp +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - -#include -#include "tester.h" -#include -#include - -namespace test -{ -// ----------------------------------------------------------------------------- - - bool be_verbose = true; - -// ----------------------------------------------------------------------------- - - static dlib::mutex spinner_mutex; - static dlib::mutex test_count_mutex; - dlib::uint64 test_count = 0; - -// ----------------------------------------------------------------------------- - - dlib::uint64 number_of_testing_statements_executed ( - ) - { - dlib::auto_mutex lock(test_count_mutex); - return test_count; - } - - void increment_test_count ( - ) - { - test_count_mutex.lock(); - ++test_count; - test_count_mutex.unlock(); - } - -// ----------------------------------------------------------------------------- - - void check_test ( - bool _exp, - long line, - const char* file, - const char* _exp_str - ) - { - test_count_mutex.lock(); - ++test_count; - test_count_mutex.unlock(); - if ( !(_exp) ) - { - std::ostringstream dlib_o_out; - dlib_o_out << "\n\nError occurred at line " << line << ".\n"; - dlib_o_out << "Error occurred in file " << file << ".\n"; - dlib_o_out << "Failing expression was " << _exp_str << ".\n"; - throw dlib::error(dlib_o_out.str()); - } - } - -// ----------------------------------------------------------------------------- - - map_of_testers& testers ( - ) - { - static map_of_testers t; - return t; - } - -// ----------------------------------------------------------------------------- - - tester:: - tester ( - const std::string& switch_name_x, - const std::string& description_x, - unsigned long num_of_args_x - ) : - switch_name(switch_name_x), - description_(description_x), - num_of_args_(num_of_args_x) - { - using namespace std; - if (testers().is_in_domain(switch_name)) - { - cerr << "ERROR: More than one tester has been defined with the switch '" << switch_name << "'." << endl; - exit(1); - } - - string temp(switch_name); - tester* t = this; - testers().add(temp,t); - } - -// ----------------------------------------------------------------------------- - - const std::string& tester:: - cmd_line_switch ( - ) const - { - return switch_name; - } - -// ----------------------------------------------------------------------------- - - const std::string& tester:: - description ( - ) const - { - return description_; - } - -// ----------------------------------------------------------------------------- - - unsigned long tester:: - num_of_args ( - ) const - { - return num_of_args_; - } - -// ----------------------------------------------------------------------------- - - void tester:: - perform_test ( - ) - { - } - -// ----------------------------------------------------------------------------- - - void tester:: - perform_test ( - const std::string& - ) - { - } - -// ----------------------------------------------------------------------------- - - void tester:: - perform_test ( - const std::string&, - const std::string& - ) - { - } - -// ----------------------------------------------------------------------------- - - void print_spinner ( - ) - { - if (be_verbose) - { - using namespace std; - dlib::auto_mutex M(spinner_mutex); - static int i = 0; - cout << "\b\b"; - switch (i) - { - case 0: cout << '|'; break; - case 1: cout << '/'; break; - case 2: cout << '-'; break; - case 3: cout << '\\'; break; - } - cout << " " << flush; - i = (i+1)%4; - } - } - -// ----------------------------------------------------------------------------- - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/tester.h b/lib/3rdParty/dlib/include/dlib/test/tester.h index 547741d1..e16647cf 100644 --- a/lib/3rdParty/dlib/include/dlib/test/tester.h +++ b/lib/3rdParty/dlib/include/dlib/test/tester.h @@ -17,10 +17,10 @@ #endif -#define DLIB_TEST(_exp) check_test(_exp, __LINE__, __FILE__, #_exp); +#define DLIB_TEST(_exp) check_test(bool(_exp), __LINE__, __FILE__, #_exp) #define DLIB_TEST_MSG(_exp,_message) \ - {increment_test_count(); if ( !(_exp) ) \ + do{increment_test_count(); if ( !(_exp) ) \ { \ std::ostringstream dlib_o_out; \ dlib_o_out << "\n\nError occurred at line " << __LINE__ << ".\n"; \ @@ -28,7 +28,7 @@ dlib_o_out << "Failing expression was " << #_exp << ".\n"; \ dlib_o_out << _message << "\n"; \ throw dlib::error(dlib_o_out.str()); \ - }} + }}while(0) namespace test { diff --git a/lib/3rdParty/dlib/include/dlib/test/thread_pool.cpp b/lib/3rdParty/dlib/include/dlib/test/thread_pool.cpp deleted file mode 100644 index 70d48a0b..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/thread_pool.cpp +++ /dev/null @@ -1,395 +0,0 @@ -// Copyright (C) 2008 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.thread_pool"); - - - struct some_struct : noncopyable - { - float val; - }; - - int global_var = 0; - - struct add_functor - { - add_functor() { var = 1;} - add_functor(int v):var(v) {} - - template - void operator()(T a, U b, V& res) - { - dlib::sleep(20); - res = a + b; - } - - void set_global_var() { global_var = 9; } - void set_global_var_const() const { global_var = 9; } - - void set_global_var_arg1(int val) { global_var = val; } - void set_global_var_const_arg1(int val) const { global_var = val; } - void set_global_var_arg2(int val, int val2) { global_var = val+val2; } - void set_global_var_const_arg2(int val, int val2) const { global_var = val+val2; } - - void operator()() - { - global_var = 9; - } - - // use an any just so that if this object goes out of scope - // then var will get all messed up. - any var; - void operator()(int& a) { dlib::sleep(100); a = var.get(); } - void operator()(int& a, int& b) { dlib::sleep(100); a = var.get(); b = 2; } - void operator()(int& a, int& b, int& c) { dlib::sleep(100); a = var.get(); b = 2; c = 3; } - void operator()(int& a, int& b, int& c, int& d) { dlib::sleep(100); a = var.get(); b = 2; c = 3; d = 4; } - }; - - - void set_global_var() { global_var = 9; } - - void gset_struct_to_zero (some_struct& a) { a.val = 0; } - void gset_to_zero (int& a) { a = 0; } - void gincrement (int& a) { ++a; } - void gadd (int a, const int& b, int& res) { dlib::sleep(20); res = a + b; } - void gadd1(int& a, int& res) { res += a; } - void gadd2 (int c, int a, const int& b, int& res) { dlib::sleep(20); res = a + b + c; } - - class thread_pool_tester : public tester - { - public: - thread_pool_tester ( - ) : - tester ("test_thread_pool", - "Runs tests on the thread_pool component.") - {} - - void perform_test ( - ) - { - add_functor f; - for (int num_threads= 0; num_threads < 4; ++num_threads) - { - future a, b, c, res, d; - thread_pool tp(num_threads); - print_spinner(); - - future obj; - - - for (int i = 0; i < 4; ++i) - { - a = 1; - b = 2; - c = 3; - res = 4; - - - DLIB_TEST(a==a); - DLIB_TEST(a!=b); - DLIB_TEST(a==1); - - tp.add_task(gset_to_zero, a); - tp.add_task(gset_to_zero, b); - tp.add_task(*this, &thread_pool_tester::set_to_zero, c); - tp.add_task(gset_to_zero, res); - DLIB_TEST(a == 0); - DLIB_TEST(b == 0); - DLIB_TEST(c == 0); - DLIB_TEST(res == 0); - - - tp.add_task(gincrement, a); - tp.add_task(*this, &thread_pool_tester::increment, b); - tp.add_task(*this, &thread_pool_tester::increment, c); - tp.add_task(gincrement, res); - - DLIB_TEST(a == 1); - DLIB_TEST(b == 1); - DLIB_TEST(c == 1); - DLIB_TEST(res == 1); - - tp.add_task(&gincrement, a); - tp.add_task(*this, &thread_pool_tester::increment, b); - tp.add_task(*this, &thread_pool_tester::increment, c); - tp.add_task(&gincrement, res); - tp.add_task(gincrement, a); - tp.add_task(*this, &thread_pool_tester::increment, b); - tp.add_task(*this, &thread_pool_tester::increment, c); - tp.add_task(gincrement, res); - - DLIB_TEST(a == 3); - DLIB_TEST(b == 3); - DLIB_TEST(c == 3); - DLIB_TEST(res == 3); - - tp.add_task(*this, &thread_pool_tester::increment, c); - tp.add_task(gincrement, res); - DLIB_TEST(c == 4); - DLIB_TEST(res == 4); - - - tp.add_task(gadd, a, b, res); - DLIB_TEST(res == a+b); - DLIB_TEST(res == 6); - a = 3; - b = 4; - res = 99; - DLIB_TEST(res == 99); - tp.add_task(*this, &thread_pool_tester::add, a, b, res); - DLIB_TEST(res == a+b); - DLIB_TEST(res == 7); - - a = 1; - b = 2; - c = 3; - res = 88; - DLIB_TEST(res == 88); - DLIB_TEST(a == 1); - DLIB_TEST(b == 2); - DLIB_TEST(c == 3); - - tp.add_task(gadd2, a, b, c, res); - DLIB_TEST(res == 6); - DLIB_TEST(a == 1); - DLIB_TEST(b == 2); - DLIB_TEST(c == 3); - - a = 1; - b = 2; - c = 3; - res = 88; - DLIB_TEST(res == 88); - DLIB_TEST(a == 1); - DLIB_TEST(b == 2); - DLIB_TEST(c == 3); - tp.add_task(*this, &thread_pool_tester::add2, a, b, c, res); - DLIB_TEST(res == 6); - DLIB_TEST(a == 1); - DLIB_TEST(b == 2); - DLIB_TEST(c == 3); - - a = 1; - b = 2; - c = 3; - res = 88; - tp.add_task(gadd1, a, b); - DLIB_TEST(a == 1); - DLIB_TEST(b == 3); - a = 2; - tp.add_task(*this, &thread_pool_tester::add1, a, b); - DLIB_TEST(a == 2); - DLIB_TEST(b == 5); - - - val = 4; - uint64 id = tp.add_task(*this, &thread_pool_tester::zero_val); - tp.wait_for_task(id); - DLIB_TEST(val == 0); - id = tp.add_task(*this, &thread_pool_tester::accum2, 1,2); - tp.wait_for_all_tasks(); - DLIB_TEST(val == 3); - id = tp.add_task(*this, &thread_pool_tester::accum1, 3); - tp.wait_for_task(id); - DLIB_TEST(val == 6); - - - obj.get().val = 8; - DLIB_TEST(obj.get().val == 8); - tp.add_task(gset_struct_to_zero, obj); - DLIB_TEST(obj.get().val == 0); - obj.get().val = 8; - DLIB_TEST(obj.get().val == 8); - tp.add_task(*this,&thread_pool_tester::set_struct_to_zero, obj); - DLIB_TEST(obj.get().val == 0); - - a = 1; - b = 2; - res = 0; - tp.add_task(f, a, b, res); - DLIB_TEST(a == 1); - DLIB_TEST(b == 2); - DLIB_TEST(res == 3); - - - global_var = 0; - DLIB_TEST(global_var == 0); - id = tp.add_task(&set_global_var); - tp.wait_for_task(id); - DLIB_TEST(global_var == 9); - - global_var = 0; - DLIB_TEST(global_var == 0); - id = tp.add_task(f); - tp.wait_for_task(id); - DLIB_TEST(global_var == 9); - - global_var = 0; - DLIB_TEST(global_var == 0); - id = tp.add_task(f, &add_functor::set_global_var); - tp.wait_for_task(id); - DLIB_TEST(global_var == 9); - - global_var = 0; - a = 4; - DLIB_TEST(global_var == 0); - id = tp.add_task(f, &add_functor::set_global_var_arg1, a); - tp.wait_for_task(id); - DLIB_TEST(global_var == 4); - - global_var = 0; - a = 4; - DLIB_TEST(global_var == 0); - id = tp.add_task_by_value(f, &add_functor::set_global_var_arg1, a); - tp.wait_for_task(id); - DLIB_TEST(global_var == 4); - - - - global_var = 0; - a = 4; - b = 3; - DLIB_TEST(global_var == 0); - id = tp.add_task(f, &add_functor::set_global_var_arg2, a, b); - tp.wait_for_task(id); - DLIB_TEST(global_var == 7); - - global_var = 0; - a = 4; - b = 3; - DLIB_TEST(global_var == 0); - id = tp.add_task_by_value(f, &add_functor::set_global_var_arg2, a, b); - tp.wait_for_task(id); - DLIB_TEST(global_var == 7); - - global_var = 0; - a = 4; - b = 3; - DLIB_TEST(global_var == 0); - id = tp.add_task(f, &add_functor::set_global_var_const_arg2, a, b); - tp.wait_for_task(id); - DLIB_TEST(global_var == 7); - - global_var = 0; - a = 4; - b = 3; - DLIB_TEST(global_var == 0); - id = tp.add_task_by_value(f, &add_functor::set_global_var_const_arg2, a, b); - tp.wait_for_task(id); - DLIB_TEST(global_var == 7); - - - - - - - global_var = 0; - a = 4; - DLIB_TEST(global_var == 0); - id = tp.add_task(f, &add_functor::set_global_var_const_arg1, a); - tp.wait_for_task(id); - DLIB_TEST(global_var == 4); - - global_var = 0; - a = 4; - DLIB_TEST(global_var == 0); - id = tp.add_task_by_value(f, &add_functor::set_global_var_const_arg1, a); - tp.wait_for_task(id); - DLIB_TEST(global_var == 4); - - global_var = 0; - DLIB_TEST(global_var == 0); - id = tp.add_task_by_value(f, &add_functor::set_global_var); - tp.wait_for_task(id); - DLIB_TEST(global_var == 9); - - - global_var = 0; - DLIB_TEST(global_var == 0); - id = tp.add_task(f, &add_functor::set_global_var_const); - tp.wait_for_task(id); - DLIB_TEST(global_var == 9); - - - global_var = 0; - DLIB_TEST(global_var == 0); - id = tp.add_task_by_value(f, &add_functor::set_global_var_const); - tp.wait_for_task(id); - DLIB_TEST(global_var == 9); - - - - } - - // add this task just to to perterb the thread pool before it goes out of scope - tp.add_task(f, a, b, res); - - for (int k = 0; k < 3; ++k) - { - print_spinner(); - global_var = 0; - tp.add_task_by_value(add_functor()); - tp.wait_for_all_tasks(); - DLIB_TEST(global_var == 9); - - a = 0; b = 0; c = 0; d = 0; - tp.add_task_by_value(add_functor(), a); - DLIB_TEST(a == 1); - a = 0; b = 0; c = 0; d = 0; - tp.add_task_by_value(add_functor(8), a, b); - DLIB_TEST(a == 8); - DLIB_TEST(b == 2); - a = 0; b = 0; c = 0; d = 0; - tp.add_task_by_value(add_functor(), a, b, c); - DLIB_TEST(a == 1); - DLIB_TEST(b == 2); - DLIB_TEST(c == 3); - a = 0; b = 0; c = 0; d = 0; - tp.add_task_by_value(add_functor(5), a, b, c, d); - DLIB_TEST(a == 5); - DLIB_TEST(b == 2); - DLIB_TEST(c == 3); - DLIB_TEST(d == 4); - } - - } - } - - long val; - void accum1(long a) { val += a; } - void accum2(long a, long b) { val += a + b; } - void zero_val() { dlib::sleep(20); val = 0; } - - - void set_struct_to_zero (some_struct& a) { a.val = 0; } - void set_to_zero (int& a) { dlib::sleep(20); a = 0; } - void increment (int& a) const { dlib::sleep(20); ++a; } - void add (int a, const int& b, int& res) { dlib::sleep(20); res = a + b; } - void add1(int& a, int& res) const { res += a; } - void add2 (int c, int a, const int& b, int& res) { res = a + b + c; } - - - } a; - - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/threads.cpp b/lib/3rdParty/dlib/include/dlib/test/threads.cpp deleted file mode 100644 index acee1c30..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/threads.cpp +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (C) 2006 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.threads"); - - class threads_tester : public tester - { - public: - threads_tester ( - ) : - tester ("test_threads", - "Runs tests on the threads component."), - sm(cm) - {} - - thread_specific_data tsd; - rmutex cm; - rsignaler sm; - int count; - bool failure; - - void perform_test ( - ) - { - failure = false; - print_spinner(); - - - count = 10; - if (!create_new_thread(*this)) failure = true; - if (!create_new_thread(*this)) failure = true; - if (!create_new_thread(*this)) failure = true; - if (!create_new_thread(*this)) failure = true; - if (!create_new_thread(*this)) failure = true; - if (!create_new_thread(*this)) failure = true; - if (!create_new_thread(*this)) failure = true; - if (!create_new_thread(*this)) failure = true; - if (!create_new_thread(*this)) failure = true; - if (!create_new_thread(*this)) failure = true; - - thread(66); - - // this should happen in the main program thread - if (is_dlib_thread()) - failure = true; - - auto_mutex M(cm); - while (count > 0 && !failure) - sm.wait(); - - - DLIB_TEST(!failure); - } - - void thread_end_handler ( - ) - { - auto_mutex M(cm); - --count; - if (count == 0) - sm.signal(); - } - - void thread1() { thread(1); } - void thread2() - { - thread(2); - if (is_dlib_thread() == false) - failure = true; - } - void thread3() { thread(3); } - void thread4() { thread(4); } - void thread5() { thread(5); } - void thread6() { thread(6); } - void thread7() { thread(7); } - void thread8() { thread(8); } - void thread9() { thread(9); } - void thread10() { thread(10); } - - void thread ( - int num - ) - { - dlog << LTRACE << "starting thread num " << num; - if (is_dlib_thread()) - register_thread_end_handler(*this,&threads_tester::thread_end_handler); - tsd.data() = num; - for (int i = 0; i < 0x3FFFF; ++i) - { - if ((i&0xFFF) == 0) - { - print_spinner(); - dlib::sleep(10); - } - // if this isn't equal to num then there is a problem with the thread specific data stuff - if (tsd.data() != num) - { - auto_mutex M(cm); - failure = true; - sm.signal(); - } - } - dlog << LTRACE << "ending of thread num " << num; - - } - } a; - - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/timer.cpp b/lib/3rdParty/dlib/include/dlib/test/timer.cpp deleted file mode 100644 index 4252f066..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/timer.cpp +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright (C) 2007 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include - -#include -#include -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace std; - using namespace dlib; - - logger dlog("test.timer"); - - class timer_test_helper - { - public: - mutex m; - int count; - dlib::uint64 timestamp; - dlib::timestamper ts; - - timer_test_helper():count(0), timestamp(0){} - void add() - { - m.lock(); - ++count; - m.unlock(); - } - - void delayed_add() - { - dlib::sleep(1000); - print_spinner(); - add(); - } - - void set_timestamp() - { - m.lock(); - timestamp = ts.get_timestamp(); - dlog << LTRACE << "in set_timestamp(), time is " << timestamp; - dlib::sleep(1); - print_spinner(); - m.unlock(); - } - }; - - template < - typename timer_t - > - void timer_test2 ( - ) - /*! - requires - - timer_t is an implementation of dlib/timer/timer_abstract.h is instantiated - timer_test_helper - ensures - - runs tests on timer_t for compliance with the specs - !*/ - { - for (int j = 0; j < 4; ++j) - { - print_spinner(); - timer_test_helper h; - - timer_t t1(h,&timer_test_helper::set_timestamp); - t1.set_delay_time(0); - dlog << LTRACE << "t1.start()"; - t1.start(); - - dlib::sleep(60); - print_spinner(); - t1.stop_and_wait(); - - dlib::uint64 cur_time = h.ts.get_timestamp(); - dlog << LTRACE << "get current time: " << cur_time; - - // make sure the action function has been called recently - DLIB_TEST_MSG((cur_time-h.timestamp)/1000 < 30, (cur_time-h.timestamp)/1000); - - } - } - - template < - typename timer_t - > - void timer_test ( - ) - /*! - requires - - timer_t is an implementation of dlib/timer/timer_abstract.h is instantiated - timer_test_helper - ensures - - runs tests on timer_t for compliance with the specs - !*/ - { - - print_spinner(); - for (int j = 0; j < 3; ++j) - { - timer_test_helper h; - - timer_t t1(h,&timer_test_helper::add); - timer_t t2(h,&timer_test_helper::add); - timer_t t3(h,&timer_test_helper::add); - - DLIB_TEST(t1.delay_time() == 1000); - DLIB_TEST(t2.delay_time() == 1000); - DLIB_TEST(t3.delay_time() == 1000); - DLIB_TEST(t1.is_running() == false); - DLIB_TEST(t2.is_running() == false); - DLIB_TEST(t3.is_running() == false); - DLIB_TEST(t1.action_function() == &timer_test_helper::add); - DLIB_TEST(t2.action_function() == &timer_test_helper::add); - DLIB_TEST(t3.action_function() == &timer_test_helper::add); - DLIB_TEST(&t1.action_object() == &h); - DLIB_TEST(&t2.action_object() == &h); - DLIB_TEST(&t3.action_object() == &h); - - t1.set_delay_time(1000); - t2.set_delay_time(500); - t3.set_delay_time(200); - - DLIB_TEST(t1.delay_time() == 1000); - DLIB_TEST(t2.delay_time() == 500); - DLIB_TEST(t3.delay_time() == 200); - DLIB_TEST(t1.is_running() == false); - DLIB_TEST(t2.is_running() == false); - DLIB_TEST(t3.is_running() == false); - DLIB_TEST(t1.action_function() == &timer_test_helper::add); - DLIB_TEST(t2.action_function() == &timer_test_helper::add); - DLIB_TEST(t3.action_function() == &timer_test_helper::add); - DLIB_TEST(&t1.action_object() == &h); - DLIB_TEST(&t2.action_object() == &h); - DLIB_TEST(&t3.action_object() == &h); - dlib::sleep(1100); - print_spinner(); - DLIB_TEST(h.count == 0); - - t1.stop_and_wait(); - t2.stop_and_wait(); - t3.stop_and_wait(); - - dlib::sleep(1100); - print_spinner(); - DLIB_TEST(h.count == 0); - DLIB_TEST(t1.delay_time() == 1000); - DLIB_TEST(t2.delay_time() == 500); - DLIB_TEST(t3.delay_time() == 200); - DLIB_TEST(t1.is_running() == false); - DLIB_TEST(t2.is_running() == false); - DLIB_TEST(t3.is_running() == false); - DLIB_TEST(t1.action_function() == &timer_test_helper::add); - DLIB_TEST(t2.action_function() == &timer_test_helper::add); - DLIB_TEST(t3.action_function() == &timer_test_helper::add); - DLIB_TEST(&t1.action_object() == &h); - DLIB_TEST(&t2.action_object() == &h); - DLIB_TEST(&t3.action_object() == &h); - - t1.start(); - t2.start(); - t3.start(); - - DLIB_TEST(t1.delay_time() == 1000); - DLIB_TEST(t2.delay_time() == 500); - DLIB_TEST(t3.delay_time() == 200); - DLIB_TEST(t1.is_running() == true); - DLIB_TEST(t2.is_running() == true); - DLIB_TEST(t3.is_running() == true); - DLIB_TEST(t1.action_function() == &timer_test_helper::add); - DLIB_TEST(t2.action_function() == &timer_test_helper::add); - DLIB_TEST(t3.action_function() == &timer_test_helper::add); - DLIB_TEST(&t1.action_object() == &h); - DLIB_TEST(&t2.action_object() == &h); - DLIB_TEST(&t3.action_object() == &h); - - t1.stop(); - t2.stop(); - t3.stop(); - - DLIB_TEST(t1.delay_time() == 1000); - DLIB_TEST(t2.delay_time() == 500); - DLIB_TEST(t3.delay_time() == 200); - DLIB_TEST(t1.is_running() == false); - DLIB_TEST(t2.is_running() == false); - DLIB_TEST(t3.is_running() == false); - DLIB_TEST(t1.action_function() == &timer_test_helper::add); - DLIB_TEST(t2.action_function() == &timer_test_helper::add); - DLIB_TEST(t3.action_function() == &timer_test_helper::add); - DLIB_TEST(&t1.action_object() == &h); - DLIB_TEST(&t2.action_object() == &h); - DLIB_TEST(&t3.action_object() == &h); - - DLIB_TEST(h.count == 0); - dlib::sleep(1100); - print_spinner(); - DLIB_TEST(h.count == 0); - - for (int i = 1; i <= 3; ++i) - { - t1.start(); - t2.start(); - t3.start(); - - DLIB_TEST(t1.is_running() == true); - DLIB_TEST(t2.is_running() == true); - DLIB_TEST(t3.is_running() == true); - - dlib::sleep(1100); - print_spinner(); - // this should allow the timers to trigger 8 times - t1.stop(); - t2.stop(); - t3.stop(); - - DLIB_TEST_MSG(h.count == 8*i,"h.count: " << h.count << " i: " << i); - dlib::sleep(1100); - DLIB_TEST_MSG(h.count == 8*i,"h.count: " << h.count << " i: " << i); - } - - - t1.stop_and_wait(); - - h.count = 0; - t1.start(); - dlib::sleep(300); - print_spinner(); - DLIB_TEST_MSG(h.count == 0,h.count); - t1.set_delay_time(400); - dlib::sleep(200); - print_spinner(); - DLIB_TEST_MSG(h.count == 1,h.count); - dlib::sleep(250); - print_spinner(); - DLIB_TEST_MSG(h.count == 1,h.count); - dlib::sleep(100); - print_spinner(); - DLIB_TEST_MSG(h.count == 2,h.count); - t1.set_delay_time(2000); - DLIB_TEST_MSG(h.count == 2,h.count); - dlib::sleep(1000); - print_spinner(); - DLIB_TEST_MSG(h.count == 2,h.count); - t1.clear(); - - h.count = 0; - t3.start(); - DLIB_TEST(t3.is_running() == true); - DLIB_TEST(t3.delay_time() == 200); - DLIB_TEST_MSG(h.count == 0,h.count); - t3.clear(); - DLIB_TEST(t3.is_running() == false); - DLIB_TEST(t3.delay_time() == 1000); - DLIB_TEST_MSG(h.count == 0,h.count); - dlib::sleep(200); - print_spinner(); - DLIB_TEST(t3.is_running() == false); - DLIB_TEST(t3.delay_time() == 1000); - DLIB_TEST_MSG(h.count == 0,h.count); - - - { - h.count = 0; - timer_t t4(h,&timer_test_helper::delayed_add); - t4.set_delay_time(100); - t4.start(); - DLIB_TEST_MSG(h.count == 0,h.count); - dlib::sleep(400); - print_spinner(); - DLIB_TEST_MSG(h.count == 0,h.count); - t4.stop_and_wait(); - DLIB_TEST_MSG(h.count == 1,h.count); - DLIB_TEST(t4.is_running() == false); - } - - { - h.count = 0; - timer_t t4(h,&timer_test_helper::delayed_add); - t4.set_delay_time(100); - t4.start(); - DLIB_TEST_MSG(h.count == 0,h.count); - dlib::sleep(400); - print_spinner(); - DLIB_TEST_MSG(h.count == 0,h.count); - t4.clear(); - DLIB_TEST(t4.is_running() == false); - DLIB_TEST_MSG(h.count == 0,h.count); - t4.stop_and_wait(); - DLIB_TEST_MSG(h.count == 1,h.count); - DLIB_TEST(t4.is_running() == false); - } - - { - h.count = 0; - timer_t t5(h,&timer_test_helper::delayed_add); - t5.set_delay_time(100); - t5.start(); - DLIB_TEST_MSG(h.count == 0,h.count); - dlib::sleep(400); - print_spinner(); - DLIB_TEST_MSG(h.count == 0,h.count); - } - DLIB_TEST_MSG(h.count == 1,h.count); - - } - - } - - - - - class timer_tester : public tester - { - public: - timer_tester ( - ) : - tester ("test_timer", - "Runs tests on the timer component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing timer_heavy with test_timer"; - timer_test > (); - dlog << LINFO << "testing timer_heavy with test_timer2"; - timer_test2 > (); - - dlog << LINFO << "testing timer with test_timer"; - timer_test > (); - dlog << LINFO << "testing timer with test_timer2"; - timer_test2 > (); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/tokenizer.cpp b/lib/3rdParty/dlib/include/dlib/test/tokenizer.cpp deleted file mode 100644 index 95a95a7e..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/tokenizer.cpp +++ /dev/null @@ -1,378 +0,0 @@ -// Copyright (C) 2005 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include - -#include -#include "tester.h" - -namespace -{ - using namespace test; - using namespace std; - using namespace dlib; - - logger dlog("test.tokenizer"); - - template < - typename tok - > - void tokenizer_kernel_test ( - ) - /*! - requires - - tok is an implementation of tokenizer_kernel_abstract.h - ensures - - runs tests on tok for compliance with the specs - !*/ - { - - print_spinner(); - - tok test; - - DLIB_TEST(test.numbers() == "0123456789"); - DLIB_TEST(test.uppercase_letters() == "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - DLIB_TEST(test.lowercase_letters() == "abcdefghijklmnopqrstuvwxyz"); - - DLIB_TEST_MSG(test.get_identifier_body() == "_" + test.lowercase_letters() + - test.uppercase_letters() + test.numbers(),""); - DLIB_TEST_MSG(test.get_identifier_head() == "_" + test.lowercase_letters() + - test.uppercase_letters(),""); - - DLIB_TEST(test.stream_is_set() == false); - test.clear(); - DLIB_TEST(test.stream_is_set() == false); - - DLIB_TEST_MSG(test.get_identifier_body() == "_" + test.lowercase_letters() + - test.uppercase_letters() + test.numbers(),""); - DLIB_TEST_MSG(test.get_identifier_head() == "_" + test.lowercase_letters() + - test.uppercase_letters(),""); - - tok test2; - - ostringstream sout; - istringstream sin; - test2.set_stream(sin); - - DLIB_TEST(test2.stream_is_set()); - DLIB_TEST(&test2.get_stream() == &sin); - - int type; - string token; - - test2.get_token(type,token); - DLIB_TEST(type == tok::END_OF_FILE); - test2.get_token(type,token); - DLIB_TEST(type == tok::END_OF_FILE); - test2.get_token(type,token); - DLIB_TEST(type == tok::END_OF_FILE); - - - sin.clear(); - sin.str(" The cat 123asdf1234 ._ \n test."); - - test2.get_token(type,token); - DLIB_TEST(type == tok::WHITE_SPACE); - DLIB_TEST(token == " "); - - DLIB_TEST(test2.peek_type() == tok::IDENTIFIER); - DLIB_TEST(test2.peek_token() == "The"); - test2.get_token(type,token); - DLIB_TEST(type == tok::IDENTIFIER); - DLIB_TEST(token == "The"); - - test2.get_token(type,token); - DLIB_TEST(type == tok::WHITE_SPACE); - DLIB_TEST(token == " "); - - test2.get_token(type,token); - DLIB_TEST(type == tok::IDENTIFIER); - DLIB_TEST(token == "cat"); - - test2.get_token(type,token); - DLIB_TEST(type == tok::WHITE_SPACE); - DLIB_TEST(token == " "); - - test2.get_token(type,token); - DLIB_TEST(type == tok::NUMBER); - DLIB_TEST_MSG(token == "123","token: " << token); - - DLIB_TEST(test2.peek_type() == tok::IDENTIFIER); - DLIB_TEST(test2.peek_token() == "asdf1234"); - DLIB_TEST(test2.peek_type() == tok::IDENTIFIER); - DLIB_TEST(test2.peek_token() == "asdf1234"); - DLIB_TEST(test2.peek_type() == tok::IDENTIFIER); - DLIB_TEST(test2.peek_token() == "asdf1234"); - test2.get_token(type,token); - DLIB_TEST(type == tok::IDENTIFIER); - DLIB_TEST(token == "asdf1234"); - - test2.get_token(type,token); - DLIB_TEST(type == tok::WHITE_SPACE); - DLIB_TEST_MSG(token == " ","token: " << token); - - test2.get_token(type,token); - DLIB_TEST(type == tok::CHAR); - DLIB_TEST_MSG(token == ".","token: " << token); - - test2.get_token(type,token); - DLIB_TEST(type == tok::IDENTIFIER); - DLIB_TEST(token == "_"); - - DLIB_TEST(test2.peek_type() == tok::WHITE_SPACE); - DLIB_TEST_MSG(test2.peek_token() == " ","token: \"" << token << "\"" << - "\ntoken size: " << (unsigned int)token.size()); - - swap(test,test2); - - DLIB_TEST(test2.stream_is_set() == false); - - DLIB_TEST(test.peek_type() == tok::WHITE_SPACE); - DLIB_TEST_MSG(test.peek_token() == " ","token: \"" << token << "\"" << - "\ntoken size: " << (unsigned int)token.size()); - test.get_token(type,token); - DLIB_TEST(type == tok::WHITE_SPACE); - DLIB_TEST_MSG(token == " ","token: \"" << token << "\"" << - "\ntoken size: " << (unsigned int)token.size()); - - test.get_token(type,token); - DLIB_TEST_MSG(type == tok::END_OF_LINE,"token: " << token); - DLIB_TEST_MSG(token == "\n","token: " << token); - - swap(test,test2); - DLIB_TEST(test.stream_is_set() == false); - - test2.get_token(type,token); - DLIB_TEST(type == tok::WHITE_SPACE); - DLIB_TEST_MSG(token == " ","token: " << token); - - test2.get_token(type,token); - DLIB_TEST(type == tok::IDENTIFIER); - DLIB_TEST_MSG(token == "test","token: " << token); - - test2.get_token(type,token); - DLIB_TEST(type == tok::CHAR); - DLIB_TEST_MSG(token == ".","token: " << token); - - test2.get_token(type,token); - DLIB_TEST(type == tok::END_OF_FILE); - - - - - - - - - - - test2.set_identifier_token("_" + test.uppercase_letters() + - test.lowercase_letters(),test.numbers() + "_" + test.uppercase_letters() - +test.lowercase_letters()); - - - sin.clear(); - sin.str(" The cat 123asdf1234 ._ \n\r test."); - - test2.get_token(type,token); - DLIB_TEST(type == tok::WHITE_SPACE); - DLIB_TEST(token == " "); - - test2.get_token(type,token); - DLIB_TEST(type == tok::IDENTIFIER); - DLIB_TEST(token == "The"); - - test2.get_token(type,token); - DLIB_TEST(type == tok::WHITE_SPACE); - DLIB_TEST(token == " "); - - test2.get_token(type,token); - DLIB_TEST(type == tok::IDENTIFIER); - DLIB_TEST(token == "cat"); - - test2.get_token(type,token); - DLIB_TEST(type == tok::WHITE_SPACE); - DLIB_TEST(token == " "); - - test2.get_token(type,token); - DLIB_TEST(type == tok::NUMBER); - DLIB_TEST_MSG(token == "123","token: " << token); - - test2.get_token(type,token); - DLIB_TEST(type == tok::IDENTIFIER); - DLIB_TEST(token == "asdf1234"); - - test2.get_token(type,token); - DLIB_TEST(type == tok::WHITE_SPACE); - DLIB_TEST_MSG(token == " ","token: " << token); - - test2.get_token(type,token); - DLIB_TEST(type == tok::CHAR); - DLIB_TEST_MSG(token == ".","token: " << token); - - test2.get_token(type,token); - DLIB_TEST(type == tok::IDENTIFIER); - DLIB_TEST(token == "_"); - - swap(test,test2); - - DLIB_TEST(test2.stream_is_set() == false); - - test.get_token(type,token); - DLIB_TEST(type == tok::WHITE_SPACE); - DLIB_TEST_MSG(token == " ","token: \"" << token << "\"" << - "\ntoken size: " << (unsigned int)token.size()); - - test.get_token(type,token); - DLIB_TEST_MSG(type == tok::END_OF_LINE,"token: " << token); - DLIB_TEST_MSG(token == "\n","token: " << token); - - swap(test,test2); - DLIB_TEST(test.stream_is_set() == false); - - test2.get_token(type,token); - DLIB_TEST(type == tok::WHITE_SPACE); - DLIB_TEST_MSG(token == "\r ","token: " << token); - - test2.get_token(type,token); - DLIB_TEST(type == tok::IDENTIFIER); - DLIB_TEST_MSG(token == "test","token: " << token); - - test2.get_token(type,token); - DLIB_TEST(type == tok::CHAR); - DLIB_TEST_MSG(token == ".","token: " << token); - - test2.get_token(type,token); - DLIB_TEST(type == tok::END_OF_FILE); - - - - - - - - - - - - - - test2.set_identifier_token(test.uppercase_letters() + - test.lowercase_letters(),test.numbers() + test.uppercase_letters() - +test.lowercase_letters()); - - - sin.clear(); - sin.str(" The cat 123as_df1234 ._ \n test."); - - test2.get_token(type,token); - DLIB_TEST(type == tok::WHITE_SPACE); - DLIB_TEST(token == " "); - - test2.get_token(type,token); - DLIB_TEST(type == tok::IDENTIFIER); - DLIB_TEST(token == "The"); - - test2.get_token(type,token); - DLIB_TEST(type == tok::WHITE_SPACE); - DLIB_TEST(token == " "); - - test2.get_token(type,token); - DLIB_TEST(type == tok::IDENTIFIER); - DLIB_TEST(token == "cat"); - - test2.get_token(type,token); - DLIB_TEST(type == tok::WHITE_SPACE); - DLIB_TEST(token == " "); - - test2.get_token(type,token); - DLIB_TEST(type == tok::NUMBER); - DLIB_TEST_MSG(token == "123","token: " << token); - - test2.get_token(type,token); - DLIB_TEST(type == tok::IDENTIFIER); - DLIB_TEST(token == "as"); - - test2.get_token(type,token); - DLIB_TEST(type == tok::CHAR); - DLIB_TEST_MSG(token == "_","token: " << token); - - test2.get_token(type,token); - DLIB_TEST(type == tok::IDENTIFIER); - DLIB_TEST(token == "df1234"); - - test2.get_token(type,token); - DLIB_TEST(type == tok::WHITE_SPACE); - DLIB_TEST_MSG(token == " ","token: " << token); - - test2.get_token(type,token); - DLIB_TEST(type == tok::CHAR); - DLIB_TEST_MSG(token == ".","token: " << token); - - test2.get_token(type,token); - DLIB_TEST(type == tok::CHAR); - DLIB_TEST(token == "_"); - - swap(test,test2); - - DLIB_TEST(test2.stream_is_set() == false); - - test.get_token(type,token); - DLIB_TEST(type == tok::WHITE_SPACE); - DLIB_TEST_MSG(token == " ","token: \"" << token << "\"" << - "\ntoken size: " << (unsigned int)token.size()); - - test.get_token(type,token); - DLIB_TEST_MSG(type == tok::END_OF_LINE,"token: " << token); - DLIB_TEST_MSG(token == "\n","token: " << token); - - swap(test,test2); - DLIB_TEST(test.stream_is_set() == false); - - test2.get_token(type,token); - DLIB_TEST(type == tok::WHITE_SPACE); - DLIB_TEST_MSG(token == " ","token: " << token); - - test2.get_token(type,token); - DLIB_TEST(type == tok::IDENTIFIER); - DLIB_TEST_MSG(token == "test","token: " << token); - - test2.get_token(type,token); - DLIB_TEST(type == tok::CHAR); - DLIB_TEST_MSG(token == ".","token: " << token); - - test2.get_token(type,token); - DLIB_TEST(type == tok::END_OF_FILE); - - - } - - - - - - class tokenizer_tester : public tester - { - public: - tokenizer_tester ( - ) : - tester ("test_tokenizer", - "Runs tests on the tokenizer component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "testing kernel_1a"; - tokenizer_kernel_test (); - dlog << LINFO << "testing kernel_1a_c"; - tokenizer_kernel_test(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/trust_region.cpp b/lib/3rdParty/dlib/include/dlib/test/trust_region.cpp deleted file mode 100644 index aa2775b9..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/trust_region.cpp +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright (C) 2010 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include "optimization_test_functions.h" -#include -#include -#include -#include -#include -#include "../rand.h" - -#include "tester.h" - - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - using namespace dlib::test_functions; - - logger dlog("test.trust_region"); - -// ---------------------------------------------------------------------------------------- - - template - struct neg_rosen_model - { - typedef matrix column_vector; - typedef matrix general_matrix; - - T operator() ( column_vector x) const - { - return -static_cast(rosen(x)); - } - - void get_derivative_and_hessian ( - const column_vector& x, - column_vector& d, - general_matrix& h - ) const - { - d = -matrix_cast(rosen_derivative(x)); - h = -matrix_cast(rosen_hessian(x)); - } - - }; - -// ---------------------------------------------------------------------------------------- - - dlib::rand rnd; - - template - void test_with_rosen() - { - print_spinner(); - - matrix ans; - ans = 1,1; - - matrix p = 100*matrix_cast(randm(2,1,rnd)) - 50; - - T obj = find_min_trust_region(objective_delta_stop_strategy(1e-12, 100), rosen_function_model(), p); - - DLIB_TEST_MSG(std::abs(obj) < 1e-10, "obj: " << obj); - DLIB_TEST_MSG(length(p-ans) < 1e-5, "length(p): " << length(p-ans)); - - matrix p2 = 100*matrix_cast(randm(2,1,rnd)) - 50; - obj = find_max_trust_region(objective_delta_stop_strategy(1e-12, 100), neg_rosen_model(), p2); - - DLIB_TEST_MSG(std::abs(obj) < 1e-10, "obj: " << obj); - DLIB_TEST_MSG(length(p-ans) < 1e-5, "length(p): " << length(p-ans)); - } - -// ---------------------------------------------------------------------------------------- - - void test_trust_region_sub_problem() - { - dlog << LINFO << "subproblem test 1"; - { - matrix B; - B = 1, 0, - 0, 1; - - matrix g, p, ans; - g = 0; - - ans = 0; - - solve_trust_region_subproblem(B,g,1,p, 0.001, 10); - - DLIB_TEST(length(p-ans) < 1e-10); - solve_trust_region_subproblem(B,g,1,p, 0.001, 1); - DLIB_TEST(length(p-ans) < 1e-10); - } - - dlog << LINFO << "subproblem test 2"; - { - matrix B; - B = 1, 0, - 0, 1; - - B *= 0.1; - - matrix g, p, ans; - g = 1; - - ans = -g / length(g); - - solve_trust_region_subproblem(B,g,1,p, 1e-6, 20); - - DLIB_TEST(length(p-ans) < 1e-4); - } - - dlog << LINFO << "subproblem test 3"; - { - matrix B; - B = 0, 0, - 0, 0; - - matrix g, p, ans; - g = 1; - - ans = -g / length(g); - - solve_trust_region_subproblem(B,g,1,p, 1e-6, 20); - - dlog << LINFO << "ans: " << trans(ans); - dlog << LINFO << "p: " << trans(p); - DLIB_TEST(length(p-ans) < 1e-4); - } - return; - - dlog << LINFO << "subproblem test 4"; - { - matrix B; - B = 2, 0, - 0, -1; - - - matrix g, p, ans; - g = 0; - - ans = 0, -1; - - solve_trust_region_subproblem(B,g,1,p, 1e-6, 20); - - DLIB_TEST(length(p-ans) < 1e-4); - } - - - dlog << LINFO << "subproblem test 5"; - { - matrix B; - B = 2, 0, - 0, -1; - - - matrix g, p, ans; - g = 0, 1; - - ans = 0, -1; - - solve_trust_region_subproblem(B,g,1,p, 1e-6, 20); - - DLIB_TEST(length(p-ans) < 1e-4); - } - - dlog << LINFO << "subproblem test 6"; - for (int i = 0; i < 10; ++i) - { - matrix B; - - B = randm(10,10, rnd); - - B = 0.01*B*trans(B); - - - matrix g, p, ans; - g = 1; - - solve_trust_region_subproblem(B,g,1,p, 1e-6, 20); - - DLIB_TEST(std::abs(length(p) - 1) < 1e-4); - } - } - -// ---------------------------------------------------------------------------------------- - - void test_problems() - { - print_spinner(); - { - matrix ch; - - ch = brown_start(); - - find_min_trust_region(objective_delta_stop_strategy(1e-7, 80), - brown_function_model(), - ch); - - dlog << LINFO << "brown obj: " << brown(ch); - dlog << LINFO << "brown der: " << length(brown_derivative(ch)); - dlog << LINFO << "brown error: " << length(ch - brown_solution()); - - DLIB_TEST(length(ch - brown_solution()) < 1e-5); - - } - print_spinner(); - { - matrix ch; - - ch = rosen_start(); - - find_min_trust_region(objective_delta_stop_strategy(1e-7, 80), - rosen_function_model(), - ch); - - dlog << LINFO << "rosen obj: " << rosen(ch); - dlog << LINFO << "rosen der: " << length(rosen_derivative(ch)); - dlog << LINFO << "rosen error: " << length(ch - rosen_solution()); - - DLIB_TEST(length(ch - rosen_solution()) < 1e-5); - } - - print_spinner(); - { - matrix ch; - - ch = chebyquad_start(2); - - find_min_trust_region(objective_delta_stop_strategy(1e-7, 80), - chebyquad_function_model(), - ch); - - dlog << LINFO << "chebyquad 2 obj: " << chebyquad(ch); - dlog << LINFO << "chebyquad 2 der: " << length(chebyquad_derivative(ch)); - dlog << LINFO << "chebyquad 2 error: " << length(ch - chebyquad_solution(2)); - - DLIB_TEST(length(ch - chebyquad_solution(2)) < 1e-5); - - } - print_spinner(); - { - matrix ch; - - ch = chebyquad_start(4); - - find_min_trust_region(objective_delta_stop_strategy(1e-7, 80), - chebyquad_function_model(), - ch); - - dlog << LINFO << "chebyquad 4 obj: " << chebyquad(ch); - dlog << LINFO << "chebyquad 4 der: " << length(chebyquad_derivative(ch)); - dlog << LINFO << "chebyquad 4 error: " << length(ch - chebyquad_solution(4)); - - DLIB_TEST(length(ch - chebyquad_solution(4)) < 1e-5); - } - print_spinner(); - { - matrix ch; - - ch = chebyquad_start(6); - - find_min_trust_region(objective_delta_stop_strategy(1e-12, 80), - chebyquad_function_model(), - ch); - - dlog << LINFO << "chebyquad 6 obj: " << chebyquad(ch); - dlog << LINFO << "chebyquad 6 der: " << length(chebyquad_derivative(ch)); - dlog << LINFO << "chebyquad 6 error: " << length(ch - chebyquad_solution(6)); - - DLIB_TEST(length(ch - chebyquad_solution(6)) < 1e-5); - - } - print_spinner(); - { - matrix ch; - - ch = chebyquad_start(8); - - find_min_trust_region(objective_delta_stop_strategy(1e-10, 80), - chebyquad_function_model(), - ch); - - dlog << LINFO << "chebyquad 8 obj: " << chebyquad(ch); - dlog << LINFO << "chebyquad 8 der: " << length(chebyquad_derivative(ch)); - dlog << LINFO << "chebyquad 8 error: " << length(ch - chebyquad_solution(8)); - - DLIB_TEST(length(ch - chebyquad_solution(8)) < 1e-5); - } - - } - - - - class optimization_tester : public tester - { - public: - optimization_tester ( - ) : - tester ("test_trust_region", - "Runs tests on the trust region optimization component.") - {} - - void perform_test ( - ) - { - dlog << LINFO << "test with rosen"; - for (int i = 0; i < 50; ++i) - test_with_rosen(); - - dlog << LINFO << "test with rosen"; - for (int i = 0; i < 50; ++i) - test_with_rosen(); - - - test_trust_region_sub_problem(); - - test_problems(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test/tuple.cpp b/lib/3rdParty/dlib/include/dlib/test/tuple.cpp deleted file mode 100644 index c00dd1b2..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/tuple.cpp +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (C) 2007 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.tuple"); - - struct nil - { - template - void operator() ( - const T& - ) const - { - } - }; - - - struct inc - { - template - void operator() ( - T& a - ) const - { - a += 1; - } - }; - - - template - void check_const ( - const T& t - ) - { - t.template get<0>(); - - typedef typename T::template get_type<0>::type type0; - t.template get(); - t.template index(); - } - - template - void check_nonconst ( - T& t - ) - { - t.template get<0>(); - - typedef typename T::template get_type<0>::type type0; - t.template get(); - t.template index(); - } - - void tuple_test ( - ) - /*! - ensures - - runs tests on tuple functions for compliance with the specs - !*/ - { - - print_spinner(); - - using dlib::tuple; - - tuple<> a; - tuple b; - tuple c; - - - a.get<1>(); - a.get<2>(); - a.get<3>(); - a.get<4>(); - a.get<5>(); - - check_nonconst(b); - check_nonconst(c); - check_const(b); - check_const(c); - - COMPILE_TIME_ASSERT((is_same_type::get_type<0>::type, null_type>::value)); - COMPILE_TIME_ASSERT((is_same_type::get_type<0>::type, int>::value)); - COMPILE_TIME_ASSERT((is_same_type::get_type<0>::type, int>::value)); - COMPILE_TIME_ASSERT((is_same_type::get_type<1>::type, float>::value)); - COMPILE_TIME_ASSERT((is_same_type::get_type<2>::type, null_type>::value)); - - b.get<0>() = 8; - DLIB_TEST(b.get() == 8); - DLIB_TEST(b.index() == 0); - - c.get<0>() = 9; - DLIB_TEST(c.get() == 9); - DLIB_TEST(c.index() == 0); - c.get<1>() = 3.0; - DLIB_TEST(c.get() == 3.0); - DLIB_TEST(c.index() == 1); - - - - { - typedef tuple T; - T a, b; - a.get<0>() = 1; - a.get<1>() = 3; - a.get<2>() = 2; - - b = a; - - inc i; - nil n; - a.for_each(inc()); - a.for_each(i); - const_cast(a).for_each(nil()); - const_cast(a).for_each(n); - - DLIB_TEST(a.get<0>() == b.get<0>()+2); - DLIB_TEST(a.get<1>() == b.get<1>()+2); - DLIB_TEST(a.get<2>() == b.get<2>()+2); - - ostringstream sout; - - serialize(a,sout); - istringstream sin(sout.str()); - deserialize(b,sin); - - DLIB_TEST(a.get<0>() == b.get<0>()); - DLIB_TEST(a.get<1>() == b.get<1>()); - DLIB_TEST(a.get<2>() == b.get<2>()); - - a.for_index(i,0); - a.for_index(inc(),1); - const_cast(a).for_index(n,2); - const_cast(a).for_index(nil(),0); - - DLIB_TEST(a.get<0>() == b.get<0>()+1); - DLIB_TEST(a.get<1>() == b.get<1>()+1); - DLIB_TEST(a.get<2>() == b.get<2>()+0); - - swap(a,b); - - DLIB_TEST(b.get<0>() == a.get<0>()+1); - DLIB_TEST(b.get<1>() == a.get<1>()+1); - DLIB_TEST(b.get<2>() == a.get<2>()+0); - } - - - } - - - - - class tuple_tester : public tester - { - public: - tuple_tester ( - ) : - tester ("test_tuple", - "Runs tests on the tuple object") - {} - - void perform_test ( - ) - { - tuple_test(); - } - } a; - -} - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/type_safe_union.cpp b/lib/3rdParty/dlib/include/dlib/test/type_safe_union.cpp deleted file mode 100644 index f9e1b2da..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/type_safe_union.cpp +++ /dev/null @@ -1,442 +0,0 @@ -// Copyright (C) 2009 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - using namespace test; - using namespace dlib; - using namespace std; - - logger dlog("test.type_safe_union"); - - struct can_not_copy: noncopyable {}; - void serialize(const can_not_copy&, std::ostream&) {} - void deserialize(can_not_copy&, std::istream&) {} - - void swap(can_not_copy&, can_not_copy&) {} - - class test - { - - private: - - enum kind - { - FLOAT, DOUBLE, CHAR, STRING, NONE - }; - - void operator() (float val) - { - DLIB_TEST(val == f_val); - last_kind = FLOAT; - } - - void operator() (double val) - { - DLIB_TEST(val == d_val); - last_kind = DOUBLE; - } - - void operator() (char val) - { - DLIB_TEST(val == c_val); - last_kind = CHAR; - } - - void operator()(std::string& val) - { - DLIB_TEST(val == s_val); - last_kind = STRING; - } - - void operator()(const std::string& val) - { - DLIB_TEST(val == s_val); - last_kind = STRING; - } - - // ------------------------------ - - friend class type_safe_union; - typedef type_safe_union tsu; - tsu a, b, c; - - float f_val; - double d_val; - char c_val; - std::string s_val; - - kind last_kind; - - public: - void test_stuff() - { - DLIB_TEST(a.is_empty() == true); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - - DLIB_TEST(a.get_type_id() == -1); - DLIB_TEST(a.get_type_id() == 1); - DLIB_TEST(a.get_type_id() == 2); - DLIB_TEST(a.get_type_id() == 3); - DLIB_TEST(a.get_type_id() == 4); - DLIB_TEST(a.get_type_id() == -1); - - - f_val = 4.345f; - a.get() = f_val; - - DLIB_TEST(a.is_empty() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == true); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - - - last_kind = NONE; - const_cast(a).apply_to_contents(*this); - DLIB_TEST(last_kind == FLOAT); - - // ----------- - - d_val = 4.345; - a.get() = d_val; - last_kind = NONE; - a.apply_to_contents(*this); - DLIB_TEST(last_kind == DOUBLE); - - // ----------- - - c_val = 'a'; - a.get() = c_val; - last_kind = NONE; - const_cast(a).apply_to_contents(*this); - DLIB_TEST(last_kind == CHAR); - - // ----------- - - s_val = "test string"; - a.get() = s_val; - last_kind = NONE; - a.apply_to_contents(*this); - DLIB_TEST(last_kind == STRING); - - // ----------- - DLIB_TEST(a.is_empty() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == true); - DLIB_TEST(a.contains() == false); - // ----------- - - a.swap(b); - - DLIB_TEST(a.is_empty() == true); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - - DLIB_TEST(b.is_empty() == false); - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == true); - DLIB_TEST(b.contains() == false); - - - last_kind = NONE; - b.apply_to_contents(*this); - DLIB_TEST(last_kind == STRING); - - // ----------- - - b.swap(a); - - DLIB_TEST(b.is_empty() == true); - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == false); - - DLIB_TEST(a.is_empty() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == true); - DLIB_TEST(a.contains() == false); - - - last_kind = NONE; - a.apply_to_contents(*this); - DLIB_TEST(last_kind == STRING); - last_kind = NONE; - b.apply_to_contents(*this); - DLIB_TEST(last_kind == NONE); - - - a.get() = 'a'; - b.get() = 'b'; - - DLIB_TEST(a.is_empty() == false); - DLIB_TEST(a.contains() == true); - DLIB_TEST(b.is_empty() == false); - DLIB_TEST(b.contains() == true); - DLIB_TEST(a.contains() == false); - DLIB_TEST(b.contains() == false); - - - DLIB_TEST(a.get() == 'a'); - DLIB_TEST(b.get() == 'b'); - - swap(a,b); - - - DLIB_TEST(a.is_empty() == false); - DLIB_TEST(a.contains() == true); - DLIB_TEST(b.is_empty() == false); - DLIB_TEST(b.contains() == true); - DLIB_TEST(a.contains() == false); - DLIB_TEST(b.contains() == false); - - DLIB_TEST(a.get() == 'b'); - DLIB_TEST(b.get() == 'a'); - - // ----------- - - a.get() = 'a'; - b.get() = "a string"; - - DLIB_TEST(a.is_empty() == false); - DLIB_TEST(a.contains() == true); - DLIB_TEST(b.is_empty() == false); - DLIB_TEST(b.contains() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(b.contains() == true); - - - DLIB_TEST(a.get() == 'a'); - DLIB_TEST(b.get() == "a string"); - - swap(a,b); - - DLIB_TEST(b.is_empty() == false); - DLIB_TEST(b.contains() == true); - DLIB_TEST(a.is_empty() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(b.contains() == false); - DLIB_TEST(a.contains() == true); - - - DLIB_TEST(b.get() == 'a'); - DLIB_TEST(a.get() == "a string"); - - - - - { - type_safe_union a, b, empty_union; - - ostringstream sout; - istringstream sin; - - a.get() = 'd'; - - serialize(a, sout); - - sin.str(sout.str()); - deserialize(b, sin); - - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == true); - DLIB_TEST(b.get() == 'd'); - - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == true); - DLIB_TEST(a.get() == 'd'); - - sin.clear(); - sout.clear(); - sout.str(""); - - a.get() = "davis"; - - serialize(a, sout); - sin.str(sout.str()); - deserialize(b, sin); - - - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == true); - DLIB_TEST(b.get() == "davis"); - - sin.clear(); - sout.clear(); - sout.str(""); - - serialize(empty_union, sout); - sin.str(sout.str()); - deserialize(b, sin); - - DLIB_TEST(b.is_empty() == true); - - } - - { - type_safe_union a, b, empty_union; - - ostringstream sout; - istringstream sin; - - a = 'd'; - - serialize(a, sout); - - sin.str(sout.str()); - deserialize(b, sin); - - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == true); - DLIB_TEST(b.get() == 'd'); - - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == true); - DLIB_TEST(a.get() == 'd'); - - sin.clear(); - sout.clear(); - sout.str(""); - - a = std::string("davis"); - - serialize(a, sout); - sin.str(sout.str()); - deserialize(b, sin); - - - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == true); - DLIB_TEST(b.get() == "davis"); - - sin.clear(); - sout.clear(); - sout.str(""); - - serialize(empty_union, sout); - sin.str(sout.str()); - deserialize(b, sin); - - DLIB_TEST(b.is_empty() == true); - - } - - { - typedef type_safe_union tsu_type; - tsu_type a('d'), aa(std::string("davis")), b, empty_union; - - ostringstream sout; - istringstream sin; - - - serialize(a, sout); - - sin.str(sout.str()); - deserialize(b, sin); - - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == true); - DLIB_TEST(b.get() == 'd'); - - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == false); - DLIB_TEST(a.contains() == true); - DLIB_TEST(a.get() == 'd'); - - DLIB_TEST(aa.contains() == false); - DLIB_TEST(aa.contains() == false); - DLIB_TEST(aa.contains() == false); - DLIB_TEST(aa.contains() == true); - - sin.clear(); - sout.clear(); - sout.str(""); - - - serialize(aa, sout); - sin.str(sout.str()); - deserialize(b, sin); - - - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == false); - DLIB_TEST(b.contains() == true); - DLIB_TEST(b.get() == "davis"); - - sin.clear(); - sout.clear(); - sout.str(""); - - serialize(empty_union, sout); - sin.str(sout.str()); - deserialize(b, sin); - - DLIB_TEST(b.is_empty() == true); - - a.get(); - DLIB_TEST(a.contains() == true); - - } - } - - }; - - - - class type_safe_union_tester : public tester - { - public: - type_safe_union_tester ( - ) : - tester ("test_type_safe_union", - "Runs tests on the type_safe_union object") - {} - - void perform_test ( - ) - { - for (int i = 0; i < 10; ++i) - { - test a; - a.test_stuff(); - } - } - } a; - -} - - - - diff --git a/lib/3rdParty/dlib/include/dlib/test/vectorstream.cpp b/lib/3rdParty/dlib/include/dlib/test/vectorstream.cpp deleted file mode 100644 index e171efcf..00000000 --- a/lib/3rdParty/dlib/include/dlib/test/vectorstream.cpp +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (C) 2012 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. - - -#include - -#include -#include -#include -#include -#include - -#include "tester.h" - -namespace -{ - - using namespace test; - using namespace dlib; - using namespace std; - - - logger dlog("test.vectorstream"); - -// ---------------------------------------------------------------------------------------- - - void test1() - { - print_spinner(); - - std::vector buf; - vectorstream s(buf); - - for (int i = -1000; i <= 1000; ++i) - { - char ch = i; - s.put(ch); - } - - DLIB_TEST(buf.size() == 2001); - - int cnt = -1000; - for (unsigned long i = 0; i < buf.size(); ++i) - { - char ch = cnt; - DLIB_TEST(buf[i] == ch); - ++cnt; - } - - for (int i = -1000; i <= 1000; ++i) - { - DLIB_TEST(s.peek() != EOF) - char ch1 = i; - char ch2 = s.get(); - DLIB_TEST(ch1 == ch2); - } - - DLIB_TEST(s.peek() == EOF); - DLIB_TEST(s.get() == EOF); - - s.clear(); - s.seekg(6); - - for (int i = -1000+6; i <= 1000; ++i) - { - DLIB_TEST(s.peek() != EOF) - char ch1 = i; - char ch2 = s.get(); - DLIB_TEST(ch1 == ch2); - } - - DLIB_TEST(s.peek() == EOF); - DLIB_TEST(s.get() == EOF); - - std::string temp; - temp = "one two three!"; - - s.seekg(0); - buf.clear(); - s.clear(); - - serialize(temp, s); - std::string temp2; - deserialize(temp2, s); - DLIB_TEST(temp2 == temp); - - s.put('1'); - s.put('2'); - s.put('3'); - s.put('4'); - DLIB_TEST(s.get() == '1'); - DLIB_TEST(s.get() == '2'); - DLIB_TEST(s.get() == '3'); - DLIB_TEST(s.get() == '4'); - - s.putback('4'); - DLIB_TEST(s.get() == '4'); - s.putback('4'); - s.putback('3'); - s.putback('2'); - s.putback('1'); - DLIB_TEST(s.get() == '1'); - DLIB_TEST(s.get() == '2'); - DLIB_TEST(s.get() == '3'); - DLIB_TEST(s.get() == '4'); - DLIB_TEST(s.good() == true); - DLIB_TEST(s.get() == EOF); - DLIB_TEST(s.good() == false); - - // make sure seeking to a crazy offset doesn't mess things up - s.clear(); - s.seekg(1000000); - DLIB_TEST(s.get() == EOF); - DLIB_TEST(s.good() == false); - s.clear(); - s.seekg(1000000); - char sbuf[100]; - s.read(sbuf, sizeof(sbuf)); - DLIB_TEST(s.good() == false); - } - -// ---------------------------------------------------------------------------------------- - - class test_vectorstream : public tester - { - public: - test_vectorstream ( - ) : - tester ("test_vectorstream", - "Runs tests on the vectorstream component.") - {} - - void perform_test ( - ) - { - test1(); - } - } a; - -} - - diff --git a/lib/3rdParty/dlib/include/dlib/test_for_odr_violations.h b/lib/3rdParty/dlib/include/dlib/test_for_odr_violations.h new file mode 100644 index 00000000..5fa5111b --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/test_for_odr_violations.h @@ -0,0 +1,57 @@ +// Copyright (C) 2014 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_TEST_FOR_ODR_VIOLATIONS_H_ +#define DLIB_TEST_FOR_ODR_VIOLATIONS_H_ + +#include "assert.h" +#include "config.h" + +extern "C" +{ +// =========================>>> WHY YOU ARE GETTING AN ERROR HERE <<<========================= +// The point of this block of code is to cause a link time error that will prevent a user +// from compiling part of their application with DLIB_ASSERT enabled and part with it +// disabled since doing that would be a violation of C++'s one definition rule. So if you +// are getting an error here then you are either not enabling DLIB_ASSERT consistently +// (e.g. by compiling part of your program in a debug mode and part in a release mode) or +// you have simply forgotten to compile dlib/all/source.cpp into your application. +// =========================>>> WHY YOU ARE GETTING AN ERROR HERE <<<========================= +#ifdef ENABLE_ASSERTS + const extern int USER_ERROR__inconsistent_build_configuration__see_dlib_faq_1; + const int DLIB_NO_WARN_UNUSED dlib_check_assert_helper_variable = USER_ERROR__inconsistent_build_configuration__see_dlib_faq_1; +#else + const extern int USER_ERROR__inconsistent_build_configuration__see_dlib_faq_1_; + const int DLIB_NO_WARN_UNUSED dlib_check_assert_helper_variable = USER_ERROR__inconsistent_build_configuration__see_dlib_faq_1_; +#endif + + + +// The point of this block of code is to cause a link time error if someone builds dlib via +// cmake as a separately installable library, and therefore generates a dlib/config.h from +// cmake, but then proceeds to use the default unconfigured dlib/config.h from version +// control. It should be obvious why this is bad, if it isn't you need to read a book +// about C++. Moreover, it can only happen if someone manually copies files around and +// messes things up. If instead they run `make install` or `cmake --build . --target +// install` things will be setup correctly, which is what they should do. To summarize: DO +// NOT BUILD A STANDALONE DLIB AND THEN GO CHERRY PICKING FILES FROM THE BUILD FOLDER AND +// MIXING THEM WITH THE SOURCE FROM GITHUB. USE CMAKE'S INSTALL SCRIPTS TO INSTALL DLIB. +// Or even better, don't install dlib at all and instead build your program as shown in +// examples/CMakeLists.txt +#if defined(DLIB_NOT_CONFIGURED) && !defined(DLIB__CMAKE_GENERATED_A_CONFIG_H_FILE) + const extern int USER_ERROR__inconsistent_build_configuration__see_dlib_faq_2; + const int DLIB_NO_WARN_UNUSED dlib_check_not_configured_helper_variable = USER_ERROR__inconsistent_build_configuration__see_dlib_faq_2; +#endif + + + +// Cause the user to get a linker error if they try to use header files from one version of +// dlib with the compiled binary from a different version of dlib. +#ifdef DLIB_CHECK_FOR_VERSION_MISMATCH + const extern int DLIB_CHECK_FOR_VERSION_MISMATCH; + const int DLIB_NO_WARN_UNUSED dlib_check_for_version_mismatch = DLIB_CHECK_FOR_VERSION_MISMATCH; +#endif + +} + +#endif // DLIB_TEST_FOR_ODR_VIOLATIONS_H_ + diff --git a/lib/3rdParty/dlib/include/dlib/threads.h b/lib/3rdParty/dlib/include/dlib/threads.h index 03801375..371a317e 100644 --- a/lib/3rdParty/dlib/include/dlib/threads.h +++ b/lib/3rdParty/dlib/include/dlib/threads.h @@ -1,5 +1,10 @@ // Copyright (C) 2003 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. + +#ifdef DLIB_ALL_SOURCE_END +#include "dlib_basic_cpp_build_tutorial.txt" +#endif + #ifndef DLIB_THREADs_ #define DLIB_THREADs_ @@ -17,6 +22,7 @@ #include "threads/thread_pool_extension.h" #include "threads/read_write_mutex_extension.h" #include "threads/parallel_for_extension.h" +#include "threads/async.h" #endif // DLIB_THREADs_ diff --git a/lib/3rdParty/dlib/include/dlib/threads/async.h b/lib/3rdParty/dlib/include/dlib/threads/async.h new file mode 100644 index 00000000..bc6fe557 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/threads/async.h @@ -0,0 +1,105 @@ +// Copyright (C) 2016 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_AsYNC_Hh_ +#define DLIB_AsYNC_Hh_ + +// C++11 things don't work in old versions of visual studio +#if !defined( _MSC_VER) || _MSC_VER >= 1900 + +#include "async_abstract.h" +#include "thread_pool_extension.h" +#include +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + template struct selector {}; + + template + void call_prom_set_value( + T& prom, + U& fun, + selector + ) + { + prom.set_value(fun()); + } + + template + void call_prom_set_value( + T& prom, + U& fun, + selector + ) + { + fun(); + prom.set_value(); + } + } + +// ---------------------------------------------------------------------------------------- + + thread_pool& default_thread_pool(); + +// ---------------------------------------------------------------------------------------- + + template < + typename Function, + typename ...Args + > + std::future::type> async( + thread_pool& tp, + Function&& f, + Args&&... args + ) + { + auto prom = std::make_shared::type>>(); + std::future::type> ret = prom->get_future(); + using bind_t = decltype(std::bind(std::forward(f), std::forward(args)...)); + auto fun = std::make_shared(std::bind(std::forward(f), std::forward(args)...)); + tp.add_task_by_value([fun, prom]() + { + try + { + impl::call_prom_set_value(*prom, *fun, impl::selector::type>()); + } + catch(...) + { + prom->set_exception(std::current_exception()); + } + }); + return std::move(ret); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename Function, + typename ...Args + > + std::future::type> async( + Function&& f, + Args&&... args + ) + { + return async(default_thread_pool(), std::forward(f), std::forward(args)...); + } + +} + +// ---------------------------------------------------------------------------------------- + +#ifdef NO_MAKEFILE +#include "async.cpp" +#endif + +#endif +#endif // DLIB_AsYNC_Hh_ + + + diff --git a/lib/3rdParty/dlib/include/dlib/threads/async_abstract.h b/lib/3rdParty/dlib/include/dlib/threads/async_abstract.h new file mode 100644 index 00000000..a9fa1e45 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/threads/async_abstract.h @@ -0,0 +1,67 @@ +// Copyright (C) 2016 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_AsYNC_ABSTRACT_Hh_ +#ifdef DLIB_AsYNC_ABSTRACT_Hh_ + +#include "thread_pool_extension_abstract.h" +#include +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + thread_pool& default_thread_pool( + ); + /*! + ensures + - returns a reference to a global thread_pool. If the DLIB_NUM_THREADS + environment variable is set to an integer then the thread pool will contain + DLIB_NUM_THREADS threads, otherwise it will contain + std::thread::hardware_concurrency() threads. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename Function, + typename ...Args + > + std::future::type> async( + thread_pool& tp, + Function&& f, + Args&&... args + ); + /*! + requires + - f must be a function and f(args...) must be a valid expression. + ensures + - This function behaves just like std::async(std::launch::async, f, args) + except that instead of spawning a new thread to process each task it submits + the task to the provided dlib::thread_pool. Therefore, dlib::async() is + guaranteed to use a bounded number of threads unlike std::async(). This also + means that calls to dlib::async() will block if there aren't any free threads + in the thread pool. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename Function, + typename ...Args + > + std::future::type> async( + Function&& f, + Args&&... args + ); + /*! + ensures + - Calling this function is equivalent to directly calling async(default_thread_pool(), f, args...) + !*/ +} + +// ---------------------------------------------------------------------------------------- + +#endif // DLIB_AsYNC_ABSTRACT_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/threads/multithreaded_object_extension.cpp b/lib/3rdParty/dlib/include/dlib/threads/multithreaded_object_extension.cpp deleted file mode 100644 index 30e5b6ec..00000000 --- a/lib/3rdParty/dlib/include/dlib/threads/multithreaded_object_extension.cpp +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright (C) 2007 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_MULTITHREADED_OBJECT_EXTENSIOn_CPP -#define DLIB_MULTITHREADED_OBJECT_EXTENSIOn_CPP - -#include "multithreaded_object_extension.h" -#include "create_new_thread_extension.h" - - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - multithreaded_object:: - multithreaded_object ( - ): - s(m_), - is_running_(false), - should_stop_(false), - threads_started(0) - { - } - -// ---------------------------------------------------------------------------------------- - - multithreaded_object:: - ~multithreaded_object ( - ) - { - DLIB_ASSERT(number_of_threads_alive() == 0, - "\tmultithreaded_object::~multithreaded_object()" - << "\n\tYou have let a multithreaded object destruct itself before terminating its threads" - << "\n\tthis: " << this - ); - } - -// ---------------------------------------------------------------------------------------- - - void multithreaded_object:: - clear ( - ) - { - auto_mutex M(m_); - stop(); - wait(); - dead_threads.clear(); - is_running_ = false; - should_stop_ = false; - } - -// ---------------------------------------------------------------------------------------- - - bool multithreaded_object:: - is_running ( - ) const - { - auto_mutex M(m_); - return is_running_; - } - -// ---------------------------------------------------------------------------------------- - - unsigned long multithreaded_object:: - number_of_threads_registered ( - ) const - { - auto_mutex M(m_); - return thread_ids.size() + dead_threads.size(); - } - -// ---------------------------------------------------------------------------------------- - - unsigned long multithreaded_object:: - number_of_threads_alive ( - ) const - { - auto_mutex M(m_); - return threads_started; - } - -// ---------------------------------------------------------------------------------------- - - void multithreaded_object:: - wait ( - ) const - { - auto_mutex M(m_); - - DLIB_ASSERT(thread_ids.is_in_domain(get_thread_id()) == false, - "\tvoid multithreaded_object::wait()" - << "\n\tYou can NOT call this function from one of the threads registered in this object" - << "\n\tthis: " << this - ); - - while (threads_started > 0) - s.wait(); - } - -// ---------------------------------------------------------------------------------------- - - void multithreaded_object:: - start ( - ) - { - auto_mutex M(m_); - const unsigned long num_threads_registered = dead_threads.size() + thread_ids.size(); - // start any dead threads - for (unsigned long i = threads_started; i < num_threads_registered; ++i) - { - if (create_new_thread(*this) == false) - { - should_stop_ = true; - is_running_ = false; - throw thread_error(); - } - ++threads_started; - } - is_running_ = true; - should_stop_ = false; - s.broadcast(); - } - -// ---------------------------------------------------------------------------------------- - - void multithreaded_object:: - pause ( - ) - { - auto_mutex M(m_); - is_running_ = false; - } - -// ---------------------------------------------------------------------------------------- - - void multithreaded_object:: - stop ( - ) - { - auto_mutex M(m_); - should_stop_ = true; - is_running_ = false; - s.broadcast(); - } - -// ---------------------------------------------------------------------------------------- - - bool multithreaded_object:: - should_stop ( - ) const - { - auto_mutex M(m_); - DLIB_ASSERT(thread_ids.is_in_domain(get_thread_id()), - "\tbool multithreaded_object::should_stop()" - << "\n\tYou can only call this function from one of the registered threads in this object" - << "\n\tthis: " << this - ); - while (is_running_ == false && should_stop_ == false) - s.wait(); - return should_stop_; - } - -// ---------------------------------------------------------------------------------------- - - multithreaded_object::raii_thread_helper:: - raii_thread_helper( - multithreaded_object& self_, - thread_id_type id_ - ) : self(self_), id(id_){} - - multithreaded_object::raii_thread_helper:: - ~raii_thread_helper() - { - auto_mutex M(self.m_); - if (self.thread_ids.is_in_domain(id)) - { - mfp temp; - thread_id_type id_temp; - self.thread_ids.remove(id,id_temp,temp); - // put this thread's registered function back into the dead_threads queue - self.dead_threads.enqueue(temp); - } - - --self.threads_started; - // If this is the last thread to terminate then - // signal that that is the case. - if (self.threads_started == 0) - { - self.is_running_ = false; - self.should_stop_ = false; - self.s.broadcast(); - } - } - -// ---------------------------------------------------------------------------------------- - - void multithreaded_object:: - thread_helper( - ) - { - mfp mf; - thread_id_type id = get_thread_id(); - - // this guy's destructor does all the necessary cleanup in this function - raii_thread_helper raii(*this, id); - - // if there is a dead_thread sitting around then pull it - // out and put it into mf - { - auto_mutex M(m_); - if (dead_threads.size() > 0) - { - dead_threads.dequeue(mf); - mfp temp(mf); - thread_ids.add(id,temp); - } - } - - if (mf.is_set()) - { - // call the registered thread function - mf(); - } - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_MULTITHREADED_OBJECT_EXTENSIOn_CPP - - diff --git a/lib/3rdParty/dlib/include/dlib/threads/parallel_for_extension.h b/lib/3rdParty/dlib/include/dlib/threads/parallel_for_extension.h index 31126702..60b64b1b 100644 --- a/lib/3rdParty/dlib/include/dlib/threads/parallel_for_extension.h +++ b/lib/3rdParty/dlib/include/dlib/threads/parallel_for_extension.h @@ -6,6 +6,7 @@ #include "parallel_for_extension_abstract.h" #include "thread_pool_extension.h" #include "../console_progress_indicator.h" +#include "async.h" namespace dlib { @@ -186,6 +187,17 @@ namespace dlib parallel_for_blocked(tp, begin, end, funct, chunks_per_thread); } + template + void parallel_for_blocked ( + long begin, + long end, + const T& funct, + long chunks_per_thread = 8 + ) + { + parallel_for_blocked(default_thread_pool(), begin, end, funct, chunks_per_thread); + } + // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- @@ -285,6 +297,19 @@ namespace dlib parallel_for(tp, begin, end, funct, chunks_per_thread); } +// ---------------------------------------------------------------------------------------- + + template + void parallel_for ( + long begin, + long end, + const T& funct, + long chunks_per_thread = 8 + ) + { + parallel_for(default_thread_pool(), begin, end, funct, chunks_per_thread); + } + // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- @@ -499,6 +524,29 @@ namespace dlib parallel_for(num_threads, begin, end, helper, chunks_per_thread); } +// ---------------------------------------------------------------------------------------- + + template + void parallel_for_verbose ( + long begin, + long end, + const T& funct, + long chunks_per_thread = 8 + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(begin <= end && chunks_per_thread > 0, + "\t void parallel_for_verbose()" + << "\n\t Invalid inputs were given to this function" + << "\n\t begin: " << begin + << "\n\t end: " << end + << "\n\t chunks_per_thread: " << chunks_per_thread + ); + + impl::parfor_verbose_helper2 helper(funct, begin, end); + parallel_for(begin, end, helper, chunks_per_thread); + } + // ---------------------------------------------------------------------------------------- template @@ -597,6 +645,29 @@ namespace dlib parallel_for_blocked(num_threads, begin, end, helper, chunks_per_thread); } +// ---------------------------------------------------------------------------------------- + + template + void parallel_for_blocked_verbose ( + long begin, + long end, + const T& funct, + long chunks_per_thread = 8 + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(begin <= end && chunks_per_thread > 0, + "\t void parallel_for_blocked_verbose()" + << "\n\t Invalid inputs were given to this function" + << "\n\t begin: " << begin + << "\n\t end: " << end + << "\n\t chunks_per_thread: " << chunks_per_thread + ); + + impl::parfor_verbose_helper2 helper(funct, begin, end); + parallel_for_blocked(begin, end, helper, chunks_per_thread); + } + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/threads/parallel_for_extension_abstract.h b/lib/3rdParty/dlib/include/dlib/threads/parallel_for_extension_abstract.h index 9c395908..ffd2e0c4 100644 --- a/lib/3rdParty/dlib/include/dlib/threads/parallel_for_extension_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/threads/parallel_for_extension_abstract.h @@ -4,6 +4,7 @@ #ifdef DLIB_PARALLEL_FoR_ABSTRACT_Hh_ #include "thread_pool_extension_abstract.h" +#include "async_abstract.h" namespace dlib { @@ -23,7 +24,6 @@ namespace dlib requires - begin <= end - chunks_per_thread > 0 - - funct does not throw any exceptions ensures - This is a convenience function for submitting a block of jobs to a thread_pool. In particular, given the half open range [begin, end), this function will @@ -60,7 +60,6 @@ namespace dlib requires - begin <= end - chunks_per_thread > 0 - - funct does not throw any exceptions ensures - This function is equivalent to the following block of code: thread_pool tp(num_threads); @@ -81,7 +80,6 @@ namespace dlib requires - chunks_per_thread > 0 - begin <= end - - funct does not throw any exceptions ensures - This is a convenience function for submitting a block of jobs to a thread_pool. In particular, given the range [begin, end), this function will @@ -116,13 +114,30 @@ namespace dlib requires - begin <= end - chunks_per_thread > 0 - - funct does not throw any exceptions ensures - This function is equivalent to the following block of code: thread_pool tp(num_threads); parallel_for_blocked(tp, begin, end, funct, chunks_per_thread); !*/ +// ---------------------------------------------------------------------------------------- + + template + void parallel_for_blocked ( + long begin, + long end, + const T& funct, + long chunks_per_thread = 8 + ); + /*! + requires + - begin <= end + - chunks_per_thread > 0 + ensures + - This function is equivalent to the following block of code: + parallel_for_blocked(default_thread_pool(), begin, end, funct, chunks_per_thread); + !*/ + // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- @@ -139,7 +154,6 @@ namespace dlib requires - begin <= end - chunks_per_thread > 0 - - funct does not throw any exceptions ensures - This function is equivalent to the following function call: parallel_for_blocked(tp, begin, end, [&](long begin_sub, long end_sub) @@ -169,7 +183,6 @@ namespace dlib requires - begin <= end - chunks_per_thread > 0 - - funct does not throw any exceptions ensures - This function is equivalent to the following block of code: thread_pool tp(num_threads); @@ -190,7 +203,6 @@ namespace dlib requires - begin <= end - chunks_per_thread > 0 - - funct does not throw any exceptions ensures - This function is equivalent to the following function call: parallel_for_blocked(tp, begin, end, [&](long begin_sub, long end_sub) @@ -218,13 +230,30 @@ namespace dlib requires - begin <= end - chunks_per_thread > 0 - - funct does not throw any exceptions ensures - This function is equivalent to the following block of code: thread_pool tp(num_threads); parallel_for(tp, begin, end, funct, chunks_per_thread); !*/ +// ---------------------------------------------------------------------------------------- + + template + void parallel_for ( + long begin, + long end, + const T& funct, + long chunks_per_thread = 8 + ); + /*! + requires + - begin <= end + - chunks_per_thread > 0 + ensures + - This function is equivalent to the following block of code: + parallel_for(default_thread_pool(), begin, end, funct, chunks_per_thread); + !*/ + // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- @@ -241,7 +270,6 @@ namespace dlib requires - begin <= end - chunks_per_thread > 0 - - funct does not throw any exceptions ensures - This function is identical to the parallel_for() routine defined above except that it will print messages to cout showing the progress in executing the @@ -263,7 +291,6 @@ namespace dlib requires - begin <= end - chunks_per_thread > 0 - - funct does not throw any exceptions ensures - This function is identical to the parallel_for() routine defined above except that it will print messages to cout showing the progress in executing the @@ -284,7 +311,6 @@ namespace dlib requires - begin <= end - chunks_per_thread > 0 - - funct does not throw any exceptions ensures - This function is identical to the parallel_for() routine defined above except that it will print messages to cout showing the progress in executing the @@ -305,13 +331,32 @@ namespace dlib requires - begin <= end - chunks_per_thread > 0 - - funct does not throw any exceptions ensures - This function is identical to the parallel_for() routine defined above except that it will print messages to cout showing the progress in executing the parallel for loop. !*/ +// ---------------------------------------------------------------------------------------- + + template + void parallel_for_verbose ( + long begin, + long end, + const T& funct, + long chunks_per_thread = 8 + ); + /*! + requires + - begin <= end + - chunks_per_thread > 0 + ensures + - This function is identical to the parallel_for() routine defined above except + that it will print messages to cout showing the progress in executing the + parallel for loop. + - It will also use the default_thread_pool(). + !*/ + // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- @@ -328,7 +373,6 @@ namespace dlib requires - begin <= end - chunks_per_thread > 0 - - funct does not throw any exceptions ensures - This function is identical to the parallel_for_blocked() routine defined above except that it will print messages to cout showing the progress in @@ -350,7 +394,6 @@ namespace dlib requires - begin <= end - chunks_per_thread > 0 - - funct does not throw any exceptions ensures - This function is identical to the parallel_for_blocked() routine defined above except that it will print messages to cout showing the progress in @@ -371,7 +414,6 @@ namespace dlib requires - begin <= end - chunks_per_thread > 0 - - funct does not throw any exceptions ensures - This function is identical to the parallel_for_blocked() routine defined above except that it will print messages to cout showing the progress in @@ -392,13 +434,32 @@ namespace dlib requires - begin <= end - chunks_per_thread > 0 - - funct does not throw any exceptions ensures - This function is identical to the parallel_for_blocked() routine defined above except that it will print messages to cout showing the progress in executing the parallel for loop. !*/ +// ---------------------------------------------------------------------------------------- + + template + void parallel_for_blocked_verbose ( + long begin, + long end, + const T& funct, + long chunks_per_thread = 8 + ); + /*! + requires + - begin <= end + - chunks_per_thread > 0 + ensures + - This function is identical to the parallel_for_blocked() routine defined + above except that it will print messages to cout showing the progress in + executing the parallel for loop. + - It will also use the default_thread_pool() + !*/ + // ---------------------------------------------------------------------------------------- } diff --git a/lib/3rdParty/dlib/include/dlib/threads/thread_function_extension.h b/lib/3rdParty/dlib/include/dlib/threads/thread_function_extension.h index f7f6916e..7ecdd652 100644 --- a/lib/3rdParty/dlib/include/dlib/threads/thread_function_extension.h +++ b/lib/3rdParty/dlib/include/dlib/threads/thread_function_extension.h @@ -1,13 +1,14 @@ // Copyright (C) 2007 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_THREAD_FUNCTIOn_ -#define DLIB_THREAD_FUNCTIOn_ +#define DLIB_THREAD_FUNCTIOn_ + +#include #include "thread_function_extension_abstract.h" #include "threads_kernel.h" #include "auto_mutex_extension.h" #include "threaded_object_extension.h" -#include "../smart_pointers.h" namespace dlib { @@ -197,7 +198,7 @@ namespace dlib f->go(); } - scoped_ptr f; + std::unique_ptr f; // restricted functions thread_function(thread_function&); // copy constructor diff --git a/lib/3rdParty/dlib/include/dlib/threads/thread_pool_extension.cpp b/lib/3rdParty/dlib/include/dlib/threads/thread_pool_extension.cpp deleted file mode 100644 index 7fdf4784..00000000 --- a/lib/3rdParty/dlib/include/dlib/threads/thread_pool_extension.cpp +++ /dev/null @@ -1,320 +0,0 @@ -// Copyright (C) 2008 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_THREAD_POOl_CPPh_ -#define DLIB_THREAD_POOl_CPPh_ - -#include "thread_pool_extension.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - thread_pool_implementation:: - thread_pool_implementation ( - unsigned long num_threads - ) : - task_done_signaler(m), - task_ready_signaler(m), - we_are_destructing(false) - { - tasks.resize(num_threads); - for (unsigned long i = 0; i < num_threads; ++i) - { - register_thread(*this, &thread_pool_implementation::thread); - } - - start(); - } - -// ---------------------------------------------------------------------------------------- - - void thread_pool_implementation:: - shutdown_pool ( - ) - { - { - auto_mutex M(m); - - // first wait for all pending tasks to finish - bool found_task = true; - while (found_task) - { - found_task = false; - for (unsigned long i = 0; i < tasks.size(); ++i) - { - // If task bucket i has a task that is currently supposed to be processed - if (tasks[i].is_empty() == false) - { - found_task = true; - break; - } - } - - if (found_task) - task_done_signaler.wait(); - } - - // now tell the threads to kill themselves - we_are_destructing = true; - task_ready_signaler.broadcast(); - } - - wait(); - } - -// ---------------------------------------------------------------------------------------- - - thread_pool_implementation:: - ~thread_pool_implementation() - { - shutdown_pool(); - } - -// ---------------------------------------------------------------------------------------- - - unsigned long thread_pool_implementation:: - num_threads_in_pool ( - ) const - { - auto_mutex M(m); - return tasks.size(); - } - -// ---------------------------------------------------------------------------------------- - - void thread_pool_implementation:: - wait_for_task ( - uint64 task_id - ) const - { - auto_mutex M(m); - if (tasks.size() != 0) - { - const unsigned long idx = task_id_to_index(task_id); - while (tasks[idx].task_id == task_id) - task_done_signaler.wait(); - } - } - -// ---------------------------------------------------------------------------------------- - - void thread_pool_implementation:: - wait_for_all_tasks ( - ) const - { - const thread_id_type thread_id = get_thread_id(); - - auto_mutex M(m); - bool found_task = true; - while (found_task) - { - found_task = false; - for (unsigned long i = 0; i < tasks.size(); ++i) - { - // If task bucket i has a task that is currently supposed to be processed - // and it originated from the calling thread - if (tasks[i].is_empty() == false && tasks[i].thread_id == thread_id) - { - found_task = true; - break; - } - } - - if (found_task) - task_done_signaler.wait(); - } - } - -// ---------------------------------------------------------------------------------------- - - bool thread_pool_implementation:: - is_worker_thread ( - const thread_id_type id - ) const - { - for (unsigned long i = 0; i < worker_thread_ids.size(); ++i) - { - if (worker_thread_ids[i] == id) - return true; - } - - // if there aren't any threads in the pool then we consider all threads - // to be worker threads - if (tasks.size() == 0) - return true; - else - return false; - } - -// ---------------------------------------------------------------------------------------- - - void thread_pool_implementation:: - thread ( - ) - { - { - // save the id of this worker thread into worker_thread_ids - auto_mutex M(m); - thread_id_type id = get_thread_id(); - worker_thread_ids.push_back(id); - } - - task_state_type task; - while (we_are_destructing == false) - { - long idx = 0; - - // wait for a task to do - { auto_mutex M(m); - while ( (idx = find_ready_task()) == -1 && we_are_destructing == false) - task_ready_signaler.wait(); - - if (we_are_destructing) - break; - - tasks[idx].is_being_processed = true; - task = tasks[idx]; - } - - // now do the task - if (task.bfp) - task.bfp(); - else if (task.mfp0) - task.mfp0(); - else if (task.mfp1) - task.mfp1(task.arg1); - else if (task.mfp2) - task.mfp2(task.arg1, task.arg2); - - // Now let others know that we finished the task. We do this - // by clearing out the state of this task - { auto_mutex M(m); - tasks[idx].is_being_processed = false; - tasks[idx].task_id = 0; - tasks[idx].bfp.clear(); - tasks[idx].mfp0.clear(); - tasks[idx].mfp1.clear(); - tasks[idx].mfp2.clear(); - tasks[idx].arg1 = 0; - tasks[idx].arg2 = 0; - task_done_signaler.broadcast(); - } - - } - } - -// ---------------------------------------------------------------------------------------- - - long thread_pool_implementation:: - find_empty_task_slot ( - ) const - { - for (unsigned long i = 0; i < tasks.size(); ++i) - { - if (tasks[i].is_empty()) - return i; - } - - return -1; - } - -// ---------------------------------------------------------------------------------------- - - long thread_pool_implementation:: - find_ready_task ( - ) const - { - for (unsigned long i = 0; i < tasks.size(); ++i) - { - if (tasks[i].is_ready()) - return i; - } - - return -1; - } - -// ---------------------------------------------------------------------------------------- - - uint64 thread_pool_implementation:: - make_next_task_id ( - long idx - ) - { - uint64 id = tasks[idx].next_task_id * tasks.size() + idx; - tasks[idx].next_task_id += 1; - return id; - } - -// ---------------------------------------------------------------------------------------- - - unsigned long thread_pool_implementation:: - task_id_to_index ( - uint64 id - ) const - { - return static_cast(id%tasks.size()); - } - -// ---------------------------------------------------------------------------------------- - - uint64 thread_pool_implementation:: - add_task_internal ( - const bfp_type& bfp, - shared_ptr& item - ) - { - auto_mutex M(m); - const thread_id_type my_thread_id = get_thread_id(); - - // find a thread that isn't doing anything - long idx = find_empty_task_slot(); - if (idx == -1 && is_worker_thread(my_thread_id)) - { - // this function is being called from within a worker thread and there - // aren't any other worker threads free so just perform the task right - // here - - M.unlock(); - bfp(); - - // return a task id that is both non-zero and also one - // that is never normally returned. This way calls - // to wait_for_task() will never block given this id. - return 1; - } - - // wait until there is a thread that isn't doing anything - while (idx == -1) - { - task_done_signaler.wait(); - idx = find_empty_task_slot(); - } - - tasks[idx].thread_id = my_thread_id; - tasks[idx].task_id = make_next_task_id(idx); - tasks[idx].bfp = bfp; - tasks[idx].function_copy.swap(item); - - task_ready_signaler.signal(); - - return tasks[idx].task_id; - } - -// ---------------------------------------------------------------------------------------- - - bool thread_pool_implementation:: - is_task_thread ( - ) const - { - auto_mutex M(m); - return is_worker_thread(get_thread_id()); - } - -// ---------------------------------------------------------------------------------------- - -} - - -#endif // DLIB_THREAD_POOl_CPPh_ - diff --git a/lib/3rdParty/dlib/include/dlib/threads/thread_pool_extension.h b/lib/3rdParty/dlib/include/dlib/threads/thread_pool_extension.h index 13f7b877..bc2e1782 100644 --- a/lib/3rdParty/dlib/include/dlib/threads/thread_pool_extension.h +++ b/lib/3rdParty/dlib/include/dlib/threads/thread_pool_extension.h @@ -3,6 +3,10 @@ #ifndef DLIB_THREAD_POOl_Hh_ #define DLIB_THREAD_POOl_Hh_ +#include +#include +#include + #include "thread_pool_extension_abstract.h" #include "multithreaded_object_extension.h" #include "../member_function_pointer.h" @@ -11,8 +15,6 @@ #include "auto_mutex_extension.h" #include "../uintn.h" #include "../array.h" -#include "../smart_pointers_thread_safe.h" -#include "../smart_pointers.h" namespace dlib { @@ -86,7 +88,7 @@ namespace dlib inline void wait () const; mutable uint64 task_id; - mutable shared_ptr_thread_safe tp; + mutable std::shared_ptr tp; T var; }; @@ -125,7 +127,7 @@ namespace dlib // ---------------------------------------------------------------------------------------- - class thread_pool_implementation : private multithreaded_object + class thread_pool_implementation { /*! CONVENTION @@ -312,7 +314,7 @@ namespace dlib uint64 add_task_internal ( const bfp_type& bfp, - shared_ptr& item + std::shared_ptr& item ); /*! ensures @@ -324,7 +326,7 @@ namespace dlib uint64 add_task_internal ( const bfp_type& bfp - ) { shared_ptr temp; return add_task_internal(bfp, temp); } + ) { std::shared_ptr temp; return add_task_internal(bfp, temp); } /*! ensures - adds a task to call the given bfp object. @@ -410,7 +412,7 @@ namespace dlib struct task_state_type { - task_state_type() : is_being_processed(false), task_id(0), next_task_id(2), arg1(0), arg2(0) {} + task_state_type() : is_being_processed(false), task_id(0), next_task_id(2), arg1(0), arg2(0), eptr(nullptr) {} bool is_ready () const /*! @@ -450,7 +452,18 @@ namespace dlib member_function_pointer mfp2; bfp_type bfp; - shared_ptr function_copy; + std::shared_ptr function_copy; + mutable std::exception_ptr eptr; // non-null if the task threw an exception + + void propagate_exception() const + { + if (eptr) + { + auto tmp = eptr; + eptr = nullptr; + std::rethrow_exception(tmp); + } + } }; @@ -462,6 +475,8 @@ namespace dlib signaler task_ready_signaler; bool we_are_destructing; + std::vector threads; + // restricted functions thread_pool_implementation(thread_pool_implementation&); // copy constructor thread_pool_implementation& operator=(thread_pool_implementation&); // assignment operator @@ -474,7 +489,7 @@ namespace dlib class thread_pool { /*! - This object is just a shell that holds a shared_ptr_thread_safe + This object is just a shell that holds a std::shared_ptr to the real thread_pool_implementation object. The reason for doing it this way is so that we can allow any mixture of destruction orders between thread_pool objects and futures. Whoever gets destroyed @@ -493,7 +508,25 @@ namespace dlib ~thread_pool ( ) { - impl->shutdown_pool(); + try + { + impl->shutdown_pool(); + } + catch (std::exception& e) + { + std::cerr << "An unhandled exception was inside a dlib::thread_pool when it was destructed." << std::endl; + std::cerr << "It's what string is: \n" << e.what() << std::endl; + using namespace std; + assert(false); + abort(); + } + catch (...) + { + std::cerr << "An unhandled exception was inside a dlib::thread_pool when it was destructed." << std::endl; + using namespace std; + assert(false); + abort(); + } } void wait_for_task ( @@ -563,7 +596,7 @@ namespace dlib { thread_pool_implementation::function_object_copy_instance* ptr = 0; ptr = new thread_pool_implementation::function_object_copy_instance(function_object); - shared_ptr function_copy(ptr); + std::shared_ptr function_copy(ptr); bfp_type temp; @@ -594,7 +627,7 @@ namespace dlib { thread_pool_implementation::function_object_copy_instance* ptr = 0; ptr = new thread_pool_implementation::function_object_copy_instance(obj); - shared_ptr function_copy(ptr); + std::shared_ptr function_copy(ptr); bfp_type temp; temp.set(ptr->item,funct); @@ -611,7 +644,7 @@ namespace dlib { thread_pool_implementation::function_object_copy_instance* ptr = 0; ptr = new thread_pool_implementation::function_object_copy_instance(obj); - shared_ptr function_copy(ptr); + std::shared_ptr function_copy(ptr); bfp_type temp; temp.set(ptr->item,funct); @@ -660,7 +693,7 @@ namespace dlib { thread_pool_implementation::function_object_copy_instance* ptr = 0; ptr = new thread_pool_implementation::function_object_copy_instance(function_object); - shared_ptr function_copy(ptr); + std::shared_ptr function_copy(ptr); bfp_type temp; temp.set(ptr->item, arg1.get()); @@ -698,7 +731,7 @@ namespace dlib { thread_pool_implementation::function_object_copy_instance* ptr = 0; ptr = new thread_pool_implementation::function_object_copy_instance(obj); - shared_ptr function_copy(ptr); + std::shared_ptr function_copy(ptr); bfp_type temp; temp.set(ptr->item,funct,arg1.get()); @@ -737,7 +770,7 @@ namespace dlib { thread_pool_implementation::function_object_copy_instance* ptr = 0; ptr = new thread_pool_implementation::function_object_copy_instance(obj); - shared_ptr function_copy(ptr); + std::shared_ptr function_copy(ptr); bfp_type temp; temp.set(ptr->item,funct,arg1.get()); @@ -798,7 +831,7 @@ namespace dlib { thread_pool_implementation::function_object_copy_instance* ptr = 0; ptr = new thread_pool_implementation::function_object_copy_instance(function_object); - shared_ptr function_copy(ptr); + std::shared_ptr function_copy(ptr); bfp_type temp; temp.set(ptr->item, arg1.get(), arg2.get()); @@ -844,7 +877,7 @@ namespace dlib { thread_pool_implementation::function_object_copy_instance* ptr = 0; ptr = new thread_pool_implementation::function_object_copy_instance(obj); - shared_ptr function_copy(ptr); + std::shared_ptr function_copy(ptr); bfp_type temp; temp.set(ptr->item, funct, arg1.get(), arg2.get()); @@ -890,7 +923,7 @@ namespace dlib { thread_pool_implementation::function_object_copy_instance* ptr = 0; ptr = new thread_pool_implementation::function_object_copy_instance(obj); - shared_ptr function_copy(ptr); + std::shared_ptr function_copy(ptr); bfp_type temp; temp.set(ptr->item, funct, arg1.get(), arg2.get()); @@ -961,7 +994,7 @@ namespace dlib { thread_pool_implementation::function_object_copy_instance* ptr = 0; ptr = new thread_pool_implementation::function_object_copy_instance(function_object); - shared_ptr function_copy(ptr); + std::shared_ptr function_copy(ptr); bfp_type temp; temp.set(ptr->item, arg1.get(), arg2.get(), arg3.get()); @@ -1015,7 +1048,7 @@ namespace dlib { thread_pool_implementation::function_object_copy_instance* ptr = 0; ptr = new thread_pool_implementation::function_object_copy_instance(obj); - shared_ptr function_copy(ptr); + std::shared_ptr function_copy(ptr); bfp_type temp; temp.set(ptr->item, funct, arg1.get(), arg2.get(), arg3.get()); @@ -1069,7 +1102,7 @@ namespace dlib { thread_pool_implementation::function_object_copy_instance* ptr = 0; ptr = new thread_pool_implementation::function_object_copy_instance(obj); - shared_ptr function_copy(ptr); + std::shared_ptr function_copy(ptr); bfp_type temp; temp.set(ptr->item, funct, arg1.get(), arg2.get(), arg3.get()); @@ -1150,7 +1183,7 @@ namespace dlib { thread_pool_implementation::function_object_copy_instance* ptr = 0; ptr = new thread_pool_implementation::function_object_copy_instance(function_object); - shared_ptr function_copy(ptr); + std::shared_ptr function_copy(ptr); bfp_type temp; temp.set(ptr->item, arg1.get(), arg2.get(), arg3.get(), arg4.get()); @@ -1212,7 +1245,7 @@ namespace dlib { thread_pool_implementation::function_object_copy_instance* ptr = 0; ptr = new thread_pool_implementation::function_object_copy_instance(obj); - shared_ptr function_copy(ptr); + std::shared_ptr function_copy(ptr); bfp_type temp; temp.set(ptr->item, funct, arg1.get(), arg2.get(), arg3.get(), arg4.get()); @@ -1274,7 +1307,7 @@ namespace dlib { thread_pool_implementation::function_object_copy_instance* ptr = 0; ptr = new thread_pool_implementation::function_object_copy_instance(obj); - shared_ptr function_copy(ptr); + std::shared_ptr function_copy(ptr); bfp_type temp; temp.set(ptr->item, funct, arg1.get(), arg2.get(), arg3.get(), arg4.get()); @@ -1322,7 +1355,7 @@ namespace dlib private: - shared_ptr_thread_safe impl; + std::shared_ptr impl; // restricted functions thread_pool(thread_pool&); // copy constructor diff --git a/lib/3rdParty/dlib/include/dlib/threads/thread_pool_extension_abstract.h b/lib/3rdParty/dlib/include/dlib/threads/thread_pool_extension_abstract.h index f2fb7efa..ba54a754 100644 --- a/lib/3rdParty/dlib/include/dlib/threads/thread_pool_extension_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/threads/thread_pool_extension_abstract.h @@ -225,9 +225,11 @@ namespace dlib such as mutex objects. EXCEPTIONS - Note that if an exception is thrown inside a task thread and - is not caught then the normal rule for uncaught exceptions in - threads applies. That is, the application will be terminated. + Note that if an exception is thrown inside a task thread and is not caught + then the exception will be trapped inside the thread pool and rethrown at a + later time when someone calls one of the add task or wait member functions + of the thread pool. This allows exceptions to propagate out of task threads + and into the calling code where they can be handled. !*/ public: @@ -249,6 +251,10 @@ namespace dlib /*! ensures - blocks until all tasks in the pool have finished. + - If one of the threads has generated an exception but it hasn't yet been + rethrown to the caller (e.g. by calling wait_for_all_tasks()) then the + program will be terminated. So make sure you handle all the possible + exceptions from your tasks. !*/ bool is_task_thread ( diff --git a/lib/3rdParty/dlib/include/dlib/threads/threaded_object_extension.cpp b/lib/3rdParty/dlib/include/dlib/threads/threaded_object_extension.cpp deleted file mode 100644 index 619bfb5d..00000000 --- a/lib/3rdParty/dlib/include/dlib/threads/threaded_object_extension.cpp +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright (C) 2007 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_THREADED_OBJECT_EXTENSIOn_CPP -#define DLIB_THREADED_OBJECT_EXTENSIOn_CPP - -#include "threaded_object_extension.h" -#include "create_new_thread_extension.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - threaded_object:: - threaded_object ( - ): - s(m_), - id1(0), - is_running_(false), - is_alive_(false), - should_stop_(false), - id_valid(false) - { - } - -// ---------------------------------------------------------------------------------------- - - threaded_object:: - ~threaded_object ( - ) - { - DLIB_ASSERT(is_alive() == false, - "\tthreaded_object::~threaded_object()" - << "\n\tYou have let a threaded object destruct itself before terminating its thread" - << "\n\tthis: " << this - ); - } - -// ---------------------------------------------------------------------------------------- - - bool threaded_object:: - is_running ( - ) const - { - auto_mutex M(m_); - - DLIB_ASSERT(id1 != get_thread_id() || id_valid == false, - "\tbool threaded_object::is_running()" - << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread" - << "\n\tthis: " << this - ); - - return is_running_; - } - -// ---------------------------------------------------------------------------------------- - - bool threaded_object:: - is_alive ( - ) const - { - auto_mutex M(m_); - - DLIB_ASSERT(id1 != get_thread_id() || id_valid == false, - "\tbool threaded_object::is_alive()" - << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread" - << "\n\tthis: " << this - ); - - return is_alive_; - } - -// ---------------------------------------------------------------------------------------- - - void threaded_object:: - wait ( - ) const - { - auto_mutex M(m_); - - DLIB_ASSERT(id1 != get_thread_id() || id_valid == false, - "\tvoid threaded_object::wait()" - << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread" - << "\n\tthis: " << this - ); - - while (is_alive_) - s.wait(); - } - -// ---------------------------------------------------------------------------------------- - - void threaded_object:: - start ( - ) - { - auto_mutex M(m_); - - DLIB_ASSERT(id1 != get_thread_id() || id_valid == false, - "\tvoid threaded_object::start()" - << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread" - << "\n\tthis: " << this - ); - - if (is_alive_ == false) - { - if (create_new_thread(*this) == false) - { - is_running_ = false; - throw thread_error(); - } - } - is_alive_ = true; - is_running_ = true; - should_stop_ = false; - s.broadcast(); - } - -// ---------------------------------------------------------------------------------------- - - void threaded_object:: - restart ( - ) - { - auto_mutex M(m_); - - DLIB_ASSERT(id1 != get_thread_id() || id_valid == false, - "\tvoid threaded_object::restart()" - << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread" - << "\n\tthis: " << this - ); - - if (is_alive_ == false) - { - if (create_new_thread(*this) == false) - { - is_running_ = false; - throw thread_error(); - } - should_respawn_ = false; - } - else - { - should_respawn_ = true; - } - is_alive_ = true; - is_running_ = true; - should_stop_ = false; - s.broadcast(); - } - -// ---------------------------------------------------------------------------------------- - - void threaded_object:: - set_respawn ( - ) - { - auto_mutex M(m_); - - DLIB_ASSERT(id1 != get_thread_id() || id_valid == false, - "\tvoid threaded_object::set_respawn()" - << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread" - << "\n\tthis: " << this - ); - - should_respawn_ = true; - } - -// ---------------------------------------------------------------------------------------- - - bool threaded_object:: - should_respawn ( - ) const - { - auto_mutex M(m_); - - DLIB_ASSERT(id1 != get_thread_id() || id_valid == false, - "\tbool threaded_object::should_respawn()" - << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread" - << "\n\tthis: " << this - ); - - return should_respawn_; - } - -// ---------------------------------------------------------------------------------------- - - void threaded_object:: - pause ( - ) - { - auto_mutex M(m_); - - DLIB_ASSERT(id1 != get_thread_id() || id_valid == false, - "\tvoid threaded_object::pause()" - << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread" - << "\n\tthis: " << this - ); - - is_running_ = false; - } - -// ---------------------------------------------------------------------------------------- - - void threaded_object:: - stop ( - ) - { - auto_mutex M(m_); - - DLIB_ASSERT(id1 != get_thread_id() || id_valid == false, - "\tvoid threaded_object::stop()" - << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread" - << "\n\tthis: " << this - ); - - should_stop_ = true; - is_running_ = false; - should_respawn_ = false; - s.broadcast(); - } - -// ---------------------------------------------------------------------------------------- - - bool threaded_object:: - should_stop ( - ) const - { - auto_mutex M(m_); - DLIB_ASSERT(is_alive_ && id1 == get_thread_id() && id_valid == true, - "\tbool threaded_object::should_stop()" - << "\n\tYou can only call this function from the thread that executes threaded_object::thread" - << "\n\tthis: " << this - ); - while (is_running_ == false && should_stop_ == false) - s.wait(); - return should_stop_; - } - -// ---------------------------------------------------------------------------------------- - - void threaded_object:: - thread_helper( - ) - { -#ifdef ENABLE_ASSERTS - id1 = get_thread_id(); - id_valid = true; -#endif - while (true) - { - m_.lock(); - should_respawn_ = false; - m_.unlock(); - - thread(); - - auto_mutex M(m_); - - if (should_respawn_) - continue; - -#ifdef ENABLE_ASSERTS - id_valid = false; -#endif - - is_alive_ = false; - is_running_ = false; - should_stop_ = false; - s.broadcast(); - - return; - } - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_THREADED_OBJECT_EXTENSIOn_CPP - diff --git a/lib/3rdParty/dlib/include/dlib/threads/threads_kernel_1.cpp b/lib/3rdParty/dlib/include/dlib/threads/threads_kernel_1.cpp deleted file mode 100644 index cb36b8d3..00000000 --- a/lib/3rdParty/dlib/include/dlib/threads/threads_kernel_1.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_THREADS_KERNEL_1_CPp_ -#define DLIB_THREADS_KERNEL_1_CPp_ - -#include "../platform.h" - -#ifdef WIN32 - -#include "threads_kernel_1.h" - -#include - - -namespace dlib -{ - namespace threads_kernel_shared_helpers - { - - // ----------------------------------------------------------------------------------- - - struct info - { - void* param; - void (*funct)(void*); - }; - - // ----------------------------------------------------------------------------------- - - unsigned int __stdcall thread_starter ( - void* param - ) - { - info* alloc_p = static_cast(param); - info p = *alloc_p; - delete alloc_p; - - p.funct(p.param); - return 0; - } - - // ----------------------------------------------------------------------------------- - - bool spawn_thread ( - void (*funct)(void*), - void* param - ) - { - info* p; - try { p = new info; } - catch (...) { return false; } - - p->funct = funct; - p->param = param; - - - unsigned int garbage; - - HANDLE thandle = (HANDLE)_beginthreadex (NULL,0,thread_starter,p,0,&garbage); - // make thread and add it to the pool - - // return false if _beginthreadex didn't work - if ( thandle == 0) - { - delete p; - return false; - } - - // throw away the thread handle - CloseHandle(thandle); - return true; - } - - // ----------------------------------------------------------------------------------- - - } - -} - -#endif // WIN32 - -#endif // DLIB_THREADS_KERNEL_1_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/threads/threads_kernel_1.h b/lib/3rdParty/dlib/include/dlib/threads/threads_kernel_1.h index 3a4bc784..586a21b7 100644 --- a/lib/3rdParty/dlib/include/dlib/threads/threads_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/threads/threads_kernel_1.h @@ -12,6 +12,9 @@ #include "../windows_magic.h" #include #include "../algs.h" +#include +#include +#include namespace dlib @@ -43,21 +46,22 @@ namespace dlib mutex ( ) { - InitializeCriticalSection(&cs); } ~mutex ( - ) { DeleteCriticalSection(&cs); } + ) { } void lock ( - ) const { EnterCriticalSection(&cs); } + ) const { cs.lock(); } void unlock ( - ) const { LeaveCriticalSection(&cs); } + ) const { cs.unlock(); } private: - mutable CRITICAL_SECTION cs; + friend class signaler; + + mutable std::mutex cs; // restricted functions mutex(mutex&); // copy constructor @@ -77,147 +81,40 @@ namespace dlib signaler ( const mutex& associated_mutex ) : - hSemaphore(CreateSemaphore (NULL, 0, 100000000, NULL)), - waiters(0), - hCountSema(CreateSemaphore (NULL,0,100000000,NULL)), m(associated_mutex) { - if (hSemaphore == NULL || hCountSema == NULL) - { - if (hSemaphore != NULL) - { - CloseHandle(hSemaphore); - } - if (hCountSema != NULL) - { - CloseHandle(hCountSema); - } - - throw dlib::thread_error(ECREATE_SIGNALER, - "in function signaler::signaler() an error occurred making the signaler" - ); - } } ~signaler ( - ) { CloseHandle(hSemaphore); CloseHandle(hCountSema);} + ) { } void wait ( ) const { - // get a lock on the mutex for the waiters variable - waiters_mutex.lock(); - // mark that one more thread will be waiting on this signaler - ++waiters; - // release the mutex for waiters - waiters_mutex.unlock(); - - // release the associated mutex - m.unlock(); - - // wait for the semaphore to be signaled - WaitForSingleObject (hSemaphore,INFINITE); - - // signal that we are awake - ReleaseSemaphore(hCountSema,(LONG)1,NULL); - - // relock the associated mutex - m.lock(); + std::unique_lock cs(m.cs, std::defer_lock); + cv.wait(cs); } bool wait_or_timeout ( unsigned long milliseconds ) const { - // get a lock on the mutex for the waiters variable - waiters_mutex.lock(); - // mark that one more thread will be waiting on this signaler - ++waiters; - // release the mutex for waiters - waiters_mutex.unlock(); - - // release the associated mutex - m.unlock(); - - bool value; - - // wait for the semaphore to be signaled - if ( WaitForSingleObject (hSemaphore, milliseconds ) == WAIT_TIMEOUT ) - { - // in this case we should decrement waiters because we are returning - // due to a timeout rather than because someone called signal() or - // broadcast(). - value = false; - - // signal that we are awake - ReleaseSemaphore(hCountSema,(LONG)1,NULL); - - // get a lock on the mutex for the waiters variable - waiters_mutex.lock(); - // mark that one less thread will be waiting on this signaler. - if (waiters != 0) - --waiters; - // release the mutex for waiters - waiters_mutex.unlock(); - } - else - { - value = true; - - // signal that we are awake - ReleaseSemaphore(hCountSema,(LONG)1,NULL); - } - - - // relock the associated mutex - m.lock(); - - return value; + std::unique_lock cs(m.cs, std::defer_lock); + auto status = cv.wait_until(cs, std::chrono::system_clock::now() + std::chrono::milliseconds(milliseconds)); + return status == std::cv_status::no_timeout; } void signal ( ) const { - // get a lock on the mutex for the waiters variable - waiters_mutex.lock(); - - if (waiters > 0) - { - --waiters; - // make the semaphore release one waiting thread - ReleaseSemaphore(hSemaphore,1,NULL); - - // wait for signaled thread to wake up - WaitForSingleObject(hCountSema,INFINITE); - } - - // release the mutex for waiters - waiters_mutex.unlock(); + cv.notify_one(); } void broadcast ( ) const { - // get a lock on the mutex for the waiters variable - waiters_mutex.lock(); - - if (waiters > 0) - { - // make the semaphore release all the waiting threads - ReleaseSemaphore(hSemaphore,(LONG)waiters,NULL); - - // wait for count to be zero - for (unsigned long i = 0; i < waiters; ++i) - { - WaitForSingleObject(hCountSema,INFINITE); - } - - waiters = 0; - } - - // release the mutex for waiters - waiters_mutex.unlock(); + cv.notify_all(); } const mutex& get_mutex ( @@ -225,13 +122,7 @@ namespace dlib private: - mutable HANDLE hSemaphore; - - mutable unsigned long waiters; - mutex waiters_mutex; - - - mutable HANDLE hCountSema; + mutable std::condition_variable cv; const mutex& m; diff --git a/lib/3rdParty/dlib/include/dlib/threads/threads_kernel_2.cpp b/lib/3rdParty/dlib/include/dlib/threads/threads_kernel_2.cpp deleted file mode 100644 index 06fb80d0..00000000 --- a/lib/3rdParty/dlib/include/dlib/threads/threads_kernel_2.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_THREADS_KERNEL_2_CPp_ -#define DLIB_THREADS_KERNEL_2_CPp_ - -#include "../platform.h" - -#ifdef POSIX - -#include "threads_kernel_2.h" - - -namespace dlib -{ - namespace threads_kernel_shared_helpers - { - - // ----------------------------------------------------------------------------------- - - struct info - { - void* param; - void (*funct)(void*); - }; - - // ----------------------------------------------------------------------------------- - - void* thread_starter ( - void* param - ) - { - info* alloc_p = static_cast(param); - info p = *alloc_p; - delete alloc_p; - - // detach self - pthread_detach(pthread_self()); - - p.funct(p.param); - return 0; - } - - // ----------------------------------------------------------------------------------- - - bool spawn_thread ( - void (*funct)(void*), - void* param - ) - { - info* p; - try { p = new info; } - catch (...) { return false; } - - p->funct = funct; - p->param = param; - - pthread_t thread_id; - if ( pthread_create (&thread_id, 0, thread_starter, p) ) - { - delete p; - return false; - } - return true; - } - - // ----------------------------------------------------------------------------------- - - } - -} - -#endif // POSIX - -#endif // DLIB_THREADS_KERNEL_2_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/threads/threads_kernel_shared.cpp b/lib/3rdParty/dlib/include/dlib/threads/threads_kernel_shared.cpp deleted file mode 100644 index 686150d6..00000000 --- a/lib/3rdParty/dlib/include/dlib/threads/threads_kernel_shared.cpp +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_THREADS_KERNEL_SHARED_CPp_ -#define DLIB_THREADS_KERNEL_SHARED_CPp_ - -#include "threads_kernel_shared.h" -#include "../assert.h" -#include "../platform.h" -#include - -// The point of this block of code is to cause a link time error that will prevent a user -// from compiling part of their application with DLIB_ASSERT enabled and part with them -// disabled since doing that would be a violation of C++'s one definition rule. -extern "C" -{ -#ifdef ENABLE_ASSERTS - int USER_ERROR__missing_dlib_all_source_cpp_file__OR__inconsistent_use_of_DEBUG_or_ENABLE_ASSERTS_preprocessor_directives; -#else - int USER_ERROR__missing_dlib_all_source_cpp_file__OR__inconsistent_use_of_DEBUG_or_ENABLE_ASSERTS_preprocessor_directives_; -#endif -} - -#ifndef DLIB_THREAD_POOL_TIMEOUT -// default to 30000 milliseconds -#define DLIB_THREAD_POOL_TIMEOUT 30000 -#endif - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- -// threader functions -// ---------------------------------------------------------------------------------------- -// ---------------------------------------------------------------------------------------- - - namespace threads_kernel_shared - { - - bool thread_pool_has_been_destroyed = false; - -// ---------------------------------------------------------------------------------------- - - threader& thread_pool ( - ) - { - static threader* thread_pool = new threader; - return *thread_pool; - } - -// ---------------------------------------------------------------------------------------- - - struct threader_destruct_helper - { - // cause the thread pool to begin its destruction process when - // global objects start to be destroyed - ~threader_destruct_helper() - { - thread_pool().destruct_if_ready(); - } - }; - static threader_destruct_helper a; - -// ---------------------------------------------------------------------------------------- - - bool threader:: - is_dlib_thread ( - thread_id_type id - ) - { - auto_mutex M(data_mutex); - return thread_ids.is_member(id); - } - -// ---------------------------------------------------------------------------------------- - - threader:: - threader ( - ) : - total_count(0), - function_pointer(0), - pool_count(0), - data_ready(data_mutex), - data_empty(data_mutex), - destruct(false), - destructed(data_mutex), - do_not_ever_destruct(false) - { -#ifdef WIN32 - // Trying to destroy the global thread pool when we are part of a DLL and the - // DLL is being unloaded can sometimes lead to weird behavior. For example, in - // the python interpreter you will get the interpreter to hang. Or if we are - // part of a MATLAB mex file and the file is being unloaded there can also be - // similar weird issues. So when we are using dlib on windows we just disable - // the destruction of the global thread pool since it doesn't matter anyway. - // It's resources will just get freed by the OS. This is even the recommended - // thing to do by Microsoft (http://blogs.msdn.com/b/oldnewthing/archive/2012/01/05/10253268.aspx). - // - // As an aside, it's worth pointing out that the reason we try and free - // resources on program shutdown on other operating systems is so we can have - // clean reports from tools like valgrind which check for memory leaks. But - // trying to do this on windows is a lost cause so we give up in this case and - // follow the Microsoft recommendation. - do_not_ever_destruct = true; -#endif // WIN32 - } - -// ---------------------------------------------------------------------------------------- - - threader:: - ~threader ( - ) - { - data_mutex.lock(); - destruct = true; - data_ready.broadcast(); - - // wait for all the threads to end - while (total_count > 0) - destructed.wait(); - - thread_pool_has_been_destroyed = true; - data_mutex.unlock(); - } - -// ---------------------------------------------------------------------------------------- - - void threader:: - destruct_if_ready ( - ) - { - if (do_not_ever_destruct) - return; - - data_mutex.lock(); - - // if there aren't any active threads, just maybe some sitting around - // in the pool then just destroy the threader - if (total_count == pool_count) - { - destruct = true; - data_ready.broadcast(); - data_mutex.unlock(); - delete this; - } - else - { - // There are still some user threads running so there isn't - // much we can really do. Just let the program end without - // cleaning up threading resources. - data_mutex.unlock(); - } - } - -// ---------------------------------------------------------------------------------------- - - void threader:: - call_end_handlers ( - ) - { - reg.m.lock(); - const thread_id_type id = get_thread_id(); - thread_id_type id_copy; - member_function_pointer<> mfp; - - // Remove all the member function pointers for this thread from the tree - // and call them. - while (reg.reg[id] != 0) - { - reg.reg.remove(id,id_copy,mfp); - reg.m.unlock(); - mfp(); - reg.m.lock(); - } - reg.m.unlock(); - } - - // ------------------------------------------------------------------------------------ - - bool threader:: - create_new_thread ( - void (*funct)(void*), - void* param - ) - { - - // get a lock on the data mutex - auto_mutex M(data_mutex); - - // loop to ensure that the new function pointer is in the data - while (true) - { - // if the data is empty then add new data and quit loop - if (function_pointer == 0) - { - parameter = param; - function_pointer = funct; - break; - } - else - { - // wait for data to become empty - data_empty.wait(); - } - } - - - // get a thread for this new data - // if a new thread must be created - if (pool_count == 0) - { - // make thread and add it to the pool - if ( threads_kernel_shared_helpers::spawn_thread(thread_starter, this) == false ) - { - function_pointer = 0; - parameter = 0; - data_empty.signal(); - return false; - } - ++total_count; - } - // wake up a thread from the pool - else - { - data_ready.signal(); - } - - return true; - } - - // ------------------------------------------------------------------------------------ - - void thread_starter ( - void* object - ) - { - // get a reference to the calling threader object - threader& self = *static_cast(object); - - - { - auto_mutex M(self.data_mutex); - - // add this thread id - thread_id_type thread_id = get_thread_id(); - self.thread_ids.add(thread_id); - - // indicate that this thread is now in the thread pool - ++self.pool_count; - - while (self.destruct == false) - { - // if data is ready then process it and launch the thread - // if its not ready then go back into the pool - while (self.function_pointer != 0) - { - // indicate that this thread is now out of the thread pool - --self.pool_count; - - // get the data for the function call - void (*funct)(void*) = self.function_pointer; - void* param = self.parameter; - self.function_pointer = 0; - - // signal that the data is now empty - self.data_empty.signal(); - - self.data_mutex.unlock(); - // Call funct with its intended parameter. If this function throws then - // we intentionally let the exception escape the thread and result in whatever - // happens when it gets caught by the OS (generally the program is terminated). - funct(param); - self.call_end_handlers(); - - self.data_mutex.lock(); - - // indicate that this thread is now back in the thread pool - ++self.pool_count; - } - - if (self.destruct == true) - break; - - // if we timed out and there isn't any work to do then - // this thread will quit this loop and end. - if (self.data_ready.wait_or_timeout(DLIB_THREAD_POOL_TIMEOUT) == false && - self.function_pointer == 0) - break; - - } - - // remove this thread id from thread_ids - thread_id = get_thread_id(); - self.thread_ids.destroy(thread_id); - - // indicate that this thread is now out of the thread pool - --self.pool_count; - --self.total_count; - - self.destructed.signal(); - - } // end of auto_mutex M(self.data_mutex) block - } - - // ------------------------------------------------------------------------------------ - - } - -// ---------------------------------------------------------------------------------------- - - bool is_dlib_thread ( - thread_id_type id - ) - { - return threads_kernel_shared::thread_pool().is_dlib_thread(id); - } - - bool is_dlib_thread ( - ) - { - return is_dlib_thread(get_thread_id()); - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_THREADS_KERNEL_SHARED_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/threads/threads_kernel_shared.h b/lib/3rdParty/dlib/include/dlib/threads/threads_kernel_shared.h index bd8cac4c..b4526e8d 100644 --- a/lib/3rdParty/dlib/include/dlib/threads/threads_kernel_shared.h +++ b/lib/3rdParty/dlib/include/dlib/threads/threads_kernel_shared.h @@ -12,48 +12,7 @@ #include "../memory_manager.h" #include "../queue.h" #include "../set.h" - - - - - - - - - - - - - - -extern "C" -{ -// =========================>>> WHY YOU ARE GETTING AN ERROR HERE <<<========================= -// The point of this block of code is to cause a link time error that will prevent a user -// from compiling part of their application with DLIB_ASSERT enabled and part with it -// disabled since doing that would be a violation of C++'s one definition rule. So if you -// are getting an error here then you are either not enabling DLIB_ASSERT consistently -// (e.g. by compiling part of your program in a debug mode and part in a release mode) or -// you have simply forgotten to compile dlib/all/source.cpp into your application. -// =========================>>> WHY YOU ARE GETTING AN ERROR HERE <<<========================= -#ifdef ENABLE_ASSERTS - extern int USER_ERROR__missing_dlib_all_source_cpp_file__OR__inconsistent_use_of_DEBUG_or_ENABLE_ASSERTS_preprocessor_directives; - inline int dlib_check_consistent_assert_usage() { USER_ERROR__missing_dlib_all_source_cpp_file__OR__inconsistent_use_of_DEBUG_or_ENABLE_ASSERTS_preprocessor_directives = 0; return 0; } -#else - extern int USER_ERROR__missing_dlib_all_source_cpp_file__OR__inconsistent_use_of_DEBUG_or_ENABLE_ASSERTS_preprocessor_directives_; - inline int dlib_check_consistent_assert_usage() { USER_ERROR__missing_dlib_all_source_cpp_file__OR__inconsistent_use_of_DEBUG_or_ENABLE_ASSERTS_preprocessor_directives_ = 0; return 0; } -#endif - const int dlib_check_assert_helper_variable = dlib_check_consistent_assert_usage(); -} - - - - - - - - - +#include "../test_for_odr_violations.h" diff --git a/lib/3rdParty/dlib/include/dlib/time_this.h b/lib/3rdParty/dlib/include/dlib/time_this.h index 2db13506..aec0d2de 100644 --- a/lib/3rdParty/dlib/include/dlib/time_this.h +++ b/lib/3rdParty/dlib/include/dlib/time_this.h @@ -4,74 +4,33 @@ #define DLIB_TIME_THIs_ -#include "platform.h" +#include - - -#ifndef WIN32 - -#include -#include -#include -#include // ---------------------------------------------------------------------------------------- -#define TIME_THIS_TO(_tt_op,_tt_out) \ - { \ - clock_t _tt_start, _tt_end; \ - tms _tt_timesbuf; \ - _tt_start = times(&_tt_timesbuf); \ - _tt_op; \ - _tt_end = times(&_tt_timesbuf); \ - long _tt_ticks = sysconf(_SC_CLK_TCK); \ - if ((double)(_tt_end-_tt_start)/(double)_tt_ticks < 1) \ - { \ - _tt_out << "\ntime: " \ - << (int)(1000*((double)(_tt_end-_tt_start)/(double)_tt_ticks)) << "ms\n"; \ - } \ - else \ - { \ - _tt_out << "\ntime: " \ - << (double)(_tt_end-_tt_start)/(double)_tt_ticks << "sec\n"; \ - } \ - } \ - +#define TIME_THIS_TO(_tt_op,_tt_out) \ + { \ + auto _tt_start = std::chrono::high_resolution_clock::now(); \ + {_tt_op;} \ + auto _tt_stop = std::chrono::high_resolution_clock::now(); \ + auto _tt_thetime = _tt_stop-_tt_start; \ + using std::chrono::duration_cast; \ + using std::chrono::duration; \ + if (_tt_thetime >= std::chrono::minutes(1)) \ + _tt_out << "\ntime: " << duration_cast>>(_tt_thetime).count() << "min\n"; \ + else if (_tt_thetime >= std::chrono::seconds(1)) \ + _tt_out << "\ntime: " << duration_cast>(_tt_thetime).count() << "sec\n"; \ + else if (_tt_thetime >= std::chrono::milliseconds(1)) \ + _tt_out << "\ntime: " << duration_cast>(_tt_thetime).count() << "ms\n"; \ + else if (_tt_thetime >= std::chrono::microseconds(1)) \ + _tt_out << "\ntime: " << duration_cast>(_tt_thetime).count() << "us\n"; \ + else \ + _tt_out << "\ntime: " << duration_cast>(_tt_thetime).count() << "ns\n"; \ + } #define TIME_THIS(_tt_op) TIME_THIS_TO(_tt_op,std::cout) // ---------------------------------------------------------------------------------------- - -#endif - -#ifdef WIN32 - -#include "windows_magic.h" -#include // for GetTickCount() -#include - -// ---------------------------------------------------------------------------------------- - -#define TIME_THIS_TO(_tt_op,_tt_out) \ - { \ - unsigned long _tt_count = GetTickCount(); \ - _tt_op; \ - _tt_count = GetTickCount() - _tt_count; \ - if (_tt_count < 1000) \ - { \ - _tt_out << "\ntime: " << _tt_count << "ms\n"; \ - } \ - else \ - { \ - _tt_out << "\ntime: " << static_cast(_tt_count)/1000 << "sec\n"; \ - } \ - } \ - -#define TIME_THIS(_tt_op) TIME_THIS_TO(_tt_op,std::cout) - -// ---------------------------------------------------------------------------------------- - -#endif - #endif // DLIB_TIME_THIs_ diff --git a/lib/3rdParty/dlib/include/dlib/timer/timer.cpp b/lib/3rdParty/dlib/include/dlib/timer/timer.cpp deleted file mode 100644 index f5d4a544..00000000 --- a/lib/3rdParty/dlib/include/dlib/timer/timer.cpp +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright (C) 2007 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_TIMER_cPPh_ -#define DLIB_TIMER_cPPh_ - -#include "timer.h" - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - timer_global_clock:: - timer_global_clock( - ): - s(m), - shutdown(false), - running(false) - { - } - -// ---------------------------------------------------------------------------------------- - - timer_global_clock:: - ~timer_global_clock() - { - m.lock(); - shutdown = true; - s.signal(); - m.unlock(); - wait(); - } - -// ---------------------------------------------------------------------------------------- - - void timer_global_clock:: - add ( - timer_base* r - ) - { - if (r->in_global_clock == false) - { - // if the thread isn't running then start it up - if (!running) - { - start(); - running = true; - } - - uint64 t = ts.get_timestamp() + r->delay*1000; - tm.reset(); - if (!tm.move_next() || t < tm.element().key()) - { - // we need to make the thread adjust its next time to - // trigger if this new event occurrs sooner than the - // next event in tm - s.signal(); - } - timer_base* rtemp = r; - uint64 ttemp = t; - tm.add(ttemp,rtemp); - r->next_time_to_run = t; - r->in_global_clock = true; - } - } - -// ---------------------------------------------------------------------------------------- - - void timer_global_clock:: - remove ( - timer_base* r - ) - { - if (r->in_global_clock) - { - tm.position_enumerator(r->next_time_to_run-1); - do - { - if (tm.element().value() == r) - { - uint64 t; - timer_base* rtemp; - tm.remove_current_element(t,rtemp); - r->in_global_clock = false; - break; - } - } while (tm.move_next()); - } - } - -// ---------------------------------------------------------------------------------------- - - void timer_global_clock:: - adjust_delay ( - timer_base* r, - unsigned long new_delay - ) - { - if (r->in_global_clock) - { - remove(r); - // compute the new next_time_to_run and store it in t - uint64 t = r->next_time_to_run; - t -= r->delay*1000; - t += new_delay*1000; - - tm.reset(); - if (!tm.move_next() || t < tm.element().key()) - { - // we need to make the thread adjust its next time to - // trigger if this new event occurrs sooner than the - // next event in tm - s.signal(); - } - - // set this incase add throws - r->running = false; - r->delay = new_delay; - - timer_base* rtemp = r; - uint64 ttemp = t; - tm.add(ttemp,rtemp); - r->next_time_to_run = t; - r->in_global_clock = true; - - // put this back now that we know add didn't throw - r->running = true; - - } - else - { - r->delay = new_delay; - } - } - -// ---------------------------------------------------------------------------------------- - - void timer_global_clock:: - thread() - { - auto_mutex M(m); - while (!shutdown) - { - unsigned long delay = 100000; - - tm.reset(); - tm.move_next(); - // loop and start all the action functions for timers that should have - // triggered. - while(tm.current_element_valid()) - { - const uint64 cur_time = ts.get_timestamp(); - uint64 t = tm.element().key(); - // if the next event in tm is ready to trigger - if (t <= cur_time + 999) - { - // remove this event from the tm map - timer_base* r = tm.element().value(); - timer_base* rtemp; - tm.remove_current_element(t,rtemp); - r->in_global_clock = false; - - // if this timer is still "running" then start its action function - if (r->running) - { - r->restart(); - } - } - else - { - // there aren't any more timers that should trigger so we compute - // the delay to the next timer event. - delay = static_cast((t - cur_time)/1000); - break; - } - } - - s.wait_or_timeout(delay); - } - } - -// ---------------------------------------------------------------------------------------- - - shared_ptr_thread_safe get_global_clock() - { - static shared_ptr_thread_safe d(new timer_global_clock); - return d; - } - -// ---------------------------------------------------------------------------------------- - - // do this just to make sure get_global_clock() gets called at program startup - class timer_global_clock_helper - { - public: - timer_global_clock_helper() - { - get_global_clock(); - } - }; - static timer_global_clock_helper call_get_global_clock; - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_TIMER_cPPh_ - diff --git a/lib/3rdParty/dlib/include/dlib/timer/timer.h b/lib/3rdParty/dlib/include/dlib/timer/timer.h index fa74471b..c8b6c0af 100644 --- a/lib/3rdParty/dlib/include/dlib/timer/timer.h +++ b/lib/3rdParty/dlib/include/dlib/timer/timer.h @@ -3,13 +3,14 @@ #ifndef DLIB_TIMEr_Hh_ #define DLIB_TIMEr_Hh_ +#include + #include "../threads.h" #include "../algs.h" #include "../misc_api.h" #include "timer_abstract.h" #include "../uintn.h" #include "../binary_search_tree.h" -#include "../smart_pointers_thread_safe.h" #include "timer_heavy.h" namespace dlib @@ -96,7 +97,7 @@ namespace dlib mutex m; - friend shared_ptr_thread_safe get_global_clock(); + friend std::shared_ptr get_global_clock(); private: timer_global_clock(); @@ -113,7 +114,7 @@ namespace dlib - spawns timer tasks as is appropriate !*/ }; - shared_ptr_thread_safe get_global_clock(); + std::shared_ptr get_global_clock(); /*! ensures - returns the global instance of the timer_global_clock object @@ -209,7 +210,7 @@ namespace dlib // data members T& ao; const af_type af; - shared_ptr_thread_safe gc; + std::shared_ptr gc; // restricted functions timer(const timer&); // copy constructor diff --git a/lib/3rdParty/dlib/include/dlib/timer/timer_heavy.h b/lib/3rdParty/dlib/include/dlib/timer/timer_heavy.h index b8e1be7f..693b91ad 100644 --- a/lib/3rdParty/dlib/include/dlib/timer/timer_heavy.h +++ b/lib/3rdParty/dlib/include/dlib/timer/timer_heavy.h @@ -48,7 +48,7 @@ namespace dlib - there is a thread running - if (is_running()) then - next_time_to_run == the time when the next execution of the action - function should occurr. (the time is given by ts.get_timestamp()) + function should occur. (the time is given by ts.get_timestamp()) - stop_running is used to tell the thread to quit. If it is set to true then the thread should end. diff --git a/lib/3rdParty/dlib/include/dlib/timing.h b/lib/3rdParty/dlib/include/dlib/timing.h index ebdf5ffa..2d5116ad 100644 --- a/lib/3rdParty/dlib/include/dlib/timing.h +++ b/lib/3rdParty/dlib/include/dlib/timing.h @@ -3,7 +3,8 @@ #ifndef DLIB_TImING_Hh_ #define DLIB_TImING_Hh_ -#include "misc_api.h" +#include +#include #include #include "string.h" @@ -76,9 +77,9 @@ namespace dlib const int TIME_SLOTS = 500; const int NAME_LENGTH = 40; - inline uint64* time_buf() + inline std::atomic* time_buf() { - static uint64 buf[TIME_SLOTS] = {0}; + static std::atomic buf[TIME_SLOTS]; return buf; } @@ -96,26 +97,26 @@ namespace dlib return buf[i]; } - inline timestamper& ts() + inline uint64_t ts() { - static timestamper ts_; - return ts_; + using namespace std::chrono; + return duration_cast>(high_resolution_clock::now().time_since_epoch()).count(); } - inline void start(int i ) + inline void start(int i) { - time_buf()[i] -= ts().get_timestamp(); + time_buf()[i] -= ts(); } inline void start(int i, const char* name) { - time_buf()[i] -= ts().get_timestamp(); + time_buf()[i] -= ts(); name_buf(i,name); } inline void stop(int i) { - time_buf()[i] += ts().get_timestamp(); + time_buf()[i] += ts(); } inline void print() @@ -130,7 +131,7 @@ namespace dlib string name; // Check if the name buffer is empty. Use the name it contains if it isn't. if (name_buf(i,"")[0] != '\0') - name = name_buf(i,""); + name = cast_to_string(i) + ": " + name_buf(i,""); else name = cast_to_string(i); max_name_length = std::max(max_name_length, name.size()); @@ -140,11 +141,11 @@ namespace dlib { if (time_buf()[i] != 0) { - double time = time_buf()[i]/1000.0; + double time = time_buf()[i]/1000.0/1000.0; string name; // Check if the name buffer is empty. Use the name it contains if it isn't. if (name_buf(i,"")[0] != '\0') - name = name_buf(i,""); + name = cast_to_string(i) + ": " + name_buf(i,""); else name = cast_to_string(i); @@ -154,9 +155,9 @@ namespace dlib if (time < 1000) cout << " " << name << ": " << time << " milliseconds" << endl; - else if (time < 1000*1000) + else if (time < 1000*60) cout << " " << name << ": " << time/1000.0 << " seconds" << endl; - else if (time < 1000*1000*60) + else if (time < 1000*60*60) cout << " " << name << ": " << time/1000.0/60.0 << " minutes" << endl; else cout << " " << name << ": " << time/1000.0/60.0/60.0 << " hours" << endl; diff --git a/lib/3rdParty/dlib/include/dlib/tokenizer/tokenizer_kernel_1.cpp b/lib/3rdParty/dlib/include/dlib/tokenizer/tokenizer_kernel_1.cpp deleted file mode 100644 index 969408d2..00000000 --- a/lib/3rdParty/dlib/include/dlib/tokenizer/tokenizer_kernel_1.cpp +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright (C) 2005 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_TOKENIZER_KERNEL_1_CPp_ -#define DLIB_TOKENIZER_KERNEL_1_CPp_ -#include "tokenizer_kernel_1.h" - -#include -#include - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - tokenizer_kernel_1:: - tokenizer_kernel_1 ( - ) : - headset(0), - bodyset(0), - have_peeked(false) - { - try - { - headset = new bool[UCHAR_MAX]; - bodyset = new bool[UCHAR_MAX]; - - clear(); - } - catch (...) - { - if (headset) delete [] headset; - if (bodyset) delete [] headset; - throw; - } - } - -// ---------------------------------------------------------------------------------------- - - tokenizer_kernel_1:: - ~tokenizer_kernel_1 ( - ) - { - delete [] bodyset; - delete [] headset; - } - -// ---------------------------------------------------------------------------------------- - - void tokenizer_kernel_1:: - clear( - ) - { - using namespace std; - - in = 0; - streambuf = 0; - have_peeked = false; - - head = "_" + lowercase_letters() + uppercase_letters(); - body = "_" + lowercase_letters() + uppercase_letters() + numbers(); - - for (unsigned long i = 0; i < UCHAR_MAX; ++i) - { - headset[i] = false; - bodyset[i] = false; - } - - for (string::size_type i = 0; i < head.size(); ++i) - headset[static_cast(head[i])] = true; - for (string::size_type i = 0; i < body.size(); ++i) - bodyset[static_cast(body[i])] = true; - } - -// ---------------------------------------------------------------------------------------- - - void tokenizer_kernel_1:: - set_stream ( - std::istream& in_ - ) - { - in = &in_; - streambuf = in_.rdbuf(); - have_peeked = false; - } - -// ---------------------------------------------------------------------------------------- - - bool tokenizer_kernel_1:: - stream_is_set ( - ) const - { - return (in != 0); - } - -// ---------------------------------------------------------------------------------------- - - std::istream& tokenizer_kernel_1:: - get_stream ( - ) const - { - return *in; - } - -// ---------------------------------------------------------------------------------------- - - void tokenizer_kernel_1:: - get_token ( - int& type, - std::string& token - ) - { - if (!have_peeked) - { - std::streambuf::int_type ch; - ch = streambuf->sbumpc(); - - switch (ch) - { - case EOF: - type = END_OF_FILE; - token.clear(); - return; - - case '\n': - type = END_OF_LINE; - token = "\n"; - return; - - case '\r': - case ' ': - case '\t': - type = WHITE_SPACE; - token = static_cast(ch); - ch = streambuf->sgetc(); - while ((ch == ' ' || ch == '\t' || ch == '\r') && ch != EOF) - { - token += static_cast(ch); - ch = streambuf->snextc(); - } - return; - - default: - if (headset[static_cast(ch)]) - { - type = IDENTIFIER; - token = static_cast(ch); - ch = streambuf->sgetc(); - while ( bodyset[static_cast(ch)] && ch != EOF ) - { - token += static_cast(ch); - ch = streambuf->snextc(); - } - } - else if ('0' <= ch && ch <= '9') - { - type = NUMBER; - token = static_cast(ch); - ch = streambuf->sgetc(); - while (('0' <= ch && ch <= '9') && ch != EOF) - { - token += static_cast(ch); - ch = streambuf->snextc(); - } - } - else - { - type = CHAR; - token = static_cast(ch); - } - return; - } // switch (ch) - } - - // if we get this far it means we have peeked so we should - // return the peek data. - type = next_type; - token = next_token; - have_peeked = false; - } - -// ---------------------------------------------------------------------------------------- - - int tokenizer_kernel_1:: - peek_type ( - ) const - { - const_cast(this)->get_token(next_type,next_token); - have_peeked = true; - return next_type; - } - -// ---------------------------------------------------------------------------------------- - - const std::string& tokenizer_kernel_1:: - peek_token ( - ) const - { - const_cast(this)->get_token(next_type,next_token); - have_peeked = true; - return next_token; - } - -// ---------------------------------------------------------------------------------------- - - void tokenizer_kernel_1:: - swap ( - tokenizer_kernel_1& item - ) - { - exchange(in,item.in); - exchange(streambuf,item.streambuf); - exchange(head,item.head); - exchange(body,item.body); - exchange(bodyset,item.bodyset); - exchange(headset,item.headset); - exchange(have_peeked,item.have_peeked); - exchange(next_type,item.next_type); - exchange(next_token,item.next_token); - } - -// ---------------------------------------------------------------------------------------- - - void tokenizer_kernel_1:: - set_identifier_token ( - const std::string& head_, - const std::string& body_ - ) - { - using namespace std; - - head = head_; - body = body_; - - for (unsigned long i = 0; i < UCHAR_MAX; ++i) - { - headset[i] = false; - bodyset[i] = false; - } - - for (string::size_type i = 0; i < head.size(); ++i) - headset[static_cast(head[i])] = true; - for (string::size_type i = 0; i < body.size(); ++i) - bodyset[static_cast(body[i])] = true; - } - -// ---------------------------------------------------------------------------------------- - - const std::string tokenizer_kernel_1:: - get_identifier_head ( - ) const - { - return head; - } - -// ---------------------------------------------------------------------------------------- - - const std::string tokenizer_kernel_1:: - get_identifier_body ( - ) const - { - return body; - } - -// ---------------------------------------------------------------------------------------- - - const std::string tokenizer_kernel_1:: - lowercase_letters ( - ) const - { - return std::string("abcdefghijklmnopqrstuvwxyz"); - } - -// ---------------------------------------------------------------------------------------- - - const std::string tokenizer_kernel_1:: - uppercase_letters ( - ) const - { - return std::string("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - } - -// ---------------------------------------------------------------------------------------- - - const std::string tokenizer_kernel_1:: - numbers ( - ) const - { - return std::string("0123456789"); - } - -// ---------------------------------------------------------------------------------------- - -} -#endif // DLIB_TOKENIZER_KERNEL_1_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/type_safe_union/type_safe_union_kernel.h b/lib/3rdParty/dlib/include/dlib/type_safe_union/type_safe_union_kernel.h index d86e42e1..76a17128 100644 --- a/lib/3rdParty/dlib/include/dlib/type_safe_union/type_safe_union_kernel.h +++ b/lib/3rdParty/dlib/include/dlib/type_safe_union/type_safe_union_kernel.h @@ -13,6 +13,17 @@ namespace dlib { +// ---------------------------------------------------------------------------------------- + + class bad_type_safe_union_cast : public std::bad_cast + { + public: + virtual const char * what() const throw() + { + return "bad_type_safe_union_cast"; + } + }; + // ---------------------------------------------------------------------------------------- struct _void{}; @@ -105,7 +116,7 @@ namespace dlib // -------------------------------------------- template - void validate_type() + void validate_type() const { // ERROR: You are trying to get a type of object that isn't // representable by this type_safe_union. I.e. The given @@ -521,6 +532,28 @@ namespace dlib return *static_cast(mem.get()); } + template + const T& cast_to ( + ) const + { + validate_type(); + if (contains()) + return *static_cast(mem.get()); + else + throw bad_type_safe_union_cast(); + } + + template + T& cast_to ( + ) + { + validate_type(); + if (contains()) + return *static_cast(mem.get()); + else + throw bad_type_safe_union_cast(); + } + template type_safe_union& operator= ( const T& item) { get() = item; return *this; } diff --git a/lib/3rdParty/dlib/include/dlib/type_safe_union/type_safe_union_kernel_abstract.h b/lib/3rdParty/dlib/include/dlib/type_safe_union/type_safe_union_kernel_abstract.h index 2aa3bb12..3d041e6a 100644 --- a/lib/3rdParty/dlib/include/dlib/type_safe_union/type_safe_union_kernel_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/type_safe_union/type_safe_union_kernel_abstract.h @@ -9,6 +9,16 @@ namespace dlib { +// ---------------------------------------------------------------------------------------- + + class bad_type_safe_union_cast : public std::bad_cast + { + /*! + This is the exception object thrown by type_safe_union::cast_to() if the + type_safe_union does not contain the type of object being requested. + !*/ + }; + // ---------------------------------------------------------------------------------------- template < @@ -224,6 +234,32 @@ namespace dlib - returns a non-const reference to the newly created T object. !*/ + template + const T& cast_to ( + ) const; + /*! + requires + - T must be one of the types given to this object's template arguments + ensures + - if (contains() == true) then + - returns a const reference to the object contained in this type_safe_union. + - else + - throws bad_type_safe_union_cast + !*/ + + template + T& cast_to ( + ); + /*! + requires + - T must be one of the types given to this object's template arguments + ensures + - if (contains() == true) then + - returns a non-const reference to the object contained in this type_safe_union. + - else + - throws bad_type_safe_union_cast + !*/ + template type_safe_union& operator= ( const T& item diff --git a/lib/3rdParty/dlib/include/dlib/unicode/unicode.cpp b/lib/3rdParty/dlib/include/dlib/unicode/unicode.cpp deleted file mode 100644 index 2facc919..00000000 --- a/lib/3rdParty/dlib/include/dlib/unicode/unicode.cpp +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (C) 2008 Keita Mochizuki, Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. -#ifndef DLIB_UNICODe_CPp_ -#define DLIB_UNICODe_CPp_ -#include "unicode.h" -#include -#include "../string.h" -#include - -namespace dlib -{ - -// ---------------------------------------------------------------------------------------- - - static const unichar SURROGATE_FIRST_TOP = 0xD800; - static const unichar SURROGATE_SECOND_TOP = 0xDC00; - static const unichar SURROGATE_CLEARING_MASK = 0x03FF; - static const unichar SURROGATE_TOP = SURROGATE_FIRST_TOP; - static const unichar SURROGATE_END = 0xE000; - static const unichar SMP_TOP = 0x10000; - static const int VALID_BITS = 10; - -// ---------------------------------------------------------------------------------------- - - template bool is_surrogate(T ch) - { - return (zero_extend_cast(ch) >= SURROGATE_TOP && - zero_extend_cast(ch) < SURROGATE_END); - } - -// ---------------------------------------------------------------------------------------- - - template unichar surrogate_pair_to_unichar(T first, T second) - { - return ((first & SURROGATE_CLEARING_MASK) << VALID_BITS) | ((second & SURROGATE_CLEARING_MASK) + SMP_TOP); - } - //110110 0000000000 - //110111 0000000000 - -// ---------------------------------------------------------------------------------------- - - void unichar_to_surrogate_pair(unichar input, unichar &first, unichar &second) - { - first = ((input - SMP_TOP) >> VALID_BITS) | SURROGATE_FIRST_TOP; - second = (input & SURROGATE_CLEARING_MASK) | SURROGATE_SECOND_TOP; - } - -// ---------------------------------------------------------------------------------------- - - template void wstr2ustring_t(const wchar_t *src, size_t src_len, ustring &dest); - - template <> void wstr2ustring_t<4>(const wchar_t *src, size_t , ustring &dest) - { - dest.assign((const unichar *)(src)); - } - - template <> void wstr2ustring_t<2>(const wchar_t *src, size_t src_len, ustring &dest) - { - size_t wlen = 0; - for (size_t i = 0; i < src_len; i++) - { - is_surrogate(src[i]) ? i++, wlen++ : wlen++; - } - dest.resize(wlen); - for (size_t i = 0, ii = 0; ii < src_len; ++i) - { - if (is_surrogate(src[ii])) - { - dest[i] = surrogate_pair_to_unichar(src[ii], src[ii+1]); - ii += 2; - }else - { - dest[i] = zero_extend_cast(src[ii]); - ii++; - } - } - } - -// ---------------------------------------------------------------------------------------- - - const ustring convert_wstring_to_utf32(const std::wstring &src) - { - ustring dest; - wstr2ustring_t(src.c_str(), src.size(), dest); - return dest; - } - -// ---------------------------------------------------------------------------------------- - - template struct ustring2wstr - { - }; - - // for the environment of sizeof(wchar_t) == 2 (i.e. Win32) - template <> struct ustring2wstr<2> - { - wchar_t *wstr; - size_t wlen; - ustring2wstr(const ustring &src){ - wlen = 0; - for (size_t i = 0; i < src.length(); ++i) - { - if (src[i] < SMP_TOP) wlen++; - else wlen += 2; - } - wstr = new wchar_t[wlen+1]; - wstr[wlen] = L'\0'; - - size_t wi = 0; - for (size_t i = 0; i < src.length(); ++i) - { - if (src[i] < SMP_TOP) - { - wstr[wi++] = (wchar_t)src[i]; - }else - { - unichar high, low; - unichar_to_surrogate_pair(src[i], high, low); - wstr[wi++] = (wchar_t)high; - wstr[wi++] = (wchar_t)low; - } - } - } - ~ustring2wstr() - { - delete[] wstr; - } - }; - - // for the environment of sizeof(wchar_t) == 4 (i.e. Unix gcc) - template <> struct ustring2wstr<4> - { - const wchar_t *wstr; - size_t wlen; - ustring2wstr(const ustring &src){ - wstr = (const wchar_t *)(src.c_str()); - wlen = src.size(); - } - }; - -// ---------------------------------------------------------------------------------------- - - const std::wstring convert_utf32_to_wstring(const ustring &src) - { - ustring2wstr conv(src); - std::wstring dest(conv.wstr); - return dest; - } - -// ---------------------------------------------------------------------------------------- - - const std::wstring convert_mbstring_to_wstring(const std::string &src) - { - std::vector wstr(src.length()+5); - std::mbstowcs(&wstr[0], src.c_str(), src.length()+1); - return std::wstring(&wstr[0]); - } - -// ---------------------------------------------------------------------------------------- - - const std::string convert_wstring_to_mbstring(const std::wstring &src) - { - using namespace std; - std::string str; - str.resize((src.length() + 1) * MB_CUR_MAX); - wcstombs(&str[0], src.c_str(), str.size()); - return std::string(&str[0]); - } - -// ---------------------------------------------------------------------------------------- - -} - -#endif // DLIB_UNICODe_CPp_ - diff --git a/lib/3rdParty/dlib/include/dlib/unicode/unicode.h b/lib/3rdParty/dlib/include/dlib/unicode/unicode.h index f64bb006..d7510e34 100644 --- a/lib/3rdParty/dlib/include/dlib/unicode/unicode.h +++ b/lib/3rdParty/dlib/include/dlib/unicode/unicode.h @@ -289,7 +289,10 @@ namespace dlib } // ---------------------------------------------------------------------------------------- - +#if defined(__GNUC__) && __GNUC__ >= 6 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmisleading-indentation" +#endif template bool is_combining_char( const T ch_ @@ -478,6 +481,9 @@ namespace dlib if ( ch < 0xE0100 )return false;if ( ch < 0xE01F0 )return true; return false; } +#if defined(__GNUC__) && __GNUC__ >= 6 +#pragma GCC diagnostic pop +#endif // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/vectorstream.h b/lib/3rdParty/dlib/include/dlib/vectorstream.h index 921ed2e9..afeb247d 100644 --- a/lib/3rdParty/dlib/include/dlib/vectorstream.h +++ b/lib/3rdParty/dlib/include/dlib/vectorstream.h @@ -4,6 +4,7 @@ #define DLIB_VECTORSTReAMh_ #include "vectorstream/vectorstream.h" +#include "vectorstream/unserialize.h" #endif // DLIB_VECTORSTReAMh_ diff --git a/lib/3rdParty/dlib/include/dlib/vectorstream/unserialize.h b/lib/3rdParty/dlib/include/dlib/vectorstream/unserialize.h new file mode 100644 index 00000000..dbfe5584 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/vectorstream/unserialize.h @@ -0,0 +1,98 @@ +// Copyright (C) 2016 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_uNSERIALIZE_Hh_ +#define DLIB_uNSERIALIZE_Hh_ + +#include "unserialize_abstract.h" + +#include "../serialize.h" +#include "../algs.h" +#include "vectorstream.h" + + + +namespace dlib +{ + class unserialize : public std::istream + { + class mystreambuf : public std::streambuf + { + typedef std::vector::size_type size_type; + size_type read_pos; // buffer[read_pos] == next byte to read from buffer + public: + std::vector buffer; + std::istream& str; + + template + mystreambuf( + const T& item, + std::istream& str_ + ) : + read_pos(0), + str(str_) + { + // put the item into our buffer. + vectorstream vstr(buffer); + serialize(item, vstr); + } + + + // ------------------------ INPUT FUNCTIONS ------------------------ + + int_type underflow( + ) + { + if (read_pos < buffer.size()) + return static_cast(buffer[read_pos]); + else + return str.peek(); + } + + int_type uflow( + ) + { + if (read_pos < buffer.size()) + return static_cast(buffer[read_pos++]); + else + return str.get(); + } + + std::streamsize xsgetn ( + char* s, + std::streamsize n + ) + { + if (read_pos < buffer.size()) + { + const size_type num = std::min(n, buffer.size()-read_pos); + std::memcpy(s, &buffer[read_pos], num); + read_pos += num; + return num; + } + else + { + return str.rdbuf()->sgetn(s,n); + } + return 0; + } + + }; + + public: + + template + unserialize ( + const T& item, + std::istream& str + ) : + std::istream(&buf), + buf(item, str) + {} + + private: + mystreambuf buf; + }; +} + +#endif // DLIB_uNSERIALIZE_Hh_ + diff --git a/lib/3rdParty/dlib/include/dlib/vectorstream/unserialize_abstract.h b/lib/3rdParty/dlib/include/dlib/vectorstream/unserialize_abstract.h new file mode 100644 index 00000000..b7d67836 --- /dev/null +++ b/lib/3rdParty/dlib/include/dlib/vectorstream/unserialize_abstract.h @@ -0,0 +1,58 @@ +// Copyright (C) 2016 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_uNSERIALIZE_ABSTRACT_Hh_ +#ifdef DLIB_uNSERIALIZE_ABSTRACT_Hh_ + +#include "../serialize.h" +#include + +namespace dlib +{ + class unserialize : public std::istream + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a tool that allows you to effectively put an object you just + deserialized from a stream back into the stream. Its use is best + illustrated via an example. + + void example(std::istream& in) + { + // Suppose that in contains serialized copies of three "some_type" + // objects. You could read them as follows: + some_type obj1, obj2, obj3; + + deserialize(obj1, in); // reads obj1 from stream. + deserialize(obj2, in); // reads obj2 from stream. + + unserialize in2(obj2, in); // make the in2 stream that has obj2 at its front. + deserialize(obj2, in2); // reads obj2 from stream again. + deserialize(obj3, in2); // reads obj3 from stream. + } + + The reason unserialize is useful is because it allows you to peek at the + next object in a stream and potentially do something different based on + what object is coming next, but still allowing subsequent deserialize() + statements to be undisturbed by the fact that you peeked at the data. + !*/ + + public: + + template + unserialize ( + const T& item, + std::istream& in + ); + /*! + requires + - T must be serializable + ensures + - The bytes in this stream begin with a serialized copy of item followed + immediately by the bytes in the given istream. + !*/ + }; +} + +#endif // DLIB_uNSERIALIZE_ABSTRACT_Hh_ + + diff --git a/lib/3rdParty/dlib/include/dlib/windows_magic.h b/lib/3rdParty/dlib/include/dlib/windows_magic.h index dc4ff25d..f17a604b 100644 --- a/lib/3rdParty/dlib/include/dlib/windows_magic.h +++ b/lib/3rdParty/dlib/include/dlib/windows_magic.h @@ -39,10 +39,10 @@ // This is something stupid you have to do to make visual studio include the right // stuff. I don't really know what the deal is with this. -//#if _WIN32_WINNT < 0x0500 -//#undef _WIN32_WINNT -//#define _WIN32_WINNT 0x0500 -//#endif +#if _WIN32_WINNT < 0x0501 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif #endif // WIN32 diff --git a/lib/3rdParty/dlib/include/dlib/xml_parser/xml_parser_kernel_1.h b/lib/3rdParty/dlib/include/dlib/xml_parser/xml_parser_kernel_1.h index e8e2e8cd..e1854bc2 100644 --- a/lib/3rdParty/dlib/include/dlib/xml_parser/xml_parser_kernel_1.h +++ b/lib/3rdParty/dlib/include/dlib/xml_parser/xml_parser_kernel_1.h @@ -49,7 +49,7 @@ namespace dlib public: - // These typedefs are here for backwards compatibily with previous versions of + // These typedefs are here for backwards compatibly with previous versions of // dlib. typedef xml_parser kernel_1a; typedef xml_parser kernel_1a_c; @@ -103,7 +103,10 @@ namespace dlib const std::string& key ) const { - return list[key]; + if (is_in_list(key)) + return list[key]; + else + throw xml_attribute_list_error("No XML attribute named " + key + " is present in tag."); } bool at_start ( @@ -124,7 +127,7 @@ namespace dlib bool move_next ( ) const { return list.move_next(); } - unsigned long size ( + size_t size ( ) const { return list.size(); } }; @@ -354,6 +357,7 @@ namespace dlib case empty_element: is_empty = true; + // fall through case element_start: { seen_root_tag = true; @@ -1412,6 +1416,8 @@ namespace dlib error_handler& eh ) { + if (!in) + throw xml_parse_error("Unexpected end of file during xml parsing."); xml_parser parser; parser.add_document_handler(dh); parser.add_error_handler(eh); @@ -1424,6 +1430,8 @@ namespace dlib document_handler& dh ) { + if (!in) + throw xml_parse_error("Unexpected end of file during xml parsing."); xml_parser parser; parser.add_document_handler(dh); parser.add_error_handler(eh); @@ -1435,6 +1443,8 @@ namespace dlib error_handler& eh ) { + if (!in) + throw xml_parse_error("Unexpected end of file during xml parsing."); xml_parser parser; parser.add_error_handler(eh); parser.parse(in); @@ -1445,6 +1455,8 @@ namespace dlib document_handler& dh ) { + if (!in) + throw xml_parse_error("Unexpected end of file during xml parsing."); xml_parser parser; parser.add_document_handler(dh); impl::default_xml_error_handler eh; diff --git a/lib/3rdParty/dlib/include/dlib/xml_parser/xml_parser_kernel_abstract.h b/lib/3rdParty/dlib/include/dlib/xml_parser/xml_parser_kernel_abstract.h index 2cfab5c5..45b513e5 100644 --- a/lib/3rdParty/dlib/include/dlib/xml_parser/xml_parser_kernel_abstract.h +++ b/lib/3rdParty/dlib/include/dlib/xml_parser/xml_parser_kernel_abstract.h @@ -223,7 +223,7 @@ namespace dlib supplied error_handler and document_handler. throws - xml_parse_error - Thrown if there is a problem opening the input file. + Thrown if there is a problem parsing the input file. !*/ void parse_xml ( @@ -237,7 +237,7 @@ namespace dlib supplied error_handler and document_handler. throws - xml_parse_error - Thrown if there is a problem opening the input file. + Thrown if there is a problem parsing the input file. !*/ void parse_xml ( @@ -250,7 +250,7 @@ namespace dlib supplied error_handler. throws - xml_parse_error - Thrown if there is a problem opening the input file. + Thrown if there is a problem parsing the input file. !*/ void parse_xml ( @@ -265,8 +265,7 @@ namespace dlib if a fatal parsing error is encountered. throws - xml_parse_error - Thrown if a fatal parsing error is encountered or if there is a problem - opening the input file. + Thrown if there is a problem parsing the input file. !*/ // ---------------------------------------------------------------------------------------- diff --git a/lib/3rdParty/dlib/include/dlib/xml_parser/xml_parser_kernel_interfaces.h b/lib/3rdParty/dlib/include/dlib/xml_parser/xml_parser_kernel_interfaces.h index a49d5339..a0edf331 100644 --- a/lib/3rdParty/dlib/include/dlib/xml_parser/xml_parser_kernel_interfaces.h +++ b/lib/3rdParty/dlib/include/dlib/xml_parser/xml_parser_kernel_interfaces.h @@ -6,10 +6,24 @@ #include #include "../interfaces/enumerable.h" #include "../interfaces/map_pair.h" +#include "../error.h" namespace dlib { +// ---------------------------------------------------------------------------------------- + + class xml_attribute_list_error : public dlib::error + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an exception object thrown by attribute_list objects if you try to + access a non-existent attribute. + !*/ + public: + xml_attribute_list_error(const std::string& msg) : dlib::error(msg){} + }; + // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- @@ -43,11 +57,12 @@ namespace dlib const std::string& key ) const =0; /*! - requires - - is_in_list(key) == true ensures - - returns a const reference to the value associated with the - attribute named key. + if (is_in_list(key) == true) then + - returns a const reference to the value associated with the attribute + named key. + - else + - throws xml_attribute_list_error !*/ protected: diff --git a/lib/3rdParty/dlib/installation_instructions.txt b/lib/3rdParty/dlib/installation_instructions.txt new file mode 100644 index 00000000..d8fb62d2 --- /dev/null +++ b/lib/3rdParty/dlib/installation_instructions.txt @@ -0,0 +1,11 @@ +We are using dlib 19.13, the libraries are pre-built for convenience, they were built using the following commands + +For win 64 bit +cmake -G "Visual Studio 14 2015 Win64" -DDLIB_JPEG_SUPPORT=0 -DDLIB_PNG_SUPPORT=0 -DDLIB_NO_GUI_SUPPORT=1 -DDLIB_ISO_CPP_ONLY=0 -DENABLE_ASSERTS=0 -DCMAKE_INSTALL_PREFIX=install .. +cmake --build . --config Debug --target INSTALL +cmake --build . --config R --target INSTALL + +For win 32 bit +cmake -G "Visual Studio 14 2015" -DDLIB_JPEG_SUPPORT=0 -DDLIB_PNG_SUPPORT=0 -DDLIB_NO_GUI_SUPPORT=1 -DDLIB_ISO_CPP_ONLY=0 -DENABLE_ASSERTS=0 -DCMAKE_INSTALL_PREFIX=install .. +cmake --build . --config Debug --target INSTALL +cmake --build . --config R --target INSTALL diff --git a/lib/3rdParty/dlib/lib/x64/v140/Debug/dlib.lib b/lib/3rdParty/dlib/lib/x64/v140/Debug/dlib.lib new file mode 100644 index 00000000..8a1f7126 Binary files /dev/null and b/lib/3rdParty/dlib/lib/x64/v140/Debug/dlib.lib differ diff --git a/lib/3rdParty/dlib/lib/x64/v140/Release/dlib.lib b/lib/3rdParty/dlib/lib/x64/v140/Release/dlib.lib new file mode 100644 index 00000000..d0887548 Binary files /dev/null and b/lib/3rdParty/dlib/lib/x64/v140/Release/dlib.lib differ diff --git a/lib/3rdParty/dlib/lib/x86/v140/Debug/dlib.lib b/lib/3rdParty/dlib/lib/x86/v140/Debug/dlib.lib new file mode 100644 index 00000000..5ef42eb6 Binary files /dev/null and b/lib/3rdParty/dlib/lib/x86/v140/Debug/dlib.lib differ diff --git a/lib/3rdParty/dlib/lib/x86/v140/Release/dlib.lib b/lib/3rdParty/dlib/lib/x86/v140/Release/dlib.lib new file mode 100644 index 00000000..2a701475 Binary files /dev/null and b/lib/3rdParty/dlib/lib/x86/v140/Release/dlib.lib differ diff --git a/lib/local/CppInerop/CppInerop.vcxproj b/lib/local/CppInerop/CppInerop.vcxproj index d35e77b2..8679dd33 100644 --- a/lib/local/CppInerop/CppInerop.vcxproj +++ b/lib/local/CppInerop/CppInerop.vcxproj @@ -194,9 +194,6 @@ {50b7d4bf-e33b-41d0-aa89-76bba57bf5cc} - - {b47a5f12-2567-44e9-ae49-35763ec82149} - {0e7fc556-0e80-45ea-a876-dde4c2fedcd7} diff --git a/lib/local/FaceAnalyser/FaceAnalyser.vcxproj b/lib/local/FaceAnalyser/FaceAnalyser.vcxproj index 8b6c7929..76872172 100644 --- a/lib/local/FaceAnalyser/FaceAnalyser.vcxproj +++ b/lib/local/FaceAnalyser/FaceAnalyser.vcxproj @@ -186,9 +186,6 @@ - - {b47a5f12-2567-44e9-ae49-35763ec82149} - {bdc1d107-de17-4705-8e7b-cdde8bfb2bf8} diff --git a/lib/local/LandmarkDetector/LandmarkDetector.vcxproj b/lib/local/LandmarkDetector/LandmarkDetector.vcxproj index fb1444df..7d40dbef 100644 --- a/lib/local/LandmarkDetector/LandmarkDetector.vcxproj +++ b/lib/local/LandmarkDetector/LandmarkDetector.vcxproj @@ -271,9 +271,6 @@ xcopy /I /E /Y /D "$(SolutionDir)lib\3rdParty\OpenCV3.4\classifiers" "$(OutDir)c - - {b47a5f12-2567-44e9-ae49-35763ec82149} - {8e741ea2-9386-4cf2-815e-6f9b08991eac} diff --git a/lib/local/Utilities/Utilities.vcxproj b/lib/local/Utilities/Utilities.vcxproj index 976a766f..a61f4e68 100644 --- a/lib/local/Utilities/Utilities.vcxproj +++ b/lib/local/Utilities/Utilities.vcxproj @@ -181,11 +181,6 @@ - - - {b47a5f12-2567-44e9-ae49-35763ec82149} - -